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

nordisk/Skidbladnir

tests/exec_start_durability.rs

//! **Z2 — the scratch-`ExecStart` trap.** A unit that points into a build tree.
//!
//! # The measurement, oden 2026-08-27
//!
//! `dwarves-server --install` builds its unit around [`std::env::current_exe`], so an
//! install run from a build directory wrote
//!
//! ```text
//! ExecStart=~/git/dwarves/target/release/dwarves-server
//! ```
//!
//! A machine-wide service executing out of a cargo target tree. Every gate that existed
//! passed: the file was there, it was a file, it had the exec bit. And then a routine
//! `cargo clean --target-dir` (a lane reclaimed 139 GB that way the same day) deletes the
//! binary of a live service. The unit stays, the manager still reports it enabled, and
//! the next start fails 203/EXEC with nothing in the unit having changed.
//!
//! **Existence is not durability**, and that is the whole gap.
//!
//! # The red, asserted rather than described
//!
//! [`the_pre_existing_gate_is_green_on_exactly_this`] asserts that
//! `validate_exec_on_disk()` — the gate that was already wired into the install path —
//! returns **Ok** for an `ExecStart` inside a real cargo target tree. That is not a
//! hypothetical: it is the hole, pinned, so the new refusal can never be mistaken for a
//! duplicate of the old one.
//!
//! # Applied output, not a state round-trip
//!
//! [`a_scratch_execstart_is_refused_and_no_unit_is_written`] drives the real
//! `install_systemd_scoped` and then asserts on the FILESYSTEM: no unit file exists. The
//! accepting half writes a real `systemctl --user` unit and reads its `ExecStart=` line
//! back off disk.

#![cfg(all(unix, target_os = "linux"))]

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

use skidbladnir::systemd::{
    Scope, SystemdServiceSpec, enclosing_cargo_target_dir, install_systemd_scoped,
};

/// A unit name no product uses, so a stray run cannot collide with a real service — and
/// specifically NOT `dwarves-server`, whose live unit another lane owns today.
const UNIT_NAME: &str = "skid-execdurable-selftest";

fn whoami() -> String {
    std::env::var("USER")
        .or_else(|_| std::env::var("LOGNAME"))
        .unwrap_or_default()
}

fn user_unit_dir() -> PathBuf {
    PathBuf::from(std::env::var("HOME").expect("HOME")).join(".config/systemd/user")
}

/// A scratch root on **md1** — never `/tmp`, which is RAM on this box (the disk law).
fn scratch(name: &str) -> PathBuf {
    let home = std::env::var("HOME").expect("HOME");
    let dir = PathBuf::from(home)
        .join("scratch")
        .join("skid-execdurable")
        .join(format!("{name}-{}", std::process::id()));
    let _ = std::fs::remove_dir_all(&dir);
    std::fs::create_dir_all(&dir).expect("create the scratch root");
    dir
}

/// **A REAL cargo target tree** — the two artefacts cargo itself writes, verbatim.
///
/// Not a directory called `target`: the detector reads the markers, so the fixture must
/// carry the markers. `CACHEDIR.TAG` gets the Cache Directory Tagging Standard signature
/// cargo emits, byte for byte, and `.rustc_info.json` sits beside it. This pair is exactly
/// what `cargo clean --target-dir <dir>` removes — verified against a live lane target dir
/// on oden 2026-08-27 (`~/scratch/cargo/doors-agent` held both).
///
/// Returns `(target_dir, exe_inside_it)`.
fn fake_cargo_target(root: &Path) -> (PathBuf, PathBuf) {
    let target = root.join("z-lane");
    std::fs::create_dir_all(target.join("release")).expect("create the target tree");
    std::fs::write(
        target.join("CACHEDIR.TAG"),
        "Signature: 8a477f597d28d172789f06886806bc55\n\
         # This file is a cache directory tag created by cargo.\n",
    )
    .expect("write CACHEDIR.TAG");
    std::fs::write(target.join(".rustc_info.json"), "{\"rustc_fingerprint\":0}")
    .expect("write .rustc_info.json");
    let exe = target.join("release").join("sleep");
    copy_real_binary(&exe);
    (target, exe)
}

/// Copy a real ELF, keeping the basename `sleep`.
///
/// A shell script would not do: `#!` makes the kernel exec the INTERPRETER, and the
/// coreutils binary on this box is a multicall that dispatches on `argv[0]` and exits at
/// once under any other name (that lesson is already paid for in
/// `tests/exec_verify_live.rs`).
fn copy_real_binary(dest: &Path) {
    let src = std::fs::canonicalize("/usr/bin/sleep")
        .or_else(|_| std::fs::canonicalize("/bin/sleep"))
        .expect("need a sleep binary");
    std::fs::create_dir_all(dest.parent().unwrap()).expect("create the dest dir");
    std::fs::copy(&src, dest).expect("copy the probe binary");
}

