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

nordisk/holger

xtask/src/forge_door.rs

//! **The media door** — `installer-iso` and `appliance-iso` are thin callers of
//! `dwarves buildthing <this checkout> --variant <medium>`.
//!
//! Owner, 2026-09-27: "BUILD thing !! all must go trough build thing". Every
//! holger medium declares its kernel (`tunnr/tunnr-kernel`), so there is nothing
//! left for this door to compose in-process: the forge builds the payload in the
//! pinned container, reads the donor kernel off its pin, and runs the MEDIA STEPS
//! (dwarves `media_steps`: the root-of-trust decision, the worktree refusal, the
//! plugins the payload consumes — built, signed, held to this commit, staged — and
//! the medium record). Nothing of that lives here; this door owns no build
//! knowledge (the LAW: xtask is a thin door onto the build thing).
//!
//! What the door still does, and why:
//! * resolves `--variant` against the RUST declaration and refuses the wrong KIND
//!   by name, before a forge is spawned (a medium for a machine with no shell is
//!   one keystroke from the wrong one);
//! * refuses a committed `.nornir/build-variants.toml` that is not the code's
//!   emission (the forge discovers the file by path);
//! * reads SUCCESS off the ISO on disk, never off an exit code.
//!
//! The forge binary: `$DWARVES_BIN`, else `cargo run --release -p dwarves
//! --features sign-step` in the sibling dwarves checkout (`$DWARVES_ROOT`, else
//! `../dwarves`). `sign-step` because a medium whose payload consumes a plugin has
//! the forge SIGN it.

use std::path::{Path, PathBuf};
use std::process::Command;

use anyhow::{bail, Context, Result};
use nornir_build_thing::variant::ArtifactKind;

/// The env that composes an open medium unenrolled ON PURPOSE (dwarves
/// `media_steps::UNENROLLED_ENV`); `--unenrolled <why>` sets it.
pub const UNENROLLED_ENV: &str = "DWARVES_UNENROLLED";

/// What the operator asked for.
#[derive(Debug, Default, PartialEq, Eq)]
pub struct Ask {
    pub variant: Option<String>,
    pub params: Vec<String>,
    pub opts: Vec<String>,
    /// `--build <edge>` — build a consumed build thing (the kernel) as a step.
    pub builds: Vec<String>,
    pub unenrolled: Option<String>,
}

/// Parse the passthrough; an unknown flag is refused, never dropped.
pub fn parse(verb: &str, args: impl IntoIterator<Item = String>) -> Result<Ask> {
    let mut ask = Ask::default();
    let mut args = args.into_iter();
    while let Some(a) = args.next() {
        let mut val = |flag: &str| args.next().with_context(|| format!("{flag} takes a value"));
        match a.as_str() {
            "--variant" => ask.variant = Some(val("--variant")?),
            "--param" => ask.params.push(val("--param")?),
            "--opt" => ask.opts.push(val("--opt")?),
            "--build" => ask.builds.push(val("--build")?),
            "--unenrolled" => ask.unenrolled = Some(val("--unenrolled")?),
            "--kernel" | "--allow-host-kernel" | "--app" => bail!(
                "{verb}: `{a}` is gone — every holger medium DECLARES its kernel (tunnr/tunnr-kernel) \
                 and its payload, and the Build Thing builds both. Build the kernel with `--build \
                 kernel` (or `dwarves buildthing tunnr --variant tunnr-kernel`)."
            ),
            other => bail!(
                "unknown argument '{other}' ({verb} takes --variant <name>, --param k=v, --opt k=v, \
                 --build <edge>, --unenrolled <why>)"
            ),
        }
    }
    Ok(ask)
}

