Skip to content

fix(resource): deleting a resource also deletes the policies on it - #2015

Merged
AmanGIT07 merged 2 commits into
mainfrom
fix/resource-delete-removes-policies
Oct 23, 2026
Merged

AmanGIT07 merged 2 commits into
mainfrom
fix/resource-delete-removes-policies

Conversation

@AmanGIT07

@AmanGIT07 AmanGIT07 commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Deleting a resource now also deletes the policies granted on it. Before, the delete removed the resource's SpiceDB relations and soft-deleted its row, but each policy on it kept its row and its two role binding relations, and ListPolicies and GetPolicy still returned it. This applies to DeleteProjectResource, DeleteOrganizationResource, and the organization delete for the org's own resources. The project delete reaches it once #2013 replaces its Purge call with Delete.

Closes #1993 together with #2013.

Changes

  • core/policy/filter.go: Filter gains ResourceID.
  • internal/store/postgres/policy_repository.go: List and Count filter on resource_id when ResourceID is set.
  • core/resource/service.go: Delete lists the live policies on the resource by the id and namespace stored on the resource and deletes each one with policy.Service.Delete, before it deletes the resource's relations and row. A policy that is already gone is skipped. Any other error stops the delete and leaves the resource in place; the policies deleted before it stay deleted, and a retry deletes the rest.

Technical Details

  • policy.Service.Delete removes the policy's role binding relations, then soft-deletes the row and writes the policy.deleted audit record in the same transaction. No app.policy.deleted event is published; only the DeletePolicy RPC publishes it, and the project delete removes its policies the same way.
  • Policies left on resources deleted before this change stay as they are.
  • Deleting all of a resource's policies or none of them needs a transaction around the whole delete, which the service layer does not have yet.
  • The resource_id condition uses the existing policies_resource_id_resource_type_idx index.

Test Plan

  • core/resource/service_test.go TestDelete: the policies on the resource are deleted before its relations and row; a policy that is already gone is skipped; a failed policy list or a failed policy delete leaves the relations and row alone, and the policies after a failed delete are not tried; the lookup uses the namespace stored on the resource, not the one the caller passed. The other cases that reach the delete expect the policy lookup.
  • internal/store/postgres/policy_repository_test.go TestList: ResourceID returns the policies on that resource and none for another id.
  • e2e TestResourceAPI case 4: after DeleteProjectResource, ListPolicies for the user granted a role on the resource is empty, GetPolicy answers not found, the user's permission on the resource is gone, and the policy's two role binding rows in relations are marked deleted.
  • e2e TestResourceAPI case 7: after DeleteOrganizationResource, GetPolicy for the member's policy on the resource answers not found.
  • Without the policy step, the unit cases and both e2e checks fail, while the permission check alone still passes because the resource delete already removes the resource's own relations; the relations check catches it. Without the resource_id condition, the repository case fails.
  • go test ./core/... ./internal/api/... and the policy repository suite pass.
  • e2e TestEndToEndAPIRegressionTestSuite, TestEndToEndServiceRegistrationRegressionTestSuite, TestEndToEndPATRegressionTestSuite, TestEndToEndServiceUsersRegressionTestSuite and TestEndToEndOnboardingRegressionTestSuite pass.
  • golangci-lint run ./core/resource/... ./core/policy/... ./internal/store/postgres/... ./test/e2e/regression/... reports no issues.

SQL Safety

  • The new condition passes resource_id through goqu.Ex{}.
  • ToSQL() callers capture and forward params (query, params, err := stmt.ToSQL(); db.…Context(ctx, …, query, params...)). Never query, _, err := ….
  • No ? placeholders inside single-quoted SQL literals in goqu.L.
  • No new //nolint:forbidigo or // #nosec G20x annotations.

Delete now lists the live policies on the resource and deletes each one
through the policy service before it removes the resource's relations and
row. A policy that is already gone is skipped; any other error stops the
delete. policy.Filter gains ResourceID for the lookup.
@coveralls

coveralls commented Oct 21, 2026 •

Copy link
Copy Markdown

Coverage Report for CI Build 39773582069

Warning

Build has drifted: This PR's base is out of sync with its target branch, so coverage data may include unrelated changes.
Quick fix: rebase this PR. Learn more →

Coverage increased (+0.08%) to 55.67%

Details

  • Coverage increased (+0.08%) from the base build.
  • Patch coverage: 18 of 18 lines across 2 files are fully covered (100%).
  • 280 coverage regressions across 7 files.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

280 previously-covered lines in 7 files lost coverage.