fn spec_for(exec: &Path, home: &Path) -> SystemdServiceSpec {
    SystemdServiceSpec::new(
        UNIT_NAME,
        "skidbladnir ExecStart-durability self test",
        exec.display().to_string(),
        whoami(),
        home.display().to_string(),
    )
    .with_arg("3000")
    .with_restart(skidbladnir::systemd::RestartPolicy::No)
}

/// ★ **THE RED.** The gate that was already in the install path is GREEN on exactly the
/// path that killed the service.
///
/// `validate_exec_on_disk` asks: absolute? stat-able? not a directory? executable? A
/// binary in a cargo target tree answers yes to all four. Pinning that here is what
/// stops the new refusal from being read as a second copy of the old one — and what
/// proves the new one is looking at something the old one structurally could not see.
#[test]
fn the_pre_existing_gate_is_green_on_exactly_this() {
    let root = scratch("red");
    let (target, exe) = fake_cargo_target(&root);
    let spec = spec_for(&exe, &root);

    assert_eq!(
        spec.validate_exec_on_disk(),
        Ok(()),
        "the EXISTING gate must accept `{}` — if it ever refuses this on its own, the \
         durability check below is redundant and should be deleted rather than kept as \
         decoration",
        exe.display()
    );

    // And the new one refuses it, naming the tree and the command that deletes it.
    let err = spec
        .validate_exec_is_durable()
        .expect_err("an ExecStart inside a cargo target tree must be REFUSED");
    assert!(
        err.contains(&target.display().to_string()),
        "the refusal must NAME the target dir: {err}"
    );
    assert!(
        err.contains("cargo clean --target-dir"),
        "…and the command that will delete it, so the operator can see why: {err}"
    );
    assert!(
        err.contains("203/EXEC"),
        "…and the failure it becomes: {err}"
    );
}

/// ★ The detector reads cargo's ARTEFACTS, not the path text — in both directions.
#[test]
fn the_target_detector_reads_the_markers_and_not_the_name() {
    let root = scratch("detect");
    let (target, exe) = fake_cargo_target(&root);
    assert_eq!(
        enclosing_cargo_target_dir(&exe).as_deref(),
        Some(target.as_path()),
        "the marker pair must be found from one level down"
    );

    // A durable location under the SAME root is not flagged: the markers are what matter,
    // not the neighbourhood.
    let durable = root.join("bin").join("sleep");
    copy_real_binary(&durable);
    assert_eq!(
        enclosing_cargo_target_dir(&durable),
        None,
        "a binary outside the marked tree must NOT be flagged"
    );

    // A directory literally NAMED `target`, with no markers, is innocent — and a
    // name-based check would libel it. This is the assertion that keeps the detector
    // honest.
    let innocent = root.join("target").join("release").join("sleep");
    copy_real_binary(&innocent);
    assert_eq!(
        enclosing_cargo_target_dir(&innocent),
        None,
        "a directory called `target` with no CACHEDIR.TAG/.rustc_info.json is not a cargo \
         target dir; flagging it would be a name check wearing a marker check's clothes"
    );

    // …and conversely, a target dir NOT called `target` IS flagged. This is the case a
    // name check misses, and it is where every build on this box actually goes
    // (`CARGO_TARGET_DIR=~/scratch/cargo/<lane>`).
    assert!(
        !target.ends_with("target"),
        "the fixture is deliberately named `z-lane`, like the real scratch lanes"
    );

    // Each marker ALONE must not be enough: plenty of caches carry a CACHEDIR.TAG.
    let half = root.join("cache-only");
    std::fs::create_dir_all(half.join("release")).unwrap();
    std::fs::write(
        half.join("CACHEDIR.TAG"),
        "Signature: 8a477f597d28d172789f06886806bc55\n",
    )
    .unwrap();
    let half_exe = half.join("release").join("sleep");
    copy_real_binary(&half_exe);
    assert_eq!(
        enclosing_cargo_target_dir(&half_exe),
        None,
        "CACHEDIR.TAG alone is any cache, not a cargo target dir"
    );
}

/// ★ **The declared program path is a refusal, not a warning** — and it discriminates.
#[test]
fn an_execstart_outside_the_declared_program_path_is_refused() {
    let root = scratch("progdir");
    let bin = root.join("bin");
    let elsewhere = root.join("elsewhere");
    let installed = bin.join("sleep");
    let stray = elsewhere.join("sleep");
    copy_real_binary(&installed);
    copy_real_binary(&stray);

    // Declared: <root>/bin. The stray copy is refused…
    let refused = spec_for(&stray, &root)
        .with_program_dirs([bin.display().to_string()])
        .validate_exec_is_durable()
        .expect_err("an ExecStart outside every declared program path must be refused");
    assert!(
        refused.contains(&elsewhere.display().to_string()),
        "the refusal must name where the binary actually is: {refused}"
    );
    assert!(
        refused.contains(&bin.display().to_string()),
        "…and what was declared: {refused}"
    );

    // …and the installed copy is accepted. Without this the guard could be a blanket
    // refusal that passes the test above for the wrong reason.
    assert_eq!(
        spec_for(&installed, &root)
            .with_program_dirs([bin.display().to_string()])
            .validate_exec_is_durable(),
        Ok(()),
        "a binary INSIDE the declared program path must install"
    );

    // A symlinked or `..`-laden spelling of the same directory is the same directory:
    // the comparison is on canonicalised paths, so an operator's `--prefix
    // <root>/bin/../bin` is not a different answer.
    let noisy = format!("{}/../bin", bin.display());
    assert_eq!(
        spec_for(&installed, &root)
            .with_program_dirs([noisy.clone()])
            .validate_exec_is_durable(),
        Ok(()),
        "`{noisy}` names the same directory and must be accepted"
    );

    // UNDECLARED (empty) leaves the program-path rule off — the build-tree refusal is
    // unconditional, this one is opt-in, and that difference has to be visible.
    assert_eq!(
        spec_for(&stray, &root).validate_exec_is_durable(),
        Ok(()),
        "with no declared program path there is nothing to be outside of"
    );
}

