holger-recipe/tests/feature_honesty.rs
//! RULE 1 and RULE 2 as plain Rust tests.
//!
//! Written in `.nornir/stinky/09-mvp-line-and-feature-honesty.md` §4.1 and §4.2
//! and homeless until 2026-09-20. They are tests, not a separate mechanism, so
//! they run wherever holger's tests run. `cargo xtask gate --rules` calls the
//! same two functions directly for an operator who wants the finding list
//! without compiling the workspace.
//!
//! Both are expected to be RED on `main` at `542e296`, and that is the point:
//! the first commit that makes each one green is the commit that decides
//! something nobody has decided yet. The failure text names the variant, the
//! package and the feature, so the decision is stated rather than guessed.
use holger_recipe::honesty::{self, Workspace};
use std::path::{Path, PathBuf};
fn root() -> PathBuf {
honesty::find_workspace_root(Path::new(env!("CARGO_MANIFEST_DIR")))
.expect("holger's [workspace] Cargo.toml above holger-recipe")
}
fn workspace() -> Workspace {
Workspace::load(&root()).expect("parse every workspace member's Cargo.toml")
}
/// A rule that parses nothing passes everything. This asserts the engine really
/// sees holger's workspace before any verdict below is believed.
#[test]
fn the_engine_is_not_vacuous() {
let ws = workspace();
assert!(
ws.members.len() > 20,
"only {} workspace members parsed; the member glob expansion is broken",
ws.members.len()
);
assert!(ws.get("holger").is_some(), "holger not parsed");
assert!(
ws.get("holger-server-lib").is_some(),
"holger-server-lib not parsed"
);
let rows = honesty::shipped_rows();
assert!(!rows.is_empty(), "no shipped rows to judge");
assert!(
rows.iter().any(|r| r.variant == "mvp-server-musl"),
"mvp-server-musl is a declared exe row and must be judged"
);
}
/// The rule must discriminate, or it is noise: a feature the ROW ITSELF
/// declares can never be reported as a rider on that row.
///
/// Note what this does NOT say. `full` IS reported as shipping
/// `holger-server-lib` feature `mini`, and that is correct: `full`'s own
/// declaration does not name `mini`; it arrives through the bench-scenarios
/// edge, which is the mechanism of feature leak 1. The rule is per row, not per
/// feature name.
#[test]
fn a_feature_the_row_itself_declares_is_never_a_rider() {
let riders = honesty::rule1_riders(&workspace());
for row in honesty::shipped_rows() {
for r in riders.iter().filter(|r| r.variant == row.variant) {
assert!(
!row.features.contains(&r.feature),
"row '{}' declares \"{}\" and it was still reported as a rider",
row.variant,
r.feature
);
}
}
}
/// **RULE 1 — every feature in a shipped artifact must be NAMED by its variant.**
///
/// MEASURED RED at `542e296`: `sign` and the `znippy-common` feature it pulls
/// ride into all five server rows from `server/cli/Cargo.toml:71`
/// (`server-lib = { …, default-features = false, features = ["sign"] }`), and no
/// variant declares either. This is the oldest of the four instances of the same
/// shape and the only one nobody had been told about.
///
/// Going green requires a decision, not a code change: either the server rows
/// declare `sign`, or `server/cli` stops enabling it on the edge. Owner question
/// 1 in `.nornir/stinky/09-mvp-line-and-feature-honesty.md` §5.
#[test]
fn every_shipped_feature_is_named_by_its_variant() {
let riders = honesty::rule1_riders(&workspace());
assert!(
riders.is_empty(),
"{} feature rider(s):\n {}",
riders.len(),
riders
.iter()
.map(|r| r.to_string())
.collect::<Vec<_>>()
.join("\n ")
);
}
/// **RULE 2 — no shipped binary may normal-depend on a bench/test/fixture crate.**
///
/// RULE 1 catches a leak once it exists; RULE 2 forbids the edge that makes the
/// class possible. MEASURED RED at `542e296` on three `nornir-testmatrix` edges:
/// `server/cli/Cargo.toml:106`, `server/lib/Cargo.toml:199`,
/// `agent/cli/Cargo.toml:75`. All three are `optional = true`, which is not
/// protection: `bench` was optional too and was in `default`, and that is how
/// `front`, `auth-passkey` and `auth-oidc` each reached a shipped binary.
#[test]
fn no_shipped_binary_normal_depends_on_a_bench_or_test_crate() {
let edges = honesty::rule2_bench_edges(&workspace());
assert!(
edges.is_empty(),
"{} bench/test edge(s) in a shipped graph:\n {}",
edges.len(),
edges
.iter()
.map(|e| e.to_string())
.collect::<Vec<_>>()
.join("\n ")
);
}
// ── W17: the provenance gate's compile census ────────────────────────────────
/// ★ **Every row that can promote carries the `provenance` gate.**
///
/// MEASURED on `main` at `bb0302e`: **none of them did.** `catalog_from_config`
/// registered `osv` unconditionally and `attested` only when
/// `promotion.require_attestation` named a predicate type; there was no gate
/// called `provenance` in any build. A config writing `gates: ["provenance"]`
/// was therefore a BOOT FAILURE (HOL-GUN-007) on all five server rows —
/// `embedded`, `mini`, `full`, `mvp-server`, `mvp-server-metered` (and
/// `mvp-server-musl`, the same features on another target) — and the unit test
/// in `promote/gate.rs` used `"provenance"` as its stock example of a name no
/// build carries.
///
/// This is a census in the shape of the other honesty guards: it reads the real
/// declaration and the real source, and it can fail. Three claims, each
/// falsifiable:
///
/// 1. every shipped row that builds `holger` is named, so the set
/// cannot shrink silently;
/// 2. `promote` and `promote::gate` are unconditional modules — nothing in the
/// path from `lib.rs` to `ProvenanceGate` is behind a `#[cfg(feature …)]`,
/// so there is no feature a row could omit to lose the gate; and
/// 3. `catalog_from_config` registers `ProvenanceGate` on the SAME unconditional
/// chain as `OsvGate`, rather than inside an `if let` the way `AttestedGate`
/// is registered.
///
/// If any one of those stops being true, a row promotes with no provenance gate
/// and, per this module's founding complaint, *"a promotion with no gate looks
/// exactly like one that passed every gate."*
#[test]
fn the_gate_is_compiled_into_every_row_that_promotes() {
// (1) The rows. `holger` is the package every promoting binary is
// built from — the gRPC `PromoteArtifact` RPC and the `holger-server
// promote` CLI verb both resolve through `HolgerConfig::promotion_engine`.
let promoting: Vec<String> = honesty::shipped_rows()
.into_iter()
.filter(|r| r.package == "holger")
.map(|r| r.variant)
.collect();
assert!(
promoting.len() >= 4,
"only {} row(s) build holger ({promoting:?}); the census has gone blind, \
which is how a gate stops shipping without anything failing",
promoting.len()
);
for expected in [
"holger",
"mvp-server-musl",
"mvp-server-metered",
"mvp-server-musl-metered",
] {
assert!(
promoting.iter().any(|v| v == expected),
"row '{expected}' no longer builds holger; it promoted at \
bb0302e and this census must be told, not surprised. Rows found: {promoting:?}"
);
}
// (2) The path from the crate root to the gate carries no feature gate.
let lib_rs = std::fs::read_to_string(root().join("server/lib/src/lib.rs"))
.expect("read server/lib/src/lib.rs");
assert!(
lib_rs.contains("\npub mod promote;"),
"`promote` must be an unconditional module of holger-server-lib: a `#[cfg]` above \
it would take the whole promotion boundary out of some row"
);
let mod_rs = std::fs::read_to_string(root().join("server/lib/src/promote/mod.rs"))
.expect("read server/lib/src/promote/mod.rs");
assert!(
mod_rs.contains("\npub mod gate;") || mod_rs.contains("\nmod gate;"),
"`promote::gate` must be an unconditional module: {}",
"found no bare `mod gate;` declaration"
);
// `meter_gate` IS feature-gated, deliberately — so this assertion has to be
// about `gate` specifically and not about the file holding no cfg at all.
let gate_decl = mod_rs
.lines()
.position(|l| l.trim_start().starts_with("pub mod gate;"))
.expect("`pub mod gate;` in promote/mod.rs");
let preceding: Vec<&str> = mod_rs.lines().take(gate_decl).collect();
assert!(
!preceding
.last()
.map(|l| l.trim_start().starts_with("#[cfg"))
.unwrap_or(false),
"a #[cfg] attribute now guards `pub mod gate;` — the promotion gate seam would \
vanish from any row that did not enable it"
);
// (3) The registration is unconditional, beside OsvGate and NOT inside the
// `if let Some(pt)` that guards `AttestedGate`.
let gate_rs = std::fs::read_to_string(root().join("server/lib/src/promote/gate.rs"))
.expect("read server/lib/src/promote/gate.rs");
assert!(
gate_rs.contains("pub struct ProvenanceGate"),
"`ProvenanceGate` has left promote/gate.rs; this census no longer measures anything"
);
assert!(
!gate_rs.contains("#[cfg(feature")
|| !gate_rs[..gate_rs.find("pub struct ProvenanceGate").unwrap()]
.rsplit('\n')
.take(3)
.any(|l| l.trim_start().starts_with("#[cfg")),
"`ProvenanceGate` is now behind a feature; a row that omits it promotes ungated"
);
let body_start = gate_rs
.find("pub fn catalog_from_config")
.expect("catalog_from_config in promote/gate.rs");
let body = &gate_rs[body_start..];
let end = body
.find("\n}\n")
.map(|i| body_start + i)
.unwrap_or(gate_rs.len());
let body = &gate_rs[body_start..end];
let reg = body
.find("ProvenanceGate::new")
.expect("catalog_from_config must register ProvenanceGate");
let guard = body.find("if let Some(pt)").unwrap_or(usize::MAX);
assert!(
reg < guard,
"ProvenanceGate is registered INSIDE the conditional that guards AttestedGate. \
It must be registered unconditionally, like OsvGate: a gate that exists only \
when it was configured cannot be named by a rung on a build that could have \
carried it, and HOL-GUN-007 then refuses the boot for the wrong reason."
);
}