Skip to content

feat(contracts): convert a contract between organization and project level - #3794

Merged
jiparis merged 3 commits into
chainloop-dev:mainfrom
jiparis:jiparis/pfm-7886-contract-scope-conversion
Nov 9, 2026
Merged

jiparis merged 3 commits into
chainloop-dev:mainfrom
jiparis:jiparis/pfm-7886-contract-scope-conversion

Conversation

@jiparis

@jiparis jiparis commented Nov 6, 2026 •

Copy link
Copy Markdown
Member

Summary

Lets an organization admin convert an existing workflow contract between the organization level and a project level, in both directions. The contract keeps its ID, name, revisions, and workflows. This implements spec issue-3644.

  • API: the contract update request gets an optional level field, either a project reference or organization_scoped. When it is not set, the level does not change (R-001, R-011, R-009).
  • CLI: chainloop workflow contract update gets --project <name> and --org-level, which cannot be used together.
  • Rules: a conversion creates no revision (R-003, R-007). A request for the current level changes nothing, and a move from one project to a different project is rejected (R-006). A conversion to a project is rejected when workflows of other projects use the contract, and the error lists them (R-005).
  • Authorization: only organization owners and admins, and organization-level API tokens, can convert a contract (R-004).
  • Audit: a new WorkflowContractScopeChanged event records the old and the new level, both read under the contract lock (R-008, D-010).
  • Workflows: workflow update now rejects a contract of a different project, as workflow create already did. Workflow create also checks the existing default contract of the workflow (R-010). Conversions and workflow changes lock the contract, so they cannot race (D-008).

Spec changes in this PR: D-009 supersedes D-003 (the flag is --org-level, because a local --org hides the global organization flag), R-011 supersedes R-002 (the same requirement with the new flag), and D-010 is new.

Closes #3644

AI disclosure: this change was implemented with the assistance of Claude Code.

…level

Adds an optional level to the contract update API and the --project and --org
flags to 'chainloop workflow contract update', so organization admins can move a
contract between the organization and a project while it keeps its revisions
and workflows. Workflow updates now reject a contract of a different project,
and conversions and workflow changes lock the contract.

Implements spec issue-3644 (R-001 to R-010, D-008).

Closes chainloop-dev#3644

Assisted-by: Claude Code
Signed-off-by: Jose Ignacio Paris Prieto <jiparis@chainloop.dev>

Chainloop-Trace-Sessions: bc6fbb4d-3bf8-4fd0-b81e-10aa03bf1e58
@jiparis
jiparis requested a review from a team November 6, 2026 11:58
@chainloop-platform

chainloop-platform Bot commented Nov 6, 2026 •

Copy link
Copy Markdown
Contributor

PR validation — ✅ 3 passing

Status Policy Material Messages
✅ Passed pr-min-approvals pr-info -
✅ Passed pr-description-required pr-info -
✅ Passed pr-user-story-linked pr-info -

View attestation ↗

AI Session Checks — 🟢 88% · ✅ 0 failing

Avg score Sessions Failing policies Attribution Files Lines Total Duration
🟢 88% 1 ✅ 0 96% AI / 4% Human 22 +1220 / -74 15h3m30s

🟢 88% — 96% AI — ✅ All policies passing

Nov 6, 2026 08:39 UTC · 15h3m30s · $32.32 · 912 in / 320.6k out · claude-code 2.1.318 (claude-opus-5-5)

View session details ↗

Change Summary

  • Adds contract conversion between organization and project levels through the existing update API and CLI.
  • Adds mutually exclusive --project and --org-level flags while preserving global organization selection.
  • Rejects unsafe cross-project workflow references and serializes workflow changes against conversions.
  • Records locked pre/post scope snapshots in conversion audit events, with regression tests and updated documentation.

AI Session Overall Score

🟢 88% — Approved intent, focused changes, and passing integration suites support confidence; concurrency acceptance needs follow-up.

AI Session Analysis Breakdown

🟢 95% · scope-discipline

No notes.

🟢 94% · context-and-planning

🟢 Four explicit questions settled caller permissions, blocking workflows, revision behavior, and CLI shape before substantive code edits. · High Impact

🟢 93% · user-trust-signal

No notes.

🟢 92% · solution-quality

🟢 Audit dispatch uses repository-owned pre/post transition snapshots instead of either stale pre-reads or post-commit reloads. · High Impact

🟢 88% · alignment

No notes.

🟡 78% · verification

🟢 Database-backed conversion and workflow regressions pass after observed initial failures and real implementation fixes. · High Impact

🟠 Workflow isolation tests are sequential; no overlapping conversion/create or conversion/update execution is captured. · Medium Severity

💡 Add coordinated transaction-overlap tests for both workflow paths, asserting rejection or safe serialization under concurrent conversion.

🟡 CLI mapping and flag rejection are checked, but successful conversion-and-describe acceptance flows are not captured. · Low Severity


File Attribution

███████████████████░ 96% AI / 4% Human

