Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/holger

server/lib/src/attest.rs

//! ATTESTATIONS — the evidence plane, keyed by ARTIFACT DIGEST.
//!
//! An attestation is a signed statement **about specific bytes**. A gate (a CVE
//! scan, a license review, a reproducible-build check, an SBOM generator) runs
//! OUTSIDE holger, emits a statement naming the digest of what it looked at, signs
//! it, and hands it here. holger VERIFIES it on receipt and records it. A later
//! promotion asks this store *"what does anybody with a key I trust claim about
//! these exact bytes?"* — and gets an answer that is true of the bytes, not of a
//! name.
//!
//! ## ★ Why the digest is the key and the coordinate is not
//!
//! `server/lib/src/sbom.rs` stores its documents under `(repo, coordinate)`, and a
//! coordinate is a MUTABLE STRING. `rust-dev/serde/1.0.0` is whatever was last
//! written to `rust-dev/serde/1.0.0`. Evidence filed under a name is evidence for
//! a name, and a promotion gate that trusts it is trusting the naming, not the
//! bytes. The SAME defect is visible one layer down: `security::artifact_from_
//! coords` hands modgunn `blob_sha256: String::new()` while modgunn's
//! `Verdict::cache_key()` is `(blob_sha256, policy_version, advisory_db_rev)` —
//! content-addressed BY DESIGN, fed an empty digest.
//!
//! This store is keyed by `<alg>/<hex>` and nothing else. Re-uploading different
//! bytes under the same coordinate produces a different digest, so it cannot
//! inherit the old bytes' evidence. That is the entire mechanism.
//!
//! ## ★ Reuse, not a seventh envelope (LAW #5)
//!
//! The house already carries five bespoke signature containers — KORPSIG1,
//! `holger.update-bundle/v1`, `gunnar-sshsig-v2`, monetize's signature-inside-the-
//! object and Skidbladnir's `.sig.json` — and each one costs a verifier nobody
//! outside the house can write. This module adds NONE. It speaks:
//!
//! * **DSSE v1** ([`znippy_common::sign::dsse_pae`] / [`dsse_verify`]) — byte-exact
//!   PAE including the payload-type-confusion defence, proven against the spec's
//!   own vector, producer AND verifier, pure Rust;
//! * **in-toto Statement v1** — the same `_type` / `subject[].digest` /
//!   `predicateType` shape `nornir-build-thing::provenance::to_slsa_statement`
//!   already emits and `modgunn::provenance::verify_sealed_provenance` already
//!   reads.
//!
//! cosign, slsa-verifier and Rekor read this. So does the rest of the suite.
//!
//! ## ★ The check ordering, and why binding comes before cryptography
//!
//! [`AttestStore::accept`] parses, then checks the SUBJECT BINDING, then verifies
//! the signature. That is deliberate and it copies modgunn: `verify_sealed_
//! provenance` recomputes the statement and requires the envelope payload to match
//! BYTE-FOR-BYTE *before* it calls `dsse_verify`. Both gates are mandatory and
//! nothing is written until both pass, so the order costs no security — and it
//! buys two things. First, the binding refusal (`holger-attest-3`) stays reachable
//! in a build without the `sign` feature, so the attack this module exists to stop
//! is covered by a test in EVERY build. Second, an operator whose gate scanned the
//! wrong artifact is told exactly that, instead of being sent to look at their key.
//!
//! ## Multiple attestations, and set-scope statements
//!
//! One artifact carries MANY attestations: an SBOM from one gate, a vulnerability
//! verdict from another, a build provenance from the forge. They are distinguished
//! by `predicateType` and stored side by side — [`AttestStore::query`] answers
//! `(digest, predicateType)` and returns ALL of them, because two gates disagreeing
//! about the same predicate is a fact the promotion boundary must see, not one the
//! store may silently resolve last-wins.
//!
//! An in-toto Statement may name MANY subjects, and "the analysis of the promoted
//! SET as a whole" is exactly that. One such envelope is stored under EVERY subject
//! digest it names, so a query for any member finds it.
//!
//! ## Storage
//!
//! ```text
//! <root>/<alg>/<digest-hex>/<predicate-key>-<envelope-key>.dsse.json
//! ```
//!
//! `<alg>` and `<digest-hex>` come from a digest this module already refused
//! unless it was a lowercase-hex string of the algorithm's exact length, so the
//! key is path-safe BY CONSTRUCTION — no sanitizing step, and therefore no
//! many-to-one sanitizer to collapse two artifacts onto one directory (the
//! `rust/prod` → `rust_prod` hazard `sbom.rs` documents). `<predicate-key>` and
//! `<envelope-key>` are blake3 prefixes over the predicate type and the envelope
//! bytes: two different envelopes for the same predicate get two files, the same
//! envelope submitted twice gets one.

#[cfg(feature = "sign")]
use crate::lock::LockOrRecover as _;
use std::collections::{BTreeMap, BTreeSet};
use std::path::{Path, PathBuf};
use std::sync::Arc;

use holger_errcode as ec;
use serde_json::Value;
use sha2::{Digest, Sha256};

// ── The standard type URIs. Spelled here once, consumed everywhere. ───────────

/// The in-toto **Statement v1** `_type`. Anything else is not a statement this
/// store will file, however well signed it is.
pub const IN_TOTO_STATEMENT_TYPE: &str = "https://in-toto.io/Statement/v1";
/// in-toto Statement v0.1: what cosign still writes, so what Chainguard's image
/// attestations carry. Accepted beside v1 (the shape is the same; only the
/// `_type` differs). Found by the bench lane 2026-10-23.
pub const IN_TOTO_STATEMENT_TYPE_V01: &str = "https://in-toto.io/Statement/v0.1";

/// The DSSE `payloadType` for an in-toto statement — what cosign, slsa-verifier
/// and Rekor key on. Identical to `znippy_common::sign::DSSE_PAYLOAD_TYPE_INTOTO`
/// and to `nornir_build_thing::provenance::DSSE_PAYLOAD_TYPE_INTOTO`; restated as
/// a `const` so the non-`sign` build can still name it.
pub const DSSE_PAYLOAD_TYPE_INTOTO: &str = "application/vnd.in-toto+json";

/// SLSA **Provenance v1** — what the forge emits (`to_slsa_statement`).
pub const SLSA_PROVENANCE_V1: &str = "https://slsa.dev/provenance/v1";

/// A **CycloneDX** BOM as an in-toto predicate. CycloneDX is a legitimate
/// predicate type, which is what lets an SBOM stop being a document filed under a
/// name and become a statement bound to a hash (see [`crate::sbom`]).
pub const CYCLONEDX_BOM: &str = "https://cyclonedx.org/bom";

/// The in-toto standard **vulnerability-scan** predicate — the shape a modgunn
/// verdict rides in. A standard predicate, not a holger invention.
pub const INTOTO_VULNS_V01: &str = "https://in-toto.io/attestation/vulns/v0.1";

/// The in-toto standard **test-result** predicate.
pub const INTOTO_TEST_RESULT_V01: &str = "https://in-toto.io/attestation/test-result/v0.1";

/// Holger's own **scan evidence** predicate: one `scanner::Evidence` record,
/// every scanner's typed verdict about these bytes. Emitted by
/// `crate::scanner::attestation`.
pub const HOLGER_SCAN_EVIDENCE_V1: &str = "https://holger.rs/attestation/scan-evidence/v1";

/// SLSA **Verification Summary v1** — the VSA.
///
/// This is the predicate holger EMITS, and the only one it emits. A VSA is the
/// standard shape for "a verifier looked at these bytes, under this policy, and
/// this is what it decided". It is exactly what a promotion produces: the gates
/// ran over a set of digests and returned a `nornir_gate::Decision`.
///
/// It is a STANDARD predicate. holger does not invent an envelope, a payload
/// type or a predicate; the house already carries six envelope formats and there
/// is one DSSE implementation in it, `znippy_common::sign`.
pub const SLSA_VSA_V1: &str = "https://slsa.dev/verification_summary/v1";

/// The digest algorithms this store keys by, with their exact lowercase-hex
/// length. A digest whose length does not match its algorithm is REFUSED: the
/// digest is the storage key, and a key of the wrong shape is either a typo or an
/// attempt to steer the write, never a legitimate hash.
const DIGEST_ALGS: &[(&str, usize)] = &[("sha256", 64), ("sha512", 128), ("blake3", 64)];

// ── Refusals ─────────────────────────────────────────────────────────────────

/// Why an attestation was refused. Every variant carries one of the frozen
/// `holger-attest-<n>` codes, and [`AttestError::code`] is an EXHAUSTIVE match on
/// purpose: adding a refusal without allocating it a code is a compile error, not
/// a runtime surprise. Same rule as `BundleError` and `MarketplaceError`.
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
pub enum AttestError {
    /// The DSSE envelope is not readable at all.
    #[error("DSSE envelope is malformed: {0}")]
    EnvelopeMalformed(String),
    /// The payload is not an in-toto Statement v1 with a digested subject.
    #[error("payload is not an in-toto Statement v1: {0}")]
    StatementMalformed(String),
    /// ★ The statement is about DIFFERENT bytes than the ones being attested.
    #[error("this statement is about other bytes: it attests {found:?}, not {want} — a valid signature over a DIFFERENT artifact is not evidence for this one")]
    SubjectMismatch {
        /// The digest the caller asked this statement to be about.
        want: String,
        /// The subject digests the statement actually names.
        found: Vec<String>,
    },
    /// No enrolled gate certificate for an envelope signature.
    #[error("no enrolled gate certificate for this envelope signature: {0}")]
    SignerUntrusted(String),
    /// The signature did not verify, or the signer does not chain to a root.
    #[error("DSSE signature did not verify or the signer does not chain to a trusted root: {0}")]
    EnvelopeUnverified(String),
    /// A `predicateType` this server does not accept.
    #[error("predicateType {0:?} is not one this server accepts")]
    PredicateUnsupported(String),
    /// A digest that is not lowercase hex of the declared algorithm's length.
    #[error("unusable artifact digest: {0}")]
    DigestUnsafe(String),
    /// The store could not be read or written. Infrastructure, not a verdict.
    #[error("attestation store I/O failed: {0}")]
    StoreIo(String),
    /// ★ A path NAMED in `attestation.trust_roots` is not a usable trust anchor:
    /// unreadable, empty, or not a DER certificate. See
    /// [`AttestTrust::from_der_root_files`].
    #[error("a declared attestation trust root is not a usable trust anchor: {0} — refusing rather than verifying against fewer roots than the operator declared")]
    TrustRootUnreadable(String),
    /// This build cannot verify DSSE envelopes at all (no `sign` feature).
    #[error("this build of holger-server-lib was compiled without the `sign` feature, so a DSSE envelope cannot be verified; refusing to store unverified evidence")]
    VerificationUnavailable,
}

impl AttestError {
    /// The frozen code for this refusal. Exhaustive by construction.
    pub fn code(&self) -> &'static ec::ErrCode {
        match self {
            AttestError::EnvelopeMalformed(_) => &ec::ATTEST_ENVELOPE_MALFORMED,
            AttestError::StatementMalformed(_) => &ec::ATTEST_STATEMENT_MALFORMED,
            AttestError::SubjectMismatch { .. } => &ec::ATTEST_SUBJECT_MISMATCH,
            AttestError::SignerUntrusted(_) => &ec::ATTEST_SIGNER_UNTRUSTED,
            AttestError::EnvelopeUnverified(_) => &ec::ATTEST_ENVELOPE_UNVERIFIED,
            AttestError::PredicateUnsupported(_) => &ec::ATTEST_PREDICATE_UNSUPPORTED,
            AttestError::DigestUnsafe(_) => &ec::ATTEST_DIGEST_UNSAFE,
            AttestError::StoreIo(_) => &ec::ATTEST_STORE_IO,
            AttestError::TrustRootUnreadable(_) => &ec::ATTEST_TRUST_ROOT_UNREADABLE,
            AttestError::VerificationUnavailable => &ec::ATTEST_VERIFICATION_UNAVAILABLE,
        }
    }

    /// Both channels in one string: `[holger-attest-3] <human sentence>`. The same
    /// shape every other holger subsystem emits, so `holger_errcode::parse` finds
    /// the code in a log line, an audit row or a gRPC status message alike.
    pub fn tagged(&self) -> String {
        self.code().tag(self)
    }
}