/// Resolve `name` to a declared variant of `kind`, refusing another kind BY NAME.
/// Returns the DELIVERY (suite) the forge builds it in — the variant's first
/// declared suite, read off the declaration (one, MVP), so the forge never has to
/// guess (`say which one with --suite`).
pub fn declared_medium(name: &str, kind: ArtifactKind, door_of_other: &str) -> Result<String> {
    let set = holger_recipe::declared();
    let v = set.require(name)?;
    if v.kind != kind {
        let of_kind: Vec<&str> = set
            .variants
            .iter()
            .filter(|v| v.kind == kind)
            .map(|v| v.name.as_str())
            .collect();
        bail!(
            "variant '{name}' is kind '{}', not '{}'{} (declared: {})",
            String::from(v.kind),
            String::from(kind),
            if matches!(v.kind, ArtifactKind::Installer | ArtifactKind::Iso) {
                format!(" — '{name}' is built by `{door_of_other} --variant {name}`")
            } else {
                String::new()
            },
            of_kind.join(", ")
        );
    }
    let has_row = match kind {
        ArtifactKind::Installer => set.installers.iter().any(|i| i.name == name),
        ArtifactKind::Iso => set.isos.iter().any(|i| i.name == name),
        _ => false,
    };
    if !has_row {
        bail!(
            "variant '{name}' has no [[build.{}]] row of the same name",
            String::from(kind)
        );
    }
    v.suites.first().cloned().with_context(|| {
        format!("variant '{name}' declares no suite — the forge cannot select it by delivery")
    })
}

/// **The sandbox entries a row packs are staged first** (lane HOLGER-MEDIA): a
/// `[[build.installer]]` row whose `payload_entries` name `.sandbox-out/` gets
/// `cargo xtask scan-worker stage` run here when the staging is absent or does not
/// match its manifest, so the forge never refuses "payload entry not there" after
/// a kernel build, and a stale staging never rides a medium. A row that names
/// nothing stages nothing (the front).
pub fn ensure_payload_entries_staged(repo_root: &Path, variant: &str) -> Result<()> {
    if !stages_the_sandbox(variant) {
        return Ok(());
    }
    let out = repo_root.join(crate::scan_worker::STAGE_OUT);
    // The tree's worker, built now (incremental: quick when it is up to date), so a staging
    // from another tree never rides the medium (HOL-NCSC).
    let worker = crate::scan_worker::build(repo_root)?;
    let worker_bytes = std::fs::read(&worker).with_context(|| worker.display().to_string())?;
    match crate::scan_worker::staged_ok(&out)
        .and_then(|m| crate::scan_worker::worker_is_current(&m, &worker_bytes).map(|()| m))
        .and_then(|m| crate::scan_worker::heimdall_is_current(repo_root, &m).map(|()| m))
    {
        Ok(m) => eprintln!(
            "sandbox entries staged in {} ({} entries, as the manifest says, the tree's worker)",
            out.display(),
            m.entries.len()
        ),
        Err(why) => {
            eprintln!("sandbox entries: {why:#}; staging now (cargo xtask scan-worker stage)");
            crate::scan_worker::stage(repo_root, &out, Some(worker), None)?;
        }
    }
    // HOL-OCI-EVIDENCE: the release's signed Sigstore trust root rides beside the sandbox.
    match crate::sigstore_trust::staged_ok(&out) {
        Ok(()) => {
            eprintln!(
                "sigstore trust root staged in {} (the pinned root)",
                out.display()
            );
            Ok(())
        }
        Err(why) => {
            eprintln!(
                "sigstore trust root: {why:#}; staging now (cargo xtask sigstore-trust stage)"
            );
            crate::sigstore_trust::stage(
                repo_root,
                &out,
                None,
                &crate::sigstore_trust::signer_dir(),
                730,
            )
        }
    }
}

/// Pure: **whether the forge stages the sandbox for `variant`**: the medium names a payload
/// entry under `.sandbox-out/`.
pub fn stages_the_sandbox(variant: &str) -> bool {
    use holger_recipe::packaging as p;
    holger_recipe::declared()
        .installers
        .into_iter()
        .find(|i| i.name == variant)
        .is_some_and(|i| {
            i.payload_entries
                .values()
                .any(|src| src.starts_with(p::SANDBOX_STAGE_DIR))
        })
}