Status Attribution File Lines
modified ai app/controlplane/pkg/biz/workflowcontract_integration_test.go +177 / -3
created ai app/controlplane/pkg/biz/workflowcontract_audit_test.go +147 / -0
modified ai app/controlplane/pkg/data/workflowcontract.go +117 / -12
modified ai app/controlplane/pkg/data/workflow.go +65 / -30
modified ai app/controlplane/internal/service/workflowcontract_integration_test.go +81 / -10
created ai app/controlplane/api/controlplane/v1/workflow_contract_test.go +76 / -0
created ai app/cli/pkg/action/workflow_contract_update_test.go +74 / -0
modified ai app/controlplane/pkg/biz/workflow_integration_test.go +72 / -0
modified ai app/controlplane/pkg/auditor/events/workflowcontract.go +48 / -1
modified ai app/controlplane/pkg/biz/workflowcontract.go +45 / -1
modified ai docs/specs/issue-3644-contract-scope-conversion.md +31 / -10
modified ai app/cli/cmd/root_test.go +39 / -0
modified ai app/controlplane/internal/service/workflowcontract.go +37 / -1
modified ai app/controlplane/pkg/auditor/events/workflowcontract_test.go +34 / -1
modified ai app/cli/pkg/action/workflow_contract_update.go +29 / -2
modified ai app/cli/documentation/cli-reference.md +24 / -1
created ai app/controlplane/pkg/auditor/events/testdata/workflowcontracts/workflow_contract_scope_changed_to_organization.json +24 / -0
created ai app/controlplane/pkg/auditor/events/testdata/workflowcontracts/workflow_contract_scope_changed_to_organization_by_api_token.json +24 / -0
created ai app/controlplane/pkg/auditor/events/testdata/workflowcontracts/workflow_contract_scope_changed_to_project.json +24 / -0
created ai app/controlplane/pkg/auditor/events/testdata/workflowcontracts/workflow_contract_scope_changed_to_project_by_api_token.json +24 / -0
modified ai app/cli/cmd/workflow_contract_update.go +19 / -2
modified ai app/controlplane/api/controlplane/v1/workflow_contract.proto +9 / -0

Policies (4)

Status Policy Material Messages
✅ Passed ai-config-ai-agents-allowed ai-coding-session-bc6fbb -
✅ Passed ai-config-no-dangerous-commands ai-coding-session-bc6fbb -
✅ Passed ai-config-no-secrets ai-coding-session-bc6fbb -
✅ Passed ai-config-mcp-servers-allowed ai-coding-session-bc6fbb -

Security Checks — ✅ 6 passing

✅ Reviewed this change against the project's security context (23 concerns hunted) — no introduced risk found.

View in Chainloop ↗ · How this works ↗
✅ Reviewed this change against the project's security context (23 concerns hunted) — no introduced risk found.

View in Chainloop ↗ · How this works ↗

✅ secret-scan

Status Policy Messages
✅ Passed secrets-detection -

✅ sast-scan

Status Policy Messages
✅ Passed owasp-top10-2025 -
✅ Passed sast -
✅ Passed cwe-top25 -
✅ Passed cwe-top26-40-cusp -

✅ iac-scan

Status Policy Messages
✅ Passed iac-misconfiguration -
Scans not applied (2)
Scan Reason
vulnerability-scan no manifest/lockfile changed
github-actions-scan no workflow files changed

View attestation ↗


Powered by Chainloop and Chainloop Trace

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All reported issues were addressed across 23 files

This PR changes authentication, authorization, or input validation. Ultrareviews find 2.4x more serious bugs than standard reviews. Comment @cubic-dev-ai ultrareview to run one.

View guided diff | Re-trigger cubic

Comment thread app/cli/cmd/workflow_contract_update.go Resolved
- Rename the CLI flag --org to --org-level. The local --org hid the global
  --org flag that selects the organization. Add a test that no command
  flag hides a global flag.
- Take the old level of the audit event from the conversion, which reads
  it under the contract lock, and write the event only when the level
  changed.
- Add validation tests for the level field of the update request.
- Spec issue-3644: D-009 supersedes D-003, R-011 supersedes R-002, add D-010.

Refs chainloop-dev#3644

Assisted-by: Claude Code
Signed-off-by: Jose Ignacio Paris Prieto <jiparis@chainloop.dev>

Chainloop-Trace-Sessions: bc6fbb4d-3bf8-4fd0-b81e-10aa03bf1e58

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All reported issues were addressed across 9 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

View guided diff | Re-trigger cubic

The repository now reports the level before and after a conversion,
both read while the conversion holds the contract lock, so a later
conversion can not change the new level that the audit event records.

Refs chainloop-dev#3644

Assisted-by: Claude Code
Signed-off-by: Jose Ignacio Paris Prieto <jiparis@chainloop.dev>

Chainloop-Trace-Sessions: bc6fbb4d-3bf8-4fd0-b81e-10aa03bf1e58
@jiparis
jiparis merged commit 06f758d into chainloop-dev:main Nov 9, 2026
17 checks passed
@jiparis
jiparis deleted the jiparis/pfm-7886-contract-scope-conversion branch November 9, 2026 11:06
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.

feat(contracts): allow converting a contract between organization-level and project-level

2 participants