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)");
}