Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/facett

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"));
}