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:497
ref := &biz.CASCredsOpts{
BackendType: string(backend.Provider),
SecretPath: backend.SecretName,
Role: casJWT.Uploader,
MaxBytes: backend.Limits.MaxBytes,
OrgID: backend.OrganizationID, // <- new
}
-
backend.OrganizationID is populated only when the Organization edge is
eager-loaded on the ent record:
app/controlplane/pkg/data/casbackend.go:411-413
if org := backend.Edges.Organization; org != nil {
r.OrganizationID = org.ID
}
-
Every direct CAS backend loader in casbackend.go chains
.WithOrganization() — but the workflow run's eager loader does not:
app/controlplane/pkg/data/workflowrun.go:169-175
func 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"}
at service.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:
GetUploadCredsfails with "org id is required"Summary
After PR #3121 (commit
21c5b930, merged 2026-05-18) theAttestationService.GetUploadCredsRPC fails for every non-inline CAS backend with:The CLI silently falls back to inline attestation storage:
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
OrgIDa hard requirement on every CAS JWT:app/controlplane/pkg/biz/cascredentials.go:60-64
The call site was updated to pass
backend.OrganizationID:app/controlplane/internal/service/attestation.go:497
backend.OrganizationIDis populated only when theOrganizationedge iseager-loaded on the ent record:
app/controlplane/pkg/data/casbackend.go:411-413
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-175
Since
GetUploadCredsreads the backend viawRun.CASBackends[0](attestation.go:481),
OrganizationIDis alwaysuuid.Nilon that path, so the OrgID check tripson every call.
Impact
(
backend.SecretName != ""). That includes OCI, S3, Azure Blob, and thenew S3 Access Point backend.
generation block entirely.
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
Point).
ERROR {"component": "service", "msg": "org id is required"}at
service.handleUseCaseErr(service.go:423) called from(*AttestationService).GetUploadCreds(attestation.go:500).WRN failed to get CAS credentials, will store inline.References
21c5b930—feat(blobmanager): add managed CAS backend via S3 Access Points239ba82a—perf(controlplane): denormalize organization_id onto workflow_runs