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

nordisk/holger

provenance/examples/verify_slsa.rs

//! Verify one artifact against its `.intoto.jsonl` the way Holger's intake does —
//! the counterpart of `sign_slsa`, for a build the dwarves build door sealed.
//!
//! ```text
//! cargo run -p holger-provenance --example verify_slsa -- \
//!     <artifact> <artifact.intoto.jsonl> <keyid> <spki-base64-or-pem-file> <builder-id> <builder-level> <slsa-min>
//! ```
//!
//! The policy is the RON floor's shape, built from the arguments: one trusted
//! Ed25519 key, one allowed builder at the given SLSA build level, and a
//! `gates.provenance: Require(slsa_min: N)`. Prints the verdict, the code and the
//! read SLSA facts; exits 0 on Pass, 1 otherwise.

use holger_provenance::{
    effective, verify_artifact, BuilderRule, KeyAlg, ProvenanceFloor, ProvenanceGate, TrustedKey,
    Verdict,
};

fn main() -> anyhow::Result<()> {
    let args: Vec<String> = std::env::args().skip(1).collect();
    let [artifact, envelope, keyid, public_key, builder, level, slsa_min] = args.as_slice() else {
        anyhow::bail!("usage: verify_slsa <artifact> <envelope> <keyid> <spki-b64|pem-file> <builder-id> <builder-level> <slsa-min>");
    };
    let public_key = match std::fs::read_to_string(public_key) {
        Ok(pem) => pem,
        Err(_) => public_key.clone(),
    };
    let floor = ProvenanceFloor {
        keys: vec![TrustedKey {
            id: keyid.clone(),
            alg: KeyAlg::Ed25519,
            public_key,
        }],
        builders: vec![BuilderRule {
            id: builder.clone(),
            level: Some(level.parse()?),
        }],
        ..Default::default()
    };
    let gate = ProvenanceGate::Require {
        identity: None,
        identities: vec![],
        builders: vec![],
        keys: vec![],
        apk_keys: vec![],
        pgp_keys: vec![],
        slsa_min: Some(slsa_min.parse()?),
    };
    let name = std::path::Path::new(envelope)
        .file_name()
        .unwrap()
        .to_string_lossy()
        .into_owned();
    let r = verify_artifact(
        &std::fs::read(artifact)?,
        &[(name, std::fs::read(envelope)?)],
        &effective(&floor, &gate),
        None,
    );
    println!("verdict: {:?}", r.verdict);
    println!("code: {}", r.code.as_deref().unwrap_or("-"));
    println!("detail: {}", r.detail);
    if let Some(c) = r.verified_provenance().next() {
        if let Some(s) = &c.slsa {
            println!(
                "builder: {} · buildType: {} · slsa_level: {:?}",
                s.builder_id, s.build_type, c.slsa_level
            );
            println!("resolvedDependencies: {}", s.resolved_dependencies.len());
        }
    }
    std::process::exit(if r.verdict == Verdict::Pass { 0 } else { 1 });
}