-
Notifications
You must be signed in to change notification settings - Fork 73
Fix workspace name uniqueness to be scoped per user #1007
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -28,3 +28,42 @@ func migration() *gormigrate.Migration { | |
| }, | ||
| } | ||
| } | ||
|
|
||
| func ownerUserIdMigration() *gormigrate.Migration { | ||
| migrateStatements := []string{ | ||
| // Add owner_user_id column with a default empty string for existing rows | ||
| `ALTER TABLE projects ADD COLUMN IF NOT EXISTS owner_user_id TEXT NOT NULL DEFAULT ''`, | ||
| // Drop the old unique index on name only | ||
| `DROP INDEX IF EXISTS idx_projects_name`, | ||
| // Create composite unique index on (owner_user_id, name) | ||
| `CREATE UNIQUE INDEX IF NOT EXISTS idx_owner_name ON projects(owner_user_id, name)`, | ||
| } | ||
| rollbackStatements := []string{ | ||
| // Drop the composite unique index | ||
| `DROP INDEX IF EXISTS idx_owner_name`, | ||
| // Recreate the old unique index on name only | ||
| `CREATE UNIQUE INDEX IF NOT EXISTS idx_projects_name ON projects(name)`, | ||
| // Drop the owner_user_id column | ||
| `ALTER TABLE projects DROP COLUMN IF EXISTS owner_user_id`, | ||
| } | ||
|
Comment on lines
+32
to
+48
Contributor
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. 🧹 Nitpick | 🔵 Trivial Consider data backfill for existing projects. Existing projects will have 🤖 Prompt for AI Agents
Comment on lines
+41
to
+48
Contributor
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. Rollback may fail if duplicate names exist. If users create projects with identical names (under different 🤖 Prompt for AI Agents |
||
|
|
||
| return &gormigrate.Migration{ | ||
| ID: "202603240001", | ||
| Migrate: func(tx *gorm.DB) error { | ||
| for _, stmt := range migrateStatements { | ||
| if err := tx.Exec(stmt).Error; err != nil { | ||
| return err | ||
| } | ||
| } | ||
| return nil | ||
| }, | ||
| Rollback: func(tx *gorm.DB) error { | ||
| for _, stmt := range rollbackStatements { | ||
| if err := tx.Exec(stmt).Error; err != nil { | ||
| return err | ||
| } | ||
| } | ||
| return nil | ||
| }, | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,7 +7,8 @@ import ( | |
|
|
||
| type Project struct { | ||
| api.Meta | ||
| Name string `json:"name" gorm:"uniqueIndex;not null"` | ||
| OwnerUserId string `json:"owner_user_id" gorm:"uniqueIndex:idx_owner_name;not null"` | ||
| Name string `json:"name" gorm:"uniqueIndex:idx_owner_name;not null"` | ||
| DisplayName *string `json:"display_name"` | ||
| Description *string `json:"description"` | ||
| Labels *string `json:"labels"` | ||
|
|
@@ -27,7 +28,7 @@ func (l ProjectList) Index() ProjectIndex { | |
| } | ||
|
|
||
| func (d *Project) BeforeCreate(tx *gorm.DB) error { | ||
| d.ID = d.Name | ||
| d.ID = api.NewID() | ||
| return nil | ||
|
Comment on lines
30
to
32
Contributor
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. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Search for any code that might construct project IDs from names
rg -n -C2 'project.*[Ii][Dd].*[Nn]ame|[Nn]ame.*project.*[Ii][Dd]' --type goRepository: ambient-code/platform Length of output: 1790 🏁 Script executed: #!/bin/bash
# Try to list files in the project to understand structure
git ls-files components/ambient-api-server/plugins/projects/ 2>/dev/null | head -20Repository: ambient-code/platform Length of output: 1888 🏁 Script executed: #!/bin/bash
# Search for previous version of the model.go file or any git history
# First, check what files exist and search for ID-related patterns
find . -name "*.go" -path "*projects*" -type f 2>/dev/null | head -10Repository: ambient-code/platform Length of output: 732 🏁 Script executed: #!/bin/bash
# Search for NewID function definition to understand its nature
rg -n "func NewID|type.*NewID" --type go 2>/dev/null | head -20Repository: ambient-code/platform Length of output: 47 🏁 Script executed: #!/bin/bash
# Search for Project struct definition and BeforeCreate
rg -n "type.*Project|BeforeCreate" --type go -A 3 2>/dev/null | head -40Repository: ambient-code/platform Length of output: 3038 🏁 Script executed: #!/bin/bash
# List all go files in projects directory to see actual structure
ls -la components/ambient-api-server/plugins/projects/*.go 2>/dev/nullRepository: ambient-code/platform Length of output: 1718 🏁 Script executed: #!/bin/bash
# Search for ID assignment patterns in projects
rg -n "d\.ID\s*=" --type go 2>/dev/null | grep -i projectRepository: ambient-code/platform Length of output: 229 🏁 Script executed: #!/bin/bash
# Read the complete model.go file
cat -n components/ambient-api-server/plugins/projects/model.goRepository: ambient-code/platform Length of output: 1471 🏁 Script executed: #!/bin/bash
# Search for git history of model.go to see what changed
git log --oneline -20 -- components/ambient-api-server/plugins/projects/model.go 2>/dev/nullRepository: ambient-code/platform Length of output: 124 🏁 Script executed: #!/bin/bash
# Search for any documentation or tests mentioning Project ID generation
rg -n "NewID|project.*id|ID.*project" --type go -i components/ambient-api-server/plugins/projects/ 2>/dev/null | head -30Repository: ambient-code/platform Length of output: 4225 🏁 Script executed: #!/bin/bash
# Search for any external API contracts or client code that might use Project IDs
rg -n "project.*id|construct.*id|derive.*id" --type go -i 2>/dev/null | grep -v ".pb.go" | head -20Repository: ambient-code/platform Length of output: 2339 🏁 Script executed: #!/bin/bash
# Get the actual diff for the commit that touched model.go
git show f246df6 -- components/ambient-api-server/plugins/projects/model.go 2>/dev/null | head -50Repository: ambient-code/platform Length of output: 1889 🏁 Script executed: #!/bin/bash
# Search for any comments in the codebase about ID generation
rg -n "deterministic|construct.*id|derive.*id|from.*name" --type go -i 2>/dev/null | head -20Repository: ambient-code/platform Length of output: 2329 🏁 Script executed: #!/bin/bash
# Search git log more broadly for projects changes
git log --oneline -50 -- components/ambient-api-server/plugins/projects/ 2>/dev/nullRepository: ambient-code/platform Length of output: 124 🏁 Script executed: #!/antml/bash
# Look for any test files that might indicate ID expectations
rg -n "NewID|project.*id|SetID" --type go components/ambient-api-server/plugins/projects/ -A 2 2>/dev/null | grep -i testRepository: ambient-code/platform Length of output: 47 🏁 Script executed: #!/bin/bash
# Search for release notes, changelog, or migration guides
find . -type f \( -name "CHANGELOG*" -o -name "RELEASE*" -o -name "MIGRATION*" -o -name "*.md" \) 2>/dev/null | head -20Repository: ambient-code/platform Length of output: 812 🏁 Script executed: #!/bin/bash
# Search for any comments or documentation about the ID change
rg -n "unique.*id|breaking.*change|project.*id" --type md -i 2>/dev/null | head -30Repository: ambient-code/platform Length of output: 4840 🏁 Script executed: #!/bin/bash
# Check if the commit mentions anything about documentation
git show f246df6 --stat 2>/dev/null | head -20Repository: ambient-code/platform Length of output: 968 Project ID generation changed from deterministic to UUID—ensure release notes document this breaking change. The commit "Fix workspace name uniqueness to be scoped per user" changed Project ID generation from 🤖 Prompt for AI Agents |
||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -101,4 +101,5 @@ func init() { | |
| }) | ||
|
|
||
| db.RegisterMigration(migration()) | ||
| db.RegisterMigration(ownerUserIdMigration()) | ||
| } | ||
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.
Missing validation when username is unavailable.
If
GetUsernameFromContextreturns an empty string, the project is created withowner_user_id = "". This defeats the per-user uniqueness goal since all such projects share the empty-owner namespace. Although auth middleware should block unauthenticated requests, defensively returning an error here prevents silent creation of orphaned projects.Proposed fix
📝 Committable suggestion
🤖 Prompt for AI Agents