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

nordisk/gunnar

installtest/src/installer_ssh.rs

//! **The `gunnar-installer` medium, installed, booted, and REACHED over SSH —
//! the mechanism, with exactly one writer.**
//!
//! `tests/installer_ssh_drive.rs` is the PROOF (it asserts, it emits rollup
//! rows, it fails a build). `bench/examples/nornir-bench.rs`'s
//! `gunnar.installer_ssh` arm is the MEASUREMENT (it reports numbers and has no
//! opinion about them). They are the same six operations — read the
//! declaration, pack the payload, compose the medium, install to a blank disk,
//! boot the installed disk with the medium detached, authenticate — and the
//! whole reason this module exists is that they must not be two copies of them.
//!
//! The precedent is this crate's own: `iso.rs`, `kvm.rs` and `container.rs` each
//! hold a `run(...)` the install tests and the `gunnar.install_*` bench arms
//! both call. This is the fourth shape, the one none of those three cover —
//! `gunnar-appliance-iso` is `kind = "iso"`, a LIVE medium whose `/data` is RAM
//! and whose identity dies at reboot; `gunnar-installer` is `kind = "installer"`,
//! it writes a GPT and `/data` is a partition. `installtest/src/iso.rs:84`
//! pins `.iso-out/gunnar-appliance-iso.iso`, so `gunnar.install_iso` has never
//! measured the installed shape and no arm in the suite did.
//!
//! Nothing here asserts. `Verdict::assert_reached` is the one exception and it
//! is called by the test, never by the arm: a benchmark that panics on a
//! product defect reports nothing at all, and a red row is more use than a
//! missing one.
use std::io::{Read, Write};
use std::net::TcpStream;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Mutex;
use std::time::{Duration, Instant};

use korp_installer::isoproof::{self, IsoInstallProof, KvmPreflight};
use korp_installer::kvmproof;
use nornir_build_thing::variant::BuildVariantSet;

/// The proof name every skip and row is spoken under.
pub const PROOF: &str = "gunnar_installer_ssh";
/// The declared installer cell — `kind = "installer"`, the one with a
/// `target_disk_gib`. NOT `gunnar-appliance-iso`, which is `kind = "iso"`, a
/// LIVE medium whose `/data` is RAM and whose identity dies at reboot.
pub const CELL: &str = "gunnar-installer";
/// The appliance variant the cell lays down.
pub const VARIANT: &str = "gunnar-server";
/// The product, as the rollup spells it.
pub const PRODUCT: &str = "gunnar";

/// The banner line that says the SSH listener is BOUND. `serve.rs:1413` writes
/// `ssh   <addr>` and then, with the control plane declared off,
/// `grpc  disabled` — so this marker is strictly after the listener exists.
pub const SERVING_MARKER: &str = "grpc  disabled";

/// The identification string gunnar's own SSH server sends — `gunnar-ssh`
/// `config.rs:155`, `format!("SSH-2.0-gunnar_{}", env!("CARGO_PKG_VERSION"))`.
pub const SSH_IDENT_PREFIX: &str = "SSH-2.0-gunnar";

/// The one sentence `DispatchError::client_message` produces for a repository
/// that is absent OR forbidden. Reaching it means a channel was opened, which
/// means userauth passed.
pub const SERVER_VOICE: &str = "repository not found, or you do not have access";

/// What a rejected key gets from stock `ssh`, one layer earlier.
pub const USERAUTH_REFUSED: &str = "Permission denied (publickey)";

/// A repository that does not exist, and cannot *by reading*: a freshly
/// installed P3 is formatted empty. Asking for it with `git-upload-pack` is
/// how the server is made to speak — reads never create, not even for the
/// admin, so this stays absent for the whole of `boot_and_reach`.
pub const ABSENT_REPO: &str = "demo/hello";

/// The repository the FIRST-PUSH door creates: the admin's first `git push`
/// on an installed appliance names it, and that push — not a verb, not a
/// control plane — brings it into existence (`gunnar_ssh::Control::
/// create_for_push`). `boot_and_first_push` is the KVM proof.
pub const DOOR_REPO: &str = "nordisk/first";

/// Scratch on DISK — sparse 64 GiB images have no business in `/tmp` (RAM).
pub const SCRATCH: &str = "~/scratch/gunnar-installer-ssh";

/// Where the declared variant's artifact lives.
pub fn build_target_dir() -> PathBuf {
    std::env::var_os("GUNNAR_EXE_TARGET_DIR")
        .map(PathBuf::from)
        .unwrap_or_else(|| crate::expand_home("~/scratch/cargo/gunnar"))
}

/// One row in the rollup, through the harness's own emitter.
pub fn row(check: &str, pass: bool, detail: &str) {
    isoproof::emit_kvm_row(PRODUCT, check, pass, detail);
}

/// A named, LOUD skip: it prints AND it records a non-pass row. A skip that
/// only prints leaves the rollup cell as empty as no run at all, and an empty
/// cell reads like "not attempted" rather than "attempted and not proven".
pub fn skip(check: &str, msg: &str) {
    eprintln!("SKIP {PROOF}/{check}: {msg}");
    row(check, false, msg);
}

// ── the machinery ───────────────────────────────────────────────────────────

/// Everything both legs share: the preflight, the declaration, the packed
/// payload and the admin keypair the medium will be composed with.
pub struct Context {
    pub pf: KvmPreflight,
    pub cell: nornir_build_thing::installer::InstallerBuild,
    pub work: PathBuf,
    /// The payload the composer streams onto P2.
    pub app: PathBuf,
    /// The PRIVATE half of the key that will be staged as `/data/admin.pub`.
    pub admin_key: PathBuf,
    /// A key the medium has never seen — rung 4.
    pub stranger_key: PathBuf,
    /// `korp.entry=` from the declaration.
    pub entry: String,
}

/// One installed disk.
pub struct Guest {
    pub name: String,
    pub disk: PathBuf,
    pub workdir: PathBuf,
    /// The cmdline read back off the installed ESP.
    pub cmdline: String,
}

/// A composed medium.
pub struct Medium {
    pub iso: PathBuf,
    pub bytes: u64,
    pub compose_ms: u128,
}