// ── The key: an artifact digest ──────────────────────────────────────────────

/// An artifact digest — `(algorithm, lowercase hex)`. This is the store's ONLY
/// key.
///
/// ★ It is validated at construction and there is no other constructor, so every
/// `ArtifactDigest` in the process is already a path-safe pair of single segments.
/// `sbom.rs` reaches the same containment by SANITIZING a coordinate, and pays for
/// it: `sanitize_repo` is many-to-one, so it must additionally refuse any name
/// that is not already its own storage key or `rust/prod` would land on the real
/// `rust_prod`. A hex digest has no such collapse to defend against.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ArtifactDigest {
    alg: String,
    hex: String,
}

impl ArtifactDigest {
    /// Parse `(alg, hex)`, refusing anything that is not a known algorithm and a
    /// lowercase-hex string of exactly that algorithm's length.
    ///
    /// Uppercase hex is refused rather than lowercased: two spellings of one
    /// digest would key two directories, and an attestation filed under `ABCD…`
    /// would be invisible to a query for `abcd…` — a fail-open that looks like an
    /// absent attestation, which is the failure mode hardest to notice.
    pub fn parse(alg: &str, hex: &str) -> Result<Self, AttestError> {
        let Some((_, want_len)) = DIGEST_ALGS.iter().find(|(a, _)| *a == alg) else {
            let known: Vec<&str> = DIGEST_ALGS.iter().map(|(a, _)| *a).collect();
            return Err(AttestError::DigestUnsafe(format!(
                "algorithm {alg:?} is not one this store keys by (known: {known:?})"
            )));
        };
        if hex.len() != *want_len {
            return Err(AttestError::DigestUnsafe(format!(
                "{alg} digest must be {want_len} hex characters, got {}",
                hex.len()
            )));
        }
        if !hex
            .bytes()
            .all(|b| b.is_ascii_digit() || (b'a'..=b'f').contains(&b))
        {
            return Err(AttestError::DigestUnsafe(format!(
                "{alg} digest is not lowercase hex (uppercase is refused, not folded: two \
                 spellings of one digest would key two directories)"
            )));
        }
        Ok(Self {
            alg: alg.to_string(),
            hex: hex.to_string(),
        })
    }

    /// A SHA-256 digest from its lowercase hex — the common case.
    pub fn sha256(hex: &str) -> Result<Self, AttestError> {
        Self::parse("sha256", hex)
    }

    /// The SHA-256 digest OF `bytes` — for the caller that holds the artifact.
    pub fn of_sha256(bytes: &[u8]) -> Self {
        Self {
            alg: "sha256".into(),
            hex: hex::encode(Sha256::digest(bytes)),
        }
    }

    /// The algorithm label (`sha256`), as it appears in an in-toto `digest` map.
    pub fn alg(&self) -> &str {
        &self.alg
    }

    /// The lowercase hex.
    pub fn hex(&self) -> &str {
        &self.hex
    }
}

impl std::fmt::Display for ArtifactDigest {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}:{}", self.alg, self.hex)
    }
}

// ── The in-toto Statement ────────────────────────────────────────────────────

/// One `subject[]` entry: a name and the digests that identify its bytes.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Subject {
    /// The subject's name — human context only. It is NEVER part of the key: the
    /// whole point of this module is that a name binds nothing.
    pub name: String,
    /// `algorithm → lowercase hex`, as in-toto spells it.
    pub digest: BTreeMap<String, String>,
}

/// An in-toto **Statement v1**, as parsed out of a DSSE payload.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Statement {
    /// Every subject the statement is about. Non-empty by construction — a
    /// statement with no digested subject is a signature over an opinion, and
    /// [`Statement::parse`] refuses it.
    pub subjects: Vec<Subject>,
    /// The `predicateType` URI.
    pub predicate_type: String,
    /// The predicate body, untouched.
    pub predicate: Value,
}

impl Statement {
    /// Parse the DSSE payload bytes as an in-toto Statement v1 or v0.1.
    ///
    /// Refuses a wrong `_type`, a missing `predicateType`, an empty `subject`, and
    /// a subject carrying no digest map. The last one matters: in-toto permits a
    /// subject to be named without a digest, and such a subject binds NOTHING.
    /// Accepting it here would let a statement claim to be about `serde 1.0.0` in
    /// words while naming no bytes at all — the coordinate defect, smuggled back
    /// in through a standard format.
    pub fn parse(payload: &[u8]) -> Result<Self, AttestError> {
        let v: Value = serde_json::from_slice(payload)
            .map_err(|e| AttestError::StatementMalformed(format!("payload is not JSON: {e}")))?;
        let ty = v.get("_type").and_then(Value::as_str).unwrap_or_default();
        if ty != IN_TOTO_STATEMENT_TYPE && ty != IN_TOTO_STATEMENT_TYPE_V01 {
            return Err(AttestError::StatementMalformed(format!(
                "_type is {ty:?}, expected {IN_TOTO_STATEMENT_TYPE:?} or {IN_TOTO_STATEMENT_TYPE_V01:?}"
            )));
        }
        let predicate_type = v
            .get("predicateType")
            .and_then(Value::as_str)
            .ok_or_else(|| AttestError::StatementMalformed("no predicateType".into()))?
            .to_string();
        let raw = v
            .get("subject")
            .and_then(Value::as_array)
            .ok_or_else(|| AttestError::StatementMalformed("no subject array".into()))?;
        if raw.is_empty() {
            return Err(AttestError::StatementMalformed(
                "subject array is empty — a statement about nothing is not evidence".into(),
            ));
        }
        let mut subjects = Vec::with_capacity(raw.len());
        for (i, s) in raw.iter().enumerate() {
            let name = s
                .get("name")
                .and_then(Value::as_str)
                .unwrap_or_default()
                .to_string();
            let map = s.get("digest").and_then(Value::as_object).ok_or_else(|| {
                AttestError::StatementMalformed(format!("subject[{i}] carries no digest map"))
            })?;
            let mut digest = BTreeMap::new();
            for (k, val) in map {
                let Some(hexstr) = val.as_str() else {
                    return Err(AttestError::StatementMalformed(format!(
                        "subject[{i}].digest.{k} is not a string"
                    )));
                };
                digest.insert(k.clone(), hexstr.to_string());
            }
            if digest.is_empty() {
                return Err(AttestError::StatementMalformed(format!(
                    "subject[{i}].digest is empty — a subject with no digest binds no bytes"
                )));
            }
            subjects.push(Subject { name, digest });
        }
        Ok(Statement {
            subjects,
            predicate_type,
            predicate: v.get("predicate").cloned().unwrap_or(Value::Null),
        })
    }

    /// ★ Does this statement attest THESE bytes?
    ///
    /// True only when some subject's digest map carries an `alg → hex` pair equal
    /// to `want`. The comparison is exact — `want` is already known lowercase hex
    /// by construction, and a subject digest that differs only in case is treated
    /// as a different digest, for the same reason [`ArtifactDigest::parse`] refuses
    /// uppercase: folding would make two spellings interchangeable and the fold
    /// would then be the trusted step.
    pub fn attests(&self, want: &ArtifactDigest) -> bool {
        self.subjects
            .iter()
            .any(|s| s.digest.get(want.alg()).map(String::as_str) == Some(want.hex()))
    }

    /// Every subject digest this statement names that this store can key by. A
    /// subject digest in an algorithm the store does not know is skipped, not
    /// refused: a statement may legitimately carry `sha1` beside `sha256` for an
    /// external consumer, and dropping the whole statement over the extra one
    /// would refuse good evidence.
    pub fn keyable_subjects(&self) -> Vec<ArtifactDigest> {
        let mut out: BTreeSet<ArtifactDigest> = BTreeSet::new();
        for s in &self.subjects {
            for (alg, hexstr) in &s.digest {
                if let Ok(d) = ArtifactDigest::parse(alg, hexstr) {
                    out.insert(d);
                }
            }
        }
        out.into_iter().collect()
    }

    /// The subject digests as `alg:hex` strings, for a refusal message.
    fn describe_subjects(&self) -> Vec<String> {
        self.subjects
            .iter()
            .flat_map(|s| s.digest.iter().map(|(a, h)| format!("{a}:{h}")))
            .collect()
    }
}

// ── Trust ────────────────────────────────────────────────────────────────────

/// Is `der` shaped like a DER-encoded X.509 certificate?
///
/// A structural gate, not a parse: it answers "could this possibly be a trust
/// anchor" so that a path the operator NAMED cannot become an anchor that matches
/// nothing. See [`AttestTrust::from_der_root_files`] for why the full parse is
/// deliberately left to `znippy_common::sign`.
fn check_der_certificate(der: &[u8]) -> Result<(), String> {
    if der.is_empty() {
        return Err(
            "the file is EMPTY. An empty root is not 'no root': it is a declared \
                    anchor that can never match, which reads in the log as a mounted \
                    evidence plane and behaves as an unmounted one"
                .to_string(),
        );
    }
    if der[0] == b'-' {
        return Err(
            "the file begins with '-', so it is PEM, not DER. Convert it: \
                    `openssl x509 -in <file> -outform der -out <file>.der`"
                .to_string(),
        );
    }
    if der[0] != 0x30 {
        return Err(format!(
            "the file does not begin with an ASN.1 SEQUENCE tag (0x30 expected, 0x{:02x} \
             found), so it is not a DER certificate",
            der[0]
        ));
    }
    // DER length: short form (< 0x80) or long form (0x8n followed by n bytes).
    let (len, header) = match der.get(1) {
        None => return Err("the file is one byte long; a DER certificate is not".to_string()),
        Some(&b) if b < 0x80 => (b as usize, 2usize),
        Some(&0x80) => {
            return Err("the SEQUENCE uses INDEFINITE length, which DER forbids".to_string())
        }
        Some(&b) => {
            let n = (b & 0x7f) as usize;
            if n > 4 || der.len() < 2 + n {
                return Err("the SEQUENCE length field is truncated or absurd".to_string());
            }
            let mut v = 0usize;
            for byte in &der[2..2 + n] {
                v = (v << 8) | *byte as usize;
            }
            (v, 2 + n)
        }
    };
    if header + len > der.len() {
        return Err(format!(
            "the DER SEQUENCE declares {len} content bytes but the file holds only {} after \
             its {header}-byte header — the certificate is TRUNCATED",
            der.len() - header
        ));
    }
    Ok(())
}

