Skip to content

feat(api): add PurgeUnused RPC for bulk-deleting unused workflow contracts#3071

Open
migmartri wants to merge 1 commit intochainloop-dev:mainfrom
migmartri:worktree-generic-sparking-whistle
Open

feat(api): add PurgeUnused RPC for bulk-deleting unused workflow contracts#3071
migmartri wants to merge 1 commit intochainloop-dev:mainfrom
migmartri:worktree-generic-sparking-whistle

Conversation

@migmartri
Copy link
Copy Markdown
Member

@migmartri migmartri commented Apr 23, 2026

Summary

Closes #3072

  • Add PurgeUnused RPC to WorkflowContractService that soft-deletes all contracts with no associated workflows, respecting RBAC project scoping
  • Extend CLI workflow contract delete with --purge-unused flag for bulk cleanup
  • Emit WorkflowContractPurged audit events and include integration tests for all purge scenarios

…racts

Adds a new PurgeUnused RPC to WorkflowContractService that soft-deletes
all contracts with no associated workflows, scoped by RBAC visibility.
Includes CLI support via --purge-unused flag on the delete command.

Signed-off-by: Miguel Martinez Trivino <miguel@chainloop.dev>
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 18 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="app/controlplane/pkg/data/workflowcontract.go">

<violation number="1" location="app/controlplane/pkg/data/workflowcontract.go:326">
P1: `SoftDeleteUnused` reuses list filtering semantics and includes global contracts in purge scope, which can bypass RBAC restrictions for global contract deletion.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.

Comment on lines +326 to +335
query := applyProjectFilter(
tx.Organization.Query().
Where(organization.ID(orgID)).
QueryWorkflowContracts().
Where(
workflowcontract.DeletedAtIsNil(),
workflowcontract.Not(workflowcontract.HasWorkflowsWith(workflow.DeletedAtIsNil())),
),
filter,
)
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot Apr 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: SoftDeleteUnused reuses list filtering semantics and includes global contracts in purge scope, which can bypass RBAC restrictions for global contract deletion.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At app/controlplane/pkg/data/workflowcontract.go, line 326:

<comment>`SoftDeleteUnused` reuses list filtering semantics and includes global contracts in purge scope, which can bypass RBAC restrictions for global contract deletion.</comment>

<file context>
@@ -331,6 +320,59 @@ func (r *WorkflowContractRepo) SoftDelete(ctx context.Context, id uuid.UUID) err
+func (r *WorkflowContractRepo) SoftDeleteUnused(ctx context.Context, orgID uuid.UUID, filter *biz.WorkflowContractListFilters) (int, error) {
+	var n int
+	if err := WithTx(ctx, r.data.DB, func(tx *ent.Tx) error {
+		query := applyProjectFilter(
+			tx.Organization.Query().
+				Where(organization.ID(orgID)).
</file context>
Suggested change
query := applyProjectFilter(
tx.Organization.Query().
Where(organization.ID(orgID)).
QueryWorkflowContracts().
Where(
workflowcontract.DeletedAtIsNil(),
workflowcontract.Not(workflowcontract.HasWorkflowsWith(workflow.DeletedAtIsNil())),
),
filter,
)
query := tx.Organization.Query().
Where(organization.ID(orgID)).
QueryWorkflowContracts().
Where(
workflowcontract.DeletedAtIsNil(),
workflowcontract.Not(workflowcontract.HasWorkflowsWith(workflow.DeletedAtIsNil())),
)
if filter != nil && len(filter.FilterByProjects) > 0 {
query = query.Where(
workflowcontract.And(
workflowcontract.ScopedResourceTypeIn(biz.ContractScopeProject),
workflowcontract.ScopedResourceIDIn(filter.FilterByProjects...),
),
)
}
Fix with Cubic

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.

Add bulk cleanup for unused workflow contracts

1 participant