Gunnar

nordisk/heimdall

crates/heimdall-core/src/fuzz_api.rs

// SPDX-License-Identifier: AGPL-3.0-only
// Copyright (C) 2026 Ignalina ApS and Vetra Automation AB

//! Entry points for the cargo-fuzz targets (fuzz/) and their seed replay
//! tests. Each function must never panic except on a broken invariant.
//! Heimdall is a defensive sandbox; these fuzz only its own parsers.

use crate::*;

const FIXTURE_SEED: [u8; 32] = [0x5a; 32];
const FIXTURE_BOOT: BootId = BootId([0x42; 16]);

/// The fixed key the fuzz targets verify against (not a secret).
pub fn fixture_key() -> BootKey {
    BootKey::from_seed(FIXTURE_SEED, FIXTURE_BOOT)
}

/// A valid wire result signed by [`fixture_key`].
pub fn fixture_wire() -> Vec<u8> {
    let r = JobResult {
        job_id: JobId([1; 16]),
        nonce: Nonce([2; 32]),
        verdict: Verdict::Accepted,
        outputs: vec![Output::of("report.json", b"{}")],
        exit: ExitInfo::exited(0),
        started_unix: 10,
        finished_unix: 20,
        runner: Features {
            runner: "heimdall-wasm".into(),
            container: false,
            seccomp: Protection::None,
            landlock: false,
            broker: false,
            wasm: true,
            image_verified_each_start: true,
        },
        events: vec![BrokerEvent {
            at_ms: 1,
            call: "emit-file".into(),
            args: vec!["report.json".into()],
            decision: Decision::Allowed,
        }],
    };
    fixture_key()
        .sign(r)
        .expect("fixture result is valid")
        .to_bytes()
}

/// Wire decode + verify. Returns whether `data` verified.
pub fn signed_result_wire(data: &[u8]) -> bool {
    if let Ok(s) = SignedResult::from_bytes(data) {
        assert_eq!(s.to_bytes(), data, "decoded wire must re-encode exactly");
    }
    let mut v = Verifier::new(fixture_key().pinned()).expect("fixture pin is valid");
    match v.verify(data) {
        Ok(s) => {
            assert_eq!(s.to_bytes(), data);
            let t = JobTicket {
                job_id: s.result.job_id,
                nonce: s.result.nonce,
            };
            assert!(v.accept(data, &t).is_ok());
            assert!(matches!(v.accept(data, &t), Err(VerifyError::Replayed(_))));
            true
        }
        Err(_) => false,
    }
}

/// Result decode; a decoded value must re-encode to the same bytes.
pub fn result_encoding(data: &[u8]) {
    if let Ok(r) = decode_result(data) {
        assert_eq!(encode_result(&r), data, "one value, one encoding");
    }
}

/// Pinned key parse. Returns whether `data` parsed.
pub fn pinned_key_text(data: &[u8]) -> bool {
    let Ok(s) = std::str::from_utf8(data) else {
        return false;
    };
    match PinnedKey::from_text(s) {
        Ok(p) => {
            assert_eq!(PinnedKey::from_text(&p.to_text()), Ok(p));
            assert!(Verifier::new(p).is_ok());
            true
        }
        Err(_) => false,
    }
}