File Lines Losing Coverage Coverage
core/deleter/service.go 74 81.9%
billing/customer/service.go 60 36.0%
internal/store/postgres/billing_customer_repository.go 51 64.2%
internal/store/postgres/billing_transactions_repository.go 42 71.92%
core/deleter/delete_notice.go 34 77.22%
billing/credit/service.go 12 64.96%
core/audit/audit.go 7 0.0%

Coverage Stats

Coverage Status
Relevant Lines: 41879
Covered Lines: 23314
Line Coverage: 55.67%
Coverage Strength: 19.33 hits per line

💛 - Coveralls

@vercel

vercel Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
frontier Ready Ready Preview Oct 22, 2026 11:50am UTC

@coderabbitai

coderabbitai Bot commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
📥 Commits

Reviewing files that changed from the base of the PR and between 019902e and ce9c6c8.

📒 Files selected for processing: 3
  • core/resource/service.go
  • core/resource/service_test.go
  • test/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.

📝 Summary

Summary by CodeRabbit

  • New Features

    • Policy listings and counts can now be filtered by resource, helping narrow results to policies associated with a specific resource.
  • Bug Fixes

    • Deleting a resource now removes its associated policies and access bindings, revoking permissions granted through them.
    • A policy that no longer exists does not prevent resource deletion.
    • If policy lookup or removal encounters an unexpected error, deletion stops without removing the resource.
    • Improved coverage confirms cleanup for deleted project and organization resources.

Resource deletion now finds policies associated with the resource and deletes them before removing relations and the resource record. Policy filters support matching by resource ID. Tests cover cleanup errors and policy removal for project and organization resources.

Changes: Resource policy cleanup

Layer / File(s) Summary
Resource policy filtering
core/policy/filter.go, internal/store/postgres/policy_repository.go, internal/store/postgres/policy_repository_test.go
Filter now accepts ResourceID. PostgreSQL policy listing and counting apply an exact resource ID filter.
Deletion policy cleanup
core/resource/service.go, core/resource/service_test.go
Resource deletion lists and removes associated policies before deleting relations and the resource record. Missing policies are ignored; other policy errors stop deletion. Tests cover cleanup order, lookup namespace, and failure handling.
Deletion regression coverage
test/e2e/regression/api_test.go
End-to-end tests verify policy and role-binding removal, and revoked access, after project and organization resource deletion.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Bug fix · Severity of issue fixed: Medium

Suggested reviewers: whoabhisheksah

Merge Risk: ⚪ Minimal · up to ce9c6

Deleting a resource now also removes the policies on it. If a later step fails, a retry finishes the deletion. No actionable merge-blocking risk remains.

Pre-merge checks: Passed 1 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Linked Issues check Warning Issue #1993 requires resource deletion to remove the policies granted on the resource. The PR adds cleanup to resource.Service.Delete, and the direct project-resource and organization-resource paths… Make the project cascade use the policy-cleaning Delete path, or add equivalent policy cleanup to the cascade. Add a regression test that deletes a project and verifies that policies on its resources are absent from ListPolicies and `Ge…
Passed Passed checks: 1 passed
Check name Status Explanation
Out of Scope Changes check Passed The ResourceID filter, repository filtering, policy cleanup in resource deletion, and the unit, repository, and end-to-end tests directly support issue #1993. No unrelated change is demonstrated.
Full details: Linked Issues check

Explanation

Issue #1993 requires resource deletion to remove the policies granted on the resource. The PR adds cleanup to resource.Service.Delete, and the direct project-resource and organization-resource paths use that behavior. The project cascade still calls resService.Purge in core/deleter/service.go. This PR does not change that call, and Purge is not shown to perform policy cleanup. Therefore, policies on resources deleted by project deletion can remain.

Resolution

Make the project cascade use the policy-cleaning Delete path, or add equivalent policy cleanup to the cascade. Add a regression test that deletes a project and verifies that policies on its resources are absent from ListPolicies and GetPolicy.

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Comment thread core/resource/service.go
Comment thread core/resource/service.go Outdated
Comment thread core/resource/service_test.go Outdated
Comment thread internal/store/postgres/policy_repository_test.go
Comment thread test/e2e/regression/api_test.go Outdated
Comment thread test/e2e/regression/api_test.go
deletePolicies takes the loaded resource, so a wrong namespace from a
caller cannot leave policies behind. Tests cover a failed policy list,
the stop at the first failed policy delete, and the stored namespace;
the e2e case also checks the user's permission and the policy's role
binding rows in relations.
@AmanGIT07
AmanGIT07 merged commit 481a5df into main Oct 23, 2026
8 checks passed
@AmanGIT07
AmanGIT07 deleted the fix/resource-delete-removes-policies branch October 23, 2026 03:21

This branch was successfully deployed

1 active deployment
Preview — ce9c6c85 Deployed Oct 22, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Deleting a resource leaves the policies granted on it

3 participants