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

nordisk/holger

errcode/tests/wiring_guard.rs

//! **THE WIRING GUARD** — the thing that makes holger's error-code registry a measurement
//! instead of a wish.
//!
//! For four sessions the registry declared 65 codes and the `tonic::Status` construction
//! sites — the ONLY surface a remote client sees — carried none of them. Nothing failed,
//! because nothing checked. A registry can always claim coverage; only a guard that reads
//! the real source tree can falsify the claim.
//!
//! This walks [`holger_errcode::ALL`] against holger's actual `.rs` files and asserts each
//! row's [`Wiring`](holger_errcode::Wiring) is the TRUTH, in BOTH directions:
//!
//! * a `wired` row MUST be referenced from its declared `src_file` — drop the code from one
//!   site and THAT row fails, naming the code and the file; and
//! * a `reserved` row must be referenced from NO production file — if it is raised, the row
//!   was lying the other way and should be promoted to `wired`.
//!
//! The second direction is what stops the split degenerating into "mark everything
//! reserved and the guard goes quiet".
//!
//! ## What counts as a raise
//!
//! holger raises a code by naming its `const` (`ec::UPDATE_UNSAFE_PATH`,
//! `&holger_errcode::SERVER_REPO_UNKNOWN`) — not by writing the wire string. So the guard
//! matches the **identifier**. `errcode/src/lib.rs` is excluded: the registry table names
//! every code as DATA, which is not a raise site. `#[cfg(test)]` items are stripped, because
//! a test that merely mentions a code is not the product raising it.

use holger_errcode::{Wiring, ALL};
use std::collections::HashMap;
use std::path::{Path, PathBuf};

/// `errcode/..` — the holger repo root, derived from this crate's manifest dir so the guard
/// reads the real files it makes claims about.
fn repo_root() -> PathBuf {
    Path::new(env!("CARGO_MANIFEST_DIR"))
        .parent()
        .expect("errcode/.. is the holger repo root")
        .to_path_buf()
}

/// Earmarks that name a file which does not exist YET, declared explicitly so an absence is
/// a decision on the record rather than a silently-tolerated typo. A `reserved` row pointing
/// anywhere else MUST resolve to a real file.
///
/// `holger-jobs/` is not a workspace member on `main` — the background job runner is still a
/// plan, and its three `jobs-*` numbers are a claim on a subsystem that does not exist.
const PLANNED_FILES: &[&str] = &["holger-jobs/src/lib.rs"];

/// Directories holger's production code lives in. Deliberately NOT the whole tree: `target/`
/// is build output and `tests/` is test vocabulary, not product behaviour.
const SOURCE_ROOTS: &[&str] = &[
    "traits/src",
    "server/lib/src",
    "server/cli/src",
    // `server/ui/src` was here until the GUI left for the holger-egui repository
    // ("server/ui leaves for holger-egui"). The directory is gone, so the entry
    // contributed zero files and this guard silently covered less than it said.
    "server/repository",
    "agent/lib/src",
    "agent/cli/src",
    "agent/connector",
    "mannequin/src",
    "update-bundle/src",
    "provenance/src",
    // The scan sandbox and its worker (lane SANDBOX-SCAN).
    "server/sandbox/src",
    // The job runners behind the Heimdall job API (lane HOL-SANDBOX-TRAIT).
    "jobs/runner/src",
    "build-space/src",
    // The public front page: one pure function and the page it serves.
    "holger-front/src",
    // The thin client (lane B3): it raises the `cli` codes.
    "holger-cli/src",
    "xtask/src",
    // The wasm package-handler lane: the ABI, the wasmtime host, the two bundle
    // handlers and their wasm shims. Production code, so it is scanned — a new
    // crate left off this list would shrink the guard's coverage silently, which
    // is what the missing-directory assertion below exists to stop.
    "plugin",
];

