Skip to content

feat(deleter): project delete soft-deletes its resources - #2013

Open
AmanGIT07 wants to merge 1 commit into
feat/project-delete-blockersfrom
feat/project-delete-soft-resources
Open

AmanGIT07 wants to merge 1 commit into
feat/project-delete-blockersfrom
feat/project-delete-soft-resources

Conversation

@AmanGIT07

Copy link
Copy Markdown
Contributor

Summary

The project delete now soft-deletes the project's live resources with resource.Service.Delete, which keeps the row and removes its SpiceDB tuples, instead of purging every row. A resource that is already gone is skipped, like the org's own resources. Purge and resource.Filter.IncludeDeleted only existed so the old hard project delete could clear every row that pointed at the project. The project row is now kept, so both are removed. Stacked on #2008.

Changes

  • core/deleter/service.go: the resource step lists live resources only and calls Delete, skipping resource.ErrNotExist. The order stays: policies, then resources, then the project row.
  • core/resource/service.go, core/resource/resource.go, internal/store/postgres/resource_repository.go: Purge removed from the service, the repository interface, and the repository. The deleter's ResourceService interface drops it too; both mocks are regenerated.
  • core/resource/filter.go, internal/store/postgres/resource_repository.go: IncludeDeleted removed; List always skips deleted rows.
  • test/e2e/regression/api_test.go: the org delete test with a disabled project now gives that project a resource.

Test Plan

  • core/deleter/service_test.go: the project and org delete cases expect a live-only list and Delete; a resource that is already gone does not stop the project delete.
  • TestPurge removed from core/resource/service_test.go and internal/store/postgres/resource_repository_test.go, with the IncludeDeleted assertion in TestSkipsSoftDeletedResources.
  • e2e TestOrganizationDeleteAlsoDeletesDisabledProjectsAndGroups: after the org delete, the disabled project's row and its resource's row are kept with deleted_at set. With the resource delete reading the project through the lookup that hides disabled projects, the org delete fails with failed to get project, so the test covers fix(resource): a resource in a disabled project can be deleted #2006's lookup.
  • go test ./core/... ./internal/api/... and the resource and project repository suites pass.
  • e2e TestEndToEndAPIRegressionTestSuite, TestEndToEndServiceUsersRegressionTestSuite and TestEndToEndPATRegressionTestSuite pass.
  • golangci-lint run ./core/... ./internal/store/postgres/... ./test/e2e/regression/... reports no issues.

SQL Safety

  • No new values in queries; List now always starts from fromLive(TABLE_RESOURCES), and the removed Purge was the only DELETE on resources.
  • 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.

The project delete now deletes the project's live resources with Delete,
which keeps the row and removes its SpiceDB tuples, instead of purging
every row. A resource that is already gone is skipped. Purge and
resource.Filter.IncludeDeleted have no users left and are removed.
@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 21, 2026 6:50am UTC

@coderabbitai

coderabbitai Bot commented Oct 21, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration
  • Configuration used: Repository: raystack/frontier/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 574902f6-35de-483a-8c6b-7163ce89aa13

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • 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.

@coveralls

Copy link
Copy Markdown

Coverage Report for CI Build 39557924168

Coverage decreased (-0.02%) to 55.598%

Details

  • Coverage decreased (-0.02%) from the base build.
  • Patch coverage: 5 of 5 lines across 2 files are fully covered (100%).
  • No coverage regressions found.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 41856
Covered Lines: 23271
Line Coverage: 55.6%
Coverage Strength: 19.29 hits per line

💛 - Coveralls

@AmanGIT07

Copy link
Copy Markdown
Contributor Author

Sandbox run: a local Frontier server with Postgres and SpiceDB in Docker, called over the Connect protocol. The binary was built from #2014 with #2011 applied, so it has main plus #2008, #2011, #2013 and #2014.

Deletion config used:

app:
  deletion:
    enabled: true
    resources:
      resource/aoi: { project: block, organization: allow }
      resource/workflow: { project: block, organization: allow }
      resource/orderitem: { project: block_unless_deletable, organization: block_unless_deletable }
      resource/insight: { project: allow, organization: allow }

resource/report has no rule.

Resources of a deleted project

Check Expected Observed
Delete a project after 4 of its 5 resources were deleted: all 5 resource rows, incl. the finished order item that was still live 5 kept with deleted_at, 0 live 5 kept with deleted_at, 0 live
Owner can get the finished order item, before → after true → false true → false
Delete a project holding only an insight ok ok
Its insight row 1 kept with deleted_at, 0 live 1 kept with deleted_at, 0 live
Owner can get the insight after the delete false false
Delete a disabled project holding an insight ok ok
Its insight row 1 kept with deleted_at, 0 live 1 kept with deleted_at, 0 live
Delete an org with a project holding an AOI and a disabled project holding an insight: both project rows kept with deleted_at 2 2
That org's 2 resource rows 2 kept with deleted_at, 0 live 2 kept with deleted_at, 0 live
With enabled: false, its 2 resource rows 2 kept with deleted_at, 0 live 2 kept with deleted_at, 0 live

Project row and access after the delete (from #2007, together with this PR)

Check Expected Observed
Project row kept with deleted_at 1 1
Policies on the project: live before → live after, marked deleted 1 → 0, 1 1 → 0, 1
Owner can get the project, before → after true → false true → false
Platform superuser can get the project, before → after true → false true → false
GetProject on the deleted project (owner) permission_denied permission_denied
Second DeleteProject on the same project permission_denied permission_denied
A new project can take the deleted project's name ok ok

This branch was successfully deployed

1 active deployment
Preview — 9b57ea6c Deployed Oct 21, 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.

2 participants