/// Where the forge leaves the medium.
pub fn iso_out(repo_root: &Path, variant: &str) -> PathBuf {
    repo_root.join(".iso-out").join(format!("{variant}.iso"))
}

/// The argv after the forge binary: `buildthing <root> --variant <v> …`.
pub fn forge_args(repo_root: &Path, suite: &str, variant: &str, ask: &Ask) -> Vec<String> {
    let mut a = vec![
        "buildthing".to_string(),
        repo_root.display().to_string(),
        "--suite".to_string(),
        suite.to_string(),
        "--variant".to_string(),
        variant.to_string(),
    ];
    for (flag, vals) in [
        ("--param", &ask.params),
        ("--opt", &ask.opts),
        ("--build", &ask.builds),
    ] {
        for v in vals {
            a.push(flag.to_string());
            a.push(v.clone());
        }
    }
    a
}

/// The variable naming a prebuilt forge binary.
pub const DWARVES_BIN_ENV: &str = "DWARVES_BIN";
/// The variable naming the dwarves checkout the forge is run from.
pub const DWARVES_ROOT_ENV: &str = "DWARVES_ROOT";

/// The forge: `$DWARVES_BIN`, else `cargo run` in the sibling dwarves checkout.
fn forge(repo_root: &Path) -> Result<Command> {
    if let Some(bin) = std::env::var_os(DWARVES_BIN_ENV).filter(|v| !v.is_empty()) {
        return Ok(Command::new(bin));
    }
    let root = std::env::var_os(DWARVES_ROOT_ENV)
        .filter(|v| !v.is_empty())
        .map(PathBuf::from)
        .unwrap_or_else(|| {
            repo_root
                .parent()
                .map(|p| p.join("dwarves"))
                .unwrap_or_default()
        });
    if !root.join("Cargo.toml").is_file() {
        bail!(
            "no forge: set $DWARVES_BIN to a dwarves built with `--features sign-step`, or put the \
             dwarves checkout at {} (or point $DWARVES_ROOT at it)",
            root.display()
        );
    }
    let mut c = Command::new(std::env::var("CARGO").unwrap_or_else(|_| "cargo".to_string()));
    c.current_dir(root)
        .args([
            "run",
            "--release",
            "-p",
            "dwarves",
            "--features",
            "sign-step",
            "--bin",
            "dwarves",
            "--",
        ])
        // `cargo run` exports CARGO_MANIFEST_DIR to its child; a grandchild
        // inheriting it makes ring & co rebuild (gunnar, measured 2026-09-23).
        .env_remove("CARGO_MANIFEST_DIR");
    Ok(c)
}

/// **Run the door**: declaration checks, the forge, and the ISO read off disk.
pub fn run(verb: &str, repo_root: &Path, suite: &str, variant: &str, ask: &Ask) -> Result<PathBuf> {
    holger_recipe::require_committed_is_emitted(repo_root)?;
    ensure_payload_entries_staged(repo_root, variant)?;
    let mut cmd = forge(repo_root)?;
    cmd.args(forge_args(repo_root, suite, variant, ask));
    if let Some(why) = &ask.unenrolled {
        cmd.env(UNENROLLED_ENV, why);
    }
    eprintln!("{verb}: `{variant}` through the Build Thing: {:?}", cmd);
    let status = cmd.status().context("spawn the forge")?;
    if !status.success() {
        bail!("the Build Thing exited {status} composing `{variant}`");
    }
    let iso = iso_out(repo_root, variant);
    let bytes = std::fs::metadata(&iso)
        .with_context(|| {
            format!(
                "the forge reported success but {} is absent — an exit code is not an artifact",
                iso.display()
            )
        })?
        .len();
    if bytes == 0 {
        bail!("{} exists but is EMPTY", iso.display());
    }
    let record = iso.with_extension("medium.json");
    let sha = std::fs::read_to_string(&record)
        .ok()
        .and_then(|s| serde_json::from_str::<serde_json::Value>(&s).ok())
        .and_then(|v| v["iso_sha256"].as_str().map(str::to_string));
    println!(
        "✅ {verb}: {} ({bytes} bytes){}",
        iso.display(),
        sha.map(|s| format!(" sha256 {s} · record {}", record.display()))
            .unwrap_or_default()
    );
    Ok(iso)
}

