fix(controlplane): bound CAS mapping resolution on artifact download#3168
Conversation
c622a65 to
f328c69
Compare
f328c69 to
72e905e
Compare
Resolving the CAS mapping for a digest could exhaust the request deadline on artifact download. The lookup fetched every mapping for the digest globally and then filtered by org and computed public visibility in memory (1+2N queries). Because the same artifact can be pushed across thousands of workflow runs, a digest accumulates thousands of mappings, while only one is needed to locate the CAS backend. The download path now resolves a single mapping directly in the database with two bounded LIMIT 1 queries: first one reachable through the requester's orgs (organization + project RBAC predicates), and, only when there is no org-level access, a public mapping (matched on its workflow's visibility via a subquery). Both prefer the default backend. Mappings whose backend is soft-deleted, or whose workflow is soft-deleted, are excluded so downloads are never pointed at removed resources. Assisted-by: Claude Code Signed-off-by: Miguel Martinez Trivino <miguel@chainloop.dev> Chainloop-Trace-Sessions: 78e84359-afc2-4811-932b-a03f056fc52a
72e905e to
cea14d4
Compare
AI Session Analysis
|
| Status | Attribution | File | Lines |
|---|---|---|---|
| modified | human | app/controlplane/pkg/biz/mocks/CASMappingRepo.go |
+216 / -40 |
| modified | ai | app/controlplane/pkg/biz/casmapping_integration_test.go |
+126 / -79 |
| modified | ai | app/controlplane/pkg/data/casmapping.go |
+93 / -24 |
| modified | ai | app/controlplane/pkg/biz/casmapping.go |
+19 / -80 |
| modified | human | app/controlplane/pkg/biz/.mockery.yml |
+1 / -0 |
Policies (4)
| Status | Policy | Material | Messages |
|---|---|---|---|
| ✅ Passed | ai-config-ai-agents-allowed |
ai-coding-session-78e843 |
- |
| ✅ Passed | ai-config-no-dangerous-commands |
ai-coding-session-78e843 |
- |
| ✅ Passed | ai-config-no-secrets |
ai-coding-session-78e843 |
- |
| ✅ Passed | ai-config-mcp-servers-allowed |
ai-coding-session-78e843 |
- |
Powered by Chainloop and Chainloop Trace
Resolving the CAS mapping for a digest could exhaust the request deadline and surface as a context deadline error on artifact download. Two problems compounded, both fixed here.
FindByDigestresolved each mapping's public visibility with two queries per mapping, producing1 + 2Nsequential round-trips. Visibility for all referenced workflow runs is now resolved in a single edge-loaded query.The download path fetched every mapping for a digest globally and filtered by org in memory. Because the same artifact can be pushed across thousands of workflow runs, a single digest accumulates thousands of mappings, yet only one is needed to locate the CAS backend. The org-scoped path now selects a single mapping directly in the database (organization + project RBAC predicates, preferring the default backend,
LIMIT 1), so its cost no longer grows with the number of mappings. The public mapping lookup remains a fallback, used only when the requester has no org-level access to the digest.Closes #3167
Assisted-by: Claude Code