impl Context {
    pub fn open(leg: &str) -> Option<Self> {
        let repo = crate::workspace_root();
        // `KORP_TEST_KERNEL` is the harness's env; `KORP_KERNEL` is what the
        // forge's ISO test uses on this box. Accept either.
        if std::env::var_os(isoproof::TEST_KERNEL_ENV).is_none() {
            if let Some(k) = std::env::var_os("KORP_KERNEL") {
                std::env::set_var(isoproof::TEST_KERNEL_ENV, k);
            }
        }
        let Some(pf) = KvmPreflight::detect(PROOF) else {
            skip(
                "host_capable",
                "qemu / OVMF / KORP_TEST_KERNEL missing — see stderr",
            );
            return None;
        };
        for tool in ["ssh", "ssh-keygen"] {
            if which(tool).is_none() {
                eprintln!("SKIP {PROOF}: no {tool} on PATH — the client half is stock OpenSSH");
                skip("host_capable", &format!("no {tool} on PATH"));
                return None;
            }
        }

        // ── the DECLARATION, as the one writer ──
        let set = BuildVariantSet::discover(&repo)
            .expect("read .nornir/build-variants.toml")
            .unwrap_or_else(|| panic!("gunnar declares a build space at {}", repo.display()));
        let cell = set
            .installers
            .iter()
            .find(|i| i.name == CELL)
            .unwrap_or_else(|| panic!("gunnar declares a `[[build.installer]]` named {CELL}"))
            .clone();
        // The admin channel is the DECLARATION's, never this drive's. A proof
        // that typed `--admin-key` itself would prove nothing about the medium.
        let admin_spec = cell
            .params
            .iter()
            .find(|p| p.name == "admin_key")
            .expect("the cell declares an `admin_key` parameter (a8ba0665)");
        assert!(
            admin_spec.required,
            "the bootstrap admin must be `required = true` — an appliance that ships without one \
             authorises nobody, for ever, and `--no-grpc` leaves no way to fix it in the field"
        );
        assert_eq!(
            admin_spec.staged_file, "admin.pub",
            "the admin key lands as a STAGED FILE: an OpenSSH key line contains spaces and the \
             `korp.env.*` channel is a whitespace-split kernel command line with no escapes"
        );
        let params = cell.effective_boot_params();
        let argv = params
            .iter()
            .find_map(|p| p.strip_prefix("korp.args="))
            .expect("the cell declares the app's argv tail as `korp.args=`");
        assert!(
            argv.contains("--admin-key") && argv.contains(&format!("@/{}", "data/admin.pub")),
            "the declared argv must READ the staged file — the staging and the flag are two \
             halves of one channel and either alone is inert: korp.args={argv}"
        );
        let entry = params
            .iter()
            .find_map(|p| p.strip_prefix("korp.entry="))
            .expect("the cell names its product with korp.entry=")
            .to_string();

        // ── the artifact the cell lays down ──
        let variant = set.get(VARIANT).expect("the chained variant is declared");
        let mut bin = build_target_dir();
        if let Some(t) = variant.target.as_deref() {
            bin = bin.join(t);
        }
        let bin = bin
            .join(variant.profile.label())
            .join(variant.bin.as_deref().expect("the variant names a bin"));
        if !bin.is_file() {
            eprintln!(
                "SKIP {PROOF}: the declared artifact is not at {} — run `{}` with \
                 CARGO_TARGET_DIR={} first",
                bin.display(),
                variant.command_line(),
                build_target_dir().display()
            );
            skip(
                "app_payload_packed",
                &format!("no artifact at {}", bin.display()),
            );
            return None;
        }

        // ── the SUPPLIED admin key, read BEFORE the scratch tree is cleared ──
        //
        // MEASURED here 2026-08-26: the obvious ordering — clear the tree, then
        // resolve the key — deleted the key it was about to be handed, because
        // the natural place to keep the previous run's pair is inside that very
        // tree (`GUNNAR_ADMIN_KEY=.../one/admin_ed25519`). The bytes are taken
        // first and re-planted below, so where the operator keeps the pair is
        // none of this function's business.
        let supplied = match std::env::var_os("GUNNAR_ADMIN_KEY").map(PathBuf::from) {
            Some(k) => {
                let pubh = k.with_extension("pub");
                let (Ok(sec), Ok(pubk)) = (std::fs::read(&k), std::fs::read(&pubh)) else {
                    panic!(
                        "GUNNAR_ADMIN_KEY={} needs BOTH halves readable: the private key and \
                         {} beside it",
                        k.display(),
                        pubh.display()
                    )
                };
                eprintln!(
                    "ADMIN KEY supplied: {} ({} B public half)",
                    k.display(),
                    pubk.len()
                );
                Some((sec, pubk))
            }
            None => None,
        };

        let work = crate::expand_home(SCRATCH).join(leg);
        let _ = std::fs::remove_dir_all(&work);
        std::fs::create_dir_all(&work).expect("scratch on disk");

        // ── the payload, through the ONE codec ──
        let raw = std::fs::read(&bin).expect("read the declared appliance binary");
        let raw_len = raw.len();
        let packed = korp_installer::payload::pack_znippy(&entry, raw, 1)
            .expect("pack the app .znippy under the declared entry");
        let app = work.join("gunnar-app.znippy");
        std::fs::write(&app, &packed).expect("stage the app payload");
        eprintln!(
            "PACKED: {raw_len} → {} bytes, entry `{entry}`",
            packed.len()
        );

        // ── the two keys ──
        //
        // `crate::keygen` is the ONE key minter in this crate and
        // its header records why `ssh-keygen` is admissible here: gunnar's
        // zero-shell rule is about what the SERVER does. A second spelling of
        // key generation in this file would be the twin that rule is kept
        // single to avoid.
        // REUSING a medium means reusing the key it was composed WITH. A fresh
        // mint against an old medium would be refused at userauth exactly as a
        // stranger's key is, and this drive would report the product defect it
        // is looking for while the defect was in the harness. So the reuse path
        // REQUIRES the key and says so; it does not guess.
        let admin_key = work.join("admin_ed25519");
        match supplied {
            Some((sec, pubk)) => {
                std::fs::write(&admin_key, sec).expect("re-plant the supplied private half");
                std::fs::write(admin_key.with_extension("pub"), pubk)
                    .expect("re-plant the supplied public half");
                // `ssh` REFUSES a private key any group or other can read, and a
                // copy lands 0644 under the default umask. A refusal here would
                // look exactly like the appliance rejecting the key.
                use std::os::unix::fs::PermissionsExt;
                std::fs::set_permissions(&admin_key, std::fs::Permissions::from_mode(0o600))
                    .expect("0600 on the private half, or `ssh` refuses to use it");
            }
            None => {
                assert!(
                    std::env::var_os("GUNNAR_INSTALLER_ISO").is_none(),
                    "GUNNAR_INSTALLER_ISO reuses a medium that was composed with SOME admin key; \
                     set GUNNAR_ADMIN_KEY=<private key path> to the one it carries, or unset \
                     GUNNAR_INSTALLER_ISO and let this drive compose a matched pair"
                );
                crate::keygen(&admin_key).expect("mint the bootstrap admin key");
            }
        }
        let stranger_key = work.join("stranger_ed25519");
        crate::keygen(&stranger_key).expect("mint a key the medium never sees");
        assert_ne!(
            std::fs::read(admin_key.with_extension("pub")).expect("admin pub"),
            std::fs::read(stranger_key.with_extension("pub")).expect("stranger pub"),
            "the two keys must differ or rung 4 proves nothing"
        );

        Some(Context {
            pf,
            cell,
            work,
            app,
            admin_key,
            stranger_key,
            entry,
        })
    }

