crates/nornir-build-thing/src/capability_probe.rs
//! **The hollow-binary gate: does a DEPLOYED artifact carry the capability its
//! feature promised?**
//!
//! The feature-rot gate ([`crate::feature_axis`]) catches the DECLARATION side — an
//! offered feature no variant builds. This module catches the OTHER end of the same
//! failure: a binary that built green but was compiled WITHOUT its real feature, so
//! it runs hollow. That is exactly what a `required-features` bin does when
//! `cargo build --all-targets` silently skips it, and what `dwarves-full` did when it
//! embedded nornir's `full-server` with no embedder — a green build, a dead runtime.
//!
//! ## How it proves capability without running anything
//!
//! A compiled-in capability leaves LITERALS in the binary — a model registry string,
//! a SQL engine name, a boot primitive. A compiled-OUT one often leaves the honest
//! "not built in" STUB string instead. So we can read the verdict off the binary's
//! own bytes with a `strings`-style scan — done here as a pure in-process byte search
//! (ROOT LAW: no shelling out to `strings`/`nm`), so it runs in CI on any platform.
//!
//! * a [`Capability`] declares the literals that PROVE it present ([`Capability::proof_any`])
//! and, optionally, the [`Capability::stub_marker`] that proves it compiled OUT;
//! * [`probe`] reads one capability off a byte slice into a [`Presence`];
//! * [`gate_binary`] fails LOUD ([`HollowBinary`]) when a binary is missing a
//! capability its deployment requires.
//!
//! ## What this cannot do — stated, not buried
//!
//! It reads bytes, not behaviour. A literal can survive dead-code the linker didn't
//! strip (a false PRESENT), and a capability with no distinctive literal cannot be
//! proven at all (a [`Presence::Unknown`], never silently "present"). It is a cheap,
//! high-value FLOOR — "this artifact provably still contains its embedder" — not an
//! execution test.
use std::collections::BTreeMap;
use std::path::Path;
use serde::{Deserialize, Serialize};
/// One capability a deployed binary must actually carry — the feature that compiles
/// it in, the literals that prove it did, and (when there is one) the stub string
/// that proves it did NOT.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Capability {
/// Human name of the capability (`"embeddings"`, `"vm-boot"`).
pub name: &'static str,
/// The cargo feature that must be enabled to compile it in — the fix a failure
/// names (`"embed-ort"`, `"vm-boot"`, `"dataview-sql"`).
pub feature: &'static str,
/// ANY of these literal substrings present in the binary proves the capability
/// is compiled in. Pick strings that ONLY the real feature emits (a model id, an
/// engine type name), never a word that also occurs in unrelated code.
pub proof_any: &'static [&'static str],
/// The DISABLED-STUB marker: an honest "feature not built in" string the code
/// emits only when the capability is compiled OUT. When present AND no
/// `proof_any` literal is found, the binary is provably [`Presence::Hollow`].
/// `None` when the feature ships no such stub (then absence of proof is only
/// [`Presence::Unknown`], never asserted hollow).
pub stub_marker: Option<&'static str>,
}
/// The verdict for one capability against one binary's bytes.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum Presence {
/// A `proof_any` literal was found — the capability is compiled in.
Present,
/// No proof literal, and the `stub_marker` WAS found — provably compiled out.
Hollow,
/// Neither proof nor stub found — cannot attest either way. Never reported as
/// present, so an unmeasurable capability can never pass silently.
Unknown,
}
impl Presence {
pub fn label(self) -> &'static str {
match self {
Presence::Present => "present",
Presence::Hollow => "hollow",
Presence::Unknown => "unknown",
}
}
}
/// **The pure byte scan** — is `needle` present as an ASCII substring of `haystack`?
/// A `strings | grep -F` done in-process (no external tool), matching bytes directly
/// so it works on any object format. Empty needle is never a match.
pub fn contains_literal(haystack: &[u8], needle: &str) -> bool {
let n = needle.as_bytes();
if n.is_empty() || n.len() > haystack.len() {
return false;
}
haystack.windows(n.len()).any(|w| w == n)
}
/// Probe one capability against a binary's bytes.
pub fn probe(bin: &[u8], cap: &Capability) -> Presence {
if cap.proof_any.iter().any(|lit| contains_literal(bin, lit)) {
return Presence::Present;
}
match cap.stub_marker {
Some(stub) if contains_literal(bin, stub) => Presence::Hollow,
_ => Presence::Unknown,
}
}
/// Probe one capability against a binary on disk.
pub fn probe_file(path: &Path, cap: &Capability) -> std::io::Result<Presence> {
let bytes = std::fs::read(path)?;
Ok(probe(&bytes, cap))
}
/// The full reading of one binary against a list of required capabilities.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ProbeReport {
pub binary: String,
/// capability name → verdict.
pub results: BTreeMap<String, Presence>,
/// capability name → the feature that would compile it in (for the fix line).
pub features: BTreeMap<String, String>,
}
impl ProbeReport {
/// The capabilities that are provably compiled OUT — the hollow ones.
pub fn hollow(&self) -> Vec<&str> {
self.results
.iter()
.filter(|(_, p)| **p == Presence::Hollow)
.map(|(n, _)| n.as_str())
.collect()
}
/// The capabilities that could not be attested either way.
pub fn unknown(&self) -> Vec<&str> {
self.results
.iter()
.filter(|(_, p)| **p == Presence::Unknown)
.map(|(n, _)| n.as_str())
.collect()
}
/// `true` ⇔ no capability is provably hollow. (Unknowns do not fail — they cannot
/// be measured — but they are reported so a caller may treat them stricter.)
pub fn is_intact(&self) -> bool {
self.hollow().is_empty()
}
}
/// **The gate.** Probe `caps` against the binary at `path` and FAIL with a
/// [`HollowBinary`] naming every capability that is provably compiled out, with the
/// feature to rebuild with. The reusable "deployed bin has its declared capability"
/// assertion the release / CI path runs after an install.
pub fn gate_binary(path: &Path, caps: &[Capability]) -> Result<ProbeReport, HollowBinary> {
let bytes = match std::fs::read(path) {
Ok(b) => b,
Err(e) => {
return Err(HollowBinary {
binary: path.display().to_string(),
hollow: Vec::new(),
read_error: Some(e.to_string()),
})
}
};
let mut results = BTreeMap::new();
let mut features = BTreeMap::new();
let mut hollow = Vec::new();
for cap in caps {
let p = probe(&bytes, cap);
if p == Presence::Hollow {
hollow.push((cap.name.to_string(), cap.feature.to_string()));
}
results.insert(cap.name.to_string(), p);
features.insert(cap.name.to_string(), cap.feature.to_string());
}
let report = ProbeReport { binary: path.display().to_string(), results, features };
if hollow.is_empty() {
Ok(report)
} else {
Err(HollowBinary { binary: path.display().to_string(), hollow, read_error: None })
}
}
/// A deployed binary that built green but is missing a capability it must carry.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct HollowBinary {
pub binary: String,
/// `(capability, feature to rebuild with)` for each provably-out capability.
pub hollow: Vec<(String, String)>,
/// Set when the binary could not even be read (then `hollow` is empty).
pub read_error: Option<String>,
}
impl std::fmt::Display for HollowBinary {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if let Some(e) = &self.read_error {
return write!(f, "capability probe could not read `{}`: {e}", self.binary);
}
writeln!(f, "HOLLOW BINARY `{}` — green build, dead runtime:", self.binary)?;
for (cap, feat) in &self.hollow {
writeln!(
f,
" · `{cap}` is compiled OUT — rebuild with `--features {feat}` (the binary \
carries the disabled-stub marker and none of the capability's proof literals)."
)?;
}
Ok(())
}
}
impl std::error::Error for HollowBinary {}
/// **The known deployable → required-capability registry**, encoding the exact
/// hollow cases this session hit, with literals VERIFIED against the installed
/// binaries (`strings`-probed 2026-07-24). Keyed by binary FILE-name so a probe can
/// look a deployed artifact up by `path.file_name()`.
///
/// This is a documented default, not the whole world: a caller may probe with its own
/// [`Capability`] list. It exists so a release/CI step can assert the constellation's
/// fat nodes are intact with one lookup.
pub const DEPLOYABLES: &[(&str, &[Capability])] = &[
// dwarves-full embeds nornir; its whole reason to exist is the embedder + the
// nornir gRPC stack. With nornir pulled `full-server` (no embedder) the embeddings
// table stays empty — the model-registry ids prove the embedder is really in.
(
"dwarves-full",
&[
Capability {
name: "embeddings",
feature: "embed-nornir nornir/embed-ort",
proof_any: &[
"sentence-transformers/all-MiniLM",
"minilm-l6-v2",
"onnx/model.onnx",
],
stub_marker: None,
},
Capability {
name: "embedded-nornir-server",
feature: "embed-nornir",
proof_any: &["server_grpc"],
stub_marker: None,
},
],
),
// dwarves-gui: the boot smoke leg and the SQL dataview both ship an honest stub
// string when their feature is off — so these are provable BOTH ways.
(
"dwarves-gui",
&[
Capability {
name: "vm-boot",
feature: "vm-boot",
proof_any: &["boot_test", "qemu-system"],
stub_marker: Some("vm-boot feature is not"),
},
Capability {
name: "dataview-sql",
feature: "dataview-sql",
proof_any: &["MemTable", "SessionContext"],
stub_marker: Some("SQL engine not built in"),
},
],
),
// korp-server / korp: the S3/MinIO ingest leg (aegir is korp's ingest engine) and
// the Spark 4.1 source.
(
"korp-server",
&[Capability {
name: "s3-minio-ingest",
feature: "containers",
proof_any: &["minio", "aegir"],
stub_marker: None,
}],
),
(
"korp",
&[Capability {
name: "spark41",
feature: "spark41",
proof_any: &["SparkConnect", "lake.knut_demo"],
stub_marker: None,
}],
),
];
/// The required capabilities for a deployed binary looked up by its file name, or an
/// empty slice if the binary is not in [`DEPLOYABLES`].
pub fn capabilities_for(bin_file_name: &str) -> &'static [Capability] {
DEPLOYABLES.iter().find(|(n, _)| *n == bin_file_name).map(|(_, c)| *c).unwrap_or(&[])
}
#[cfg(test)]
mod tests {
use super::*;
const EMBED: Capability = Capability {
name: "embeddings",
feature: "embed-ort",
proof_any: &["sentence-transformers/all-MiniLM", "minilm-l6-v2"],
stub_marker: Some("no embedder compiled in"),
};
#[test]
fn a_present_literal_reads_present() {
let bin = b"....sentence-transformers/all-MiniLM-L6-v2....other bytes";
assert_eq!(probe(bin, &EMBED), Presence::Present);
}
#[test]
fn the_stub_marker_with_no_proof_reads_hollow() {
// the exact green-build-dead-runtime shape: only the disabled stub is present.
let bin = b"....no embedder compiled in - rebuild with --features embed-ort....";
assert_eq!(probe(bin, &EMBED), Presence::Hollow);
}
#[test]
fn neither_proof_nor_stub_is_unknown_never_present() {
let bin = b"an unrelated binary with none of the literals";
assert_eq!(probe(bin, &EMBED), Presence::Unknown);
}
#[test]
fn contains_literal_is_a_plain_substring_scan() {
assert!(contains_literal(b"aXboot_testYc", "boot_test"));
assert!(!contains_literal(b"short", "a much longer needle"));
assert!(!contains_literal(b"anything", ""));
}
/// RED→GREEN on a synthetic file: a hollow binary FAILS the gate naming the
/// capability + the feature to rebuild with; the same file with the proof literal
/// PASSES.
#[test]
fn gate_binary_fails_on_hollow_and_passes_once_the_capability_is_present() {
let dir = tempfile::tempdir().unwrap();
let caps = capabilities_for("dwarves-gui");
assert!(!caps.is_empty(), "dwarves-gui is a known deployable");
// A hollow build: both features off — each ships its stub, no proof literal.
let hollow = dir.path().join("dwarves-gui");
std::fs::write(
&hollow,
b"binary...the `vm-boot feature is not` wired...SQL engine not built in ...",
)
.unwrap();
let err = gate_binary(&hollow, caps).expect_err("hollow build must fail the gate");
let msg = err.to_string();
assert!(msg.contains("HOLLOW BINARY"), "{msg}");
assert!(msg.contains("vm-boot") && msg.contains("--features vm-boot"), "{msg}");
assert!(msg.contains("dataview-sql") && msg.contains("--features dataview-sql"), "{msg}");
// The real (intact) build carries the proof literals for both.
let intact = dir.path().join("dwarves-gui-full");
std::fs::write(&intact, b"binary...boot_test...qemu-system...MemTable...SessionContext...")
.unwrap();
let report = gate_binary(&intact, caps).expect("intact build passes the gate");
assert!(report.is_intact());
assert_eq!(report.results["vm-boot"], Presence::Present);
assert_eq!(report.results["dataview-sql"], Presence::Present);
}
#[test]
fn an_unreadable_path_is_a_failure_not_a_pass() {
let missing = Path::new("/no/such/binary/anywhere");
let err = gate_binary(missing, capabilities_for("korp")).expect_err("missing file fails");
assert!(err.read_error.is_some());
assert!(err.to_string().contains("could not read"));
}
}