xtask/tests/build_is_a_thin_door.rs
//! **`cargo xtask build` is a THIN DOOR onto facett-build-thing** (workspace LAW).
//!
//! Held from the xtask side, without compiling anything: the door resolves the CODE,
//! refuses the rows cargo cannot build BY NAME with the door that does, and the
//! xtask sources spell no build knowledge the recipe owns. The recipe side is
//! `facett-build-thing/tests/thin_door.rs`.
use std::path::PathBuf;
use facett_build_thing::{declared, nornir_build_thing::variant::ArtifactKind};
use xtask::door;
fn root() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR")).parent().unwrap().to_path_buf()
}
fn argv(a: &[&str]) -> Vec<String> {
a.iter().map(|s| s.to_string()).collect()
}
#[test]
fn list_resolves_every_row_from_the_code_and_names_each_refusal() {
let set = declared();
let r = door::resolve(&set, &argv(&["--list"])).expect("resolves");
assert_eq!(r.suite, "ORIGINAL");
assert_eq!(r.chosen.len(), set.variants.len());
let text = door::list_lines(&r).join("\n");
for v in &set.variants {
assert!(text.contains(&v.name), "--list lost row {}:\n{text}", v.name);
}
// 3 images + 2 packages (the facett and facett-demo wheels) are refused, each with
// its door; the cargo rows print the argv edda materializes.
assert_eq!(text.matches("REFUSED here").count(), 5, "{text}");
assert_eq!(text.matches("dwarves buildthing facett --variant").count(), 5, "{text}");
assert!(text.contains("cargo build -p facet-wrapped --profile release --target wasm32-unknown-unknown"), "{text}");
}
#[test]
fn a_row_cargo_cannot_build_is_refused_by_name_with_its_door() {
let set = declared();
for v in set.variants.iter().filter(|v| !v.kind.is_cargo()) {
let e = door::resolve(&set, &argv(&["--variant", &v.name])).err().expect("refused");
assert!(e.contains("refused") && e.contains(&v.name), "{e}");
let door_word = if v.kind == ArtifactKind::Package { "cargo ops publish-pip" } else { "dwarves buildthing" };
assert!(e.contains(door_word), "{} refused without naming `{door_word}`: {e}", v.name);
// And the building half refuses too, before any road is entered: `run`
// partitions on this same refusal, so no engine is asked for these rows.
assert!(door::refusal(v).is_some_and(|r| r.contains(&v.name)));
}
}
#[test]
fn an_unknown_row_and_a_forge_only_flag_are_refused() {
let set = declared();
let e = door::resolve(&set, &argv(&["--variant", "no-such-row"])).err().expect("refused");
assert!(e.contains("no such variant"), "{e}");
let e = door::resolve(&set, &argv(&["--variant", "facett-demo", "--build", "kernel"])).err().expect("refused");
assert!(e.contains("forge"), "{e}");
}
/// wrap-wasm's argv is the ROW's, materialized by edda — the same string the forge
/// runs. It used to be `build --release --lib -p facet-wrapped --target …`, spelled here.
#[test]
fn wrap_wasm_is_the_declared_row() {
let set = declared();
let row = set.require(facett_build_thing::WASM_VARIANT).unwrap();
assert_eq!(row.command_line(), "cargo build -p facet-wrapped --profile release --target wasm32-unknown-unknown");
let cell = set.wasm(&row.name).expect("the row declares its stages");
let outs = cell.outputs(row);
for f in facett_build_thing::WASM_OUTPUTS {
assert!(outs.iter().any(|o| o.ends_with(f)), "the cell does not produce {f}: {outs:?}");
}
}
/// The sources own no build knowledge the recipe declares. `panel-wasm` used to be
/// the one named exception (a cargo EXAMPLE could not be a row); since edda grew
/// `BuildVariant::example` it is the `facett-wasm-demo-panel` row, and main.rs
/// spells neither its package nor its example.
#[test]
fn the_xtask_sources_spell_no_row_knowledge() {
let src = |f: &str| std::fs::read_to_string(root().join("xtask/src").join(f)).unwrap();
let door_rs = src("door.rs");
let code: String = door_rs.lines().filter(|l| !l.trim_start().starts_with("//")).collect::<Vec<_>>().join("\n");
for banned in ["wasm32", "\"facet-wrapped", "\"facett-demo", "--features", "--target", "\"nordisk-"] {
assert!(!code.contains(banned), "door.rs spells `{banned}`");
}
let main = src("main.rs");
let code: String = main.lines().filter(|l| !l.trim_start().starts_with("//")).collect::<Vec<_>>().join("\n");
for banned in ["\"wasm32-unknown-unknown\"", "\"facet-wrapped\"", "\"facett-demo\"", "\"--no-typescript\"", "\"manifest\"", "\"facett-wasm-demo\"", "\"panel\"", "\"--example\"", "Command::new"] {
assert!(!code.contains(banned), "main.rs spells `{banned}`");
}
let pip = std::fs::read_to_string(root().join("facett-ops/src/pip.rs")).unwrap();
for banned in ["\"nordisk-pip-toolchain\"", "\"facet_wrapped_web\"", "\"pkg-facet-wrapped\"", "\"facett_demo\"", "\"py/dist\""] {
assert!(!pip.contains(banned), "pip.rs spells `{banned}`");
}
}
/// ONE edge to the engine: through the recipe's re-export, never a direct dep.
#[test]
fn xtask_reaches_the_engine_only_through_the_recipe() {
let manifest = std::fs::read_to_string(root().join("xtask/Cargo.toml")).unwrap();
let direct = manifest.lines().any(|l| l.trim_start().starts_with("nornir-build-thing"));
assert!(!direct, "xtask/Cargo.toml names nornir-build-thing directly");
assert!(manifest.lines().any(|l| l.starts_with("facett-build-thing = ")));
}
/// THE CONTAINER LAW, the half that needs no engine: the declared toolchain
/// validates, and every way of having no pinned image is refused BY NAME before
/// an engine is asked — there is no host fallback to fall into.
#[test]
fn the_build_road_is_the_pinned_image_or_a_named_refusal() {
let set = declared();
let tc = door::toolchain(&set).expect("facett's [build.toolchain] validates");
assert!(tc.image_ref().contains("@sha256:"), "{}", tc.image_ref());
assert!(!tc.network, "the compile must be airgapped");
assert!(tc.cpus <= set.toolchain.as_ref().unwrap().cpus, "a run-time cap may only LOWER the bound");
let mut none = declared();
none.toolchain = None;
let e = door::toolchain(&none).expect_err("no toolchain is refused");
assert!(e.contains("[build.toolchain]") && e.contains("does NOT fall back to host cargo"), "{e}");
let mut unpinned = declared();
unpinned.toolchain.as_mut().unwrap().image_sha256.clear();
let e = door::toolchain(&unpinned).expect_err("an unpinned image is refused");
assert!(e.contains("no `image_sha256`"), "{e}");
}
/// No host cargo in the door: the only cargo spawn it reaches is the container's.
#[test]
fn the_door_has_no_host_cargo_road() {
let src = std::fs::read_to_string(root().join("xtask/src/door.rs")).unwrap();
let code: String = src.lines().filter(|l| !l.trim_start().starts_with("//")).collect::<Vec<_>>().join("\n");
assert!(!code.contains("nbt::build_variant("), "door.rs builds on the host");
assert!(code.contains("container_road::build_row("), "door.rs does not build through edda's container road");
}
/// The wasm STAGES are the container's too: `build` hands `run_stages` the
/// container runner, never edda's host-side `XtaskWasmStageRunner` (which spawns
/// the host's wasm-bindgen and host cargo). And the stage runner, like the door,
/// owns no row knowledge — the stage, its input, out dir and flags arrive typed.
#[test]
fn the_wasm_stages_run_in_the_image_and_spell_no_row_knowledge() {
let strip = |f: &str| {
std::fs::read_to_string(root().join("xtask/src").join(f))
.unwrap()
.lines()
.filter(|l| !l.trim_start().starts_with("//"))
.collect::<Vec<_>>()
.join("\n")
};
let door_rs = strip("door.rs");
assert!(!door_rs.contains("XtaskWasmStageRunner"), "door.rs runs the wasm stages on the host");
assert!(door_rs.contains("container_road::build_row("), "door.rs does not hand the row (and its stages) to the image");
// The stage runner is edda's now (`container_road.rs`, lifted from `xtask/src/stages.rs`
// on 2026-09-30); it is held to the same rules from here, read off the sibling.
let stages: String = std::fs::read_to_string(root().join("../edda/crates/nornir-build-thing/src/container_road.rs"))
.expect("edda's container_road.rs is a sibling of this checkout")
.split("#[cfg(test)]")
.next()
.unwrap()
.lines()
.filter(|l| !l.trim_start().starts_with("//"))
.collect::<Vec<_>>()
.join("\n");
// `--target` is allowed here: it is wasm-bindgen's flag, and its value is the
// cell's typed `BindgenTarget`, not a triple. `--features` likewise: its value is
// the ROW's typed `features`, never a string spelled here.
for banned in ["wasm32", "\"facet-wrapped", "\"facett-demo", "\"nordisk-", "\"manifest\"", "\"web\"", "\"docs\"", "\"model3d\""] {
assert!(!stages.contains(banned), "container_road.rs spells `{banned}`");
}
for banned in ["Command::new", "std::process"] {
assert!(!stages.contains(banned), "container_road.rs spawns a host process (`{banned}`)");
}
assert!(stages.contains("--offline"), "the in-image bindgen install must not reach the network");
}
/// The stage runner, driven with a fake engine: what reaches the container is the
/// cell's typed stage with every host path mapped to its bind, airgapped, at the
/// declared bounds — and a stage that exits non-zero is a named red.
#[test]
fn the_container_stages_map_paths_and_refuse_a_failed_stage() {
use facett_build_thing::anyhow;
use facett_build_thing::nornir_build_thing::{
cargo_container::{CargoContainerRunner, CargoRunOutcome, CargoRunRequest, HostPaths},
wasm::{WasmStageRun, WasmStageRunner},
};
use std::cell::RefCell;
struct Fake {
seen: RefCell<Vec<CargoRunRequest>>,
exit: i64,
}
impl CargoContainerRunner for Fake {
fn run(&self, req: &CargoRunRequest) -> anyhow::Result<CargoRunOutcome> {
self.seen.borrow_mut().push(req.clone());
Ok(CargoRunOutcome { exit_code: Some(self.exit), stdout: vec![], stderr: vec!["boom".into()] })
}
}
let set = declared();
let tc = door::toolchain(&set).unwrap();
let root = root();
// A wasm row with no feature axis, and one with (a bundle group) — found by
// shape, not by name.
let wasm_rows = || set.variants.iter().filter(|v| set.wasm(&v.name).is_some());
let plain = wasm_rows().find(|v| v.features.is_empty() && !v.no_default_features).expect("a plain wasm row");
let gated = wasm_rows().find(|v| !v.features.is_empty()).expect("a feature-gated wasm row (a bundle group)");
let target = std::env::temp_dir().join("facett-stage-fake-target");
let paths = HostPaths { target_dir: target.clone(), registry: PathBuf::from("/nonexistent") };
let fake = Fake { seen: RefCell::new(vec![]), exit: 0 };
let stages = facett_build_thing::nornir_build_thing::container_road::ContainerStages { tc: &tc, paths: &paths, runner: &fake, row: plain };
stages
.run(
&WasmStageRun::Bindgen {
input: target.join("t/release/x.wasm"),
out_dir: root.join("some/dist"),
target: "web",
typescript: false,
},
&root,
)
.expect("a clean fake run is green");
let req = fake.seen.borrow()[0].clone();
assert_eq!(req.image, tc.image_ref());
assert!(!req.network && req.cpus == tc.cpus && req.mem_limit_mb == tc.mem_limit_mb);
let work = tc.container_repo_dir(&root);
assert!(req.script.contains("'/target/t/release/x.wasm'"), "{}", req.script);
assert!(req.script.contains(&format!("'{work}/some/dist'")), "{}", req.script);
assert!(req.script.contains("--no-typescript") && req.script.contains("--target 'web'"), "{}", req.script);
assert!(req.script.contains("cargo install --offline --locked wasm-bindgen-cli"), "{}", req.script);
assert!(!req.script.contains(&*root.to_string_lossy()), "a host path leaked into the script:\n{}", req.script);
let red = Fake { seen: RefCell::new(vec![]), exit: 101 };
let stages = facett_build_thing::nornir_build_thing::container_road::ContainerStages {
tc: &tc,
paths: &paths,
runner: &red,
row: gated,
};
let e = stages
.run(
&WasmStageRun::ComponentManifest {
package: "p".into(),
example: "e".into(),
out_file: root.join("some/dist/m.json"),
},
&root,
)
.expect_err("a non-zero stage is refused");
let e = format!("{e:#}");
assert!(e.contains("manifest") && e.contains("101") && e.contains("boom"), "{e}");
let want = format!(
"--offline --quiet --example 'e' -p 'p' {}",
facett_build_thing::stages::GroupStageRunner { variant: gated }
.feature_args()
.iter()
.map(|a| format!("'{a}'"))
.collect::<Vec<_>>()
.join(" ")
);
assert!(red.seen.borrow()[0].script.contains(&want),
"the manifest example must be built with the ROW's features: {}",
red.seen.borrow()[0].script
);
// A path the container cannot see is refused before any engine is asked.
let e = facett_build_thing::nornir_build_thing::container_road::ContainerStages { tc: &tc, paths: &paths, runner: &fake, row: plain }
.run(
&WasmStageRun::Bindgen { input: "/elsewhere/x.wasm".into(), out_dir: root.join("d"), target: "web", typescript: false },
&root,
)
.expect_err("an unbound path is refused");
assert!(format!("{e:#}").contains("cannot see it"));
}