Files
git.stella-ops.org/docs/modules/evidence-locker/promotion-evidence-contract.md
2026-02-11 01:32:14 +02:00

96 lines
3.3 KiB
Markdown

# Promotion Evidence Contract
## Purpose
This contract defines the evidence payload that promotion gates consume. It freezes
ownership boundaries and required fields for deterministic and offline-capable
release decisions.
## Ownership Boundaries
| Capability | Owning module | Notes |
| --- | --- | --- |
| Evidence storage and retrieval | EvidenceLocker | Stores immutable evidence; does not decide allow/deny. |
| DSSE signing | Signer | Produces signed envelopes and signer metadata. |
| Transparency logging and proof material | Attestor | Produces Rekor UUID/log index/proof references and verifies proofs. |
| PASS/FAIL policy decisioning | Policy Engine | Evaluates gate logic and emits decision outputs. |
| Promotion orchestration | Release Orchestrator | Consumes evidence + policy outputs to progress promotion state. |
## Canonical Promotion Gate Input
The promotion gate input MUST be serializable as canonical JSON with stable
key order and UTC timestamps.
```json
{
"artifact": {
"artifactId": "string",
"digest": "sha256:..."
},
"evidence": {
"evidenceScore": "lowercase-hex-sha256",
"bundleId": "guid",
"bundleDigest": "sha256:..."
},
"sbom": {
"canonicalDigest": "sha256:...",
"format": "cyclonedx|spdx"
},
"attestations": [
{
"predicateType": "string",
"dsseDigest": "sha256:...",
"signerKeyId": "string"
}
],
"transparency": {
"rekorUuid": "string",
"logIndex": 0,
"proofRef": "cas://..."
},
"vex": {
"mergedDigest": "sha256:...",
"statusSummary": "affected|not_affected|under_investigation|mixed"
},
"inToto": {
"layoutDigest": "sha256:...",
"linkDigests": ["sha256:..."]
}
}
```
## EvidenceLocker API Mapping
| Endpoint | Contract fields populated |
| --- | --- |
| `POST /evidence` | `artifact.*`, `evidence.evidenceScore` |
| `GET /evidence/score?artifact_id=...` | `evidence.evidenceScore` |
| `POST /evidence/snapshot` | `evidence.bundleId`, `evidence.bundleDigest` |
| `GET /evidence/{bundleId}` | `sbom.*`, `attestations[]`, `vex.*`, `inToto.*` |
| `POST /evidence/verify` | `transparency.*` verification status and proof linkage |
| `GET /evidence/{bundleId}/portable` | Offline bundle material for air-gapped verification |
## Determinism Requirements
- Serialize gate input with stable ordering and invariant casing.
- Use UTC RFC3339 timestamps only.
- Sort all arrays that do not carry semantic order by deterministic key:
- `attestations[]` by `predicateType`, then `dsseDigest`
- `inToto.linkDigests[]` lexicographically
- Treat digest values as lowercase.
- Fail closed if required evidence fields are missing.
## Offline Verification Requirements
- Promotion gates MUST accept proof references from offline bundles.
- Rekor verification may use tile/proof material from local mirrors.
- If transparency data is unavailable, gate outcome must be explicit policy output
(for example deny, or break-glass path with auditable reason).
## Implementation References
- EvidenceLocker architecture: `docs/modules/evidence-locker/architecture.md`
- EvidenceLocker attestation contract: `docs/modules/evidence-locker/attestation-contract.md`
- Policy ownership contract: `docs/modules/policy/promotion-gate-ownership-contract.md`
- Release Orchestrator runtime gap plan: `docs/modules/release-orchestrator/promotion-runtime-gap-closure-plan.md`