Skip to main content

Endpoint

GET /api/v1/decisions/:id/provenance — admin-gated.

Response

Why a separate endpoint

The bundle is a point-in-time snapshot of every artifact a regulator or auditor needs to reconstruct one decision: the trace itself, the model versions referenced, the rule cascade that produced the candidate set, the audit chain, the build identity (so they can verify the code that ran), and the fairness slice in effect at the time. Returning these via the existing /decision-traces/:id route would either bloat the trace endpoint or require N+1 fetches. The bundle endpoint runs all the joins server-side and emits a stable, hash-friendly document.

Reproducible digest

Output is canonicalized — JSON with sorted object keys — so the X-Provenance-Digest is deterministic. The same trace re-emitted from any pod produces the same digest. Verifiers can re-fetch the bundle days later and confirm bit-identity.

Cosign signing

When the COSIGN_KEY env var is set, the canonical bundle bytes are signed by spawning the real cosign sign-blob binary (installed in the platform Docker image) and the detached base64 signature lands in X-Provenance-Signature. The earlier deterministic placeholder (hash-of-hash) has been removed. Full mechanics — argv, failure modes, timeouts, key handling — are on Provenance signing with cosign. The header value "unsigned" indicates the bundle was generated without a usable signing path (no COSIGN_KEY, missing binary, or a signing failure — the audit row records the typed reason). Consumers can use this signal to refuse unsigned bundles in compliance workflows.

Build identity inputs

The route reads these env vars and includes them in buildIdentity: When all of GIT_SHA / GIT_REPO / IMAGE_NAME / IMAGE_DIGEST are set, buildIdentity.slsaAttestation is populated by the supply-chain SLSA-provenance builder.

Audit trail

Every bundle emission writes one audit-log row with action: "decision_provenance_emit", entityId: <traceId>, and changes: { digestSha256, signed, modelCount, auditLogCount }. DSAR exports cite these rows.

Honest limits

  • Bundle includes per-modelType snapshots (the hash of each modelState), not the full state. Auditors who need bit-exact model reproduction request the model record separately via the registry endpoint.
  • Signing is fail-soft by design: a broken signing path degrades to an "unsigned" bundle rather than failing the request — see “Cosign signing” above.
  • Effective-rules cascade is computed at bundle-emission time, not at decision time. Rule edits between the decision and the bundle request will surface in the cascade trace; the trace itself records what rules fired at decision time via qualificationResults / contactPolicyResults.
  • PII redaction runs over the trace before signing. The redactor is lib/explanations/pii-redact.ts; bugs there could leak PII into provenance bundles. Treat unsigned bundles as untrusted.