    /// Compose the medium through the SAME door `dwarves buildthing --installer`
    /// drives, with the admin key supplied as the declared parameter.
    pub fn compose(&self) -> Option<Medium> {
        let repo = crate::workspace_root();
        if let Some(p) = std::env::var_os("GUNNAR_INSTALLER_ISO").map(PathBuf::from) {
            if p.is_file() {
                eprintln!(
                    "REUSING a composed medium: {} — composition is NOT exercised this run",
                    p.display()
                );
                row(
                    "installer_iso_composed",
                    false,
                    &format!("SKIPPED: reused {}", p.display()),
                );
                let bytes = std::fs::metadata(&p).expect("stat the reused medium").len();
                return Some(Medium {
                    iso: p,
                    bytes,
                    compose_ms: 0,
                });
            }
        }
        // The root of trust is armed with the published DEVELOPMENT key, so the
        // installed ESP carries a real `korp/app.sig` + `korp/root.pub`. With
        // this UNSET the composition is an UNENROLLED medium and bakes
        // `korp.require_signed=0` onto the installed cmdline — a start-app that
        // execs whatever bytes are on P2. Arming it here is not decoration.
        std::env::set_var(
            korp_installer::rootkey::SIGNING_KEY_ENV,
            korp_installer::rootkey::DEVELOPMENT_SELECTOR,
        );
        let admin_pub = self.admin_key.with_extension("pub");
        let params = vec![format!("admin_key=@{}", admin_pub.display())];
        let t0 = Instant::now();
        let iso = match nornir_build_thing::suite_cli::run_installer(
            &repo,
            PRODUCT,
            Some(CELL),
            &self.pf.kernel,
            &self.app,
            &params,
            &korp_installer::isocompose::ForgeComposer,
        ) {
            Ok(p) => p,
            Err(e) => {
                row("installer_iso_composed", false, &format!("{e:#}"));
                panic!("composing {CELL} with the declared admin_key: {e:#}");
            }
        };
        let compose_ms = t0.elapsed().as_millis();
        let bytes = std::fs::metadata(&iso)
            .unwrap_or_else(|e| {
                panic!(
                    "the composer claimed success but produced no {}: {e}",
                    iso.display()
                )
            })
            .len();
        assert!(
            bytes > 8 * 1024 * 1024,
            "a medium carrying a kernel and a payload is not {bytes} bytes"
        );

        // The key is ON the volume, read with the crate's own ISO-9660 reader —
        // no mount, no loop device, no root. A composed value nobody can read
        // back off the medium is a claim, not a measurement.
        let mut vol = korp_installer::iso9660::Iso9660::open(
            std::fs::File::open(&iso).expect("open the composed medium"),
        )
        .expect("the composed medium is ISO-9660");
        let on_iso = vol
            .read_file("admin.pub")
            .expect("the ISO volume carries admin.pub at its root (staged_file)");
        let want = std::fs::read(&admin_pub).expect("read the admin public half");
        assert_eq!(
            String::from_utf8_lossy(&on_iso).trim(),
            String::from_utf8_lossy(&want).trim(),
            "the admin.pub ON THE MEDIUM is the key this drive composed with, byte for byte"
        );
        eprintln!(
            "MEDIUM: {} — {bytes} bytes, admin.pub staged ({} B)",
            iso.display(),
            on_iso.len()
        );
        row(
            "installer_iso_composed",
            true,
            &format!(
                "{} ({bytes} B) in {compose_ms} ms, volume_id={}, admin.pub on the volume",
                iso.display(),
                self.cell.volume_id
            ),
        );
        Some(Medium {
            iso,
            bytes,
            compose_ms,
        })
    }

