Skip to content

feat(api): add CheckProjectDelete - #2011

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

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

Conversation

@AmanGIT07

Copy link
Copy Markdown
Contributor

Summary

Adds the CheckProjectDelete handler. It returns can_delete and the blockers that would refuse DeleteProject, each RESOURCES_EXIST blocker with the number of blocking resources in count. It changes nothing, so a client can show the blockers before the user tries to delete. Stacked on #2008.

Changes

  • core/deleter/service.go: CheckProjectDelete finds the project and returns ProjectResourceBlockers. DeleteProject and CheckProjectDelete share one lookup, getProject: an id that is not a uuid returns project.ErrInvalidUUID, and a missing project returns project.ErrNotExist. Disabled projects are found.
  • internal/api/v1beta1connect/deleter.go: the CheckProjectDelete handler answers not_found for a missing project or an id that is not a uuid. transformBlockersToPB builds the response blockers for both check RPCs and now copies count.
  • internal/api/v1beta1connect/interfaces.go, mocks/cascade_deleter.go: CheckProjectDelete on CascadeDeleter; mock regenerated.
  • pkg/server/connect_interceptors/authorization.go: CheckProjectDelete needs delete permission on the project, the same as DeleteProject. Without a rule every call was denied.

Test Plan

  • core/deleter/service_test.go TestCheckProjectDelete: two blocking resources come back as one blocker with count 2; an allowed resource gives no blockers; a missing project returns project.ErrNotExist; a name returns project.ErrInvalidUUID. TestDeleteProject passes unchanged.
  • internal/api/v1beta1connect/deleter_test.go TestHandler_CheckProjectDelete: blockers with their count and can_delete false; can_delete true with no blockers; not_found for a missing project and for a name.
  • e2e TestProjectDeleteRefusedWhileResourcesBlock: the check reports the compute/order blocker with count 1 before the delete, and can_delete true once the resource is deleted.
  • go test ./core/... ./internal/api/... ./pkg/server/... passes.
  • e2e TestEndToEndAPIRegressionTestSuite, TestEndToEndServiceUsersRegressionTestSuite and TestEndToEndPATRegressionTestSuite pass.
  • golangci-lint run ./core/deleter/... ./internal/api/v1beta1connect/... ./pkg/server/... ./test/e2e/regression/... reports no issues.

@vercel

vercel Bot commented Oct 20, 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 20, 2026 4:36pm UTC

@coderabbitai

coderabbitai Bot commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

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: fa4c1a03-0987-4049-965c-0298463b3984

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

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository: raystack/frontier/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: d15ebe45-9538-4eaf-9586-7048202d2fce
📥 Commits

Reviewing files that changed from the base of the PR and between 26f3314 and 26c0f21.

📒 Files selected for processing: 8
  • core/deleter/service.go
  • core/deleter/service_test.go
  • internal/api/v1beta1connect/deleter.go
  • internal/api/v1beta1connect/deleter_test.go
  • internal/api/v1beta1connect/interfaces.go
  • internal/api/v1beta1connect/mocks/cascade_deleter.go
  • pkg/server/connect_interceptors/authorization.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
    • Added a project deletion check that reports blocking resources and their counts before deletion.
    • Projects without blockers are reported as eligible for deletion.
    • Added appropriate handling for invalid or missing project identifiers.
    • Added permission checks for project deletion reviews.
  • Bug Fixes
    • Organization deletion checks now include resource blocker counts.
    • Deletion eligibility is reevaluated after blocking resources are removed.

The service now checks project deletion blockers without deleting the project. The Connect API exposes this check, returns blocker counts, and requires project-level delete permission. Tests cover service behavior, API responses, and an end-to-end deletion flow.

Changes: Project deletion check

Layer / File(s) Summary
Service preflight and project lookup
core/deleter/service.go, core/deleter/service_test.go
The service adds CheckProjectDelete and shares project lookup and validation with DeleteProject. Tests cover blockers, allowed projects, missing projects, and invalid IDs.
Connect endpoint and authorization
internal/api/v1beta1connect/interfaces.go, internal/api/v1beta1connect/deleter.go, pkg/server/connect_interceptors/authorization.go, internal/api/v1beta1connect/mocks/cascade_deleter.go, internal/api/v1beta1connect/deleter_test.go, test/e2e/regression/api_test.go
The Connect API exposes project deletion checks and converts blockers, including counts. The endpoint requires project-level DeletePermission. Mock, API, and end-to-end tests cover blocker reporting and eligibility after resource removal.

