fix(serviceuser): symmetric SpiceDB cleanup on delete#1630
Conversation
SU creation writes both Subject-side relations (e.g. platform sudo) and Object-side relations (the serviceuser#org identity link). Delete only swept the Subject side, so the identity-link tuple leaked whenever the membership cascade was skipped — most commonly when the SU had no remaining org policies at delete time, since RemoveOrganizationMember returns ErrNotMember early and never reaches the cascade where that cleanup lives. Add an Object-side wildcard delete after the existing Subject-side one, tolerating relation.ErrNotExist. Same shape as the policy.Delete fix. Also add a mockery entry for core/serviceuser and seed unit coverage for Service.Delete (happy path, membership-failure-swallowed path, ErrNotExist tolerance, both failure short-circuit paths). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (7)
📝 WalkthroughSummary by CodeRabbitRelease Notes
WalkthroughThis PR fixes a relation tuple leak in service user deletion by making the cleanup symmetric. It adds mockery configuration to generate test mocks, updates Service.Delete to clean relations where the service user is the object (not just subject), and provides comprehensive test coverage for the corrected behavior. ChangesService User Delete Cleanup
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 2✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Coverage Report for CI Build 26141719376Coverage increased (+0.1%) to 42.554%Details
Uncovered ChangesNo uncovered changes found. Coverage RegressionsNo coverage regressions found. Coverage Stats
💛 - Coveralls |
Manual verification — direct SpiceDB tuple inspectionTested against a local Frontier (PR1630 build) with SpiceDB on Postgres. For each case I snapshot the
The SQL probe used at every checkpoint: SELECT namespace, object_id, relation, userset_namespace, userset_object_id
FROM relation_tuple
WHERE deleted_xid = '9223372036854775807'::xid8
AND (object_id = '<SU>' OR userset_object_id = '<SU>'); |
Problem
serviceuser.Service.Deleteleaks theapp/serviceuser:<su>#org@app/organization:<org>identity-link tuple when the SU has no remaining org policies at delete time.Chain:
Deletecallsmembership.RemoveOrganizationMemberbest-effort.RemoveOrganizationMemberreturnsErrNotMemberearly when the SU has zero org policies — never reachescascadeRemovePrincipal, where the identity-link cleanup lives.relationService.Delete(Subject={SU})only sweeps tuples where the SU is the Subject. The identity link has the SU as the Object — missed.Result: tuple lives in SpiceDB forever, even though the SU row is gone.
Fix
Add a second
relationService.Deleteafter the existing Subject-side one, keyed by Object on the SU. Toleratesrelation.ErrNotExistfor forward-compat. Same shape as #1624.Tests
New
core/serviceuser/service_test.gocovers:ErrNotExistfrom Object-side sweep is toleratedErrNotExistObject-side failure blocks repo deleteAlso added a
core/serviceusermockery entry and the generated mocks.Closes #1629.
🤖 Generated with Claude Code