    /// LIFETIME 1 for one guest: a blank disk, the medium on VIRTIO (trap 1,
    /// applied by the harness), an unattended install.
    pub fn install_one(&self, medium: &Medium, idx: usize) -> Guest {
        let name = format!("g{idx}");
        let disk = self.work.join(format!("{name}.img"));
        let disk_arg = disk.to_str().expect("a UTF-8 scratch path").to_string();
        let workdir = self.work.join(format!("{name}-install"));
        let admin_pub = std::fs::read(self.admin_key.with_extension("pub")).expect("admin pub");
        let t0 = Instant::now();
        let installed = IsoInstallProof {
            product: PRODUCT,
            check: "install_ok",
            iso: &medium.iso,
            disk: &disk,
            disk_bytes: self.cell.target_disk_bytes(),
            disk_args: self.cell.kvm_disk_args(&disk_arg),
            workdir: &workdir,
            marker: korp_installer::INSTALL_OK_MARKER,
            timeout: Duration::from_secs(900),
            expect_serial: &["INSTALLER: partition", "INSTALLER: esp"],
            expect_cmdline: &[
                "korp.entry=gunnar",
                "korp.env.GUNNAR_APPLIANCE=1",
                "korp.env.GUNNAR_DATA_ROOT=/data",
                // The half of the channel that READS the staged file. Without
                // it the key on P3 is a file nothing opens.
                "--admin-key",
                "@/data/admin.pub",
            ],
            // ── WHY `admin.pub` IS NOT ASSERTED HERE, THOUGH IT IS READ BELOW ──
            //
            // MEASURED 2026-08-26, twice, one run each way: the identical
            // install passed this byte-compare on the first run and FAILED it on
            // the second (`gunnar: the installed data home carries admin.pub`,
            // isoproof.rs:330) with a byte-identical install serial, including
            // `INSTALLER: payload admin.pub materialized off the ISO volume (100
            // bytes)`. The install is not flaky; the READBACK is, and it is the
            // same defect the sibling drive names for a different file:
            // `boot_iso_until` ends in `child.kill()` the instant INSTALL-OK
            // lands, so P3's FAT directory is whatever QEMU had flushed at that
            // microsecond. A small file written late is a coin toss.
            //
            // Making a coin toss a hard gate would mean this drive failed half
            // the time for a reason that has nothing to do with the appliance —
            // exactly the kind of green/red nobody can read. It is observed
            // below as its own row instead, and the LOAD-BEARING proof of the
            // same fact is strictly stronger and not racy: the booted appliance
            // AUTHENTICATES that key. A file that had not landed could not
            // authenticate anybody.
            expect_data_files: &[],
            detail: &format!(
                "{name}: {} GiB target from {}",
                self.cell.target_disk_gib,
                medium.iso.display()
            ),
        }
        .run(&self.pf);
        let install_ms = t0.elapsed().as_millis();
        eprintln!(
            "INSTALLED {name} in {install_ms} ms — cmdline: {}",
            installed.cmdline.trim()
        );
        // The staged file on P3, OBSERVED. See the `expect_data_files` note
        // above for why this is a row and not a gate.
        match installed.data_file("admin.pub") {
            Some(got) if got == admin_pub => {
                eprintln!(
                    "  P3 admin.pub: {} B, byte-identical to the composed key",
                    got.len()
                )
            }
            Some(got) => eprintln!(
                "  P3 admin.pub: {} B and NOT the composed key ({} B) — that is a real \
                 disagreement, not the flush race",
                got.len(),
                admin_pub.len()
            ),
            None => eprintln!(
                "  P3 admin.pub: not readable off the image — the flush race (see above); \
                 the SSH leg below is what settles whether it landed"
            ),
        }
        // The signing gate, read off the disk rather than believed. An UNSIGNED
        // medium bakes `korp.require_signed=0`, and shipping one as if it were
        // fine is the failure this line refuses to let pass silently.
        assert!(
            installed.cmdline.contains("korp.require_signed=1"),
            "the installed cmdline must require a signed payload — an unsigned medium bakes \
             `korp.require_signed=0` and the start-app execs whatever is on P2: {}",
            installed.cmdline.trim()
        );
        Guest {
            name,
            disk,
            workdir: self.work.join(format!("g{idx}-boot")),
            cmdline: installed.cmdline,
        }
    }

    /// The boot argv for LIFETIMES 2+3, with the medium **absent** (trap 2 —
    /// it is not attached at all, not merely deprioritised) and the guest's
    /// :2222 forwarded to a fresh host port. ONE writer, because the assert in
    /// here is what keeps a careless edit from re-attaching the medium: trap 2
    /// cost an earlier run 35 unattended reinstalls, each one reformatting the
    /// data partition.
    fn boot_args(&self, guest: &Guest) -> (Vec<String>, u16) {
        let host_port = isoproof::free_port();
        let disk_arg = guest
            .disk
            .to_str()
            .expect("a UTF-8 scratch path")
            .to_string();
        let mut args = self.cell.kvm_disk_args(&disk_arg);
        assert!(
            !args.iter().any(|a| a.ends_with(".iso") || a == "-cdrom"),
            "the boot leg must carry NO medium: {args:?}"
        );
        isoproof::attach_slirp_nic(&mut args, Some((host_port, 2222)));
        std::fs::create_dir_all(&guest.workdir).expect("the boot workdir");
        (args, host_port)
    }

    /// LIFETIMES 2+3 in one: boot the installed disk with the medium absent,
    /// hold the guest RUNNING past the serving marker, and reach it.
    pub fn boot_and_reach(&self, guest: &Guest, timeout: Duration) -> Verdict {
        let (args, host_port) = self.boot_args(guest);

        let state: Mutex<Verdict> = Mutex::new(Verdict::default());
        let done = AtomicBool::new(false);
        let t0 = Instant::now();
        // `boot_disk_until_verdict` is `kvmproof`'s own held-open door: it polls
        // the serial log to `marker`, then keeps the guest alive while `hold`
        // forms the verdict. Everything about the boot — the qemu argv, the
        // OVMF staging, the NUL-stripped poll — is the harness's; only the
        // verdict is this drive's.
        let serial = kvmproof::boot_disk_until_verdict(
            &self.pf.qemu,
            &self.pf.ovmf_code,
            &self.pf.ovmf_vars,
            &args,
            &guest.workdir,
            SERVING_MARKER,
            timeout,
            || {
                if done.load(Ordering::SeqCst) {
                    return true;
                }
                let mut v = state.lock().expect("verdict");
                if self.probe(host_port, &mut v, t0) {
                    done.store(true, Ordering::SeqCst);
                    return true;
                }
                false
            },
            Duration::from_secs(120),
        );
        let mut v = state.into_inner().expect("verdict");
        v.serial_bytes = serial.len();
        v.panicked = serial.contains("Kernel panic");
        v.reached_marker = serial.contains(SERVING_MARKER);
        v.serial = serial;
        v.port = host_port;
        v.cmdline = guest.cmdline.clone();
        v
    }

