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

nordisk/nornir

crates/nornir-guard/src/selftest.rs

//! # Functional-status emit bridge — `nornir-guard` → test matrix
//!
//! The single internal call site this crate uses to push a *functional* row
//! into the [`nornir_testmatrix`] matrix, so `nornir test --features testmatrix`
//! records whether `nornir-guard`'s real guard checks (status / apply-readonly /
//! manifest roundtrip / drift verify / intact gate) ACTUALLY work.
//!
//! ## Release strips everything
//! The `testmatrix` cargo feature gates the whole bridge: with it OFF (the
//! release default) [`emit`] is an `#[inline]` no-op and `nornir-testmatrix` is
//! not even linked. Lit ONLY under `cargo … --features testmatrix`.

/// The aspect tag every self-emitted row carries (matches `functional_row`).
pub const ASPECT_FUNCTIONAL: &str = "functional";

/// Push ONE functional-status row for a single real check (feature ON).
#[cfg(feature = "testmatrix")]
#[inline]
pub fn emit(component: &str, check: &str, ok: bool, detail: &str) {
    nornir_testmatrix::functional_status(component, check, ok, detail);
}

/// No-op stub when the `testmatrix` feature is OFF (release builds).
#[cfg(not(feature = "testmatrix"))]
#[inline]
pub fn emit(_component: &str, _check: &str, _ok: bool, _detail: &str) {}

/// `assert!`-with-emit: assert on the real return value AND record the verdict
/// as a matrix row.
#[macro_export]
macro_rules! assert_emit {
    ($component:expr, $check:expr, $ok:expr, $($detail:tt)+) => {{
        let __ok: bool = $ok;
        let __detail = ::std::format!($($detail)+);
        $crate::selftest::emit($component, $check, __ok, &__detail);
        ::std::assert!(__ok, "{}::{} — {}", $component, $check, __detail);
    }};
}

// ─── inject-and-assert wiring test (feature ON only) ─────────────────────────
#[cfg(all(test, feature = "testmatrix"))]
mod wiring {
    use std::io::Write;

    /// Drive `nornir-guard`'s real checks on a synthetic workspace, emit an
    /// honest row per surface, then drain the process-global functional buffer
    /// and assert the rows landed — proving the emit bridge is wired end to end.
    #[test]
    fn emits_honest_rows_for_guard_checks() {
        let dir = tempfile::tempdir().unwrap();
        let root = dir.path();
        let forbidden = vec!["secret.txt".to_string()];
        {
            let mut f = std::fs::File::create(root.join("secret.txt")).unwrap();
            writeln!(f, "append-only history").unwrap();
        }

        // Surface: status reports the forbidden path as existing + writable.
        let st = crate::status(root, &forbidden);
        let status_ok = st.len() == 1 && st[0].exists && st[0].writable;
        assert_emit!(
            "nornir-guard",
            "status_reports_existing_writable",
            status_ok,
            "exists={} writable={}",
            st[0].exists,
            st[0].writable
        );

        // Surface: apply chmod -w → path becomes read-only.
        let applied = crate::apply(root, &forbidden);
        let apply_ok = applied
            .as_ref()
            .map(|v| v.len() == 1 && v[0].exists && !v[0].writable)
            .unwrap_or(false);
        assert_emit!(
            "nornir-guard",
            "apply_makes_readonly",
            apply_ok,
            "applied={:?}",
            applied.is_ok()
        );

        // Surface: manifest roundtrips through disk unchanged.
        let m = crate::manifest(root, &forbidden);
        crate::write_manifest(root, &m).unwrap();
        let read_back = crate::read_manifest(root);
        let roundtrip_ok = read_back
            .as_ref()
            .map(|r| r.entries.len() == m.entries.len())
            .unwrap_or(false);
        assert_emit!(
            "nornir-guard",
            "manifest_roundtrips",
            roundtrip_ok,
            "entries={}",
            m.entries.len()
        );

        // Surface: verify against the just-recorded manifest → no drift.
        let clean = crate::verify(root, &m);
        let clean_ok = clean.iter().all(|v| v.ok());
        assert_emit!(
            "nornir-guard",
            "verify_clean_no_drift",
            clean_ok,
            "paths={}",
            clean.len()
        );
        // …and the gate form agrees the workspace is intact.
        crate::selftest::emit(
            "nornir-guard",
            "intact_gate_passes_when_clean",
            crate::intact(root, &m).is_ok(),
            "intact ok",
        );

        // Tamper: restore write + change contents, then verify DETECTS drift.
        crate::release(root, &forbidden).unwrap();
        {
            let mut f = std::fs::File::create(root.join("secret.txt")).unwrap();
            writeln!(f, "tampered by an agent").unwrap();
        }
        let drifted = crate::verify(root, &m);
        let drift_ok = drifted.iter().any(|v| !v.ok());
        assert_emit!(
            "nornir-guard",
            "verify_detects_tamper_drift",
            drift_ok,
            "drifted={}",
            drifted.iter().filter(|v| !v.ok()).count()
        );
        crate::selftest::emit(
            "nornir-guard",
            "intact_gate_fails_on_drift",
            crate::intact(root, &m).is_err(),
            "intact fails after tamper",
        );

        // Surface: status_outcome shapes a PathStatus report into a CommandOutcome.
        let report = crate::status(root, &forbidden);
        let outcome = crate::status_outcome(&report);
        crate::selftest::emit(
            "nornir-guard",
            "status_outcome_is_command",
            !outcome.command.is_empty(),
            &format!("command={}", outcome.command),
        );

        let rows = nornir_testmatrix::drain_functional_rows();
        for want in [
            "status_reports_existing_writable",
            "apply_makes_readonly",
            "manifest_roundtrips",
            "verify_clean_no_drift",
            "intact_gate_passes_when_clean",
            "verify_detects_tamper_drift",
            "intact_gate_fails_on_drift",
            "status_outcome_is_command",
        ] {
            assert!(
                rows.iter().any(|r| r.suite == "nornir-guard"
                    && r.test_name == want
                    && r.status == "pass"),
                "missing green row {want}: {rows:?}"
            );
        }
        assert!(
            rows.iter().all(|r| r.aspect == "functional"),
            "rows={rows:?}"
        );
    }
}