ldeflate/tests/no_c_toolchain.rs
//! **Appliance-eligibility guard.** `ldeflate` must pull no C, no cmake, no
//! bindgen and no `*-sys` crate, because anything that does is disqualified
//! from the appliance (this is exactly why OpenZL is a problem elsewhere in the
//! tree, and why znippy's C/cmake/network build requirement is logged as a
//! blocker in gunnar's `P-006`).
//!
//! The risk this guards is not the direct dependency — that is one visible line
//! in `Cargo.toml`. It is a **transitive** one: `flate2` will happily pull
//! `libz-sys` (C + cmake, via `zlib-ng-compat`) or `libz-ng-sys` if a feature is
//! added anywhere in the workspace and unification reaches us. So the check is
//! run against the resolved dependency graph, not the manifest.
use std::process::Command;
fn tree(pkg: &str) -> Option<String> {
let out = Command::new("cargo")
.args(["tree", "--offline", "-p", pkg, "-e", "normal,build"])
.current_dir(env!("CARGO_MANIFEST_DIR"))
.output()
.ok()?;
if !out.status.success() {
return None;
}
Some(String::from_utf8_lossy(&out.stdout).into_owned())
}
/// Crate-name fragments that mean "a C toolchain, cmake, or a native library is
/// required to build this".
const C_MARKERS: &[&str] = &[
"libz-sys",
"libz-ng-sys",
"cloudflare-zlib-sys",
"zstd-sys",
"bzip2-sys",
"openssl-sys",
"cmake",
"bindgen",
];
/// Does `line` name a package whose name matches a C marker? Matches on the
/// package-name token only, so a path containing e.g. "cmake" in a directory
/// name cannot false-positive.
fn c_hit(line: &str) -> Option<String> {
let name = line
.trim_start_matches(['├', '─', '│', '└', ' ', '[', ']'])
.split_whitespace()
.next()
.unwrap_or("");
if name == "cc" || C_MARKERS.iter().any(|m| name == *m) {
return Some(name.to_string());
}
None
}
#[test]
fn ldeflate_pulls_no_c_no_cmake_no_sys_crate() {
let Some(t) = tree("ldeflate") else {
eprintln!("SKIP no-C guard: `cargo tree --offline` unavailable here");
return;
};
let hits: Vec<String> = t.lines().filter_map(c_hit).collect();
assert!(
hits.is_empty(),
"ldeflate's resolved dependency graph pulls a C/cmake/sys crate: {hits:?}\n\
This disqualifies it from the appliance. The usual cause is a `flate2` \
feature (zlib / zlib-ng / zlib-ng-compat / cloudflare_zlib) reaching us \
through feature unification. `ldeflate` must stay on \
`default-features = false, features = [\"zlib-rs\"]`.\n\nfull tree:\n{t}"
);
}
/// **RED-first control.** The marker scan above is worthless if it cannot
/// actually detect a C dependency. `zstd-sys-rs` in this same workspace vendors
/// libzstd and builds it with `cc` + `bindgen` — so the *same* scan run against
/// it must fire. If this test ever goes quiet, the guard above is blind.
#[test]
fn the_c_marker_scan_actually_fires_on_a_crate_that_has_c() {
let Some(t) = tree("zstd-sys-rs") else {
eprintln!("SKIP no-C guard control: `cargo tree --offline` unavailable here");
return;
};
let hits: Vec<String> = t.lines().filter_map(c_hit).collect();
assert!(
!hits.is_empty(),
"the C-marker scan found NOTHING in zstd-sys-rs, which demonstrably \
compiles ~25 vendored .c files via `cc` and generates bindings with \
`bindgen`. The scan is broken, so the ldeflate guard above proves \
nothing.\n\nfull tree:\n{t}"
);
eprintln!("control OK — scan fired on zstd-sys-rs: {hits:?}");
}
/// The crate must own no build script and no native sources of its own.
#[test]
fn ldeflate_has_no_build_script_and_no_native_sources() {
let root = std::path::Path::new(env!("CARGO_MANIFEST_DIR"));
assert!(
!root.join("build.rs").exists(),
"ldeflate must have no build.rs"
);
let mut stack = vec![root.to_path_buf()];
while let Some(d) = stack.pop() {
let Ok(rd) = std::fs::read_dir(&d) else {
continue;
};
for e in rd.flatten() {
let p = e.path();
if p.is_dir() {
if p.file_name().is_some_and(|n| n == "target") {
continue;
}
stack.push(p);
continue;
}
let ext = p.extension().and_then(|x| x.to_str()).unwrap_or("");
assert!(
!matches!(ext, "c" | "h" | "cc" | "cpp" | "S"),
"ldeflate carries a native source file: {}",
p.display()
);
assert!(
p.file_name().is_none_or(|n| n != "CMakeLists.txt"),
"ldeflate carries a CMakeLists.txt: {}",
p.display()
);
}
}
}