use std::collections::BTreeSet;
use std::path::{Path, PathBuf};
struct Reviewed {
name: &'static str,
version: &'static str,
reason: &'static str,
}
const REVIEWED: &[Reviewed] = &[
Reviewed {
name: "boxlite",
version: "0.9.7",
reason: "Downloads the prebuilt sandbox runtime with an unverified `curl` and embeds it \
with include_bytes!. Governed: `crates/rto-exec/src/runtime_pins.rs` pins the \
SHA-256 and size of every published archive, `roteiro security prefetch \
--allow-download` verifies before installing, and `crates/rto-exec/build.rs` \
refuses to build unless BOXLITE_RUNTIME_URL names a local file matching the \
pin — so its curl never reaches the network. See NOTICE-boxlite-runtime.md \
for what the archive contains and the licence duties it creates.",
},
Reviewed {
name: "libkrun-sys",
version: "0.9.7",
reason: "Would download libkrunfw and build vendored libkrun, but the published package \
excludes those sources and its build script detects a crates.io package and \
returns before fetching anything (stub mode). It is inert here; the runtime \
that actually executes comes through `boxlite` above. Re-review if the crate \
ever ships its `vendor/` directory.",
},
];
const FETCH_MARKERS: &[&str] = &[
"\"curl\"",
"\"wget\"",
"\"aria2c\"",
"reqwest",
"ureq",
"attohttpc",
"isahc",
"minreq",
"curl::",
"hyper::",
"native_tls",
"TcpStream",
"\"https://",
"\"http://",
];
const GIT_REMOTE_MARKERS: &[&str] = &[
"\"clone\"",
"\"fetch\"",
"\"pull\"",
"\"submodule\"",
"\"ls-remote\"",
];
#[test]
fn no_dependency_build_script_fetches_anything_unpinned() {
let metadata = cargo_metadata();
let packages = metadata["packages"]
.as_array()
.expect("cargo metadata should list packages");
let mut scanned = 0usize;
let mut offenders: Vec<String> = Vec::new();
let mut matched_reviews: BTreeSet<(String, String)> = BTreeSet::new();
for package in packages {
let name = package["name"].as_str().unwrap_or_default().to_owned();
let version = package["version"].as_str().unwrap_or_default().to_owned();
let manifest = Path::new(package["manifest_path"].as_str().unwrap_or_default());
let Some(root) = manifest.parent() else {
continue;
};
for script in build_scripts(root, package.get("build").and_then(|b| b.as_str())) {
scanned += 1;
let Ok(source) = std::fs::read_to_string(&script) else {
continue;
};
let Some(marker) = fetch_marker(&source) else {
continue;
};
match REVIEWED
.iter()
.find(|r| r.name == name && r.version == version)
{
Some(_) => {
matched_reviews.insert((name.clone(), version.clone()));
}
None => offenders.push(format!(
" {name} {version}\n {}\n matched: {marker}",
script.display()
)),
}
break;
}
}
assert!(
scanned > 0,
"no build scripts were scanned at all — the audit is not looking at anything, \
which would make it pass vacuously"
);
eprintln!(
"build-script audit: {} packages, {scanned} build scripts, {} flagged, \
{} reviewed exception(s) matched",
packages.len(),
offenders.len() + matched_reviews.len(),
matched_reviews.len()
);
assert!(
offenders.is_empty(),
"{} dependency build script(s) look like they fetch, and are not reviewed:\n\n{}\n\n\
A build script that downloads something is how {} of GPL binaries entered a build \
that `cargo deny` called clean. If the fetch is real, pin what it fetches by digest \
and record the pin — then add an entry to REVIEWED in this file saying what pins it. \
Do not add an entry without one.",
offenders.len(),
offenders.join("\n"),
"25 MB"
);
for review in REVIEWED {
assert!(
matched_reviews.contains(&(review.name.to_owned(), review.version.to_owned())),
"REVIEWED lists {} {} but nothing in the graph matches it — either the dependency \
is gone, or its version moved and the new one has not been reviewed. Remove the \
entry or update it; do not leave it here.",
review.name,
review.version
);
}
}
#[test]
fn the_matcher_matches_exactly_what_the_docs_claim() {
for caught in [
r#"Command::new("curl").arg("-fsSL")"#,
r#"Command::new("wget")"#,
r"let body = reqwest::blocking::get(url)",
r"ureq::get(&url).call()",
r#"let u = "https://example.com/x.tgz";"#,
r#"let u = "http://example.com/x.tgz";"#,
"let u = r#\"https://example.com/x.tgz\"#;",
"let u = r\"https://example.com/x.tgz\";",
r#"Command::new("git").args(["clone", url])"#,
] {
assert!(
fetch_marker(caught).is_some(),
"should have been flagged: {caught}"
);
}
for missed in [
"// see https://example.com/x.tgz for the artifact layout",
"/* fetched from http://example.com by CI, not here */",
"//! Upstream docs: https://example.com/",
r#"let u = format!("{HOST}/x.tgz");"#,
r#"Command::new("git").args(["rev-parse", "HEAD"])"#,
] {
assert!(
fetch_marker(missed).is_none(),
"should NOT have been flagged — the docs promise it is not: {missed}"
);
}
assert!(fetch_marker(r#""https://x""#).is_some());
assert!(fetch_marker("https://x").is_none());
}
#[test]
fn every_reviewed_exception_states_what_pins_it() {
for review in REVIEWED {
assert!(
review.reason.len() > 80,
"REVIEWED entry for {} {} has no real reasoning: {:?}",
review.name,
review.version,
review.reason
);
let names_a_pin = ["pin", "digest", "sha256", "verif", "inert", "stub"]
.iter()
.any(|token| review.reason.to_ascii_lowercase().contains(token));
assert!(
names_a_pin,
"REVIEWED entry for {} {} does not say what pins or neutralises the fetch. \
An exception without one is an unsolved problem, not an exception.",
review.name, review.version
);
}
}
fn fetch_marker(source: &str) -> Option<&'static str> {
if let Some(marker) = FETCH_MARKERS.iter().find(|m| source.contains(**m)) {
return Some(marker);
}
if source.contains("git") {
return GIT_REMOTE_MARKERS
.iter()
.find(|m| source.contains(**m))
.copied();
}
None
}
fn build_scripts(root: &Path, declared: Option<&str>) -> Vec<PathBuf> {
let mut found = Vec::new();
let default = root.join("build.rs");
if default.is_file() {
found.push(default);
}
if let Some(declared) = declared
&& declared != "build.rs"
{
let path = root.join(declared);
if path.is_file() {
found.push(path);
}
}
let dir = root.join("build");
if dir.is_dir() {
collect_rs(&dir, &mut found);
}
found
}
fn collect_rs(dir: &Path, into: &mut Vec<PathBuf>) {
let Ok(entries) = std::fs::read_dir(dir) else {
return;
};
for entry in entries.flatten() {
let path = entry.path();
if path.is_dir() {
collect_rs(&path, into);
} else if path.extension().is_some_and(|e| e == "rs") {
into.push(path);
}
}
}
fn cargo_metadata() -> serde_json::Value {
let workspace = Path::new(env!("CARGO_MANIFEST_DIR"))
.ancestors()
.nth(2)
.expect("rto-exec lives two directories below the workspace root")
.to_path_buf();
let output = std::process::Command::new(env!("CARGO"))
.args([
"metadata",
"--all-features",
"--format-version",
"1",
"--locked",
])
.current_dir(&workspace)
.output()
.expect("cargo metadata should be runnable");
assert!(
output.status.success(),
"cargo metadata failed, so the build-script audit could not run. It must fail loudly \
rather than skip: a gate that quietly does nothing is what this test exists to \
replace.\n{}",
String::from_utf8_lossy(&output.stderr)
);
serde_json::from_slice(&output.stdout).expect("cargo metadata should emit JSON")
}