    /// One probe attempt. Returns true when the verdict is FORMED (either way):
    /// the hold ends on a formed verdict, not on a good one.
    fn probe(&self, port: u16, v: &mut Verdict, t0: Instant) -> bool {
        // Rung 1: a bound listener speaking gunnar's own identification string.
        if v.banner.is_none() {
            match read_ident(port) {
                Some(b) => {
                    v.banner_ms = Some(t0.elapsed().as_millis());
                    if !b.starts_with(SSH_IDENT_PREFIX) {
                        v.note = Some(format!("the listener is not gunnar's: {b:?}"));
                        return true;
                    }
                    v.banner = Some(b);
                }
                None => return false,
            }
        }
        // Rung 2+3: the STAGED admin key, and the server's own voice.
        let known = self.work.join(format!("known_hosts.{port}"));
        let _ = std::fs::remove_file(&known);
        let admin = ssh_verb(&self.admin_key, &known, port, ABSENT_REPO);
        // Rung 4: a key the medium never saw, against the SAME pinned host key.
        let stranger = ssh_verb(&self.stranger_key, &known, port, ABSENT_REPO);
        v.host_key = read_pinned_host_key(&known);
        v.admin_said = admin.clone();
        v.stranger_said = stranger.clone();
        v.authenticated = admin.contains(SERVER_VOICE) && !admin.contains(USERAUTH_REFUSED);
        v.stranger_refused = stranger.contains(USERAUTH_REFUSED);
        if v.authenticated {
            v.auth_ms = Some(t0.elapsed().as_millis());
        }
        // A transient "Connection refused" while the listener finishes binding
        // is not a verdict. Only a real answer from either side ends the hold.
        v.authenticated || admin.contains(USERAUTH_REFUSED) || admin.contains(SERVER_VOICE)
    }

    /// **The FIRST-PUSH door, on the installed appliance itself.**
    ///
    /// `boot_and_reach` proves the admin key opens a session and is then told
    /// "repository not found" — the brick, measured 2026-08-25. This leg
    /// proves the unbricking: with the guest held open, a real `git push`
    /// (stock git, the STAGED admin key) to [`DOOR_REPO`] — a name no control
    /// plane ever created — succeeds, the ref is listed back, a second push
    /// goes through the ordinary path, and the stranger's key still dies at
    /// userauth. Reads stay barren: the same admin's `git-upload-pack` for
    /// [`ABSENT_REPO`] still gets the fused refusal, in the same session
    /// window, so the door is the push and only the push.
    ///
    /// Stock `git` on the host is admissible for the same reason stock
    /// OpenSSH and `ssh-keygen` are (see `crate::keygen`): gunnar's zero-shell
    /// rule is about what the SERVER executes, and the only honest client for
    /// a git server is git.
    pub fn boot_and_first_push(&self, guest: &Guest, timeout: Duration) -> PushVerdict {
        assert!(
            which("git").is_some(),
            "the first-push leg drives stock `git`; none is on PATH"
        );
        // The working tree the admin pushes, prepared before the guest boots.
        // sha256, because the door creates the repository with the server
        // default and a sha1 tree would be refused by git itself.
        let tree = self.work.join(format!("{}-push-tree", guest.name));
        std::fs::create_dir_all(&tree).expect("the push working tree");
        let content = "the first bytes pushed onto this appliance\n";
        git_in(
            &tree,
            &[
                "init",
                "--quiet",
                "--object-format=sha256",
                "--initial-branch=main",
                ".",
            ],
        );
        std::fs::write(tree.join("hello.txt"), content).expect("stage the file");
        git_in(&tree, &["add", "hello.txt"]);
        git_in(&tree, &["commit", "--quiet", "-m", "the first commit"]);

        let (args, host_port) = self.boot_args(guest);
        let state: Mutex<PushVerdict> = Mutex::new(PushVerdict::default());
        let done = AtomicBool::new(false);
        let serial = kvmproof::boot_disk_until_verdict(
            &self.pf.qemu,
            &self.pf.ovmf_code,
            &self.pf.ovmf_vars,
            &args,
            &guest.workdir,
            SERVING_MARKER,
            timeout,
            || {
                if done.load(Ordering::SeqCst) {
                    return true;
                }
                let mut v = state.lock().expect("verdict");
                if self.push_probe(host_port, &tree, &mut v) {
                    done.store(true, Ordering::SeqCst);
                    return true;
                }
                false
            },
            Duration::from_secs(120),
        );
        let mut v = state.into_inner().expect("verdict");
        v.serial_bytes = serial.len();
        v.panicked = serial.contains("Kernel panic");
        v.reached_marker = serial.contains(SERVING_MARKER);
        v.serial = serial;
        v.port = host_port;
        v
    }