#[cfg(test)]
mod tests {
    use super::*;

    fn s(v: &[&str]) -> Vec<String> {
        v.iter().map(|s| s.to_string()).collect()
    }

    /// Lane HOL-CDS-5: every declared medium that carries the sandbox (the downstream media
    /// too: their bundles are verified in jobs) gets it staged, the sigstore trust with it;
    /// a medium that carries none (the front) stages nothing.
    #[test]
    fn every_medium_that_carries_the_sandbox_has_it_staged() {
        let set = holger_recipe::declared();
        let mut carrying = 0;
        for i in &set.installers {
            let carries = i
                .payload_entries
                .values()
                .any(|src| src.starts_with(holger_recipe::packaging::SANDBOX_STAGE_DIR));
            carrying += usize::from(carries);
            assert_eq!(stages_the_sandbox(&i.name), carries, "{}", i.name);
        }
        assert!(
            carrying >= 5,
            "the main media and both downstream media carry it"
        );
        assert!(stages_the_sandbox("holger-downstream-oneway-installer"));
        assert!(!stages_the_sandbox("no-such-medium"));
    }

    #[test]
    fn the_passthrough_reaches_the_forge_in_order() {
        let ask = parse(
            "installer-iso",
            s(&[
                "--variant",
                "holger-installer-metered",
                "--param",
                "holger_ron=@x.ron",
                "--opt",
                "kernel.preset=nuked",
                "--build",
                "kernel",
                "--param",
                "site=a",
            ]),
        )
        .unwrap();
        assert_eq!(
            forge_args(
                Path::new("/w/holger"),
                "MVP",
                "holger-installer-metered",
                &ask
            ),
            s(&[
                "buildthing",
                "/w/holger",
                "--suite",
                "MVP",
                "--variant",
                "holger-installer-metered",
                "--param",
                "holger_ron=@x.ron",
                "--param",
                "site=a",
                "--opt",
                "kernel.preset=nuked",
                "--build",
                "kernel"
            ])
        );
    }

    #[test]
    fn the_operator_kernel_is_gone_and_says_where_it_went() {
        for flag in ["--kernel", "--allow-host-kernel", "--app"] {
            let e = parse("installer-iso", s(&[flag, "/boot/vmlinuz"]))
                .unwrap_err()
                .to_string();
            assert!(
                e.contains("DECLARES its kernel") && e.contains("--build kernel"),
                "{e}"
            );
        }
        let e = parse("installer-iso", s(&["--atom", "x"]))
            .unwrap_err()
            .to_string();
        assert!(e.contains("unknown argument '--atom'"), "{e}");
    }

    #[test]
    fn the_wrong_kind_is_refused_and_pointed_at_its_door() {
        assert_eq!(
            declared_medium("holger-installer-metered", ArtifactKind::Installer, "x").unwrap(),
            "MVP"
        );
        assert!(declared_medium("holger-appliance-iso", ArtifactKind::Iso, "x").is_ok());
        let e = declared_medium(
            "holger-appliance-iso",
            ArtifactKind::Installer,
            "cargo xtask appliance-iso",
        )
        .unwrap_err()
        .to_string();
        assert!(
            e.contains("not 'installer'") && e.contains("cargo xtask appliance-iso"),
            "{e}"
        );
        let e = declared_medium("mvp-server-musl", ArtifactKind::Installer, "x")
            .unwrap_err()
            .to_string();
        assert!(
            e.contains("holger-installer-metered"),
            "the refusal lists the declared media: {e}"
        );
    }
}