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

116 lines
5.6 KiB
Markdown

# Evidence Locker Attestation Contract (v1 · frozen 2025-11-20)
Scope: Evidence Bundle v1 produced by Evidence Locker and consumed by Concelier, Excititor, Export Center, CLI, and Policy Engine.
## Predicates & subjects
- **Subject (mandatory):** Merkle root derived from `checksums.txt` (sha256 of the sorted file) for the sealed bundle. OCI digest of the tarball remains recorded as `bundle_oci_digest` inside the predicate for registry mirroring but is not the DSSE subject.
- **Predicates (DSSE/In-Toto)**
- `stellaops.evidence.bundle.v1`: declares bundle layout (manifests, CAS paths, replay log offsets, Merkle recipe, chunking strategy).
- `stellaops.evidence.transparency.v1`: Rekor/log inclusion proof (UUID, log index, root hash at inclusion). Required when network-permitted; when offline, include `reason="offline"` and omit log pointers.
- `stellaops.evidence.integrity.v1`: hashes for each payload (SBOMs, VEX, policy packs, telemetry snapshots), keyed by canonical path; must match entries in `bundle.manifest.schema.json`.
## Required claim set
- `bundle_id` (UUID v4)
- `produced_at` (UTC ISO-8601)
- `producer` (`evidence-locker:<region>`)
- `subject_merkle_root` (sha256 from checksums.txt)
- `hashes` (map: canonicalPath → sha256) sorted lexicographically
- `sbom` (array of SPDX/CycloneDX digests and mediaTypes)
- `vex` (array of VEX doc digests and schema versions)
- `replay_manifest` (optional; digest + sequence number, ledger URI, dsseEnvelope)
- `transparency` (optional; Rekor UUID, logIndex, rootHash, inclusionProof) or `reason="offline"`
- `signing_profile` (`sovereign-default` | `fips` | `gost` | `pq-experimental`)
## Bundling & signing rules
- DSSE envelope is **mandatory** for every sealed bundle using the configured `ICryptoProviderRegistry` profile; keys must be short-lived (<24h) and recorded in provider registry.
- Subject = sha256(Merkle root) from `checksums.txt`; verifier must recompute to match.
- Hash list must match `bundle.manifest.schema.json` (entries + optional `hashSummary`), sorted by `canonicalPath`.
- Rekor/logging policy:
- If outbound log is allowed, submit to configured log and embed UUID/logIndex/rootHash in `transparency`.
- If outbound log is disallowed/offline, set `transparency` to null and include `reason="offline"` plus `log_policy="skip"` inside the predicate.
## Verification plan
- Verify DSSE signature against provider registry (per profile) and check key expiry.
- Recompute sha256 for every manifest entry and the Merkle root; fail if subject differs.
- If `transparency` present, verify inclusion proof against bundled Rekor root; fail closed on mismatch. If absent, require `reason="offline"` and `log_policy="skip"`.
- Emit verification report JSON (deterministic key order) and store beside bundle as `verify.json`.
## Fixtures
- Sample bundle + report: `docs/modules/evidence-locker/samples/bundle-v1-sample.tar.gz` (sha256 TBD at publish time).
- Sample attestation envelope: `docs/modules/evidence-locker/samples/attestation-v1-sample.json`.
## Ownership
- Primary: Evidence Locker Guild.
- Reviewers: Concelier Core Guild, Excititor Guild, Export Center Guild, Policy Guild.
## Gate Artifact Evidence Score Contract (v1, 2026-02-09)
Evidence Locker accepts a producer bundle and emits a single deterministic gate value (`evidence_score`) used by Release Orchestrator promotion gates.
### Producer submission
`POST /evidence`
Request body:
- `producer_bundle.artifact_id` (required)
- `producer_bundle.canonical_bom_sha256` (required, 64 hex)
- `producer_bundle.dsse_envelope_path` (required)
- `producer_bundle.payload_digest` (required, 64 hex)
- `producer_bundle.rekor.index` (required, integer >= 0)
- `producer_bundle.rekor.tile_id` (required)
- `producer_bundle.rekor.inclusion_proof_path` (required)
- `producer_bundle.attestation_refs[]` (optional list of stable refs)
- `raw_bom_path` (optional)
- `vex_refs[]` (optional list of refs)
Response body:
- `evidence_id`
- `evidence_score`
- `stored`
### Score lookup
`GET /evidence/score?artifact_id=<artifact-id>`
Response body:
- `evidence_score`
- `status` (`ready`)
### Deterministic scoring algorithm
Inputs:
- `canonical_bom_sha256`
- `payload_digest`
- `sorted(attestation_refs)` using ordinal lexical sort
Computation:
- join inputs with ASCII Unit Separator (`0x1F`)
- `evidence_score = SHA256(joined_bytes)` (lowercase hex)
Validation is fail-closed:
- reject non-hex or non-64-byte digests
- reject missing required producer fields
- reject invalid Rekor index values
This contract is authoritative for Sprint 110 and blocks CONCELIER-ATTEST-73-001/002 and EXCITITOR-ATTEST-01-003/73-001/73-002.
## Gate Artifact Extension (v1.1, 2026-02-10)
Promotion evidence consumers now rely on additional optional fields for policy-gate semantics:
- `producer_bundle.evidence_score_value` (0-100 numeric score for threshold checks)
- `producer_bundle.build_link.exists` (bool)
- `producer_bundle.build_link.product_digest.sha256|sha512` (optional digest binding inputs)
- `producer_bundle.artifact_digest.sha256|sha512` (optional explicit artifact digest)
- `producer_bundle.dsse_signatures[]`:
- `key_id`
- `algorithm`
- `valid`
- `producer_bundle.rekor.checked_at` (UTC RFC3339 timestamp for freshness TTL checks)
- `producer_bundle.human_decision_dsse_ref` (optional DSSE reference for signed escalation disposition)
Offline exports must retain enough metadata for air-gapped gate replay:
- Rekor proof references (`tile_id`, `inclusion_proof_path`) and freshness timestamp.
- DSSE signer evidence needed for k-of-n verification.
- Human decision DSSE reference when escalation policy requires signed disposition.