Conversation
…y uses it RoleRepository.Delete locks the live role row, then sets deleted_at unless a live policy still references the role. A missing or already deleted role reports not found, and a role in use reports ErrRoleInUse as before. The service comments no longer describe the foreign key.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. 📝 SummarySummary by CodeRabbit
WalkthroughRole deletion now locks the live role row and soft-deletes it only when no live policy references it. Tests cover repository outcomes, concurrent policy insertion, repeated API operations, and role recreation. ChangesRole deletion
Priority: ⬇️ Low Estimated code review effort: 3 (Moderate) | ~25 minutes Change: Feature Suggested reviewers: Merge Risk: 🔵 Low · up to Concurrent policy creation and role deletion can leave a policy referencing a deleted role. The risk is narrow but remains actionable; make live-role validation transactional with policy insertion. Security Architecture ReviewSecurity architecture risk: 🟡 Moderate · up to A policy request that started before deletion can still attach to the deleted role. Successful permission cleanup prevents that binding from granting access, but interrupted or failed cleanup can leave grants effective while ordinary deletion retries report the role as missing. Retained concerns
Security review detailsSecurity Blast Radius
Security Findings and Attack Paths
Trust Boundaries and Controls
Resilience and Maintainability Implications
Hardening Proposals
🚥 Pre-merge checks | ✅ 2✅ Passed checks (2 passed)
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 |
There was a problem hiding this comment.
Actionable comments posted: 1
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository: raystack/frontier/.coderabbit.yaml
Review profile: CHILL
Plan: Advanced
Run ID: bfb29883-47d8-45d9-be06-5d00de963b26
📒 Files selected for processing (5)
core/role/service.gocore/role/service_test.gointernal/store/postgres/role_repository.gointernal/store/postgres/role_repository_test.gotest/e2e/regression/api_test.go
Included review availability: This review used your included allowance. Your plan provides up to 2 included reviews per hour; 1 remain after this review.
Coverage Report for CI Build 36825456600Coverage increased (+0.03%) to 53.003%Details
Uncovered Changes
Coverage RegressionsNo coverage regressions found. Coverage Stats
💛 - Coveralls |
rohilsurana
left a comment
There was a problem hiding this comment.
Looks good. Checked the lock and delete order, the error mapping, and that every other read of roles skips deleted rows. The policy-side live-role check is planned as the follow-up.
Summary
DeleteOrganizationRoleandDeleteRolenow setdeleted_aton the role row instead of removing it. The check that refuses the delete of a role still in use moves from thepolicies.role_idforeign key into the delete query. Callers get the same responses as before.Changes
RoleRepository.Deleteruns one transaction with two statements. The first locks the live role row withSELECT ... FOR UPDATE; no row means not found. The second setsdeleted_atthroughsoftDelete(feat(store): add a helper that marks rows as deleted #1959), only when no live policy references the role; no row changed meansErrRoleInUse.DELETEwaited on the foreign key. The check then sees that policy.role.Service.Deletekeeps its flow: read the role, delete it, remove the role's permission tuples from SpiceDB. Only its comments change. The organization delete cascade uses the same path.ErrRoleInUsetoFailedPreconditionandErrNotExisttoNotFound.Technical Details
Role reads skip deleted rows (#1938) and role names are unique among live rows only (#1961), so a deleted name can be created again and lands on a new row.
The
policies.role_idforeign key stays. It never fires on the soft delete because the role row stays. A policy insert that waits for a role delete to commit still succeeds today, because the row it points at exists. The check that the role is live on the policy side comes with the policy soft delete.roles.org_idhas no foreign key, so the kept rows do not block the organization delete, which is still a hard delete.Test Plan
go test ./internal/store/postgres/passes. NewTestDeletecases: the row stays, a second delete reports not found, a live policy makes the delete report in use and the role stays readable, deleted policies do not block, and the delete waits for an uncommitted policy insert and then reports in use.go test ./core/role/andgo test ./core/deleter/pass.TestOrganizationRoleDeleteInUse(e2e) gains: get returns not found, a second delete returns not found, the same name is created again with a new id, and the organization delete still works. These steps also pass againstmain; the repository test is what checks that the row is kept.main's hard delete fails three of them, removing the lock fails the waiting case, removing the policy check fails the in-use and waiting cases.golangci-lint runreports no issues.mainon the same database, with only the binary swapped.deleted_atsetdeleted_atsetAdminService) while a policy uses itdeleted_atsetThe last three rows hold the policy insert open in a
psqltransaction and watchpg_stat_activityfor the waiting session.SQL Safety
goqu.Ex{}; theNOT EXISTSsubquery is built from goqu expressions with no caller input.ToSQL()callers capture and forward params (query, params, err := stmt.ToSQL(); db.…Context(ctx, …, query, params...)). Neverquery, _, err := ….?placeholders inside single-quoted SQL literals ingoqu.L.//nolint:forbidigoor// #nosec G20xannotations.