/// Every production `.rs` file under [`SOURCE_ROOTS`], with `target/`, `tests/` and dotdirs
/// pruned.
fn production_sources(root: &Path) -> Vec<PathBuf> {
    // A root that no longer exists scans nothing and reports nothing, so the
    // whole guard silently shrinks every time a crate is removed and its entry
    // is left behind. `holger-audit/src` had been listed with no directory
    // under it. Name the stale entry instead of walking past it.
    let missing: Vec<&str> = SOURCE_ROOTS
        .iter()
        .copied()
        .filter(|d| !root.join(d).is_dir())
        .collect();
    assert!(
        missing.is_empty(),
        "SOURCE_ROOTS names {} that do not exist: {:?}\n\
         Each one contributes zero files, so this guard covers less than it claims. \
         Delete the entry, or restore the directory.",
        if missing.len() == 1 {
            "a directory"
        } else {
            "directories"
        },
        missing
    );
    let mut out = Vec::new();
    let mut stack: Vec<PathBuf> = SOURCE_ROOTS.iter().map(|d| root.join(d)).collect();
    while let Some(dir) = stack.pop() {
        let Ok(rd) = std::fs::read_dir(&dir) else {
            continue;
        };
        for e in rd.flatten() {
            let p = e.path();
            let name = e.file_name().to_string_lossy().to_string();
            if p.is_dir() {
                if name != "target"
                    && name != "tests"
                    && name != "benches"
                    && !name.starts_with('.')
                {
                    stack.push(p);
                }
            } else if p.extension().is_some_and(|x| x == "rs") {
                out.push(p);
            }
        }
    }
    out
}

/// Strip `#[cfg(test)]` items by brace-matching from the attributed item's opening `{` to its
/// close.
///
/// Deliberately NOT "cut the file at the first `#[cfg(test)]`": holger's test modules are not
/// always last (`update-bundle/src/error.rs` has one mid-file), and cutting there would
/// discard most of the file and make every scan quietly UNDER-read it — a guard that reads
/// less than it claims is the same disease in a new coat.
fn strip_test_items(text: &str) -> String {
    let lines: Vec<&str> = text.lines().collect();
    let mut out = String::with_capacity(text.len());
    let mut i = 0usize;
    while i < lines.len() {
        let t = lines[i].trim_start();
        if t.starts_with("#[cfg(test)]") || t.starts_with("#[cfg(all(test") {
            let mut depth = 0i32;
            let mut opened = false;
            while i < lines.len() {
                for c in lines[i].chars() {
                    match c {
                        '{' => {
                            depth += 1;
                            opened = true;
                        }
                        '}' => depth -= 1,
                        _ => {}
                    }
                }
                i += 1;
                if opened && depth <= 0 {
                    break;
                }
                if !opened && lines[i - 1].trim_end().ends_with(';') {
                    break;
                }
            }
            continue;
        }
        out.push_str(lines[i]);
        out.push('\n');
        i += 1;
    }
    out
}

/// The registry const's identifier, recovered from the code (`holger-update-22` has no
/// identifier in it, so the guard is handed the map instead). See [`ident_map`].
fn ident_map() -> HashMap<&'static str, String> {
    // The identifier is not derivable from `(subsystem, n)` — `holger-update-3` is
    // `UPDATE_UNSAFE_PATH`. Recover it from the registry SOURCE, which is the one place
    // both halves sit on the same line: `wired UPDATE_UNSAFE_PATH = ("update", 3, …`.
    let src = std::fs::read_to_string(repo_root().join("errcode/src/lib.rs"))
        .expect("errcode/src/lib.rs is readable");
    let mut map = HashMap::new();
    for line in src.lines() {
        let t = line.trim_start();
        let rest = t
            .strip_prefix("wired ")
            .or_else(|| t.strip_prefix("reserved "))
            .unwrap_or("");
        let Some((ident, args)) = rest.split_once(" = (") else {
            continue;
        };
        // args starts `"update", 3, …` — take subsystem + n to rebuild the code.
        let mut parts = args.splitn(3, ',');
        let Some(sub) = parts.next() else { continue };
        let Some(n) = parts.next() else { continue };
        let code = format!("holger-{}-{}", sub.trim().trim_matches('"'), n.trim());
        if let Some(row) = ALL.iter().find(|c| c.code == code) {
            map.insert(row.code, ident.trim().to_string());
        }
    }
    // Never let a parse failure pass for "everything is fine" — an empty/short map would
    // make every `raises` check trivially true and the whole guard hollow.
    assert_eq!(
        map.len(),
        ALL.len(),
        "the guard recovered {} of {} registry identifiers from errcode/src/lib.rs — \
         the `<wired|reserved> IDENT = (\"sub\", n, …);` row shape must have changed. \
         FIX THE PARSER: with a short map this guard silently checks nothing.",
        map.len(),
        ALL.len(),
    );
    map
}