/// The trust anchors an attestation is verified against.
///
/// TWO layers, and they answer two different questions:
///
/// * `roots` — DER CA certificates the signer must CHAIN to. Loaded exactly the
///   way `repository.rs`'s `ron_trusted_roots` loads them (a DER file per root,
///   read at wiring time, failing closed), so this is the SAME trust-root
///   mechanism the znippy archive path already uses and not a second one.
/// * `enrolled` — the SHA-256 fingerprints of the specific gate certificates this
///   server accepts verdicts from.
///
/// ★ The second layer is not redundant. A corporate CA signs hundreds of leaf
/// certificates; chaining proves the key belongs to the organisation, not that it
/// belongs to the SCANNER. Without enrolment, anybody inside the CA's perimeter
/// could sign "no vulnerabilities" and holger would file it as a gate verdict.
/// Enrolment is what makes `holger-attest-4` a different sentence from
/// `holger-attest-5`, and the two failures want different fixes: enrol the key, or
/// fix the signature.
#[derive(Debug, Clone, Default)]
pub struct AttestTrust {
    roots: Vec<Vec<u8>>,
    enrolled: BTreeSet<String>,
}

/// **A certificate file's DER**: the file as it is, or the first `CERTIFICATE` of a PEM file
/// (a medium's staged parameters are text, lane HOL-CDS-5). A PEM that does not decode is
/// handed on as it is, so the DER check names it.
pub fn der_of(file: &[u8]) -> Vec<u8> {
    use base64::Engine as _;
    let Ok(text) = std::str::from_utf8(file) else {
        return file.to_vec();
    };
    let (Some(a), Some(b)) = (
        text.find("-----BEGIN CERTIFICATE-----"),
        text.find("-----END CERTIFICATE-----"),
    ) else {
        return file.to_vec();
    };
    let body: String = text[a + "-----BEGIN CERTIFICATE-----".len()..b]
        .chars()
        .filter(|c| !c.is_whitespace())
        .collect();
    base64::engine::general_purpose::STANDARD
        .decode(body)
        .unwrap_or_else(|_| file.to_vec())
}

impl AttestTrust {
    /// An empty trust set. With no roots and no enrolled gates, every `accept`
    /// refuses — fail-closed, which is the only safe default for an evidence
    /// store.
    pub fn new() -> Self {
        Self::default()
    }

    /// Load DER root certificates from `paths`, mirroring `ron_trusted_roots`.
    ///
    /// ★ **Every declared path must yield a usable anchor, or NONE of them is
    /// loaded.** Until 2026-09-21 this read the file and pushed the bytes, so a
    /// zero-byte file, a PEM file somebody forgot to convert, or a path pointing
    /// at a directory listing became a "root" that could never match anything.
    /// The boot succeeded, the log said the evidence plane was mounted, and the
    /// trust set was effectively empty — an estate that believed it was verifying
    /// against `n` roots while verifying against `n - k`.
    ///
    /// This is [`crate::attest`]'s copy of the rule the plugin host has enforced
    /// since `holger-plugin-8` (`plugin/host/src/verify.rs`): *refusing rather
    /// than verifying against fewer roots than the operator declared.* It was
    /// written there in prose and in code; here it was written only in prose.
    ///
    /// The check is structural and costs no dependency: a DER certificate is an
    /// ASN.1 `SEQUENCE`, so byte 0 is `0x30` and the encoded length must account
    /// for the whole file. That refuses empty files, PEM (`-----BEGIN`), text and
    /// truncation. It is deliberately NOT a full X.509 parse — the parse that
    /// decides trust is `znippy_common::sign`'s, at verification time, and a
    /// second half-parse here would be a second place for the rule to be wrong.
    pub fn from_der_root_files(paths: &[PathBuf]) -> Result<Self, AttestError> {
        let mut t = Self::new();
        for p in paths {
            let der = std::fs::read(p).map(|b| der_of(&b)).map_err(|e| {
                AttestError::TrustRootUnreadable(format!(
                    "reading trusted root {}: {e}",
                    p.display()
                ))
            })?;
            check_der_certificate(&der).map_err(|why| {
                AttestError::TrustRootUnreadable(format!("trusted root {}: {why}", p.display()))
            })?;
            t.roots.push(der);
        }
        Ok(t)
    }

    /// Add a DER root certificate directly (the in-process / test path).
    pub fn add_root_der(&mut self, der: Vec<u8>) -> &mut Self {
        self.roots.push(der);
        self
    }

    /// Enrol a gate's signer certificate and return its SHA-256 fingerprint hex —
    /// the same fingerprint `znippy_common::sign` puts in a DSSE `keyid` and the
    /// same one `openssl x509 -fingerprint -sha256` prints.
    ///
    /// Computed here with `sha2` over the DER, not through the `sign` feature:
    /// enrolment is bookkeeping and must work in every build, including the one
    /// that cannot verify.
    pub fn enrol_signer_der(&mut self, der: &[u8]) -> String {
        let fp = hex::encode(Sha256::digest(der));
        self.enrolled.insert(fp.clone());
        fp
    }

    /// Enrol a gate by fingerprint hex alone (the config path: an operator pastes
    /// a fingerprint, not a certificate).
    pub fn enrol_fingerprint(&mut self, fp_hex: &str) -> &mut Self {
        self.enrolled.insert(fp_hex.to_ascii_lowercase());
        self
    }

    /// Is this fingerprint an enrolled gate?
    pub fn is_enrolled(&self, fp_hex: &str) -> bool {
        self.enrolled.contains(&fp_hex.to_ascii_lowercase())
    }

    /// The DER root certificates.
    pub fn roots(&self) -> &[Vec<u8>] {
        &self.roots
    }

    /// The enrolled gate fingerprints.
    pub fn enrolled(&self) -> &BTreeSet<String> {
        &self.enrolled
    }
}

/// Which `predicateType`s this server will file.
///
/// ★ An allowlist, never "anything goes". Storing a predicate nothing in this
/// build knows how to evaluate lets a later gate read a claim it cannot check and
/// count it as satisfied — a fail-open with extra steps. The default set is the
/// four STANDARD predicates the suite already produces or consumes; a deployment
/// adds its own with [`AttestPolicy::accept`].
#[derive(Debug, Clone)]
pub struct AttestPolicy {
    accepted: BTreeSet<String>,
}

impl Default for AttestPolicy {
    fn default() -> Self {
        let mut accepted = BTreeSet::new();
        // SLSA_VSA_V1 is in the default set because holger EMITS it. A store
        // whose default policy refused holger's own verification summary would
        // make the evidence path work only after the operator opted into the one
        // predicate this server produces.
        for pt in [
            SLSA_PROVENANCE_V1,
            CYCLONEDX_BOM,
            INTOTO_VULNS_V01,
            INTOTO_TEST_RESULT_V01,
            SLSA_VSA_V1,
            HOLGER_SCAN_EVIDENCE_V1,
        ] {
            accepted.insert(pt.to_string());
        }
        Self { accepted }
    }
}

impl AttestPolicy {
    /// A policy accepting NOTHING — the base an operator builds an explicit set on.
    pub fn none() -> Self {
        Self {
            accepted: BTreeSet::new(),
        }
    }

    /// Also accept `predicate_type`.
    pub fn accept(mut self, predicate_type: &str) -> Self {
        self.accepted.insert(predicate_type.to_string());
        self
    }

    /// Is this predicate type accepted?
    pub fn accepts(&self, predicate_type: &str) -> bool {
        self.accepted.contains(predicate_type)
    }
}

// ── What a successful accept / query yields ──────────────────────────────────

/// The outcome of filing one verified attestation.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Accepted {
    /// The envelope's content id (blake3 hex of the stored bytes) — stable, so a
    /// re-submission of the same envelope is the same id and the same file.
    pub envelope_id: String,
    /// The statement's `predicateType`.
    pub predicate_type: String,
    /// Every subject digest it was filed under. More than one ⇒ a set-scope
    /// statement.
    pub subjects: Vec<ArtifactDigest>,
    /// The verified signers, by certificate fingerprint hex.
    pub signers: Vec<String>,
}

/// One attestation read back out of the store.
#[derive(Debug, Clone)]
pub struct StoredAttestation {
    /// The envelope content id.
    pub envelope_id: String,
    /// The DSSE envelope, byte-identical to what was filed.
    pub envelope_json: Vec<u8>,
    /// Its parsed statement.
    pub statement: Statement,
}

// ── The store ────────────────────────────────────────────────────────────────

/// The on-disk attestation store, keyed by artifact digest.
pub struct AttestStore {
    root: PathBuf,
    trust: AttestTrust,
    policy: AttestPolicy,
}

/// **A store's trust, as data** (lane HOL-SANDBOX-TRAIT): the DER roots, the enrolled
/// gate fingerprints and the accepted predicate types, so a verify-bundle job checks
/// the evidence of an airgap import with exactly this side's trust and nothing more.
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[serde(deny_unknown_fields)]
pub struct TrustDoc {
    /// Each root certificate, DER, lower-case hex.
    pub roots: Vec<String>,
    pub enrolled: Vec<String>,
    pub accepted: Vec<String>,
}

impl AttestStore {
    /// This store's trust as a [`TrustDoc`].
    pub fn trust_doc(&self) -> TrustDoc {
        TrustDoc {
            roots: self.trust.roots.iter().map(hex::encode).collect(),
            enrolled: self.trust.enrolled.iter().cloned().collect(),
            accepted: self.policy.accepted.iter().cloned().collect(),
        }
    }

    /// A store over `root` that trusts exactly what `doc` says (a job's copy: it
    /// verifies, it files nothing).
    pub fn from_trust_doc(root: impl Into<PathBuf>, doc: &TrustDoc) -> Result<Self, String> {
        let mut roots = Vec::new();
        for r in &doc.roots {
            roots.push(hex::decode(r).map_err(|e| format!("a root is not hex: {e}"))?);
        }
        let trust = AttestTrust {
            roots,
            enrolled: doc.enrolled.iter().cloned().collect(),
        };
        let policy = AttestPolicy {
            accepted: doc.accepted.iter().cloned().collect(),
        };
        Ok(Self::new(root).with_trust(trust).with_policy(policy))
    }
}

impl AttestStore {
    /// A store rooted at `root`, with no trust anchors (every `accept` refuses)
    /// and the default predicate allowlist.
    pub fn new(root: impl Into<PathBuf>) -> Self {
        Self {
            root: root.into(),
            trust: AttestTrust::new(),
            policy: AttestPolicy::default(),
        }
    }

    /// The same store with these trust anchors.
    pub fn with_trust(mut self, trust: AttestTrust) -> Self {
        self.trust = trust;
        self
    }

    /// The same store with this predicate allowlist.
    pub fn with_policy(mut self, policy: AttestPolicy) -> Self {
        self.policy = policy;
        self
    }

    /// The trust anchors in force.
    pub fn trust(&self) -> &AttestTrust {
        &self.trust
    }

    /// The directory holding every attestation about `digest`.
    /// The store's root on disk. Public because the ESTATE replication
    /// (`crate::replication::replicate_estate`, plan §3 W10) has to be able to
    /// say WHICH directory a twin is missing when it holds artifacts and no
    /// evidence — `replicate_pairs` moves bytes by coordinate and this tree is
    /// the thing it cannot move.
    pub fn root(&self) -> &Path {
        &self.root
    }

    /// Where the envelopes about `digest` live. Public for the same reason as
    /// [`root`](Self::root): a caller that must PROVE a twin holds the evidence
    /// needs to name the place, and a second private copy of this one-line path
    /// rule elsewhere is how the two would drift.
    pub fn digest_dir(&self, digest: &ArtifactDigest) -> PathBuf {
        self.root.join(digest.alg()).join(digest.hex())
    }

    /// The 16-hex blake3 prefix that keys a predicate type in a filename. A
    /// predicate type is a URI full of `/` and `:`; hashing it makes the filename
    /// a single safe segment without inventing an escaping scheme whose inverse
    /// somebody would then have to maintain. The real predicate type is read back
    /// from the STATEMENT, never from the filename, so the hash never has to be
    /// undone.
    fn predicate_key(predicate_type: &str) -> String {
        blake3::hash(predicate_type.as_bytes()).to_hex()[..16].to_string()
    }

