Documentation Index
Fetch the complete documentation index at: https://docs.kaireonai.com/llms.txt
Use this file to discover all available pages before exploring further.
What it does
Every call toGET /api/v1/decisions/:id/provenance returns a
canonicalised provenance bundle (decision trace + model snapshots +
audit chain + SLSA attestation + fairness slice). When the deployment
is configured for sigstore signing, the bundle is also signed with
cosign sign-blob and the detached signature lands in the response
header:
Configuration
Two env vars on the runtime container:| Env var | Required | Meaning |
|---|---|---|
COSIGN_KEY | yes (for signing) | Cosign-format private key bytes (e.g., the contents of cosign.key your operator generated with cosign generate-key-pair). Cosign accepts the raw bytes via the env:// URI scheme — see below. |
COSIGN_BINARY | no | Override the binary path (default: cosign on PATH). The image installs cosign at /usr/local/bin/cosign. |
How the signing works
lib/supply-chain/cosign-sign-blob.ts invokes:
spawnonly — neverexec. No shell is invoked, so there is no command-injection surface. The full argv is a fixed array of constants.- The signing key never appears on argv. Cosign reads the key
bytes from the env var named by the
env://COSIGN_KEYURI; only the URI string lives in argv. - The blob payload arrives via stdin. No tempfile, no argv leak. The canonical-JSON bundle is piped to the child’s stdin and the stream is closed immediately.
src/lib/supply-chain/__tests__/cosign-sign-blob.test.ts
asserts that the secret bytes never appear in spawn’s argv (it scans
every argv entry for the literal key value).
Failure modes (fail-soft to “unsigned”)
| Condition | Header value | Audit log changes field |
|---|---|---|
COSIGN_KEY env unset | unsigned | signed: false (no signatureFailureCode) |
| Cosign binary missing on PATH | unsigned | signed: false, signatureFailureCode: "binary_missing" |
| Cosign exited non-zero | unsigned | signed: false, signatureFailureCode: "exit_nonzero" |
| Cosign exited 0 but with empty stdout | unsigned | signed: false, signatureFailureCode: "exit_nonzero" |
| 30s spawn timeout | unsigned | signed: false, signatureFailureCode: "timeout" |
spawn-time error (EACCES, ENOMEM, etc.) | unsigned | signed: false, signatureFailureCode: "spawn_error" |
diagnostics field — never to the
response body, never to the response header.
Image layout
The runtime stage ofplatform/Dockerfile installs cosign:
cosign verify-blob against the sigstore root after image build, as a
separate CI step. That bootstrap is operator-authorised follow-up.
Operational checklist
- Generate the key pair with
cosign generate-key-pair(cosign prompts for a password — setCOSIGN_PASSWORDenv when scripting). - Store
cosign.keyand the password in your secret store (e.g., AWS Secrets Manager, App Runner secrets). - Inject as
COSIGN_KEYandCOSIGN_PASSWORDenv vars on the runtime container. - Hit
/api/v1/decisions/:id/provenanceand verify the response includesX-Provenance-Signature: <base64>(notunsigned). - Verify offline:
- Audit-log spot-check:
auditLog.changes.signedshould betruefor every successful bundle. AsignatureFailureCodefield means the wire intended to sign but couldn’t — page whoever owns the image / key-management layer.
Roadmap
- Keyless signing (Fulcio + OIDC + Rekor upload) so the deployment does not need a long-lived private key.
- Image-time
cosign verify-blobof the cosign release artefact itself (closes the bootstrap-trust gap noted above). - Reproducible-build verification step that re-canonicalises the bundle and re-signs against a CI-only key, comparing digests.