    /// One attempt at the whole push ladder. Returns true when the verdict is
    /// FORMED, either way. Everything after the first real server answer runs
    /// in ONE pass: once the push lands, the repository exists, so this is not
    /// re-enterable past that point — which is why a transient "Connection
    /// refused" must return `false` BEFORE anything is created.
    fn push_probe(&self, port: u16, tree: &Path, v: &mut PushVerdict) -> bool {
        if v.banner.is_none() {
            match read_ident(port) {
                Some(b) => {
                    if !b.starts_with(SSH_IDENT_PREFIX) {
                        v.note = Some(format!("the listener is not gunnar's: {b:?}"));
                        return true;
                    }
                    v.banner = Some(b);
                }
                None => return false,
            }
        }
        let known = self.work.join(format!("known_hosts.push.{port}"));
        let _ = std::fs::remove_file(&known);

        // Rung A: a READ of an absent repository, with the admin key, still
        // gets the fused refusal — the door must not have turned reads into
        // creation. This also settles that the listener is really up; only a
        // real answer lets the ladder continue.
        let read = ssh_verb(&self.admin_key, &known, port, ABSENT_REPO);
        if !(read.contains(SERVER_VOICE) || read.contains(USERAUTH_REFUSED)) {
            return false; // still binding; retry
        }
        v.read_said = read.clone();
        v.read_still_refused = read.contains(SERVER_VOICE) && !read.contains(USERAUTH_REFUSED);
        if !v.read_still_refused {
            return true; // formed: the admin key does not even authenticate
        }
        v.host_key = read_pinned_host_key(&known);

        let url = format!("ssh://git@127.0.0.1:{port}/{DOOR_REPO}.git");
        let admin_ssh = git_ssh_command(&self.admin_key, &known);

        // Rung B: THE FIRST PUSH — to a repository nothing ever created.
        let (ok, said) = git_ssh(tree, &admin_ssh, &["push", &url, "HEAD:refs/heads/main"]);
        v.first_push_ok = ok;
        v.first_push_said = said;
        if !v.first_push_ok {
            return true; // formed: the door did not open
        }

        // Rung C: the ref is really there — listed back off the appliance.
        let (ok, said) = git_ssh(tree, &admin_ssh, &["ls-remote", &url, "refs/heads/main"]);
        v.listed = ok && said.contains("refs/heads/main");
        v.listed_said = said;

        // Rung D: the SECOND push goes through the ordinary resolve.
        std::fs::write(tree.join("hello.txt"), "the second commit\n").expect("edit");
        git_in(tree, &["commit", "--quiet", "-am", "two"]);
        let (ok, said) = git_ssh(tree, &admin_ssh, &["push", &url, "HEAD:refs/heads/main"]);
        v.second_push_ok = ok;
        v.second_push_said = said;

        // Rung E: the stranger still dies at userauth, one layer before any
        // of this exists.
        let stranger_ssh = git_ssh_command(&self.stranger_key, &known);
        let (_, said) = git_ssh(tree, &stranger_ssh, &["push", &url, "HEAD:refs/heads/main"]);
        v.stranger_refused = said.contains(USERAUTH_REFUSED);
        v.stranger_said = said;
        true
    }
}

/// What one guest's boot proved.
#[derive(Default)]
pub struct Verdict {
    pub port: u16,
    pub banner: Option<String>,
    pub banner_ms: Option<u128>,
    pub auth_ms: Option<u128>,
    /// The SSH host key stock `ssh` pinned on the first connection — WHICH
    /// server answered. The fleet leg counts these.
    pub host_key: Option<String>,
    pub admin_said: String,
    pub stranger_said: String,
    pub authenticated: bool,
    pub stranger_refused: bool,
    pub reached_marker: bool,
    pub panicked: bool,
    pub serial: String,
    pub serial_bytes: usize,
    pub cmdline: String,
    pub note: Option<String>,
}

impl Verdict {
    pub fn summary(&self) -> String {
        format!(
            "port {} banner={:?} auth={} stranger_refused={} host_key={} marker={} panic={} \
             ({} B serial)",
            self.port,
            self.banner.as_deref().unwrap_or("—"),
            self.authenticated,
            self.stranger_refused,
            self.host_key
                .as_deref()
                .map(|k| &k[..k.len().min(24)])
                .unwrap_or("—"),
            self.reached_marker,
            self.panicked,
            self.serial_bytes
        )
    }

    pub fn bench_line(&self, m: &Medium, g: &Guest) -> String {
        format!(
            "compose {} ms, medium {} B, boot→banner {} ms, boot→authenticated {} ms, cmdline {:?}, \
             disk {}",
            m.compose_ms,
            m.bytes,
            self.banner_ms.unwrap_or_default(),
            self.auth_ms.unwrap_or_default(),
            self.cmdline.trim(),
            g.disk.display()
        )
    }

    /// **The exchange, verbatim, on the PASSING path too.**
    ///
    /// A proof whose evidence is only visible when it fails is a proof nobody can
    /// quote. These four lines are the whole claim of this file and they cost
    /// nothing to print, so a reader of the log can see WHO was let in and WHO
    /// was not rather than taking two booleans on trust.
    pub fn print_exchange(&self) {
        eprintln!("── the SSH exchange on 127.0.0.1:{} ──", self.port);
        eprintln!("  ident  : {:?}", self.banner.as_deref().unwrap_or("—"));
        eprintln!(
            "  hostkey: {}",
            self.host_key.as_deref().unwrap_or("— (nothing pinned)")
        );
        eprintln!(
            "  ADMIN key (staged on P3 as /data/admin.pub):\n{}",
            indent(&self.admin_said)
        );
        eprintln!(
            "  STRANGER key (the medium never saw it):\n{}",
            indent(&self.stranger_said)
        );
    }

    /// The whole ladder, asserted in the order a failure is most informative.
    pub fn assert_reached(&self, name: &str) {
        assert!(
            self.reached_marker,
            "{name}: the installed disk never reached {SERVING_MARKER:?} — it did not serve at \
             all, so there was nothing to SSH into.\n{}",
            tail(&self.serial, 40)
        );
        assert!(
            !self.panicked,
            "{name}: the boot panicked:\n{}",
            tail(&self.serial, 30)
        );
        let banner = self.banner.as_deref().unwrap_or("");
        assert!(
            banner.starts_with(SSH_IDENT_PREFIX),
            "{name}: nothing on the forwarded port answered with gunnar's own identification \
             string (got {banner:?}); note={:?}\n{}",
            self.note,
            tail(&self.serial, 40)
        );
        assert!(
            self.authenticated,
            "{name}: the STAGED admin key did not open a session. `ssh` said:\n{}\nserial:\n{}",
            self.admin_said,
            tail(&self.serial, 40)
        );
        assert!(
            self.stranger_refused,
            "{name}: a key the medium NEVER SAW was not refused at userauth — rung 3 means \
             nothing without it, because `client_message` fuses absent and forbidden into one \
             sentence. `ssh` said:\n{}",
            self.stranger_said
        );
        assert!(
            self.host_key.is_some(),
            "{name}: stock `ssh` pinned no host key, so nothing here proves WHICH server answered"
        );
    }
}

// ── the client half: stock OpenSSH, one verb ────────────────────────────────

