crates/dwarves-slsa/tests/workspace_example.rs
//! `[[workspace_example]]`: a release step that runs an example of a workspace from the
//! release's SOURCES (`cargo run --release --locked --offline --example <name>`) in a
//! sealed, network-off build container, and takes the files it writes as subjects. The
//! case it is for: Heimdall's verify-bundle guest, whose `dist` example builds the three
//! wasm components (job, verifier, decoder) and their `.wasm.blake3` reproducibly; the
//! guest is its own workspace, so its lock is a second `lock` of the release.
use std::collections::{BTreeMap, BTreeSet};
use std::path::Path;
use std::process::Command;
use std::sync::Arc;
use dwarves_runa::{Pipeline, Step};
use dwarves_slsa::runner::{
self, check_isolation, fetch_container, release_pipeline, workspace_example_container,
Executor, Layout, ReleaseRun, RunOptions, RunRecord, StepRecord, ACTIONS,
FORGE_COLLECT_EXAMPLE,
};
use dwarves_slsa::spec::ReleaseSpec;
use dwarves_slsa::Result;
const IMAGE: &str = "localhost/nordisk-cargo-toolchain@sha256:5470ba85216b3c38d35de0bbb36a4244e104995fce4e9bf79a0c0357e9b8b29f";
const ROOT: &str = "/home/u/slsa-runs/heimdall-guests-0.2.1-20261031T120000Z";
const OUTPUTS: [&str; 6] = [
"guests/heimdall-verify-bundle.wasm",
"guests/heimdall-verify-bundle.wasm.blake3",
"guests/heimdall-verify-bundle-verifier.wasm",
"guests/heimdall-verify-bundle-verifier.wasm.blake3",
"guests/heimdall-verify-bundle-decoder.wasm",
"guests/heimdall-verify-bundle-decoder.wasm.blake3",
];
fn spec_text(commit: &str, extra: &str) -> String {
let outputs = OUTPUTS.iter().map(|o| format!("{o:?}")).collect::<Vec<_>>().join(", ");
format!(
r#"
name = "heimdall-guests-0.2.1"
image = "{IMAGE}"
lock = ["heimdall/Cargo.toml", "heimdall/guests/verify-bundle/Cargo.toml"]
[[repo]]
name = "heimdall"
org = "nordisk"
commit = "{commit}"
[[workspace_example]]
manifest = "heimdall/guests/verify-bundle/Cargo.toml"
example = "dist"
args = ["{{out}}/guests", "/target/guests"]
outputs = [{outputs}]
{extra}"#
)
}
fn spec() -> ReleaseSpec {
ReleaseSpec::parse(&spec_text(&"a".repeat(40), "")).unwrap()
}
fn refused(edit: impl Fn(String) -> String, why: &str) {
let text = edit(spec_text(&"a".repeat(40), ""));
let e = ReleaseSpec::parse(&text).unwrap_err();
assert!(e.0.contains(why), "want {why:?} in: {e}");
}
#[test]
fn a_release_of_one_workspace_example_only_is_a_release() {
let s = spec();
assert!(s.crates.is_empty() && s.workspace_binaries.is_empty());
let w = &s.workspace_examples[0];
assert_eq!(w.manifest, "heimdall/guests/verify-bundle/Cargo.toml");
assert_eq!(w.example, "dist");
assert_eq!(w.args, ["{out}/guests", "/target/guests"]);
assert_eq!(w.outputs.len(), 6);
let ep = s.external_parameters();
assert_eq!(ep["workspaceExamples"][0]["example"], "dist");
assert_eq!(ep["workspaceExamples"][0]["outputs"][0], OUTPUTS[0]);
// the TOML round-trips
assert_eq!(ReleaseSpec::parse(&s.to_toml().unwrap()).unwrap(), s);
}
#[test]
fn the_guest_lock_is_a_second_lock_vendored_with_the_first() {
let s = spec();
assert_eq!(s.locks, ["heimdall/Cargo.toml", "heimdall/guests/verify-bundle/Cargo.toml"]);
let c = fetch_container(&Layout::new(ROOT), &s);
assert_eq!(
c.cmd,
[
"cargo", "vendor", "--locked", "--versioned-dirs", "-s",
"/src/heimdall/guests/verify-bundle/Cargo.toml", "/vendor/crates"
]
);
assert_eq!(c.workdir, "/src/heimdall");
}
#[test]
fn a_workspace_example_of_an_unpinned_repo_or_outside_path_is_refused() {
refused(
|t| t.replace("manifest = \"heimdall/guests", "manifest = \"edda/guests"),
"pinned",
);
refused(
|t| t.replace("manifest = \"heimdall/guests/verify-bundle/Cargo.toml\"", "manifest = \"heimdall/../x/Cargo.toml\""),
"manifest",
);
refused(
|t| t.replace("manifest = \"heimdall/guests/verify-bundle/Cargo.toml\"", "manifest = \"heimdall/guests/verify-bundle/x.rs\""),
"manifest",
);
}
#[test]
fn a_workspace_example_names_only_safe_names_and_paths() {
refused(|t| t.replace("example = \"dist\"", "example = \"../dist\""), "example");
refused(|t| t.replace("example = \"dist\"", "example = \"\""), "example");
refused(|t| t.replace("\"{out}/guests\"", "\"{out}/../guests\""), "{out}");
refused(|t| t.replace("\"{out}/guests\"", "\"{out}guests\""), "{out}");
refused(|t| t.replace("\"/target/guests\"", "\"/target/../src\""), "..");
}
#[test]
fn a_workspace_example_declares_its_outputs_once_each_inside_out() {
refused(|t| t.replace(&format!("{:?}", OUTPUTS[1]), "\"/etc/passwd\""), "output");
refused(|t| t.replace(&format!("{:?}", OUTPUTS[1]), "\"guests/../x\""), "output");
refused(|t| t.replace(&format!("{:?}", OUTPUTS[1]), &format!("{:?}", OUTPUTS[0])), "twice");
refused(
|t| {
let start = t.find("outputs = [").unwrap();
let end = t[start..].find(']').unwrap() + start + 1;
format!("{}outputs = []{}", &t[..start], &t[end..])
},
"output",
);
// two examples may not write the same file
let two = spec_text(
&"a".repeat(40),
&format!(
"[[workspace_example]]\nmanifest = \"heimdall/guests/verify-bundle/Cargo.toml\"\nexample = \"dist\"\nargs = [\"{{out}}\"]\noutputs = [{:?}]\n",
OUTPUTS[0]
),
);
let e = ReleaseSpec::parse(&two).unwrap_err();
assert!(e.0.contains("twice"), "{e}");
}
#[test]
fn a_workspace_example_runs_offline_from_the_snapshot_in_a_sealed_container() {
let s = spec();
let l = Layout::new(ROOT);
let c = workspace_example_container(&l, &s, 0, &s.workspace_examples[0], 6);
check_isolation(&c, &l, true).unwrap();
assert!(!c.network, "network none");
assert_eq!(
c.cmd,
[
"cargo", "run", "--release", "--locked", "--offline", "--manifest-path",
"/src/heimdall/guests/verify-bundle/Cargo.toml", "--example", "dist",
"--target-dir", "/target/example-0", "--", "/example-out/guests", "/target/guests"
]
);
// the example's own cargo (it builds the guest for wasm32) is offline by construction
assert!(c.env.contains(&("CARGO_NET_OFFLINE".to_string(), "true".to_string())), "{:?}", c.env);
assert!(c.env.contains(&("CARGO_HOME".to_string(), "/cargo-home".to_string())));
assert_eq!(c.workdir, "/src/heimdall/guests/verify-bundle");
let o = c.bind("/example-out").expect("its own output directory");
assert!(!o.read_only);
assert_eq!(o.host, Path::new(ROOT).join("example-out/0"));
assert!(c.bind("/out").is_none(), "the build never writes out/ itself: the forge collects");
for ro in ["/src", "/vendor", "/stage", "/plan", "/published"] {
assert!(c.bind(ro).unwrap().read_only, "{ro}");
}
}
#[test]
fn the_pipeline_runs_the_example_after_the_vendor_check_then_collects_it() {
let s = spec();
let p = release_pipeline(&s, &Layout::new(ROOT), &BTreeSet::new(), 4).unwrap();
let names: Vec<&str> = p.stages.iter().map(|s| s.name.as_str()).collect();
assert_eq!(
names,
[
"sources", "seal-sources", "fetch", "probe-lock", "probe-vendor", "vendor-check",
"workspace-example-0-dist", "workspace-example-0-dist-out",
]
);
match &p.stages[6].steps[0] {
Step::Sandbox { cmd, network, .. } => {
assert_eq!(cmd[..2], ["cargo", "run"]);
assert!(!network);
}
other => panic!("{other:?}"),
}
match &p.stages[7].steps[0] {
Step::Forge { action, args } => {
assert_eq!(action, FORGE_COLLECT_EXAMPLE);
assert_eq!(args, &["0"]);
}
other => panic!("{other:?}"),
}
assert!(ACTIONS.contains(&FORGE_COLLECT_EXAMPLE));
p.validate().unwrap();
}
fn write(p: &Path, body: &[u8]) {
std::fs::create_dir_all(p.parent().unwrap()).unwrap();
std::fs::write(p, body).unwrap();
}
fn written(l: &Layout) {
for o in OUTPUTS {
write(&l.example_out().join("0").join(o), o.as_bytes());
}
}
#[test]
fn the_forge_collects_exactly_the_declared_outputs_into_out() {
let d = tempfile::tempdir().unwrap();
let l = Layout::new(d.path());
let rr = ReleaseRun::new(spec(), l.clone(), None, BTreeMap::new());
written(&l);
rr.forge(FORGE_COLLECT_EXAMPLE, &["0".into()], &mut |_| {}).unwrap();
for o in OUTPUTS {
assert_eq!(std::fs::read(l.out().join(o)).unwrap(), o.as_bytes(), "{o}");
}
// a second collect would overwrite a subject
let e = rr.forge(FORGE_COLLECT_EXAMPLE, &["0".into()], &mut |_| {}).unwrap_err();
assert!(e.0.contains("twice") || e.0.contains("exists"), "{e}");
// an index that is not a step
let e = rr.forge(FORGE_COLLECT_EXAMPLE, &["7".into()], &mut |_| {}).unwrap_err();
assert!(e.0.contains("7"), "{e}");
}
#[test]
fn the_forge_refuses_a_missing_an_undeclared_or_a_linked_output() {
// missing
let d = tempfile::tempdir().unwrap();
let l = Layout::new(d.path());
let rr = ReleaseRun::new(spec(), l.clone(), None, BTreeMap::new());
written(&l);
std::fs::remove_file(l.example_out().join("0").join(OUTPUTS[3])).unwrap();
let e = rr.forge(FORGE_COLLECT_EXAMPLE, &["0".into()], &mut |_| {}).unwrap_err();
assert!(e.0.contains(OUTPUTS[3]), "{e}");
assert!(!l.out().join(OUTPUTS[0]).exists(), "nothing collected from a refused step");
// undeclared
let d = tempfile::tempdir().unwrap();
let l = Layout::new(d.path());
let rr = ReleaseRun::new(spec(), l.clone(), None, BTreeMap::new());
written(&l);
write(&l.example_out().join("0/guests/extra.wasm"), b"x");
let e = rr.forge(FORGE_COLLECT_EXAMPLE, &["0".into()], &mut |_| {}).unwrap_err();
assert!(e.0.contains("extra.wasm") && e.0.contains("not declared"), "{e}");
assert!(!l.out().join(OUTPUTS[0]).exists());
// a link
let d = tempfile::tempdir().unwrap();
let l = Layout::new(d.path());
let rr = ReleaseRun::new(spec(), l.clone(), None, BTreeMap::new());
written(&l);
let f = l.example_out().join("0").join(OUTPUTS[5]);
std::fs::remove_file(&f).unwrap();
std::os::unix::fs::symlink("/etc/hostname", &f).unwrap();
let e = rr.forge(FORGE_COLLECT_EXAMPLE, &["0".into()], &mut |_| {}).unwrap_err();
assert!(e.0.contains("not a regular file"), "{e}");
assert!(!l.out().join(OUTPUTS[0]).exists());
}
// ───────── the whole release, with a stand-in for the sealed containers ─────────
fn git(dir: &Path, args: &[&str]) -> String {
let o = Command::new("git")
.arg("-C")
.arg(dir)
.args(["-c", "user.name=t", "-c", "user.email=t@example.invalid", "-c", "commit.gpgsign=false"])
.args(args)
.output()
.unwrap();
assert!(o.status.success(), "git {args:?}: {}", String::from_utf8_lossy(&o.stderr));
String::from_utf8_lossy(&o.stdout).trim().to_string()
}
/// A repository `heimdall` with a workspace lock and the guest's own lock.
fn repo(from: &Path) -> String {
let r = from.join("heimdall");
for (p, body) in [
("Cargo.toml", "[workspace]\nmembers = []\n"),
("Cargo.lock", "version = 4\n"),
("guests/verify-bundle/Cargo.toml", "[package]\nname = \"g\"\nversion = \"0.1.0\"\nedition = \"2021\"\n[workspace]\n"),
("guests/verify-bundle/Cargo.lock", "version = 4\n\n[[package]]\nname = \"g\"\nversion = \"0.1.0\"\n"),
("guests/verify-bundle/examples/dist.rs", "fn main() {}\n"),
] {
write(&r.join(p), body.as_bytes());
}
git(&r, &["init", "-q"]);
git(&r, &["add", "-A"]);
git(&r, &["commit", "-q", "-m", "heimdall"]);
git(&r, &["rev-parse", "HEAD"])
}
struct StandIn {
leave_out: Option<&'static str>,
}
impl Executor for StandIn {
fn execute(&self, p: &Pipeline, run: Arc<ReleaseRun>, run_id: &str) -> Result<RunRecord> {
let l = &run.layout;
let mut steps = Vec::new();
for st in &p.stages {
for s in &st.steps {
let ok = match s {
Step::Forge { action, args } => run
.forge(action, args, &mut |m| eprintln!(" [{}] {m}", st.name))
.map_err(|e| eprintln!("{}: {e}", st.name))
.is_ok(),
Step::Sandbox { cmd, mounts, .. } => {
match cmd[1].as_str() {
"vendor" => std::fs::create_dir_all(l.vendor().join("crates")).unwrap(),
"generate-lockfile" => std::fs::write(
l.probe().join("Cargo.lock"),
"version = 4\n\n[[package]]\nname = \"dwarves-slsa-probe\"\nversion = \"0.0.0\"\n",
)
.unwrap(),
"run" => {
// what `dist` writes into /example-out
let m = mounts.iter().find(|m| m.path == "/example-out").unwrap();
for o in OUTPUTS.iter().filter(|o| Some(**o) != self.leave_out) {
write(&Path::new(&m.host).join(o), format!("bytes of {o}").as_bytes());
}
}
other => panic!("{other}"),
}
true
}
other => panic!("{other:?}"),
};
steps.push(StepRecord {
stage: st.name.clone(),
step: "s".into(),
status: if ok { "passed" } else { "failed" }.into(),
duration_ms: 1,
log: None,
});
if !ok {
return Ok(RunRecord { run_id: run_id.into(), pipeline: p.name.clone(), green: false, steps, reason: Some(format!("{} failed", st.name)) });
}
}
}
Ok(RunRecord { run_id: run_id.into(), pipeline: p.name.clone(), green: true, steps, reason: None })
}
}
fn opts(run_dir: &Path, from: &Path) -> RunOptions {
RunOptions {
run_dir: run_dir.into(),
from: Some(from.into()),
jobs: 2,
rebuild_published: false,
keep: false,
run_id: Some("heimdall-guests-0.2.1-test".into()),
builder_version: BTreeMap::new(),
}
}
#[test]
fn a_release_of_the_guests_has_the_example_outputs_as_its_subjects() {
let d = tempfile::tempdir().unwrap();
let from = d.path().join("from");
let commit = repo(&from);
let run_dir = d.path().join("run");
let s = ReleaseSpec::parse(&spec_text(&commit, "")).unwrap();
let st = runner::run(&s, &opts(&run_dir, &from), &StandIn { leave_out: None }).unwrap();
let v: serde_json::Value = serde_json::from_slice(&std::fs::read(&st).unwrap()).unwrap();
let names: BTreeSet<&str> = v["subject"].as_array().unwrap().iter().map(|x| x["name"].as_str().unwrap()).collect();
assert_eq!(names, OUTPUTS.into_iter().collect::<BTreeSet<_>>());
for x in v["subject"].as_array().unwrap() {
let f = run_dir.join("out").join(x["name"].as_str().unwrap());
assert_eq!(x["digest"]["sha256"], dwarves_slsa::subjects::sha256_file(&f).unwrap());
}
let pred = &v["predicate"]["buildDefinition"];
assert_eq!(pred["externalParameters"]["workspaceExamples"][0]["example"], "dist");
// both locks are recorded
let res = pred["resolvedDependencies"].as_array().unwrap();
for lock in ["heimdall/Cargo.lock", "heimdall/guests/verify-bundle/Cargo.lock"] {
assert!(res.iter().any(|r| r["name"] == lock), "{lock} recorded");
}
assert!(!run_dir.join("example-out").exists(), "the example's scratch output is cleaned like target/");
}
#[test]
fn a_release_whose_example_left_out_an_output_is_red_and_writes_no_statement() {
let d = tempfile::tempdir().unwrap();
let from = d.path().join("from");
let commit = repo(&from);
let run_dir = d.path().join("run");
let s = ReleaseSpec::parse(&spec_text(&commit, "")).unwrap();
let e = runner::run(&s, &opts(&run_dir, &from), &StandIn { leave_out: Some(OUTPUTS[4]) }).unwrap_err();
assert!(e.0.contains("red"), "{e}");
assert!(!run_dir.join("release.statement.json").exists());
}