    /// ★ Every check [`accept`](Self::accept) makes, and no write: parse,
    /// predicate, subject binding, enrolment, cryptography. Returns the verified
    /// statement. This is how a reader verifies an envelope it was handed or read
    /// back, and a changed byte anywhere in it fails here.
    pub fn verify(
        &self,
        envelope_json: &[u8],
        signer_certs_der: &[Vec<u8>],
        required_subject: Option<&ArtifactDigest>,
    ) -> Result<Statement, AttestError> {
        Ok(self
            .check(envelope_json, signer_certs_der, required_subject)?
            .0)
    }

    fn check(
        &self,
        envelope_json: &[u8],
        signer_certs_der: &[Vec<u8>],
        required_subject: Option<&ArtifactDigest>,
    ) -> Result<(Statement, Vec<String>), AttestError> {
        let (payload, payload_type, keyids) = parse_envelope(envelope_json)?;
        if payload_type != DSSE_PAYLOAD_TYPE_INTOTO {
            return Err(AttestError::EnvelopeMalformed(format!(
                "payloadType is {payload_type:?}, expected {DSSE_PAYLOAD_TYPE_INTOTO:?} — DSSE \
                 binds the type INTO the signed bytes (PAE), so a mismatch here is a \
                 payload-type confusion attempt, not a formatting preference"
            )));
        }
        let statement = Statement::parse(&payload)?;

        if !self.policy.accepts(&statement.predicate_type) {
            return Err(AttestError::PredicateUnsupported(
                statement.predicate_type.clone(),
            ));
        }

        if let Some(want) = required_subject {
            if !statement.attests(want) {
                return Err(AttestError::SubjectMismatch {
                    want: want.to_string(),
                    found: statement.describe_subjects(),
                });
            }
        }

        // Enrolment: every signature must name a gate this server accepts verdicts
        // from AND a certificate must actually be on offer for it. An envelope with
        // an empty `keyid` is refused here rather than being tried against every
        // candidate — DSSE allows the wildcard, but "some key I hold verified this"
        // is not an identity, and the audit row must be able to say WHO.
        let mut signers = Vec::with_capacity(keyids.len());
        for keyid in &keyids {
            if keyid.is_empty() {
                return Err(AttestError::SignerUntrusted(
                    "envelope signature carries no keyid; this store files evidence against a \
                     NAMED gate, never against 'whichever key happened to verify'"
                        .into(),
                ));
            }
            if !self.trust.is_enrolled(keyid) {
                return Err(AttestError::SignerUntrusted(format!(
                    "keyid {keyid} is not an enrolled gate on this server"
                )));
            }
            let offered = signer_certs_der
                .iter()
                .any(|d| hex::encode(Sha256::digest(d)).eq_ignore_ascii_case(keyid));
            if !offered {
                return Err(AttestError::SignerUntrusted(format!(
                    "no certificate was offered for keyid {keyid}"
                )));
            }
            signers.push(keyid.clone());
        }

        verify_dsse(envelope_json, signer_certs_der, self.trust.roots())?;
        Ok((statement, signers))
    }

    /// ★ Verify an attestation and file it.
    ///
    /// `envelope_json` is a DSSE envelope. `signer_certs_der` are the candidate
    /// signer certificates (a gate ships its leaf certificate alongside the
    /// envelope, the way `modgunn::provenance::DsseSeal` carries `signer_certs`).
    /// `required_subject`, when given, is the artifact this evidence is claimed to
    /// be about — and the statement MUST name it.
    ///
    /// The order is parse → predicate → **subject binding** → enrolment →
    /// cryptography → write. See the module docs for why binding precedes
    /// cryptography; both are mandatory and nothing touches the disk until every
    /// one has passed.
    pub fn accept(
        &self,
        envelope_json: &[u8],
        signer_certs_der: &[Vec<u8>],
        required_subject: Option<&ArtifactDigest>,
    ) -> Result<Accepted, AttestError> {
        let (statement, signers) = self.check(envelope_json, signer_certs_der, required_subject)?;

        // Everything passed. File it under EVERY subject digest the statement
        // names — a set-scope statement about N artifacts is findable from any of
        // them.
        let subjects = statement.keyable_subjects();
        if subjects.is_empty() {
            return Err(AttestError::StatementMalformed(
                "no subject digest is in an algorithm this store keys by".into(),
            ));
        }
        let envelope_id = blake3::hash(envelope_json).to_hex().to_string();
        let file = format!(
            "{}-{}.dsse.json",
            Self::predicate_key(&statement.predicate_type),
            &envelope_id[..16]
        );
        for d in &subjects {
            let dir = self.digest_dir(d);
            std::fs::create_dir_all(&dir)
                .map_err(|e| AttestError::StoreIo(format!("creating {}: {e}", dir.display())))?;
            let path = dir.join(&file);
            // Staged then renamed, so a concurrent query never observes a
            // half-written envelope — the same discipline `SbomStore::attach` uses.
            let tmp = path.with_extension("json.tmp");
            std::fs::write(&tmp, envelope_json)
                .map_err(|e| AttestError::StoreIo(format!("writing {}: {e}", tmp.display())))?;
            std::fs::rename(&tmp, &path)
                .map_err(|e| AttestError::StoreIo(format!("committing {}: {e}", path.display())))?;
        }
        Ok(Accepted {
            envelope_id,
            predicate_type: statement.predicate_type,
            subjects,
            signers,
        })
    }

    /// Every attestation filed about `digest`, newest-first ordering NOT promised —
    /// the caller is asking for a SET of claims, and imposing an order would invite
    /// somebody to read the first one and stop.
    pub fn list(&self, digest: &ArtifactDigest) -> Result<Vec<StoredAttestation>, AttestError> {
        let dir = self.digest_dir(digest);
        let rd = match std::fs::read_dir(&dir) {
            Ok(rd) => rd,
            // No directory ⇒ no attestations. Absence is not-found, never an error:
            // "nothing has attested these bytes" is the normal state of a fresh
            // artifact and a promotion gate must be able to observe it plainly.
            Err(e) if e.kind() == std::io::ErrorKind::NotFound => return Ok(Vec::new()),
            Err(e) => {
                return Err(AttestError::StoreIo(format!(
                    "reading {}: {e}",
                    dir.display()
                )))
            }
        };
        let mut out = Vec::new();
        for entry in rd.flatten() {
            let path = entry.path();
            if !path.to_string_lossy().ends_with(".dsse.json") {
                continue; // a crash-leftover `.tmp` is never served
            }
            let bytes = std::fs::read(&path)
                .map_err(|e| AttestError::StoreIo(format!("reading {}: {e}", path.display())))?;
            let (payload, _, _) = parse_envelope(&bytes)?;
            let statement = Statement::parse(&payload)?;
            out.push(StoredAttestation {
                envelope_id: blake3::hash(&bytes).to_hex().to_string(),
                envelope_json: bytes,
                statement,
            });
        }
        Ok(out)
    }

    /// Every attestation about `digest` with this `predicateType`.
    ///
    /// ★ Returns ALL of them, not one. Two gates that disagree about the same
    /// predicate is a FACT the promotion boundary must see; collapsing it here
    /// (last-wins, or first-match) would let the store decide a trust question
    /// silently — which is exactly the defect `sbom.rs`'s last-wins attach has.
    pub fn query(
        &self,
        digest: &ArtifactDigest,
        predicate_type: &str,
    ) -> Result<Vec<StoredAttestation>, AttestError> {
        Ok(self
            .list(digest)?
            .into_iter()
            .filter(|a| a.statement.predicate_type == predicate_type)
            .collect())
    }

    /// Is there at least one attestation of this predicate type about these bytes?
    pub fn has(&self, digest: &ArtifactDigest, predicate_type: &str) -> bool {
        self.query(digest, predicate_type)
            .map(|v| !v.is_empty())
            .unwrap_or(false)
    }
}

/// A shared handle for wiring into the gRPC state + HTTP gateway, matching
/// [`crate::sbom::SharedSbomStore`].
pub type SharedAttestStore = Arc<AttestStore>;

// ── The DSSE seam ────────────────────────────────────────────────────────────
//
// Two shapes of the same two functions, selected by the `sign` feature, exactly
// the way `repository.rs` carries two shapes of `wire_verified_znippy`. The
// feature-off twin REFUSES; it never degrades to storing unverified evidence,
// because a store that files whatever it is handed when the crypto is missing is
// worse than no store — it produces green audit rows with nothing behind them.

/// Parse a DSSE envelope into `(payload, payloadType, keyids)`.
#[cfg(feature = "sign")]
fn parse_envelope(envelope_json: &[u8]) -> Result<(Vec<u8>, String, Vec<String>), AttestError> {
    let text = std::str::from_utf8(envelope_json)
        .map_err(|e| AttestError::EnvelopeMalformed(format!("not UTF-8: {e}")))?;
    let env = znippy_common::sign::DsseEnvelope::from_json(text)
        .map_err(|e| AttestError::EnvelopeMalformed(format!("{e:#}")))?;
    let keyids = env
        .signatures
        .iter()
        .map(|s| s.keyid.to_ascii_lowercase())
        .collect();
    Ok((env.payload, env.payload_type, keyids))
}

/// Verify every envelope signature over `PAE(payloadType, payload)` and chain each
/// signer to `roots`. Delegates WHOLLY to `znippy_common::sign::dsse_verify` — the
/// PAE, the algorithm dispatch off the signer certificate's SPKI and the chain
/// walk are all already there, spec-exact and tested against the DSSE spec's own
/// vector. Re-implementing any of it here would be the sixth envelope in a new
/// costume.
#[cfg(feature = "sign")]
fn verify_dsse(
    envelope_json: &[u8],
    signer_certs_der: &[Vec<u8>],
    roots_der: &[Vec<u8>],
) -> Result<(), AttestError> {
    use znippy_common::sign::{dsse_verify, CertStore, DsseEnvelope};
    let text = std::str::from_utf8(envelope_json)
        .map_err(|e| AttestError::EnvelopeMalformed(format!("not UTF-8: {e}")))?;
    let env = DsseEnvelope::from_json(text)
        .map_err(|e| AttestError::EnvelopeMalformed(format!("{e:#}")))?;
    let store = CertStore::from_der_certs(roots_der).map_err(|e| {
        AttestError::EnvelopeUnverified(format!("cannot load trusted roots: {e:#}"))
    })?;
    let verified = dsse_verify(&env, signer_certs_der, &store)
        .map_err(|e| AttestError::EnvelopeUnverified(format!("{e:#}")))?;
    if verified.is_empty() {
        return Err(AttestError::EnvelopeUnverified(
            "envelope produced no verified signer".into(),
        ));
    }
    Ok(())
}

/// Fail-closed twin for a build WITHOUT `sign`: an envelope cannot even be read,
/// so it certainly cannot be trusted.
#[cfg(not(feature = "sign"))]
fn parse_envelope(_envelope_json: &[u8]) -> Result<(Vec<u8>, String, Vec<String>), AttestError> {
    Err(AttestError::VerificationUnavailable)
}

/// Fail-closed twin for a build WITHOUT `sign`.
#[cfg(not(feature = "sign"))]
fn verify_dsse(
    _envelope_json: &[u8],
    _signer_certs_der: &[Vec<u8>],
    _roots_der: &[Vec<u8>],
) -> Result<(), AttestError> {
    Err(AttestError::VerificationUnavailable)
}