/// Ask the appliance for `repo` over its own SSH, with `key`, pinning the host
/// key into `known` on the first connection. Returns everything the client and
/// the server said, merged — the caller reads it for the two sentences that
/// live at two different protocol layers.
pub fn ssh_verb(key: &Path, known: &Path, port: u16, repo: &str) -> String {
    // The one git verb the server admits, spelled the way stock `git` spells
    // it. gunnar has no shell to ask for.
    ssh_exec(key, known, port, &format!("git-upload-pack '/{repo}'"))
}

/// Run ONE exec line on the appliance's SSH with `key`, pinning the host key
/// into `known` — [`ssh_verb`]'s dial with the line chosen by the caller.
/// Returns `exit=<code>` and everything the client and the server said.
pub fn ssh_exec(key: &Path, known: &Path, port: u16, line: &str) -> String {
    Command::new("ssh")
        .args([
            "-i",
            &key.display().to_string(),
            "-o",
            "IdentitiesOnly=yes",
            "-o",
            "StrictHostKeyChecking=accept-new",
            "-o",
            &format!("UserKnownHostsFile={}", known.display()),
            "-o",
            "LogLevel=ERROR",
            "-o",
            "ConnectTimeout=10",
            "-o",
            "BatchMode=yes",
            "-p",
            &port.to_string(),
            "git@127.0.0.1",
            line,
        ])
        .output()
        .map(|o| {
            format!(
                "exit={:?}\n{}{}",
                o.status.code(),
                String::from_utf8_lossy(&o.stdout),
                String::from_utf8_lossy(&o.stderr)
            )
        })
        .unwrap_or_else(|e| format!("spawning ssh: {e}"))
}

/// **The sealed box's tunnel-address exec line** (T17): the verb
/// `gunnar-ssh` answers (`TUNNEL_ADDRESS_VERB`) and one CIDR.
pub fn tunnel_address_line(address: std::net::Ipv4Addr, prefix: u8) -> String {
    format!("gunnar-tunnel-address {address}/{prefix}")
}

/// What [`ssh_exec`] of [`tunnel_address_line`] said, judged: `Ok` = the box
/// holds exactly `want` (`a.b.c.d/p`) and names its key; `Err` = anything else,
/// with the words. `None` = no answer yet (the listener was not up) — not a
/// verdict, the hold keeps polling.
pub fn judge_tunnel_answer(
    said: &str,
    want: &str,
) -> Option<Result<gunnar_proto::AssignTunnelAddressResponse, String>> {
    let body: String = said
        .lines()
        .skip_while(|l| l.starts_with("exit="))
        .collect::<Vec<_>>()
        .join("\n");
    if !said.contains("wg_public_key ") && !said.contains("error: ") {
        return None;
    }
    Some(match gunnar_proto::parse_tunnel_answer(&body) {
        Ok(a) if a.address == want => Ok(a),
        Ok(a) => Err(format!("the box holds {:?}, not {want}", a.address)),
        Err(why) => Err(why),
    })
}

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

    #[test]
    fn the_drives_line_and_its_judge_agree_with_the_server_writer() {
        assert_eq!(
            tunnel_address_line("10.77.0.2".parse().unwrap(), 16),
            "gunnar-tunnel-address 10.77.0.2/16"
        );
        let a = gunnar_proto::AssignTunnelAddressResponse {
            wg_public_key: "6yUuA2NvUdRuoHwFmS9OD1V8pFpXmDgVQjJ+YEptGm4=".into(),
            address: "10.77.0.2/16".into(),
            changed: true,
            tunnel_up: true,
            detail: "wg0 is up".into(),
        };
        let said = format!("exit=Some(0)\n{}", gunnar_proto::render_tunnel_answer(&a));
        let ok = judge_tunnel_answer(&said, "10.77.0.2/16")
            .expect("an answer")
            .expect("the address");
        assert_eq!(ok.wg_public_key, a.wg_public_key);
        assert!(
            judge_tunnel_answer(&said, "10.77.0.3/16").unwrap().is_err(),
            "another address is not a pass"
        );
        assert!(
            judge_tunnel_answer("exit=Some(1)\nerror: never re-pointed\n", "10.77.0.2/16")
                .unwrap()
                .is_err()
        );
        assert!(
            judge_tunnel_answer(
                "exit=Some(255)\nssh: connect to host 127.0.0.1 port 2: Connection refused\n",
                "x"
            )
            .is_none(),
            "no listener yet is no verdict"
        );
    }
}

/// `GIT_SSH_COMMAND` for `key`, pinning into `known` — the SAME options
/// [`ssh_verb`] uses, spelled once each, so both halves of a proof talk to
/// the same pinned host key.
pub fn git_ssh_command(key: &Path, known: &Path) -> String {
    format!(
        "ssh -i {} -o IdentitiesOnly=yes -o StrictHostKeyChecking=accept-new \
         -o UserKnownHostsFile={} -o LogLevel=ERROR -o ConnectTimeout=10 -o BatchMode=yes",
        key.display(),
        known.display()
    )
}

/// Run stock `git` in `cwd` with a hermetic environment (no system or user
/// config, a fixed identity), and panic on failure — for the LOCAL plumbing
/// (`init`, `add`, `commit`) whose failure is a harness fault, not a verdict.
pub fn git_in(cwd: &Path, args: &[&str]) {
    let (ok, said) = git_ssh(cwd, "ssh", args);
    assert!(
        ok,
        "local `git {args:?}` failed in {}:\n{said}",
        cwd.display()
    );
}

/// Run stock `git` in `cwd` with `ssh` as its transport. Returns success and
/// the merged output — the REMOTE half, where failure IS the measurement.
pub fn git_ssh(cwd: &Path, ssh: &str, args: &[&str]) -> (bool, String) {
    let out = Command::new("git")
        .current_dir(cwd)
        .env("GIT_SSH_COMMAND", ssh)
        .env("GIT_TERMINAL_PROMPT", "0")
        .env("GIT_CONFIG_NOSYSTEM", "1")
        .env("HOME", cwd)
        .env("GIT_AUTHOR_NAME", "Installer Drive")
        .env("GIT_AUTHOR_EMAIL", "drive@installtest.invalid")
        .env("GIT_COMMITTER_NAME", "Installer Drive")
        .env("GIT_COMMITTER_EMAIL", "drive@installtest.invalid")
        .args(args)
        .output();
    match out {
        Ok(o) => (
            o.status.success(),
            format!(
                "exit={:?}\n{}{}",
                o.status.code(),
                String::from_utf8_lossy(&o.stdout),
                String::from_utf8_lossy(&o.stderr)
            ),
        ),
        Err(e) => (false, format!("spawning git: {e}")),
    }
}

