ADR-039: Evidence Bundle as in-toto / SCITT Attestation¶
Status¶
Proposed (June 2026) — trigger-gated.
Depends on ADR-051 (contract seam).
Context¶
The evidence bundle has a manifest, Merkle root, and content-addressed events, but is not emitted as an attestation statement. DSSE signing already exists, scoped to the mandate subsystem (assay-evidence/src/mandate/signing.rs), and CI emits SLSA build-provenance for the binary. The bundle itself cannot be anchored or verified offline as a portable claim. As of 2026 the in-toto Attestation Framework (ITE-6) is the common envelope that Sigstore and SLSA already use, and SCITT continues through the IETF, synergising with RATS and WIMSE.
Correction (2026-08-14): the shipped
run_rootis SHA-256 over newline-delimited event content-hash strings, with a trailing newline, in event sequence order — not a tree root, and notevent_idbytes. The historical wording above describes the model used at the time and is not a claim about the shipped evidence format.
Decision¶
Emit the bundle manifest and the coverage/claim verdict as an in-toto v1 Statement under a named custom predicate type (mirroring how SLSA defines its predicate), wrapped in a DSSE envelope, reusing the mandate signing path. Keep the anchor pluggable (SCITT statement or OpenTimestamps); do not build a transparency log or trust root. The per-fact claim-state (basis) is a first-class predicate field.
Gate¶
Publish the predicate type and ship the emitter only once an independent consumer evaluates or consumes it. Until that trigger, this ADR records the decision and the shape; it is intentionally not built, to avoid freezing a predicate no one consumes.
Consequences¶
- An Assay coverage/claim verdict becomes a portable attestation other systems can anchor and verify offline, composable under a SCITT statement or content-addressed record.
- Adds a predicate schema to version and keep stable once published.
Best-practice basis (2026)¶
- in-toto ITE-6 as the common envelope; SLSA provenance is an in-toto attestation with a named predicate; SCITT in the IETF with RATS + WIMSE.
Non-claims¶
- Attestation binds who-said-it and the semantic event chain; it does not upgrade observed support (proven in the attested-observed work) and provides no trust root or transparency log.
- The subject does not identify the artifact.
statement_from_manifestusesmanifest.run_rootas the subject digest, andrun_rootchains the per-event content hashes. Those cover exactly{specversion, type, datacontenttype, subject?, data}and nothing else, so a re-export at a different time keeps the same chain. Everything outside that set is excluded by construction -- stream identity,time, trace context, producer and policy metadata, and the privacy flags;crypto/id.rscarries the enumerated list, and it is the one place worth reading, because a second copy of it is a second thing to keep true. The cost of that property is that a bundle whoserun_id, event ids, producer, timestamps and PII flags are all rewritten consistently has a bit-identicalrun_rootand satisfies the same attestation. in-toto assumes the opposite: "Subjects are assumed to be immutable" and subjects are "matched purely by digest". So a consumer who reads a satisfied attestation as proof of which bundle they hold is relying on a property this subject does not have. The repair is to separate the two roles, not to widen the digest -- widening it would break the deterministic re-export the profile makes normative (docs/profiles/privileged-mcp-action/v0.md:124) andcrypto/id.rsimplements. Tracked as its own ADR on the programme ledger (#1866).
References¶
assay-evidence/src/mandate/signing.rs- ADR-051 (contract seam)