// SPDX-License-Identifier: AGPL-3.0-only
//! Property tests: random module bytes never get past load and never panic
//! the host; random input to a good guest always ends in a verdict, the same
//! one twice. Heimdall is a defensive sandbox.
mod common;
use common::*;
use heimdall_wasm::RunLimits;
use proptest::prelude::*;
use std::sync::OnceLock;
fn kit() -> &'static Kit {
static K: OnceLock<Kit> = OnceLock::new();
K.get_or_init(|| Kit::new("prop"))
}
fn good() -> &'static heimdall_wasm::Guest {
static G: OnceLock<heimdall_wasm::Guest> = OnceLock::new();
G.get_or_init(|| kit().guest("good", &good_wat()))
}
proptest! {
#![proptest_config(ProptestConfig { cases: 64, ..ProptestConfig::default() })]
#[test]
fn signed_random_bytes_never_load_and_never_panic(bytes in proptest::collection::vec(any::<u8>(), 0..4096)) {
prop_assert!(kit().try_load("random", &bytes).is_err());
}
#[test]
fn signed_random_bytes_behind_a_component_header_never_load(tail in proptest::collection::vec(any::<u8>(), 0..4096)) {
let mut bytes = b"\0asm\x0d\0\x01\0".to_vec();
bytes.extend(tail);
prop_assert!(kit().try_load("random-component", &bytes).is_err());
}
#[test]
fn any_input_ends_in_a_verdict_and_the_same_one_twice(input in proptest::collection::vec(any::<u8>(), 0..2048)) {
let a = good().run(&input, &none(), &RunLimits::default());
let b = good().run(&input, &none(), &RunLimits::default());
prop_assert_eq!(&a, &b);
match input.first() {
Some(b'T') => prop_assert_eq!(a.verdict.reason(), Some("input signature mismatch")),
Some(b'M') => prop_assert!(a.verdict.reason().unwrap().starts_with("guest trapped (")),
_ => {
prop_assert!(a.verdict.is_accepted());
prop_assert_eq!(&a.files[0].bytes, &input);
}
}
}
#[test]
fn any_params_reach_the_guest_without_harm(params in proptest::collection::btree_map(".{0,40}", ".{0,40}", 0..20)) {
let o = good().run(b"x", ¶ms, &RunLimits::default());
prop_assert!(o.verdict.is_accepted());
}
}