-
Notifications
You must be signed in to change notification settings - Fork 281
fix(dashboard-api): team name validation in dashboard API #2347
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,6 +6,7 @@ | |
| "errors" | ||
| "io" | ||
| "net/http" | ||
| "regexp" | ||
| "strings" | ||
|
|
||
| "github.com/gin-gonic/gin" | ||
|
|
@@ -18,6 +19,8 @@ | |
| "github.com/e2b-dev/infra/packages/shared/pkg/telemetry" | ||
| ) | ||
|
|
||
| var teamNamePattern = regexp.MustCompile(`^[a-zA-Z0-9]+(?:[ _.-][a-zA-Z0-9]+)*$`) | ||
|
|
||
| func (s *APIStore) PatchTeamsTeamID(c *gin.Context, teamID api.TeamID) { | ||
| ctx := c.Request.Context() | ||
| telemetry.ReportEvent(ctx, "update team") | ||
|
|
@@ -42,10 +45,15 @@ | |
| return | ||
| } | ||
|
|
||
| if body.NameSet && strings.TrimSpace(body.Name) == "" { | ||
| s.sendAPIStoreError(c, http.StatusBadRequest, "Name must not be empty") | ||
| if body.NameSet { | ||
| name, err := validateUpdateTeamName(body.Name) | ||
| if err != nil { | ||
| s.sendAPIStoreError(c, http.StatusBadRequest, err.Error()) | ||
|
|
||
| return | ||
| return | ||
| } | ||
|
|
||
| body.Name = name | ||
| } | ||
|
|
||
| row, err := s.db.UpdateTeam(ctx, queries.UpdateTeamParams{ | ||
|
|
@@ -84,6 +92,23 @@ | |
| return &b.Name | ||
| } | ||
|
|
||
| func validateUpdateTeamName(name string) (string, error) { | ||
| trimmedName := strings.TrimSpace(name) | ||
| if trimmedName == "" { | ||
| return "", errors.New("Team name cannot be empty") | ||
| } | ||
|
|
||
| if len(trimmedName) > 32 { | ||
| return "", errors.New("Team name cannot be longer than 32 characters") | ||
| } | ||
|
|
||
| if !teamNamePattern.MatchString(trimmedName) { | ||
| return "", errors.New("Names can only contain letters and numbers, separated by spaces, underscores, hyphens, or dots") | ||
| } | ||
|
|
||
|
Check failure on line 108 in packages/dashboard-api/internal/handlers/team_update.go
|
||
|
Comment on lines
+95
to
+108
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔴 The Extended reasoning...What the bug is and how it manifests The PR introduces The specific code path that triggers it
Why existing code doesn't prevent it The What the impact would be The PR's documented goal—"trim names server-side before persisting so backend behavior matches the dashboard zod schema"—is not met. A client that sends a whitespace-padded name (e.g. from a form that does not pre-trim) receives a 400 rejection instead of having the name silently normalized. This is a stricter policy than the dashboard's own behavior, creating an inconsistency rather than parity. Additionally, the How to fix it Two consistent options exist:
Step-by-step proof
|
||
| return trimmedName, nil | ||
| } | ||
|
|
||
| func parseUpdateTeamBody(bodyReader io.Reader) (updateTeamBody, error) { | ||
| var body updateTeamBody | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -460,11 +460,13 @@ components: | |
| UpdateTeamRequest: | ||
| type: object | ||
| minProperties: 1 | ||
| additionalProperties: false | ||
| properties: | ||
| name: | ||
| type: string | ||
| minLength: 1 | ||
| maxLength: 255 | ||
| maxLength: 32 | ||
| pattern: '^[a-zA-Z0-9]+(?:[ _.-][a-zA-Z0-9]+)*$' | ||
|
Comment on lines
+468
to
+469
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Useful? React with 👍 / 👎. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OpenAPI pattern prevents server-side whitespace trimmingMedium Severity The OpenAPI spec Additional Locations (1)Reviewed by Cursor Bugbot for commit 307762d. Configure here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The pattern added here rejects strings with leading/trailing whitespace at the oapi request-validator middleware layer, before the handler's The If accepting untrimmed inputs is intentional, remove or widen the pattern in the spec. If the middleware should always reject them, the |
||
| profilePictureUrl: | ||
| type: string | ||
| nullable: true | ||
|
|
||


There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New test uses manual assertions instead of testify
Low Severity
The new
TestValidateUpdateTeamNamefunction uses manualt.Fatalfcomparisons (e.g.if err == nil { t.Fatalf(...) },if got != tt.expected { t.Fatalf(...) }) instead ofrequire.NoError,require.Error,require.EqualError, andassert.Equalfromgithub.com/stretchr/testify. This violates the team convention for unified test failure messages.Triggered by learned rule: Use testify require/assert instead of manual t.Errorf in Go tests
Reviewed by Cursor Bugbot for commit 307762d. Configure here.