/// Whether `text` references `ident` as a whole word (so `SERVER_READ_ONLY` is not found
/// inside `SERVER_READ_ONLY_EXTRA`).
fn references(text: &str, ident: &str) -> bool {
    let b = text.as_bytes();
    let mut from = 0usize;
    while let Some(rel) = text[from..].find(ident) {
        let at = from + rel;
        let before_ok = at == 0 || !(b[at - 1].is_ascii_alphanumeric() || b[at - 1] == b'_');
        let end = at + ident.len();
        let after_ok = end >= b.len() || !(b[end].is_ascii_alphanumeric() || b[end] == b'_');
        if before_ok && after_ok {
            return true;
        }
        from = at + 1;
    }
    false
}

/// THE GUARD. Both directions, over the real tree.
#[test]
fn wiring_claims_match_the_real_source_tree() {
    let root = repo_root();
    let idents = ident_map();
    let registry_file = root.join("errcode/src/lib.rs");

    // Read the production corpus ONCE (stripped of `#[cfg(test)]` items).
    let files = production_sources(&root);
    assert!(
        files.len() > 100,
        "the guard found only {} production sources under {} — it is reading the wrong tree, \
         and an empty corpus makes every `reserved` row trivially pass",
        files.len(),
        root.display(),
    );
    let corpus: Vec<(PathBuf, String)> = files
        .into_iter()
        .filter(|p| *p != registry_file)
        .filter_map(|p| {
            std::fs::read_to_string(&p)
                .ok()
                .map(|t| (p, strip_test_items(&t)))
        })
        .collect();

    let mut problems: Vec<String> = Vec::new();

    for row in ALL {
        let ident = &idents[row.code];
        let declared = root.join(row.src_file);
        match row.wiring {
            Wiring::Wired => {
                let Ok(text) = std::fs::read_to_string(&declared) else {
                    problems.push(format!(
                        "{} is WIRED but its declared src_file {} does not exist",
                        row.code, row.src_file
                    ));
                    continue;
                };
                if !references(&strip_test_items(&text), ident) {
                    problems.push(format!(
                        "{} is marked WIRED but {} never references `{}` — either raise it \
                         there or mark the row `reserved`",
                        row.code, row.src_file, ident
                    ));
                }
            }
            Wiring::Reserved => {
                if !PLANNED_FILES.contains(&row.src_file) && !declared.exists() {
                    problems.push(format!(
                        "{} is RESERVED against {}, which does not exist and is not in \
                         PLANNED_FILES — fix the earmark or declare it planned",
                        row.code, row.src_file
                    ));
                }
                if let Some((p, _)) = corpus.iter().find(|(_, t)| references(t, ident)) {
                    problems.push(format!(
                        "{} is marked RESERVED but `{}` IS referenced from {} — promote the \
                         row to `wired`",
                        row.code,
                        ident,
                        p.strip_prefix(&root).unwrap_or(p).display()
                    ));
                }
            }
        }
    }

    assert!(
        problems.is_empty(),
        "{} registry row(s) LIE about their wiring:\n  · {}",
        problems.len(),
        problems.join("\n  · "),
    );
}

/// The honest ratio, printed so `cargo test -- --nocapture` reports coverage as a NUMBER.
/// Also a floor: the whole point of SK178 was that the gRPC surface raised nothing, so the
/// `auth` + `server` subsystems must never go back to zero wired rows.
#[test]
fn the_grpc_surface_raises_codes_at_all() {
    let wired = holger_errcode::wired_count();
    let reserved = holger_errcode::reserved_count();
    println!(
        "holger-errcode: {} codes — {wired} wired, {reserved} reserved",
        ALL.len()
    );

    for sub in ["auth", "server"] {
        let w = ALL
            .iter()
            .filter(|c| c.subsystem == sub && c.wiring == Wiring::Wired)
            .count();
        assert!(
            w > 0,
            "subsystem `{sub}` has ZERO wired codes — that is exactly the SK178 state: a \
             registry declaring codes the wire never raises"
        );
    }
}

/// ★ H2's estate cut (HCUT): the guard reads the source text, so a module behind a
/// default-off feature (`estate`: the twin's mutual TLS, the grow plane, the disks pane) is
/// held to its codes like any other; the files it scans include them.
#[test]
fn the_guard_reads_the_estate_halves_too() {
    let root = repo_root();
    let scanned = production_sources(&root);
    for f in [
        "server/lib/src/twin_tls/mtls.rs",
        "server/lib/src/twin_tls/mtls_off.rs",
        "server/lib/src/grow/plane.rs",
        "server/lib/src/admin_view/disks.rs",
    ] {
        assert!(
            scanned.iter().any(|p| p.ends_with(f)),
            "the wiring guard does not scan {f}"
        );
    }
}