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

nordisk/gunnar

crates/gunnar-build-thing/tests/no_logic_in_the_shim.rs

//! **The shim must stay a shim**, and this is why that is a correctness rule
//! rather than tidiness.
//!
//! A receipt addresses its recipe as `krate:version:hash`, and the `hash` is
//! computed by **`gunnar-recipe`'s** `build.rs` over `gunnar-recipe/src/**/*.rs`
//! — that is the field whose whole job is to say *which bytes actually ran*.
//! This crate's sources are not in it. So any logic that ran from here would be
//! outside the hash: two artifacts could carry byte-identical coordinates and
//! have been built by different code, which is precisely the claim the hash
//! exists to make impossible.
//!
//! Splitting the crate (2026-09-04, for cargo#6313 — see the manifest) created
//! that gap. This closes it by construction: there is nothing here to miss.
//!
//! Extending the shim is allowed — it just has to be a deliberate act that also
//! moves the hash. Either put the code in `gunnar-recipe` where the hash covers
//! it (almost always right), or hash this crate's sources too and say so here.

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

fn shim_src() -> PathBuf {
    Path::new(env!("CARGO_MANIFEST_DIR")).join("src")
}

/// Every non-comment, non-blank line of `src/lib.rs` is either the `pub use` of
/// the recipe or the `export_build_thing!` line.
///
/// Asserted on the FILE, not on a symbol count: a symbol count would pass for a
/// `const fn` that computed something, and the thing being forbidden is *any*
/// code path whose bytes are outside the recipe's hash.
///
/// Seen RED by adding `pub fn shim_helper() -> u8 { 7 }` to `src/lib.rs`:
/// `the shim has grown logic: src/lib.rs:52 `pub fn shim_helper() -> u8 { 7 }``.
#[test]
fn the_shim_holds_nothing_but_a_reexport_and_the_abi_export() {
    let lib = shim_src().join("lib.rs");
    let text = std::fs::read_to_string(&lib).expect("read the shim's lib.rs");

    let mut offenders = Vec::new();
    for (i, raw) in text.lines().enumerate() {
        let line = raw.trim();
        if line.is_empty() || line.starts_with("//") {
            continue;
        }
        let allowed = line == "pub use gunnar_recipe::*;"
            || line == "nornir_build_thing::export_build_thing!(GunnarBuildThing);";
        if !allowed {
            offenders.push(format!("src/lib.rs:{}: {line}", i + 1));
        }
    }
    assert!(
        offenders.is_empty(),
        "the shim has grown logic, and the receipt's `hash` does not cover this crate's \
         sources — so an artifact could name a recipe by coordinate and have been built by \
         code the coordinate cannot see. Move it to `gunnar-recipe`, or hash this crate too \
         and rewrite this test's header:\n  {}",
        offenders.join("\n  ")
    );
}

/// **The shim has exactly one source file besides the bin.** A second module
/// would be logic by another door, and the check above only reads `lib.rs`.
///
/// `main.rs` is expected and is not a hazard: it is the `emit` door, it runs
/// only when an operator types `cargo run -p gunnar-build-thing -- emit`, and it
/// writes no receipt.
///
/// Seen RED by `touch src/helper.rs`: "the shim gained a module: helper.rs".
#[test]
fn the_shim_has_no_modules_of_its_own() {
    let mut found: Vec<String> = std::fs::read_dir(shim_src())
        .expect("read the shim's src/")
        .flatten()
        .map(|e| e.file_name().to_string_lossy().into_owned())
        .filter(|n| n.ends_with(".rs"))
        .collect();
    found.sort();
    assert_eq!(
        found,
        vec!["lib.rs".to_string(), "main.rs".to_string()],
        "the shim gained a module: anything beyond lib.rs and main.rs is code outside the \
         recipe's content hash"
    );
}

/// **The two crates carry the same version**, because a receipt's coordinate is
/// `gunnar-build-thing:<version>` (`gunnar_recipe::recipe::KRATE` is the literal
/// `"gunnar-build-thing"`, deliberately unchanged by the split) while the recipe
/// that produced it is `gunnar-recipe` at ITS version. If those drift, the
/// coordinate names a `gunnar-build-thing` whose recipe is a different one.
///
/// Read out of the two manifests rather than from `CARGO_PKG_VERSION`, because
/// this crate only knows its own.
///
/// Seen RED by bumping `gunnar-recipe`'s version to `0.1.1`: "the coordinate
/// would name gunnar-build-thing 0.1.0 built by gunnar-recipe 0.1.1".
#[test]
fn the_shim_and_the_recipe_share_one_version() {
    let version_of = |manifest: &Path| -> String {
        let text = std::fs::read_to_string(manifest)
            .unwrap_or_else(|e| panic!("read {}: {e}", manifest.display()));
        // The first `version = "…"` after the `[package]` header — deliberately
        // not a toml parse, so this test needs no dependency.
        let pkg = text.find("[package]").expect("a [package] table");
        text[pkg..]
            .lines()
            .find_map(|l| l.trim().strip_prefix("version = \""))
            .and_then(|v| v.split('"').next())
            .expect("a version in [package]")
            .to_string()
    };
    let here = Path::new(env!("CARGO_MANIFEST_DIR"));
    let shim = version_of(&here.join("Cargo.toml"));
    let recipe = version_of(&here.parent().unwrap().join("gunnar-recipe/Cargo.toml"));
    assert_eq!(
        shim, recipe,
        "the coordinate would name gunnar-build-thing {shim} built by gunnar-recipe {recipe}; \
         `recipe::KRATE` is the literal \"gunnar-build-thing\", so these two versions are one \
         number or the coordinate is unfetchable"
    );
}