guests/static-scan/tests/common/guests.rs
// SPDX-License-Identifier: AGPL-3.0-only
//! The guest as Heimdall runs it: built for wasm32-unknown-unknown, turned
//! into a component against heimdall-wasm's WIT, signed like a Holger plugin
//! (`.wasm.p7s` + `.wasm.blake3`) and loaded by the real host (no WASI).
//! Heimdall is a defensive sandbox.
#![allow(dead_code)]
use std::path::{Path, PathBuf};
use std::process::Command;
use std::sync::OnceLock;
use guest_host::verify::sign::{dev, sign_module};
use heimdall_wasm::{Guest, Host, HostConfig};
/// Build the core module for wasm32 (its own target dir, `--locked`).
fn build_core() -> Vec<u8> {
let crate_dir = Path::new(env!("CARGO_MANIFEST_DIR"));
let target = Path::new(env!("CARGO_TARGET_TMPDIR")).join("guest-wasm");
let st = Command::new(std::env::var("CARGO").unwrap_or_else(|_| "cargo".into()))
.args([
"build",
"--release",
"--locked",
"--lib",
"--target",
"wasm32-unknown-unknown",
"--manifest-path",
])
.arg(crate_dir.join("Cargo.toml"))
.arg("--target-dir")
.arg(&target)
.env_remove("RUSTFLAGS")
.env_remove("CARGO_ENCODED_RUSTFLAGS")
.status()
.expect("cargo could not be started");
assert!(st.success(), "building the guest for wasm32 failed");
std::fs::read(target.join("wasm32-unknown-unknown/release/heimdall_guest_static_scan.wasm"))
.unwrap()
}
pub fn core_module() -> &'static [u8] {
static M: OnceLock<Vec<u8>> = OnceLock::new();
M.get_or_init(build_core)
}
pub fn component() -> &'static [u8] {
static C: OnceLock<Vec<u8>> = OnceLock::new();
C.get_or_init(|| {
wit_component::ComponentEncoder::default()
.module(core_module())
.unwrap()
.validate(true)
.encode()
.unwrap()
})
}
/// The names a core module imports, as `module::name`.
pub fn imports(core: &[u8]) -> Vec<String> {
let mut out = Vec::new();
for payload in wasmparser::Parser::new(0).parse_all(core) {
if let wasmparser::Payload::ImportSection(r) = payload.unwrap() {
for imp in r.into_imports() {
let imp = imp.unwrap();
out.push(format!("{}::{}", imp.module, imp.name));
}
}
}
out
}
/// A signing CA, a release signer and a host that trusts the CA.
pub struct Lab {
pub dir: tempfile::TempDir,
pub host: Host,
signer: guest_host::verify::sign::Ed25519Signer,
}
impl Lab {
pub fn new() -> Lab {
let dir = tempfile::tempdir().unwrap();
let (ca_key, ca_der) = dev::mint_ca("heimdall-guest-test-ca").unwrap();
let root = dir.path().join("root.der");
std::fs::write(&root, &ca_der).unwrap();
let signer = dev::new_ed25519_signer(&ca_key, &ca_der, "heimdall-guest-release").unwrap();
let host = Host::new(HostConfig::new([root])).unwrap();
Lab { dir, host, signer }
}
/// Write `bytes` as `<name>.wasm`, signed and pinned; returns its path.
pub fn signed(&self, name: &str, bytes: &[u8]) -> PathBuf {
let module = self.dir.path().join(format!("{name}.wasm"));
std::fs::write(&module, bytes).unwrap();
std::fs::write(
self.dir.path().join(format!("{name}.wasm.p7s")),
sign_module(bytes, &self.signer).unwrap(),
)
.unwrap();
std::fs::write(
self.dir.path().join(format!("{name}.wasm.blake3")),
format!("{}\n", blake3::hash(bytes).to_hex()),
)
.unwrap();
module
}
}
pub struct Loaded {
pub lab: Lab,
pub guest: Guest,
}
pub fn loaded() -> &'static Loaded {
static L: OnceLock<Loaded> = OnceLock::new();
L.get_or_init(|| {
let lab = Lab::new();
let p = lab.signed("static-scan", component());
let guest = lab
.host
.load(&p)
.unwrap_or_else(|e| panic!("the host refused the guest: {e}"));
Loaded { lab, guest }
})
}