Priority: ⬇️ Low

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

Change: Feature

Suggested reviewers: whoabhisheksah, kushsharma

Merge Risk: ⚪ Minimal · up to 26c0f

This adds a read-only check for whether a project can be deleted, protected by the same project-level delete permission. No merge-blocking risk was identified.

Pre-merge checks: Passed 2
Check name Status Explanation
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
  • 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

coveralls commented Oct 20, 2026 •

Copy link
Copy Markdown

Coverage Report for CI Build 39458686287

Coverage increased (+0.02%) to 55.64%

Details

  • Coverage increased (+0.02%) from the base build.
  • Patch coverage: 7 uncovered changes across 3 files (35 of 42 lines covered, 83.33%).
  • No coverage regressions found.

Uncovered Changes

File Changed Covered %
pkg/server/connect_interceptors/authorization.go 4 0 0.0%
core/deleter/service.go 19 17 89.47%
internal/api/v1beta1connect/deleter.go 19 18 94.74%

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 41918
Covered Lines: 23323
Line Coverage: 55.64%
Coverage Strength: 19.29 hits per line

💛 - Coveralls

CheckProjectDelete returns can_delete and the blockers that would refuse
DeleteProject, with the number of blocking resources per namespace. It
changes nothing. The caller needs delete permission on the project. Both
check RPCs now copy the blocker count into the response.
@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.

CheckProjectDelete responses

Project with 2 AOIs, 1 workflow, 1 order item still processing, and 1 finished order item ("deletable": true):
CheckProjectDelete → HTTP 200

{
  "blockers": [
    {
      "type": "RESOURCES_EXIST",
      "subject": "resource/aoi",
      "subject_type": "resource_namespace",
      "count": 2
    },
    {
      "type": "RESOURCES_EXIST",
      "subject": "resource/orderitem",
      "subject_type": "resource_namespace",
      "count": 1
    },
    {
      "type": "RESOURCES_EXIST",
      "subject": "resource/workflow",
      "subject_type": "resource_namespace",
      "count": 1
    }
  ]
}

Project with 1 order item whose deletable is the string "true":
CheckProjectDelete → HTTP 200

{
  "blockers": [
    {
      "type": "RESOURCES_EXIST",
      "subject": "resource/orderitem",
      "subject_type": "resource_namespace",
      "count": 1
    }
  ]
}

Project with 1 resource/report resource (no rule in the config):
CheckProjectDelete → HTTP 200

{
  "blockers": [
    {
      "type": "RESOURCES_EXIST",
      "subject": "resource/report",
      "subject_type": "resource_namespace",
      "count": 1
    }
  ]
}

Disabled project with 1 AOI:
CheckProjectDelete → HTTP 200

{
  "blockers": [
    {
      "type": "RESOURCES_EXIST",
      "subject": "resource/aoi",
      "subject_type": "resource_namespace",
      "count": 1
    }
  ]
}

With enabled: false, a project with an AOI and a resource/report resource:
CheckProjectDelete → HTTP 200

{
  "can_delete": true
}

When can_delete is false it is left out of the JSON, because proto3 JSON drops default values; Connect clients read it as false.

Other checks

Check Expected Observed
Check an empty project (owner) ok, can_delete=true, no blockers ok, can_delete=true, no blockers
Check by an org viewer (no delete permission) permission_denied permission_denied
Check by a user outside the org permission_denied permission_denied
Check with the project name instead of the id not_found not_found
Check with an unknown id permission_denied permission_denied
Check the first project above after deleting its 4 blocking resources (the finished order item stays) ok, can_delete=true, no blockers ok, can_delete=true, no blockers
Check a project holding only an insight (rule allow) ok, can_delete=true, no blockers ok, can_delete=true, no blockers
With enabled: false, check a project holding an AOI and a resource/report ok, can_delete=true, no blockers ok, can_delete=true, no blockers

This branch was successfully deployed

1 active deployment
Preview — 2e149454 Deployed Oct 20, 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