Uh oh!
There was an error while loading. Please reload this page.
feat(controlplane): scope CAS mappings to products - #3360
Conversation
AI Session Checks — 🟡 79% · ✅ 0 failing
|
| Status | Attribution | File | Lines |
|---|---|---|---|
| modified | ai | app/controlplane/pkg/biz/casmapping_integration_test.go | +209 / -33 |
| modified | ai | app/controlplane/pkg/biz/mocks/CASMappingRepo.go | +89 / -15 |
| modified | ai | app/controlplane/pkg/biz/casmapping.go | +75 / -23 |
| modified | ai | app/controlplane/pkg/data/casmapping.go | +59 / -16 |
| modified | ai | app/controlplane/pkg/biz/membership.go | +63 / -11 |
| modified | ai | app/controlplane/pkg/biz/project.go | +0 / -12 |
| modified | ai | app/controlplane/internal/service/cascredential.go | +5 / -5 |
| modified | ai | app/controlplane/pkg/data/ent/migrate/schema.go | +5 / -4 |
| modified | ai | app/controlplane/pkg/biz/referrer.go | +4 / -3 |
| modified | ai | app/controlplane/pkg/data/ent/schema/casmapping.go | +5 / -1 |
| modified | ai | app/controlplane/pkg/data/ent/migrate/migrations/atlas.sum | +2 / -1 |
| created | ai | app/controlplane/pkg/data/ent/migrate/migrations/20260820221508.sql | +2 / -0 |
Policies (4)
| Status | Policy | Material | Messages |
|---|---|---|---|
| ✅ Passed | ai-config-ai-agents-allowed | ai-coding-session-d81e13 | - |
| ✅ Passed | ai-config-no-dangerous-commands | ai-coding-session-d81e13 | - |
| ✅ Passed | ai-config-no-secrets | ai-coding-session-d81e13 | - |
| ✅ Passed | ai-config-mcp-servers-allowed | ai-coding-session-d81e13 | - |
Security Checks — ✅ 2 passing
PR info
| Status | Policy | Messages |
|---|---|---|
| ✅ Passed | pr-description-required | - |
| ✅ Passed | pr-user-story-linked | - |
⏭️ 3 scans not applied
| Scan | Reason |
|---|---|
vulnerability-scan | no manifest/lockfile changed |
github-actions-scan | no workflow files changed |
iac-scan | no IaC files changed |
Powered by Chainloop and Chainloop Trace
Artifacts stored in the CAS are scoped to a project so that the download lookup can honour project RBAC. Evidence attached to a product-level override has no project, so its mapping ends up unscoped and unreachable for any user whose organization role has RBAC enabled. Add an optional product_id to cas_mappings and extend the download filter, so that a mapping is reachable through a project OR a product membership. Product memberships already live in this database, written by the Chainloop platform, so the filter only needs to read rows it already stores. The column is additive and inert on its own: nothing here writes it, and an all-NULL column changes no existing query result. Assisted-by: Claude Code Signed-off-by: Miguel Martinez Trivino <miguel@chainloop.dev> Chainloop-Trace-Sessions: d81e130c-5011-4bf4-99bc-9902a6fafb43
deab390 to
03d3d87CompareUh oh!
There was an error while loading. Please reload this page.
Refs PFM-6978
What
CAS mappings can now be scoped to a product, in addition to a project, and the artifact download lookup honours product memberships.
Artifacts stored in the CAS carry the project they belong to so the download lookup can enforce project RBAC. Evidence attached to a product-level override has no project, so its mapping ends up unscoped and unreachable for any user whose organization role has RBAC enabled, and unreachable for product-only roles regardless.
Changes
cas_mappingsgains an optionalproduct_id. Products live in a downstream database, so it is a plain UUID reference with no edge and no foreign key, following theworkflow_run_idprecedent.CASMappingCreateOptsaccepts aProductID, and the two scopes are mutually exclusive: the download filter grants access on either one, so a mapping carrying both would be reachable by the members of two unrelated resources.biz.RBACScopes(visible projects and products per organization) instead of a bare project map, so the two dimensions cannot be transposed at a call site. Product memberships already live in this database, written by the Chainloop platform, so the filter only reads rows that are already stored.project_id IN (visible projects) OR product_id IN (visible products). A subject with no grants still matches nothing.ListByDigestInOrg, an unfiltered lookup of an artifact's existing scopes and backends. It has no consumer in this repository; the Chainloop platform needs it to reconcile mappings for evidence uploaded before this scope existed, and it has to ship in the same release the platform bumps to for the scope itself.The column is additive and inert on its own: nothing in this repository writes it, and an all-NULL column changes no existing query result.
Testing
Integration tests cover the filter across project-only, product-only, both and neither grants, and pin the cross-repository contract by seeding a product membership row directly and asserting the download honours it.
AI disclosure
This contribution was produced with AI assistance (Claude Code); the affected commit carries an
Assisted-by:trailer.🤖 Posted by Maximus bot (Claude Code) on behalf of @migmartri