Gunnar

nordisk/heimdall

guests/verify-bundle/tests/fuzz_seeds.rs

// SPDX-License-Identifier: AGPL-3.0-only
//! The fuzz targets' entry points, replayed over the committed seed corpus
//! (`fuzz/seeds/<target>/`) and over freshly made real inputs, so every
//! `cargo test` exercises what `cargo fuzz` exercises.
//!
//! `HEIMDALL_WRITE_SEEDS=1 cargo test --test fuzz_seeds` rewrites the corpus.

mod common;
use common::*;

use heimdall_guest_verify_bundle::fuzz_api;

fn seeds() -> Vec<(&'static str, String, Vec<u8>)> {
    let fx = good();
    let archive = fx.pack();
    let a = holger_update_bundle::digest::sha256_hex(b"x");
    let env = format!(
        r#"{{"payloadType":"application/vnd.in-toto+json","payload":"e30=","signatures":[{{"keyid":"{a}","sig":"AAAA"}}]}}"#
    );
    vec![
        ("archive", "good-stored".into(), archive.clone()),
        (
            "archive",
            "raw-7-byte-chunks".into(),
            zwriter::RawArchive::from_members(&fx.members, 7).encode(),
        ),
        ("bundle", "good-stored".into(), archive),
        ("dsse_envelope", "minimal".into(), env.into_bytes()),
        ("params", "good".into(), fx.params()),
        ("certificate", "release".into(), fx.release.cert_der.clone()),
        (
            "archive",
            "openzl-4k-chunks".into(),
            zwriter::RawArchive::from_members_openzl(&fx.members, 4096).encode(),
        ),
        (
            "openzl_frame",
            "text".into(),
            zwriter::openzl_frame(&fx.release.cert_der.repeat(20)),
        ),
        (
            "openzl_frame",
            "ramp".into(),
            zwriter::openzl_frame(&(0..70_000u32).map(|i| (i % 251) as u8).collect::<Vec<_>>()),
        ),
        (
            "openzl_frame",
            "zeros".into(),
            zwriter::openzl_frame(&[0u8; 100_000]),
        ),
        ("openzl_frame", "tiny".into(), zwriter::openzl_frame(b"x")),
    ]
}

fn run(target: &str, data: &[u8]) {
    match target {
        "archive" => fuzz_api::archive(data),
        "bundle" => fuzz_api::bundle(data),
        "dsse_envelope" => fuzz_api::dsse_envelope(data),
        "params" => fuzz_api::params(data),
        "certificate" => fuzz_api::certificate(data),
        #[cfg(feature = "openzl")]
        "openzl_frame" => fuzz_api::openzl_frame(data),
        #[cfg(not(feature = "openzl"))]
        "openzl_frame" => {}
        other => panic!("no target {other}"),
    }
}

#[test]
fn every_fuzz_target_survives_its_seeds_and_their_truncations() {
    let dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("fuzz/seeds");
    let write = std::env::var_os("HEIMDALL_WRITE_SEEDS").is_some();
    for (target, name, data) in seeds() {
        if write {
            std::fs::create_dir_all(dir.join(target)).unwrap();
            std::fs::write(dir.join(target).join(&name), &data).unwrap();
        }
        run(target, &data);
        for cut in [0, 1, data.len() / 2, data.len().saturating_sub(1)] {
            run(target, &data[..cut]);
        }
    }
}

#[test]
fn every_committed_seed_replays_without_panicking() {
    let dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("fuzz/seeds");
    let mut n = 0;
    for t in [
        "archive",
        "bundle",
        "dsse_envelope",
        "params",
        "certificate",
    ] {
        let Ok(rd) = std::fs::read_dir(dir.join(t)) else {
            continue;
        };
        for e in rd.flatten() {
            run(t, &std::fs::read(e.path()).unwrap());
            n += 1;
        }
    }
    assert!(n >= 6, "the seed corpus is missing ({n} seeds)");
}