Repository navigation
bug: CLI falls back to inline storage #3133
Description
Regression: GetUploadCreds fails with "org id is required"
Summary
After PR #3121 (commit 21c5b930, merged 2026-05-18) the AttestationService.GetUploadCreds RPC fails for every non-inline CAS backend with:
ERROR {"component": "service", "msg": "org id is required"}
The CLI silently falls back to inline attestation storage:
WRN failed to get CAS credentials, will store inline
error="rpc error: code = Internal desc = server error"
So artifacts that should land in the configured CAS backend (OCI, S3, Azure Blob, S3 Access Point) end up embedded inside the attestation envelope instead. The keyless signing flow itself is unaffected — this only impacts the CAS upload credentials path.
Root cause
PR #3121 made OrgID a hard requirement on every CAS JWT:
-
app/controlplane/pkg/biz/cascredentials.go:60-64
func (uc *CASCredentialsUseCase) GenerateTemporaryCredentials(backendRef *CASCredsOpts) (string, error) { if backendRef.OrgID == uuid.Nil { return "", fmt.Errorf("org id is required") } ... }
-
The call site was updated to pass
backend.OrganizationID:
app/controlplane/internal/service/attestation.go:497ref := &biz.CASCredsOpts{ BackendType: string(backend.Provider), SecretPath: backend.SecretName, Role: casJWT.Uploader, MaxBytes: backend.Limits.MaxBytes, OrgID: backend.OrganizationID, // <- new }
-
backend.OrganizationIDis populated only when theOrganizationedge is
eager-loaded on the ent record:
app/controlplane/pkg/data/casbackend.go:411-413if org := backend.Edges.Organization; org != nil { r.OrganizationID = org.ID }
-
Every direct CAS backend loader in
casbackend.gochains
.WithOrganization()— but the workflow run's eager loader does not:
app/controlplane/pkg/data/workflowrun.go:169-175func eagerLoadWorkflowRun(client *ent.Client) *ent.WorkflowRunQuery { return client.WorkflowRun.Query(). WithWorkflow(func(q *ent.WorkflowQuery) { q.WithOrganization().WithProject() }). WithVersion(). WithContractVersion(). WithCasBackends() // <- missing WithOrganization }
Since GetUploadCreds reads the backend via
wRun.CASBackends[0]
(attestation.go:481),
OrganizationID is always uuid.Nil on that path, so the OrgID check trips
on every call.
Impact
- Affected: every workflow run that uses a CAS backend with credentials
(backend.SecretName != ""). That includes OCI, S3, Azure Blob, and the
new S3 Access Point backend. - Not affected: inline-only setups (no SecretName) — these skip the JWT
generation block entirely. - Severity: silent functional regression. The CLI's fallback to inline
storage hides the failure unless you read the control plane logs or
notice attestations growing unexpectedly large. No data loss, but the
configured CAS backend is effectively bypassed.
Reproduction
- Configure a CAS backend with credentials (OCI / S3 / Azure / S3 Access
Point). - Run an attestation push against a workflow on that backend.
- Observe the control plane log:
ERROR {"component": "service", "msg": "org id is required"}
atservice.handleUseCaseErr(service.go:423) called from
(*AttestationService).GetUploadCreds(attestation.go:500). - The CLI logs
WRN failed to get CAS credentials, will store inline.
References
- Regression: PR feat(blobmanager): add managed CAS backend via S3 Access Points #3121 / commit
21c5b930—
feat(blobmanager): add managed CAS backend via S3 Access Points - Related: PR perf(controlplane): denormalize organization_id onto workflow_runs #3127 / commit
239ba82a—
perf(controlplane): denormalize organization_id onto workflow_runs
Activity