/// Build the canonical bytes of an in-toto Statement v1 — the exact payload a DSSE
/// envelope signs.
///
/// Key-sorted and compact, matching
/// `nornir_build_thing::provenance::slsa_statement_bytes`, so a producer over
/// there and a verifier here fold to the same bytes. `serde_json::Value` is a
/// `BTreeMap` under `preserve_order`-off, which is holger's build — hence sorted
/// by construction; the compactness comes from `to_vec` rather than `to_vec_pretty`.
pub fn statement_bytes(
    subjects: &[(String, ArtifactDigest)],
    predicate_type: &str,
    predicate: Value,
) -> Vec<u8> {
    let subject: Vec<Value> = subjects
        .iter()
        .map(|(name, d)| {
            serde_json::json!({
                "name": name,
                "digest": { d.alg(): d.hex() },
            })
        })
        .collect();
    let statement = serde_json::json!({
        "_type": IN_TOTO_STATEMENT_TYPE,
        "subject": subject,
        "predicateType": predicate_type,
        "predicate": predicate,
    });
    serde_json::to_vec(&statement).expect("a Value built from literals always serializes")
}

// ── Emitting evidence: the VSA a promotion writes ────────────────────────────

/// Build the in-toto Statement payload for a **Verification Summary** over the
/// whole promoted set.
///
/// One statement, N subjects. `attest.rs` already files a set-scope statement
/// under EVERY member digest (`a_set_scope_statement_is_keyable_from_every_member`),
/// so one signature covers the promotion and is still findable from any single
/// artifact in it.
///
/// `verified_levels` is left empty on purpose: holger does not claim a SLSA
/// build level it did not verify. The fields it fills are the ones it actually
/// knows — who verified, when, against which policy, with what result, and which
/// gates ran.
///
/// Pure: no signing, no I/O. The caller signs it.
pub fn verification_summary_bytes(
    subjects: &[(String, ArtifactDigest)],
    verifier_id: &str,
    result: VerificationResult,
    policy: &str,
    gates_run: &[String],
    timestamp_rfc3339: &str,
) -> Vec<u8> {
    let predicate = serde_json::json!({
        "verifier": { "id": verifier_id },
        "timeVerified": timestamp_rfc3339,
        "policy": { "uri": policy },
        "verificationResult": result.as_str(),
        "verifiedLevels": Vec::<String>::new(),
        // Not part of the SLSA schema's required set; carried because the whole
        // point of the record is which checks ran. A reader that does not know
        // the key ignores it; a reader that does can tell an artifact that
        // passed three gates from one that passed none.
        "gatesRun": gates_run,
    });
    statement_bytes(subjects, SLSA_VSA_V1, predicate)
}

/// Format a Unix timestamp (seconds, UTC) as RFC 3339, which is what the SLSA
/// VSA schema's `timeVerified` requires.
///
/// Written here rather than taken as a dependency: holger's server library
/// carries no date/time crate, and the airgap tiers are judged on their
/// dependency closure (`holger_recipe::rules::judge_artifact`). Fifteen lines of
/// civil-date arithmetic is cheaper than a crate, and it is the standard
/// days-from-civil algorithm, not an approximation.
pub fn rfc3339_utc(unix_secs: i64) -> String {
    let days = unix_secs.div_euclid(86_400);
    let secs = unix_secs.rem_euclid(86_400);
    // days-from-civil, inverted (Howard Hinnant's chrono algorithms).
    let z = days + 719_468;
    let era = z.div_euclid(146_097);
    let doe = z.rem_euclid(146_097);
    let yoe = (doe - doe / 1460 + doe / 36_524 - doe / 146_096) / 365;
    let y = yoe + era * 400;
    let doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
    let mp = (5 * doy + 2) / 153;
    let d = doy - (153 * mp + 2) / 5 + 1;
    let m = if mp < 10 { mp + 3 } else { mp - 9 };
    let y = if m <= 2 { y + 1 } else { y };
    format!(
        "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}Z",
        y,
        m,
        d,
        secs / 3600,
        (secs % 3600) / 60,
        secs % 60
    )
}

/// The two values a VSA's `verificationResult` may take.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VerificationResult {
    Passed,
    Failed,
}

impl VerificationResult {
    pub fn as_str(&self) -> &'static str {
        match self {
            VerificationResult::Passed => "PASSED",
            VerificationResult::Failed => "FAILED",
        }
    }
}

/// holger's own signing identity for the evidence it emits.
///
/// A PKCS#8 private key plus the X.509 certificate that carries its public key.
/// Both are supplied by the operator; holger mints nothing. That is deliberate:
/// `nornir --seal` signs with `ZnippySealer::dev()`, which mints an in-memory CA
/// and DISCARDS the root, so every provenance signature produced that way chains
/// to a CA nobody has. This type has no `dev()` and cannot be constructed without
/// a key and a certificate the operator already owns.
#[cfg(feature = "sign")]
pub struct AttestSigner {
    /// `sign_raw` takes `&self`, but the trait object is only `Send`, so the
    /// mutex is what makes the signer shareable across the server's threads.
    /// Signing a few hundred bytes of PAE is microseconds; there is no
    /// contention worth designing around.
    inner: std::sync::Mutex<Box<dyn znippy_common::sign::ArchiveSigner + Send>>,
    cert_der: Vec<u8>,
}

/// The same name in a build without `sign`, so callers need no `cfg`.
/// [`AttestSigner::from_pkcs8`] then REFUSES rather than silently producing no
/// evidence.
#[cfg(not(feature = "sign"))]
pub struct AttestSigner {
    _uninhabited: std::convert::Infallible,
}

impl AttestSigner {
    /// Load the signer from a PKCS#8 private key and its certificate, both DER.
    ///
    /// `alg` is `"ed25519"` or `"ecdsa-p256"`, the two
    /// `znippy_common::sign::SigAlg` values.
    #[cfg(feature = "sign")]
    pub fn from_pkcs8(alg: &str, pkcs8_key: &[u8], cert_der: &[u8]) -> Result<Self, AttestError> {
        let alg = znippy_common::sign::SigAlg::from_name(alg)
            .map_err(|e| AttestError::EnvelopeMalformed(format!("signer algorithm: {e:#}")))?;
        let signer = znippy_common::sign::signer_from_pkcs8(alg, pkcs8_key, cert_der)
            .map_err(|e| AttestError::EnvelopeMalformed(format!("loading the signer: {e:#}")))?;
        Ok(Self {
            inner: std::sync::Mutex::new(signer),
            cert_der: cert_der.to_vec(),
        })
    }

    /// Wrap an already-constructed znippy signer.
    ///
    /// The seam a key store (or a test's dev PKI) uses when it holds a signer
    /// rather than raw PKCS#8. Same shape as
    /// `nornir::build::seal::ZnippySealer::new`.
    #[cfg(feature = "sign")]
    pub fn from_signer(
        signer: Box<dyn znippy_common::sign::ArchiveSigner + Send>,
        cert_der: Vec<u8>,
    ) -> Self {
        Self {
            inner: std::sync::Mutex::new(signer),
            cert_der,
        }
    }

    #[cfg(not(feature = "sign"))]
    pub fn from_pkcs8(
        _alg: &str,
        _pkcs8_key: &[u8],
        _cert_der: &[u8],
    ) -> Result<Self, AttestError> {
        Err(AttestError::EnvelopeMalformed(
            "this build has no `sign` feature, so it carries no DSSE implementation and cannot \
             emit a verification summary. Refusing rather than promoting with no evidence written \
             and no error, which is indistinguishable from evidence that was written."
                .to_string(),
        ))
    }

    /// The signer certificate, DER. The verifier needs it to check the envelope.
    #[cfg(feature = "sign")]
    pub fn cert_der(&self) -> &[u8] {
        &self.cert_der
    }
}

/// The audit chain's checkpoints are signed by the same signer as every
/// attestation: one signing identity per server, one DSSE implementation.
#[cfg(feature = "sign")]
impl crate::audit::chain::CheckpointSigner for AttestSigner {
    fn sign_checkpoint(
        &self,
        payload_type: &str,
        payload: &[u8],
    ) -> Result<crate::audit::chain::SignedCheckpoint, String> {
        let guard = self.inner.lock_or_recover();
        let env = znippy_common::sign::dsse_sign(
            payload_type,
            payload,
            &[&**guard as &dyn znippy_common::sign::ArchiveSigner],
        )
        .map_err(|e| format!("signing the checkpoint: {e:#}"))?;
        Ok(crate::audit::chain::SignedCheckpoint {
            envelope_json: env
                .to_json()
                .map_err(|e| format!("rendering the envelope: {e:#}"))?,
            cert_der: self.cert_der.clone(),
        })
    }
}

