fix(auth/seed): relocate Purchaser group to free UUID + recover admin-backfill (closes #942) - #943
Conversation
…-backfill (closes #942) Migration 000057 claimed UUID 00000000-0000-5000-8000-000000000005 for "Standard Users". Migration 000059 tried to seed "Purchaser" at the same UUID and ended with ON CONFLICT (id) DO NOTHING, silently no-op'ing on every database that ran both migrations. Admins never received execute:purchases / approve-any:purchases / retry-any:purchases. Migration 000064 relocates Purchaser to 00000000-0000-5000-8000-000000000007 (the next free UUID in the seeded namespace). The DO block handles three cases: relocate an existing Purchaser at a wrong UUID, insert a fresh row when none exists (the common bug-case), and fall through if already at the target UUID. The admin-backfill UPDATE re-runs idempotently so all Administrators members also join Purchaser. A pre-run guard RAISE EXCEPTION if the new UUID is claimed by a different group, preventing a repeat of the same silent-collision bug class. Updates DefaultPurchaserGroupID (internal/auth/types.go) and PURCHASER_GROUP_ID (frontend/src/permissions.ts) to match. Adds an integration test that covers: Purchaser existence at new UUID after full migration run, admin-backfill fires on 000064, and idempotency.
|
@coderabbitai review |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughMigration 000064 relocates the Purchaser system group from UUID ChangesPurchaser Group UUID Relocation and Backfill
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Suggested labels
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
✅ Action performedReview finished.
|
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
frontend/src/permissions.ts (1)
80-86:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winUpdate the Purchaser migration reference comment to match the relocation.
The constant value is correct, but the docblock still references the old seed migration path and not the 000064 relocation context used by this UUID.
Proposed doc fix
- * Well-known group UUID for the Purchaser group seeded by migration - * 000058 (issue `#923`). The three money-spending verbs + * Well-known group UUID for the Purchaser group relocated by migration + * 000064 (issue `#942`; originally seeded for issue `#923`). The three money-spending verbs🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@frontend/src/permissions.ts` around lines 80 - 86, Update the docblock above PURCHASER_GROUP_ID to reference the correct migration/relocation context (000064) instead of the old seed migration path (000058); locate the doc comment for the exported constant PURCHASER_GROUP_ID and change the migration reference text to mention the 000064 relocation context so the comment matches the actual relocation used for this UUID.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@frontend/src/permissions.ts`:
- Around line 80-86: Update the docblock above PURCHASER_GROUP_ID to reference
the correct migration/relocation context (000064) instead of the old seed
migration path (000058); locate the doc comment for the exported constant
PURCHASER_GROUP_ID and change the migration reference text to mention the 000064
relocation context so the comment matches the actual relocation used for this
UUID.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: bc9749fd-55af-4ad5-9ce2-299b9bbf3e50
📒 Files selected for processing (5)
frontend/src/permissions.tsinternal/auth/types.gointernal/database/postgres/migrations/000064_relocate_purchaser_group.down.sqlinternal/database/postgres/migrations/000064_relocate_purchaser_group.up.sqlinternal/database/postgres/migrations/000064_relocate_purchaser_group_test.go
…gration 000064 Update the comment above PURCHASER_GROUP_ID to reference the relocation migration 000064 (issue #942) instead of the original seed migration path (000058), as the UUID was relocated by the purchaser-uuid-collision fix.
|
@coderabbitai review |
✅ Action performedReview finished.
|
|
@coderabbitai review |
✅ Action performedReview finished.
|
Root cause
Migration
000057_drop_user_role_to_groups.up.sql:18seeds "Standard Users" at UUID00000000-0000-5000-8000-000000000005. Migration000059_seed_purchaser_group.up.sql:45-62later tries to seed "Purchaser" at the same UUID. Because 000057 runs first and 000059 ends withON CONFLICT (id) DO NOTHING, the Purchaser INSERT is silently no-op'd on every database that applied both migrations. The guard in 000059 only catches a name collision, not a UUID collision from the other direction.The admin-backfill UPDATE in 000059 then attaches admins to "Standard Users" (the actual occupant of
...000005), not to Purchaser. Full admins end up withoutexecute:purchases,approve-any:purchases, andretry-any:purchases-- all three verbs carved out ofadmin:*by issue #923.Closes #942.
Fix
Migration
000064_relocate_purchaser_group.up.sqlrelocates Purchaser to00000000-0000-5000-8000-000000000007(the next free UUID:...000005= Standard Users,...000006= Read-Only Users,...000007= Purchaser).The
DO $$block handles all three states a database can be in:group_idsreferences then relocate the group row.A pre-run guard
RAISE EXCEPTIONfires if...000007is taken by a different group, preventing the same class of silent UUID collision.The admin-backfill
UPDATEre-runs idempotently so all Administrators group members join Purchaser, restoring the intent of 000059's backfill.DefaultPurchaserGroupIDininternal/auth/types.goandPURCHASER_GROUP_IDinfrontend/src/permissions.tsare updated to...000007.Risk surface
system_managedcolumn added by 000059 is preserved; the group row moves, it is not deleted and re-inserted (Case 1). Case 2 inserts withsystem_managed = TRUE.PURCHASER_GROUP_IDis imported symbolically in all tests; no test hardcodes the old UUID for Purchaser, so the update is safe.Test plan
TestMigration_RelocatePurchaserGroup/Purchaser_seeded_at_new_UUID_after_full_migration_runasserts Purchaser exists at...000007after all migrations run.TestMigration_RelocatePurchaserGroup/admin-backfill:_Administrators_members_land_in_Purchaserverifies the backfill fires when 000064 is applied.TestMigration_RelocatePurchaserGroup/idempotent:_re-running_migrations_does_not_duplicate_Purchaser_membershipverifies theDISTINCT(unnest)guard.go build ./...passes.go vet ./internal/auth/... ./internal/database/...passes.Summary by CodeRabbit