/// What one guest's boot proved about the FIRST-PUSH door.
#[derive(Default)]
pub struct PushVerdict {
    pub port: u16,
    pub banner: Option<String>,
    pub host_key: Option<String>,
    /// The admin's `git-upload-pack` for [`ABSENT_REPO`]: reads must still be
    /// refused with the fused sentence, door or no door.
    pub read_said: String,
    pub read_still_refused: bool,
    pub first_push_ok: bool,
    pub first_push_said: String,
    pub listed: bool,
    pub listed_said: String,
    pub second_push_ok: bool,
    pub second_push_said: String,
    pub stranger_refused: bool,
    pub stranger_said: String,
    pub reached_marker: bool,
    pub panicked: bool,
    pub serial: String,
    pub serial_bytes: usize,
    pub note: Option<String>,
}

impl PushVerdict {
    /// The exchange, verbatim, on the passing path too — same rule as
    /// [`Verdict::print_exchange`].
    pub fn print_exchange(&self) {
        eprintln!("── the first-push door on 127.0.0.1:{} ──", self.port);
        eprintln!("  ident   : {:?}", self.banner.as_deref().unwrap_or("—"));
        eprintln!(
            "  hostkey : {}",
            self.host_key.as_deref().unwrap_or("— (nothing pinned)")
        );
        eprintln!(
            "  READ of {ABSENT_REPO} (admin key):\n{}",
            indent(&self.read_said)
        );
        eprintln!(
            "  FIRST PUSH to {DOOR_REPO}:\n{}",
            indent(&self.first_push_said)
        );
        eprintln!("  ls-remote:\n{}", indent(&self.listed_said));
        eprintln!("  SECOND PUSH:\n{}", indent(&self.second_push_said));
        eprintln!("  STRANGER push:\n{}", indent(&self.stranger_said));
    }

    /// The whole ladder, asserted in the order a failure is most informative.
    pub fn assert_created(&self, name: &str) {
        assert!(
            self.reached_marker,
            "{name}: the installed disk never reached {SERVING_MARKER:?}\n{}",
            tail(&self.serial, 40)
        );
        assert!(
            !self.panicked,
            "{name}: the boot panicked:\n{}",
            tail(&self.serial, 30)
        );
        let banner = self.banner.as_deref().unwrap_or("");
        assert!(
            banner.starts_with(SSH_IDENT_PREFIX),
            "{name}: nothing answered with gunnar's identification string (got {banner:?}); \
             note={:?}",
            self.note
        );
        assert!(
            self.read_still_refused,
            "{name}: the admin's READ of {ABSENT_REPO} was not the fused refusal — either the \
             key no longer authenticates or reads have started creating. `ssh` said:\n{}",
            self.read_said
        );
        assert!(
            self.first_push_ok,
            "{name}: the admin's FIRST PUSH to {DOOR_REPO} was refused — the appliance is still \
             the brick measured 2026-08-25. git said:\n{}\nserial:\n{}",
            self.first_push_said,
            tail(&self.serial, 40)
        );
        assert!(
            self.listed,
            "{name}: the pushed ref did not list back — the push 'succeeded' into nothing:\n{}",
            self.listed_said
        );
        assert!(
            self.second_push_ok,
            "{name}: the SECOND push failed — created, but not a working repository:\n{}",
            self.second_push_said
        );
        assert!(
            self.stranger_refused,
            "{name}: the stranger's key was not refused at userauth — the door is only \
             acceptable while it is invisible to every other key. git said:\n{}",
            self.stranger_said
        );
        assert!(
            self.host_key.is_some(),
            "{name}: no host key pinned, so nothing says WHICH server answered"
        );
    }
}

/// The one host key `accept-new` pinned — WHICH server answered.
pub fn read_pinned_host_key(known: &Path) -> Option<String> {
    let text = std::fs::read_to_string(known).ok()?;
    let mut keys: Vec<String> = text
        .lines()
        .filter(|l| !l.trim().is_empty() && !l.starts_with('#'))
        .filter_map(|l| l.split_whitespace().nth(2).map(str::to_string))
        .collect();
    keys.sort();
    keys.dedup();
    // Two answers on one pinned address is not a result, it is a substitution.
    (keys.len() == 1).then(|| keys.remove(0))
}

/// Connect and read the SSH identification string. `None` while nothing answers.
pub fn read_ident(port: u16) -> Option<String> {
    let mut s = TcpStream::connect_timeout(
        &std::net::SocketAddr::from(([127, 0, 0, 1], port)),
        Duration::from_secs(2),
    )
    .ok()?;
    s.set_read_timeout(Some(Duration::from_secs(3))).ok()?;
    let mut buf = [0u8; 256];
    let n = s.read(&mut buf).ok()?;
    (n > 0).then(|| {
        // Say something back so the server's own logs record a peer that spoke
        // rather than a half-open probe it has to time out.
        let _ = s.write_all(b"SSH-2.0-probe\r\n");
        String::from_utf8_lossy(&buf[..n]).trim().to_string()
    })
}

fn which(bin: &str) -> Option<PathBuf> {
    std::env::var_os("PATH").and_then(|paths| {
        std::env::split_paths(&paths)
            .map(|d| d.join(bin))
            .find(|p| p.is_file())
    })
}

/// Four spaces in front of every line, so a multi-line capture reads as one
/// block instead of merging into the log around it.
fn indent(s: &str) -> String {
    s.lines()
        .map(|l| format!("    {l}"))
        .collect::<Vec<_>>()
        .join("\n")
}

fn tail(s: &str, n: usize) -> String {
    let lines: Vec<&str> = s.lines().collect();
    lines[lines.len().saturating_sub(n)..].join("\n")
}