/// **The refusal writes NOTHING** — no systemd needed.
///
/// The applied-output assertion is the FILESYSTEM, not a `Result`: after the refusal there
/// must be no unit file at all. An installer that refused after writing the unit would
/// return the same `Err` and leave the trap armed. The refusal comes before any bus is
/// dialled, so this half runs everywhere, a container with no `systemd --user` included.
///
/// Until 2026-10-25 this and the accepting install below were ONE test, so a box with no
/// user bus (the CI container, ODEN-CI round 1) saw the whole test red at the install
/// half, for a reason that had nothing to do with the refusal.
#[test]
fn a_scratch_execstart_is_refused_and_no_unit_is_written() {
    let root = scratch("refuse");
    let (target, scratch_exe) = fake_cargo_target(&root);

    let unit_file = user_unit_dir().join(format!("{UNIT_NAME}.service"));
    // Start from a known state; a leftover from an interrupted run would fake either
    // answer.
    let _ = std::fs::remove_file(&unit_file);
    assert!(!unit_file.exists(), "the fixture starts with no unit file");

    let err = install_systemd_scoped(&spec_for(&scratch_exe, &root), Scope::User)
        .expect_err("installing a unit around a build-tree binary must be refused");
    let msg = format!("{err:#}");
    assert!(
        msg.contains(&target.display().to_string()),
        "the refusal must name the target tree: {msg}"
    );
    assert!(
        !unit_file.exists(),
        "REFUSED BUT WROTE ANYWAY: {} exists. A refusal after the write leaves the trap \
         armed and returns the same Err.",
        unit_file.display()
    );
}

/// ★ **LIVE, against real systemd: the accepting install writes the durable path.**
///
/// It installs a scratch `systemctl --user` unit (never a live one), so it needs the
/// caller's user bus and is `#[ignore]` by this repository's rule
/// (`tests/live_tests_are_ignored.rs`). Without a bus it FAILS, it never passes green.
/// Run it with `cargo test --test exec_start_durability -- --ignored` on a box with
/// `systemd --user`.
#[test]
#[ignore = "live: installs a scratch systemctl --user unit; needs the caller's user bus"]
fn a_durable_execstart_installs_and_the_unit_execs_the_durable_path() {
    let root = scratch("live");
    let installed = root.join("bin").join("sleep");
    copy_real_binary(&installed);
    let home = PathBuf::from(std::env::var("HOME").expect("HOME"));
    let unit_file = home
        .join(".config/systemd/user")
        .join(format!("{UNIT_NAME}.service"));
    let _ = std::fs::remove_file(&unit_file);

    // ── the accepting install, with the program path DECLARED ─────────────────────
    let spec = spec_for(&installed, &root)
        .with_program_dirs([root.join("bin").display().to_string()]);
    install_systemd_scoped(&spec, Scope::User).expect("a durable ExecStart must install");

    let unit = std::fs::read_to_string(&unit_file).expect("the unit file must now exist");
    let exec_line = unit
        .lines()
        .find(|l| l.starts_with("ExecStart="))
        .expect("the unit must carry an ExecStart");
    assert!(
        exec_line.contains(&installed.display().to_string()),
        "the APPLIED ExecStart must be the durable path, got `{exec_line}`"
    );
    assert!(
        enclosing_cargo_target_dir(Path::new(
            exec_line
                .trim_start_matches("ExecStart=")
                .split_whitespace()
                .next()
                .unwrap()
        ))
        .is_none(),
        "and the path systemd will actually exec must not be in a build tree: {exec_line}"
    );

    // Clean up: stop + disable + remove the unit through the ship's own verb, never by
    // hand.
    let lc = skidbladnir::service::Lifecycle::new(
        skidbladnir::service::ServiceSpec::new(
            UNIT_NAME,
            "skidbladnir ExecStart-durability self test",
            installed.display().to_string(),
        )
        .scope(Scope::User),
    );
    let _ = lc.uninstall();
    let _ = std::fs::remove_file(&unit_file);
}