#[cfg(feature = "sign")]
impl AttestStore {
    /// ★ Sign a statement payload and file it through the store's own door.
    ///
    /// The envelope is built by `znippy_common::sign::dsse_sign` — the ONE DSSE
    /// implementation in this house — and then handed straight to
    /// [`accept`](Self::accept). It is not written by a side door: holger's own
    /// evidence is parsed, predicate-checked, subject-bound, enrolment-checked
    /// and cryptographically verified on the same path as evidence from anyone
    /// else. If holger's signer does not chain to a configured trust root, its
    /// own VSA is refused, which is the correct answer: a statement nobody can
    /// verify is not evidence.
    ///
    /// `required_subject` is passed through so the caller can bind the write to
    /// one artifact; for a set-scope VSA it is `None` and the statement's own
    /// subject list decides where it is filed.
    pub fn emit_signed(
        &self,
        payload: &[u8],
        signer: &AttestSigner,
        required_subject: Option<&ArtifactDigest>,
    ) -> Result<Accepted, AttestError> {
        let json = {
            let guard = signer.inner.lock_or_recover();
            let env = znippy_common::sign::dsse_sign(
                DSSE_PAYLOAD_TYPE_INTOTO,
                payload,
                &[&**guard as &dyn znippy_common::sign::ArchiveSigner],
            )
            .map_err(|e| AttestError::EnvelopeMalformed(format!("signing the statement: {e:#}")))?;
            env.to_json().map_err(|e| {
                AttestError::EnvelopeMalformed(format!("rendering the envelope: {e:#}"))
            })?
        };
        self.accept(
            json.as_bytes(),
            std::slice::from_ref(&signer.cert_der),
            required_subject,
        )
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    /// A medium's staged certificate is PEM text (lane HOL-CDS-5): its DER is decoded, and a
    /// DER file is taken as it is.
    #[test]
    fn a_pem_certificate_reads_as_its_der() {
        use base64::Engine as _;
        let der = vec![0x30u8, 0x82, 0x01, 0x0a, 1, 2, 3, 4, 5];
        let b64 = base64::engine::general_purpose::STANDARD.encode(&der);
        let pem = format!(
            "-----BEGIN CERTIFICATE-----\n{}\n{}\n-----END CERTIFICATE-----\n",
            &b64[..4],
            &b64[4..]
        );
        assert_eq!(der_of(pem.as_bytes()), der);
        assert_eq!(der_of(&der), der);
    }

    const D_A: &str = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
    const D_B: &str = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";

    fn stmt(subjects: &[(&str, &str)], pt: &str) -> Vec<u8> {
        let subs: Vec<(String, ArtifactDigest)> = subjects
            .iter()
            .map(|(n, h)| ((*n).to_string(), ArtifactDigest::sha256(h).unwrap()))
            .collect();
        statement_bytes(&subs, pt, serde_json::json!({"note": "test"}))
    }

    // ── The key is a digest, and a digest is validated ───────────────────────

    /// A digest that is not lowercase hex of the algorithm's exact length is
    /// REFUSED BY NAME. The digest IS the path, so this is the containment
    /// argument: there is nothing to sanitize because nothing unsafe is ever
    /// constructed.
    #[test]
    fn a_digest_that_is_not_a_digest_is_refused_not_sanitized() {
        for (alg, hexstr) in [
            ("sha256", "../../../etc/passwd"),
            ("sha256", "short"),
            ("sha256", &format!("{D_A}extra")),
            // Uppercase: refused, never folded — two spellings would key two dirs.
            ("sha256", &D_A.to_ascii_uppercase()),
            (
                "sha256",
                "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz",
            ),
            ("md5", D_A),
            ("sha256/../..", D_A),
        ] {
            let err =
                ArtifactDigest::parse(alg, hexstr).expect_err("{alg}:{hexstr} must be refused");
            assert_eq!(err.code().code, "holger-attest-7", "{alg}: {err}");
        }
        assert!(ArtifactDigest::sha256(D_A).is_ok());
    }

    /// An accepted digest is exactly two path segments below the root, always.
    #[test]
    fn an_accepted_digest_is_two_segments_below_the_root() {
        let tmp = tempfile::tempdir().unwrap();
        let store = AttestStore::new(tmp.path());
        let p = store.digest_dir(&ArtifactDigest::sha256(D_A).unwrap());
        assert!(p.starts_with(tmp.path()));
        assert_eq!(p.strip_prefix(tmp.path()).unwrap().components().count(), 2);
    }

    // ── The statement ───────────────────────────────────────────────────────

    /// ★ THE REFUSAL THIS MODULE EXISTS FOR. A statement about digest B is not
    /// evidence about digest A — however impeccably it is signed. Asserted on the
    /// REFUSAL CODE, not on any content.
    #[test]
    fn a_statement_about_other_bytes_does_not_attest_these_bytes() {
        let s = Statement::parse(&stmt(&[("other-artifact", D_B)], CYCLONEDX_BOM)).unwrap();
        let a = ArtifactDigest::sha256(D_A).unwrap();
        let b = ArtifactDigest::sha256(D_B).unwrap();
        assert!(!s.attests(&a), "a statement about B must NOT attest A");
        assert!(s.attests(&b));
    }

    /// A subject named in words but carrying NO digest binds nothing, and is
    /// refused — otherwise the coordinate defect walks back in wearing in-toto.
    #[test]
    fn a_statement_whose_subject_carries_no_digest_is_refused() {
        let payload = serde_json::json!({
            "_type": IN_TOTO_STATEMENT_TYPE,
            "subject": [{ "name": "serde 1.0.0" }],
            "predicateType": CYCLONEDX_BOM,
            "predicate": {},
        });
        let err = Statement::parse(&serde_json::to_vec(&payload).unwrap())
            .expect_err("a subject with no digest must be refused");
        assert_eq!(err.code().code, "holger-attest-2", "{err}");
    }

    /// The Chainguard fixture of the intake bench (`cgr.dev/chainguard/python`'s
    /// cosign attestation, fetched 2026-10-23): a DSSE envelope whose statement is
    /// in-toto v0.1 with a SLSA v1 predicate.
    fn chainguard_fixture() -> (Vec<u8>, serde_json::Value) {
        let dir = concat!(
            env!("CARGO_MANIFEST_DIR"),
            "/../../bench-scenarios/fixtures/intake/chainguard-python"
        );
        let env = std::fs::read(format!("{dir}/att-0.payload")).expect("the bench fixture");
        let ann = serde_json::from_slice(
            &std::fs::read(format!("{dir}/att-0.annotations.json")).unwrap(),
        )
        .unwrap();
        (env, ann)
    }

    fn base64_decode(s: &str) -> Option<Vec<u8>> {
        use base64::Engine as _;
        base64::engine::general_purpose::STANDARD.decode(s).ok()
    }

    /// cosign writes in-toto Statement v0.1; Chainguard's attestations are read.
    #[test]
    fn an_in_toto_v01_statement_is_accepted() {
        let (env, _) = chainguard_fixture();
        let v: serde_json::Value = serde_json::from_slice(&env).unwrap();
        let payload = base64_decode(v["payload"].as_str().unwrap()).unwrap();
        let st = Statement::parse(&payload).expect("a v0.1 statement parses");
        assert_eq!(st.predicate_type, SLSA_PROVENANCE_V1);
        assert_eq!(st.subjects.len(), 1);
        assert!(st.subjects[0].digest.contains_key("sha256"));
    }

    /// The whole Chainguard envelope through the store's own verifier: P-256 over
    /// the PAE with the Fulcio leaf, chained through the Sigstore intermediate to
    /// the root the attachment carries (znippy-common 0.10.1).
    #[cfg(feature = "sign")]
    #[test]
    fn a_chainguard_envelope_chains_through_fulcio_to_the_sigstore_root() {
        let (env, ann) = chainguard_fixture();
        let pems = |k: &str| -> Vec<Vec<u8>> {
            let text = ann[k].as_str().unwrap_or_default();
            let mut out = Vec::new();
            for block in text.split("-----END CERTIFICATE-----") {
                if let Some(i) = block.find("-----BEGIN CERTIFICATE-----") {
                    let b64: String = block[i + 27..].split_whitespace().collect();
                    out.push(base64_decode(&b64).unwrap());
                }
            }
            out
        };
        let leaf = pems("dev.sigstore.cosign/certificate");
        let chain = pems("dev.sigstore.cosign/chain");
        assert_eq!((leaf.len(), chain.len()), (1, 2));
        verify_dsse(&env, &leaf, &chain).expect("the Chainguard envelope verifies and chains");
        let mut bad = env.clone();
        let i = String::from_utf8_lossy(&bad)
            .find("\"payload\":\"")
            .unwrap()
            + 11;
        bad[i] ^= 1;
        assert!(verify_dsse(&bad, &leaf, &chain).is_err());
        assert!(
            verify_dsse(&env, &leaf, &chain[1..]).is_err(),
            "the root alone: the intermediate is not invented"
        );
    }

    /// Every malformed shape is refused by the SAME named code, and none of them
    /// panics or parses half-way.
    #[test]
    fn malformed_statements_are_refused_by_name() {
        let cases: Vec<Vec<u8>> = vec![
            b"not json at all".to_vec(),
            serde_json::to_vec(&serde_json::json!({
                "_type": "https://in-toto.io/Statement/v2",
                "subject": [{"name":"x","digest":{"sha256":D_A}}],
                "predicateType": CYCLONEDX_BOM,
            }))
            .unwrap(),
            serde_json::to_vec(&serde_json::json!({
                "_type": IN_TOTO_STATEMENT_TYPE,
                "subject": [],
                "predicateType": CYCLONEDX_BOM,
            }))
            .unwrap(),
            serde_json::to_vec(&serde_json::json!({
                "_type": IN_TOTO_STATEMENT_TYPE,
                "subject": [{"name":"x","digest":{"sha256":D_A}}],
            }))
            .unwrap(),
            serde_json::to_vec(&serde_json::json!({
                "_type": IN_TOTO_STATEMENT_TYPE,
                "subject": [{"name":"x","digest":{}}],
                "predicateType": CYCLONEDX_BOM,
            }))
            .unwrap(),
        ];
        for (i, payload) in cases.iter().enumerate() {
            let err = Statement::parse(payload).expect_err("case {i} must be refused");
            assert_eq!(err.code().code, "holger-attest-2", "case {i}: {err}");
        }
    }

    /// A set-scope statement — one signed claim about N artifacts — is keyable from
    /// EVERY member. "Analysis of the promoted set as a whole" is precisely this
    /// shape, so a store that only understood one subject could not hold it.
    #[test]
    fn a_set_scope_statement_is_keyable_from_every_member() {
        let s = Statement::parse(&stmt(&[("a", D_A), ("b", D_B)], INTOTO_VULNS_V01)).unwrap();
        let keys = s.keyable_subjects();
        assert_eq!(keys.len(), 2);
        assert!(s.attests(&ArtifactDigest::sha256(D_A).unwrap()));
        assert!(s.attests(&ArtifactDigest::sha256(D_B).unwrap()));
    }

    /// A subject digest in an algorithm the store cannot key by is SKIPPED, not
    /// fatal — a statement legitimately carries `sha1` beside `sha256` for an
    /// external consumer, and refusing the whole thing would drop good evidence.
    #[test]
    fn an_unkeyable_extra_algorithm_does_not_discard_the_statement() {
        let payload = serde_json::json!({
            "_type": IN_TOTO_STATEMENT_TYPE,
            "subject": [{"name":"x","digest":{"sha256": D_A, "sha1": "deadbeef"}}],
            "predicateType": CYCLONEDX_BOM,
            "predicate": {},
        });
        let s = Statement::parse(&serde_json::to_vec(&payload).unwrap()).unwrap();
        let keys = s.keyable_subjects();
        assert_eq!(keys.len(), 1, "only the sha256 is keyable: {keys:?}");
        assert_eq!(keys[0].hex(), D_A);
    }

    /// The canonical statement bytes really are an in-toto Statement v1 that
    /// round-trips through the parser — producer and verifier in one crate.
    #[test]
    fn statement_bytes_round_trip_through_the_parser() {
        let bytes = stmt(&[("serde-1.0.0.crate", D_A)], SLSA_PROVENANCE_V1);
        let s = Statement::parse(&bytes).unwrap();
        assert_eq!(s.predicate_type, SLSA_PROVENANCE_V1);
        assert_eq!(s.subjects[0].name, "serde-1.0.0.crate");
        assert!(s.attests(&ArtifactDigest::sha256(D_A).unwrap()));
        let v: Value = serde_json::from_slice(&bytes).unwrap();
        assert_eq!(v["_type"], IN_TOTO_STATEMENT_TYPE);
    }

    // ── Trust bookkeeping (works in every build) ─────────────────────────────

    /// Enrolment is by SHA-256 over the certificate DER — the same fingerprint
    /// `znippy_common::sign` writes into a DSSE `keyid`. Anything not enrolled is
    /// not enrolled, including a plausible near-miss.
    #[test]
    fn enrolment_keys_on_the_certificate_fingerprint() {
        let mut t = AttestTrust::new();
        let fp = t.enrol_signer_der(b"pretend-der-bytes");
        assert_eq!(fp, hex::encode(Sha256::digest(b"pretend-der-bytes")));
        assert!(t.is_enrolled(&fp));
        assert!(
            t.is_enrolled(&fp.to_ascii_uppercase()),
            "a keyid's case must not matter"
        );
        assert!(!t.is_enrolled(D_A));
    }

    /// The default policy accepts the four STANDARD predicates and nothing else —
    /// an unknown predicate is refused by name, not filed "just in case".
    #[test]
    fn the_predicate_allowlist_refuses_what_it_does_not_know() {
        let p = AttestPolicy::default();
        for pt in [
            SLSA_PROVENANCE_V1,
            CYCLONEDX_BOM,
            INTOTO_VULNS_V01,
            INTOTO_TEST_RESULT_V01,
        ] {
            assert!(p.accepts(pt), "{pt} must be accepted by default");
        }
        assert!(!p.accepts("https://example.invalid/whatever/v1"));
        assert!(AttestPolicy::none().accept("x").accepts("x"));
        assert!(!AttestPolicy::none().accepts(SLSA_PROVENANCE_V1));
    }

    /// An artifact nothing has attested lists EMPTY — never an error. "No evidence
    /// yet" is the normal state of a fresh artifact, and a gate must be able to
    /// observe it plainly rather than through an I/O failure.
    #[test]
    fn an_unattested_artifact_lists_empty_rather_than_erroring() {
        let tmp = tempfile::tempdir().unwrap();
        let store = AttestStore::new(tmp.path());
        let d = ArtifactDigest::sha256(D_A).unwrap();
        assert!(store.list(&d).unwrap().is_empty());
        assert!(store.query(&d, CYCLONEDX_BOM).unwrap().is_empty());
        assert!(!store.has(&d, CYCLONEDX_BOM));
    }

    /// Every refusal has a DISTINCT frozen code. Collapsed, they would demand four
    /// different operator responses and get one — which is the whole reason the
    /// registry exists.
    #[test]
    fn the_refusals_are_distinguishable_by_code() {
        let all = [
            AttestError::EnvelopeMalformed("x".into()),
            AttestError::StatementMalformed("x".into()),
            AttestError::SubjectMismatch {
                want: "a".into(),
                found: vec!["b".into()],
            },
            AttestError::SignerUntrusted("x".into()),
            AttestError::EnvelopeUnverified("x".into()),
            AttestError::PredicateUnsupported("x".into()),
            AttestError::DigestUnsafe("x".into()),
            AttestError::StoreIo("x".into()),
            AttestError::VerificationUnavailable,
        ];
        let codes: BTreeSet<&str> = all.iter().map(|e| e.code().code).collect();
        assert_eq!(
            codes.len(),
            all.len(),
            "two refusals share a code: {codes:?}"
        );
        for e in &all {
            let tagged = e.tagged();
            assert_eq!(
                holger_errcode::parse(&tagged).map(|c| c.code),
                Some(e.code().code),
                "the code must survive the message: {tagged}"
            );
        }
    }

    /// Without the `sign` feature the accept path REFUSES rather than storing
    /// unverified evidence. Fail-closed, by name, and nothing reaches the disk.
    #[cfg(not(feature = "sign"))]
    #[test]
    fn a_build_without_sign_refuses_to_store_unverified_evidence() {
        let tmp = tempfile::tempdir().unwrap();
        let store = AttestStore::new(tmp.path());
        let err = store
            .accept(b"{}", &[], None)
            .expect_err("must fail closed");
        assert_eq!(err.code().code, "holger-attest-9", "{err}");
        assert_eq!(std::fs::read_dir(tmp.path()).unwrap().count(), 0);
    }

    /// The VSA's `timeVerified` must be RFC 3339. Three fixed points, including
    /// a leap day and the epoch, because the civil-date arithmetic is hand-rolled.
    #[test]
    fn unix_seconds_render_as_rfc3339_utc() {
        assert_eq!(rfc3339_utc(0), "1970-01-01T00:00:00Z");
        assert_eq!(rfc3339_utc(951_782_400), "2000-02-29T00:00:00Z");
        assert_eq!(rfc3339_utc(1_758_326_400), "2025-09-20T00:00:00Z");
        assert_eq!(rfc3339_utc(1_758_326_400 + 3_661), "2025-09-20T01:01:01Z");
    }

    /// The emitted statement is an in-toto Statement with the SLSA VSA
    /// predicate type and one subject per promoted artifact — one signature over
    /// the whole set, findable from any member.
    #[test]
    fn a_verification_summary_names_every_member_of_the_set() {
        let a = ArtifactDigest::sha256(D_A).unwrap();
        let b = ArtifactDigest::sha256(D_B).unwrap();
        let payload = verification_summary_bytes(
            &[
                ("one".to_string(), a.clone()),
                ("two".to_string(), b.clone()),
            ],
            "holger",
            VerificationResult::Passed,
            "holger://promotion-gates",
            &["allowed by 1 gate(s): osv".to_string()],
            &rfc3339_utc(0),
        );
        let s = Statement::parse(&payload).expect("the emitted payload is a valid Statement");
        assert_eq!(s.predicate_type, SLSA_VSA_V1);
        assert!(s.attests(&a));
        assert!(s.attests(&b));
        assert_eq!(s.keyable_subjects().len(), 2);
    }

    // ── The real cryptographic path ─────────────────────────────────────────

    #[cfg(feature = "sign")]
    mod signed {
        use super::*;
        use std::path::Path;
        use znippy_common::sign::{dev, dsse_sign, ArchiveSigner, EcdsaP256Signer};

        /// One in-memory CA plus a gate signer issued by it — the dev PKI
        /// `znippy_common::sign::dev` already ships (`server/repository/
        /// znippy-package/src/lib.rs:439` uses the same helpers), so no test
        /// fixture files and no second PKI.
        struct Gate {
            ca_der: Vec<u8>,
            signer: EcdsaP256Signer,
        }

        fn gate(cn: &str) -> Gate {
            let (ca_key, ca_der) = dev::mint_ca(&format!("{cn}-ca")).unwrap();
            let signer = dev::new_p256_signer(&ca_key, &ca_der, cn).unwrap();
            Gate { ca_der, signer }
        }

        /// A signing identity for holger ITSELF: its own CA, its own leaf, and
        /// the leaf wrapped in [`AttestSigner`]. Returns `(ca_der, cert_der,
        /// signer)` so a test can decide whether the store trusts it.
        fn holger_identity(cn: &str) -> (Vec<u8>, Vec<u8>, AttestSigner) {
            let (ca_key, ca_der) = dev::mint_ca(&format!("{cn}-ca")).unwrap();
            let leaf = dev::new_p256_signer(&ca_key, &ca_der, cn).unwrap();
            let cert = leaf.certificate_der().to_vec();
            (
                ca_der,
                cert.clone(),
                AttestSigner::from_signer(Box::new(leaf), cert),
            )
        }

        impl Gate {
            fn cert(&self) -> Vec<u8> {
                self.signer.certificate_der().to_vec()
            }
            fn sign(&self, payload: &[u8]) -> Vec<u8> {
                dsse_sign(DSSE_PAYLOAD_TYPE_INTOTO, payload, &[&self.signer])
                    .unwrap()
                    .to_json()
                    .unwrap()
                    .into_bytes()
            }
        }

        fn store_trusting(root: &Path, g: &Gate) -> AttestStore {
            let mut trust = AttestTrust::new();
            trust.add_root_der(g.ca_der.clone());
            trust.enrol_signer_der(&g.cert());
            AttestStore::new(root).with_trust(trust)
        }

        /// The happy path, stated once so the refusals below are known to be
        /// refusing something that would otherwise work.
        #[test]
        fn a_verified_attestation_is_filed_under_its_subject_digest() {
            let tmp = tempfile::tempdir().unwrap();
            let g = gate("cve-gate");
            let store = store_trusting(tmp.path(), &g);
            let a = ArtifactDigest::sha256(D_A).unwrap();

            let env = g.sign(&stmt(&[("serde-1.0.0.crate", D_A)], INTOTO_VULNS_V01));
            let accepted = store.accept(&env, &[g.cert()], Some(&a)).unwrap();
            assert_eq!(accepted.predicate_type, INTOTO_VULNS_V01);
            assert_eq!(accepted.subjects, vec![a.clone()]);

            assert_eq!(store.query(&a, INTOTO_VULNS_V01).unwrap().len(), 1);
            assert!(store.has(&a, INTOTO_VULNS_V01));
            // …and it is NOT evidence for other bytes.
            let b = ArtifactDigest::sha256(D_B).unwrap();
            assert!(store.list(&b).unwrap().is_empty());
        }

        // ── Emitting: the VSA a promotion writes ────────────────────────────

        /// holger signs a Verification Summary over the promoted artifact and
        /// files it through its OWN door, so the statement it wrote back is
        /// findable by the digest a later gate will ask about.
        ///
        /// Before this existed, `attest.rs` had no constructor and no consumer
        /// anywhere in the shipped tree: 1458 lines of verification nothing
        /// could reach.
        #[test]
        fn a_promotion_verification_summary_is_signed_filed_and_findable() {
            let tmp = tempfile::tempdir().unwrap();
            let (ca_der, cert, signer) = holger_identity("holger");
            let mut trust = AttestTrust::new();
            trust.add_root_der(ca_der);
            trust.enrol_signer_der(&cert);
            let store = AttestStore::new(tmp.path()).with_trust(trust);
            let bytes = b"the promoted artifact";
            let digest = ArtifactDigest::of_sha256(bytes);

            let payload = verification_summary_bytes(
                &[("serde-1.0.0.crate".to_string(), digest.clone())],
                "holger",
                VerificationResult::Passed,
                "holger://promotion-gates",
                &["allowed by 1 gate(s): osv".to_string()],
                &rfc3339_utc(1_758_326_400),
            );
            let accepted = store
                .emit_signed(&payload, &signer, Some(&digest))
                .expect("holger's own evidence must verify through its own door");
            assert_eq!(accepted.predicate_type, SLSA_VSA_V1);
            assert_eq!(accepted.subjects, vec![digest.clone()]);
            assert!(store.has(&digest, SLSA_VSA_V1));
        }

        /// holger's own statement is NOT privileged. A signer that does not
        /// chain to a configured trust root is refused exactly as anyone else's
        /// would be, and nothing is written. A statement nobody can verify is
        /// not evidence.
        #[test]
        fn holgers_own_summary_is_refused_when_its_signer_is_not_trusted() {
            let tmp = tempfile::tempdir().unwrap();
            let trusted = gate("trusted");
            let store = store_trusting(tmp.path(), &trusted);

            let (_stranger_ca, _stranger_cert, signer) = holger_identity("stranger");
            let bytes = b"the promoted artifact";
            let digest = ArtifactDigest::of_sha256(bytes);
            let payload = verification_summary_bytes(
                &[("x".to_string(), digest.clone())],
                "holger",
                VerificationResult::Passed,
                "holger://promotion-gates",
                &[],
                &rfc3339_utc(0),
            );
            assert!(store.emit_signed(&payload, &signer, Some(&digest)).is_err());
            assert!(
                store.list(&digest).unwrap().is_empty(),
                "nothing may be written"
            );
        }

        /// ★ THE TEST THIS SLICE IS FOR. A PERFECTLY SIGNED envelope from a
        /// PERFECTLY TRUSTED gate, whose statement names DIFFERENT bytes, is
        /// REFUSED — and nothing is written. Assert on the refusal.
        #[test]
        fn an_attestation_about_different_bytes_is_refused_by_name() {
            let tmp = tempfile::tempdir().unwrap();
            let g = gate("cve-gate");
            let store = store_trusting(tmp.path(), &g);
            let a = ArtifactDigest::sha256(D_A).unwrap();

            // A genuine, verifying envelope — about B.
            let env = g.sign(&stmt(&[("some-other-artifact", D_B)], INTOTO_VULNS_V01));
            let err = store
                .accept(&env, &[g.cert()], Some(&a))
                .expect_err("a statement about other bytes must be refused");
            assert_eq!(err.code().code, "holger-attest-3", "{err}");

            // Nothing was filed — not under A, and not under B either: the
            // submission was refused, not re-routed to the bytes it happened to
            // name.
            assert!(store.list(&a).unwrap().is_empty());
            assert!(store
                .list(&ArtifactDigest::sha256(D_B).unwrap())
                .unwrap()
                .is_empty());
        }

        /// An envelope signed by a key from a DIFFERENT CA is refused: the
        /// signature verifies against its own certificate, and the chain walk is
        /// what says no.
        #[test]
        fn an_envelope_signed_by_an_untrusted_key_is_refused() {
            let tmp = tempfile::tempdir().unwrap();
            let good = gate("cve-gate");
            let rogue = gate("rogue");
            let a = ArtifactDigest::sha256(D_A).unwrap();

            // The rogue's fingerprint IS enrolled (so this is not the enrolment
            // refusal) but its CA is not a root — only the chain can refuse it.
            let mut trust = AttestTrust::new();
            trust.add_root_der(good.ca_der.clone());
            trust.enrol_signer_der(&rogue.cert());
            let store = AttestStore::new(tmp.path()).with_trust(trust);

            let env = rogue.sign(&stmt(&[("serde-1.0.0.crate", D_A)], INTOTO_VULNS_V01));
            let err = store
                .accept(&env, &[rogue.cert()], Some(&a))
                .expect_err("a signer outside the trusted roots must be refused");
            assert_eq!(err.code().code, "holger-attest-5", "{err}");
            assert!(store.list(&a).unwrap().is_empty());
        }

        /// A key that chains PERFECTLY to the trusted root but was never enrolled
        /// as a gate is still refused — and with a DIFFERENT code, because the fix
        /// is different: enrol the key, not fix the signature. This is the layer
        /// that stops anybody inside the corporate CA's perimeter from minting
        /// scanner verdicts.
        #[test]
        fn a_chaining_but_unenrolled_signer_is_refused_with_its_own_code() {
            let tmp = tempfile::tempdir().unwrap();
            let (ca_key, ca_der) = dev::mint_ca("corp-ca").unwrap();
            let enrolled = dev::new_p256_signer(&ca_key, &ca_der, "cve-gate").unwrap();
            let interloper = dev::new_p256_signer(&ca_key, &ca_der, "somebody-else").unwrap();

            let mut trust = AttestTrust::new();
            trust.add_root_der(ca_der.clone());
            trust.enrol_signer_der(enrolled.certificate_der());
            let store = AttestStore::new(tmp.path()).with_trust(trust);

            let a = ArtifactDigest::sha256(D_A).unwrap();
            let payload = stmt(&[("serde-1.0.0.crate", D_A)], INTOTO_VULNS_V01);
            let env = dsse_sign(DSSE_PAYLOAD_TYPE_INTOTO, &payload, &[&interloper])
                .unwrap()
                .to_json()
                .unwrap()
                .into_bytes();

            let err = store
                .accept(&env, &[interloper.certificate_der().to_vec()], Some(&a))
                .expect_err("an unenrolled gate must be refused");
            assert_eq!(err.code().code, "holger-attest-4", "{err}");
            assert!(store.list(&a).unwrap().is_empty());
        }

        /// A TAMPERED payload breaks the signature, because DSSE signs
        /// `PAE(payloadType, payload)` and not the payload alone. Flip one byte of
        /// the statement inside a genuine envelope and it stops verifying.
        #[test]
        fn a_tampered_payload_is_refused() {
            let tmp = tempfile::tempdir().unwrap();
            let g = gate("cve-gate");
            let store = store_trusting(tmp.path(), &g);
            let a = ArtifactDigest::sha256(D_A).unwrap();

            let genuine = g.sign(&stmt(&[("serde-1.0.0.crate", D_A)], INTOTO_VULNS_V01));
            // Re-encode the envelope with a different payload, keeping the signature.
            let mut v: Value = serde_json::from_slice(&genuine).unwrap();
            v["payload"] = Value::String(znippy_common::sign::base64_encode(&stmt(
                &[("serde-1.0.0.crate", D_A)],
                INTOTO_TEST_RESULT_V01,
            )));
            let forged = serde_json::to_vec(&v).unwrap();

            let err = store
                .accept(&forged, &[g.cert()], Some(&a))
                .expect_err("a spliced payload must not verify");
            assert_eq!(err.code().code, "holger-attest-5", "{err}");
            assert!(store.list(&a).unwrap().is_empty());
        }

        /// A predicate this server does not accept is refused BEFORE any storage —
        /// an unknown claim filed is a claim a later gate may read and count as
        /// satisfied.
        #[test]
        fn an_unsupported_predicate_is_refused() {
            let tmp = tempfile::tempdir().unwrap();
            let g = gate("cve-gate");
            let store = store_trusting(tmp.path(), &g)
                .with_policy(AttestPolicy::none().accept(CYCLONEDX_BOM));
            let a = ArtifactDigest::sha256(D_A).unwrap();

            let env = g.sign(&stmt(&[("serde-1.0.0.crate", D_A)], INTOTO_VULNS_V01));
            let err = store
                .accept(&env, &[g.cert()], Some(&a))
                .expect_err("an unlisted predicate must be refused");
            assert_eq!(err.code().code, "holger-attest-6", "{err}");
            assert!(store.list(&a).unwrap().is_empty());
        }

        /// Malformed envelope bytes are refused by their own code, distinct from a
        /// malformed STATEMENT — the producer's bug is in a different place.
        #[test]
        fn a_malformed_envelope_is_refused_by_its_own_code() {
            let tmp = tempfile::tempdir().unwrap();
            let g = gate("cve-gate");
            let store = store_trusting(tmp.path(), &g);
            for bad in [
                &b"not json"[..],
                b"{}",
                br#"{"payload":"!!!","payloadType":"x"}"#,
            ] {
                let err = store
                    .accept(bad, &[g.cert()], None)
                    .expect_err("must refuse");
                assert_eq!(err.code().code, "holger-attest-1", "{err}");
            }
            // A well-formed envelope carrying the WRONG payloadType is the
            // payload-type-confusion case, and it is refused at the same door.
            let payload = stmt(&[("x", D_A)], CYCLONEDX_BOM);
            let env = dsse_sign(
                "application/vnd.something-else+json",
                &payload,
                &[&g.signer],
            )
            .unwrap()
            .to_json()
            .unwrap()
            .into_bytes();
            let err = store
                .accept(&env, &[g.cert()], None)
                .expect_err("must refuse");
            assert_eq!(err.code().code, "holger-attest-1", "{err}");
        }

        /// MULTIPLE attestations coexist on one artifact: different predicate types
        /// from different gates, and two DIFFERENT claims of the SAME predicate.
        /// The store returns all of them — it never resolves a disagreement between
        /// gates on the promotion boundary's behalf.
        #[test]
        fn many_attestations_coexist_and_a_query_returns_all_of_them() {
            let tmp = tempfile::tempdir().unwrap();
            let g1 = gate("cve-gate");
            let g2 = gate("sbom-gate");
            let mut trust = AttestTrust::new();
            trust.add_root_der(g1.ca_der.clone());
            trust.add_root_der(g2.ca_der.clone());
            trust.enrol_signer_der(&g1.cert());
            trust.enrol_signer_der(&g2.cert());
            let store = AttestStore::new(tmp.path()).with_trust(trust);
            let a = ArtifactDigest::sha256(D_A).unwrap();

            let vulns = g1.sign(&stmt(&[("serde", D_A)], INTOTO_VULNS_V01));
            let sbom = g2.sign(&stmt(&[("serde", D_A)], CYCLONEDX_BOM));
            // A SECOND vulns claim about the same bytes, from the same gate, with a
            // different predicate body — a genuine disagreement.
            let subs = vec![("serde".to_string(), a.clone())];
            let vulns2 = g1.sign(&statement_bytes(
                &subs,
                INTOTO_VULNS_V01,
                serde_json::json!({"scanResults": [{"id": "CVE-2021-44228"}]}),
            ));
            store.accept(&vulns, &[g1.cert()], Some(&a)).unwrap();
            store.accept(&sbom, &[g2.cert()], Some(&a)).unwrap();
            store.accept(&vulns2, &[g1.cert()], Some(&a)).unwrap();

            assert_eq!(store.list(&a).unwrap().len(), 3, "all three are held");
            assert_eq!(
                store.query(&a, INTOTO_VULNS_V01).unwrap().len(),
                2,
                "BOTH vulns claims come back — the store does not pick a winner"
            );
            assert_eq!(store.query(&a, CYCLONEDX_BOM).unwrap().len(), 1);
            assert!(store.query(&a, SLSA_PROVENANCE_V1).unwrap().is_empty());
        }

        /// Re-submitting the IDENTICAL envelope is idempotent: same content id, one
        /// file. An evidence store that grew a duplicate per retry would turn a
        /// flaky network into a fake quorum.
        #[test]
        fn resubmitting_the_same_envelope_is_idempotent() {
            let tmp = tempfile::tempdir().unwrap();
            let g = gate("cve-gate");
            let store = store_trusting(tmp.path(), &g);
            let a = ArtifactDigest::sha256(D_A).unwrap();
            let env = g.sign(&stmt(&[("serde", D_A)], INTOTO_VULNS_V01));

            let first = store.accept(&env, &[g.cert()], Some(&a)).unwrap();
            let second = store.accept(&env, &[g.cert()], Some(&a)).unwrap();
            assert_eq!(first.envelope_id, second.envelope_id);
            assert_eq!(store.list(&a).unwrap().len(), 1);
        }

        /// A SET-SCOPE statement — one signature over N artifacts — is filed under
        /// every member and found from any of them. This is what "analysis of the
        /// promoted set as a whole" needs, and a store keyed one-subject-deep could
        /// not hold it.
        #[test]
        fn a_set_scope_statement_is_filed_under_every_member() {
            let tmp = tempfile::tempdir().unwrap();
            let g = gate("set-gate");
            let store = store_trusting(tmp.path(), &g);
            let a = ArtifactDigest::sha256(D_A).unwrap();
            let b = ArtifactDigest::sha256(D_B).unwrap();

            let env = g.sign(&stmt(
                &[("a.crate", D_A), ("b.crate", D_B)],
                INTOTO_VULNS_V01,
            ));
            let accepted = store.accept(&env, &[g.cert()], Some(&a)).unwrap();
            assert_eq!(accepted.subjects.len(), 2);
            assert_eq!(store.query(&a, INTOTO_VULNS_V01).unwrap().len(), 1);
            assert_eq!(store.query(&b, INTOTO_VULNS_V01).unwrap().len(), 1);
            // …and the SAME envelope bytes come back from both.
            assert_eq!(
                store.query(&a, INTOTO_VULNS_V01).unwrap()[0].envelope_json,
                store.query(&b, INTOTO_VULNS_V01).unwrap()[0].envelope_json
            );
        }

        /// A crash-leftover `.tmp` sibling is never served — only committed
        /// `.dsse.json` files are read back.
        #[test]
        fn a_leftover_staging_file_is_never_served() {
            let tmp = tempfile::tempdir().unwrap();
            let g = gate("cve-gate");
            let store = store_trusting(tmp.path(), &g);
            let a = ArtifactDigest::sha256(D_A).unwrap();
            store
                .accept(
                    &g.sign(&stmt(&[("serde", D_A)], INTOTO_VULNS_V01)),
                    &[g.cert()],
                    Some(&a),
                )
                .unwrap();

            let dir = store.digest_dir(&a);
            std::fs::write(dir.join("half.json.tmp"), b"not an envelope").unwrap();
            assert_eq!(
                store.list(&a).unwrap().len(),
                1,
                "the half-written file is ignored"
            );
        }

        /// A signature whose `keyid` names a gate but for which NO certificate was
        /// offered is refused as untrusted: a keyid is an unauthenticated hint, and
        /// trusting it alone would be trusting the attacker's own label.
        #[test]
        fn a_keyid_with_no_certificate_on_offer_is_refused() {
            let tmp = tempfile::tempdir().unwrap();
            let g = gate("cve-gate");
            let store = store_trusting(tmp.path(), &g);
            let a = ArtifactDigest::sha256(D_A).unwrap();
            let env = g.sign(&stmt(&[("serde", D_A)], INTOTO_VULNS_V01));

            let err = store
                .accept(&env, &[], Some(&a))
                .expect_err("no cert on offer");
            assert_eq!(err.code().code, "holger-attest-4", "{err}");
        }
    }
}