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 \
the extracted files with include_bytes!. Governed at the point the bytes \
enter the artifact: `crates/rto-exec/src/runtime_file_pins.rs` pins the \
SHA-256 and size of every file of every published archive — derived from the \
archive pins in `runtime_pins.rs` by `scripts/derive-runtime-file-pins.py`, \
never hand-written — and `crates/rto-exec/build.rs` verifies boxlite's \
extracted runtime directory against them before anything links, refusing a \
mismatch, a missing file or an unpinned extra one. Setting \
BOXLITE_RUNTIME_URL to a `file://` copy provisioned by `roteiro security \
prefetch --analyzer sandbox --allow-download` additionally verifies the \
archive *before* extraction and keeps the curl off the network entirely; \
without it the fetch does happen, over TLS to the pinned release URL, and \
the build says so on its own output. 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 unaudited: Vec<String> = Vec::new();
let mut matched_reviews: BTreeSet<(String, String)> = BTreeSet::new();
for package in packages {
let name = expect_str(package, "name").to_owned();
let version = expect_str(package, "version").to_owned();
let manifest = Path::new(expect_str(package, "manifest_path"));
let root = manifest
.parent()
.unwrap_or_else(|| panic!("manifest path for {name} {version} has no directory"));
let (scripts, unlistable) = build_scripts(root, &custom_build_sources(package));
for dir in unlistable {
unaudited.push(format!(" {name} {version}\n {dir}"));
}
for script in scripts {
scanned += 1;
let marker = match scan_script(&script) {
Scan::Inspected(Some(marker)) => marker,
Scan::Inspected(None) => continue,
Scan::Unreadable(err) => {
unaudited.push(format!(
" {name} {version}\n {}\n {err}",
script.display()
));
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, {} unaudited",
packages.len(),
offenders.len() + matched_reviews.len(),
matched_reviews.len(),
unaudited.len()
);
assert!(
unaudited.is_empty(),
"{} build script(s) could not be read, so they were never audited:\n\n{}\n\n\
This is not a pass. A script that cannot be inspected is unknown, not clean, and \
the flagged count above is a lower bound while any of these is outstanding. There is \
no allow-list for this on purpose — a script that is merely not UTF-8 is scanned \
lossily and never lands here, so what is left is a broken checkout, a permissions \
fault, or tampering. Fix the environment; do not add an exception.",
unaudited.len(),
unaudited.join("\n")
);
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 a_build_script_that_is_not_utf8_is_still_scanned() {
let script = Path::new(env!("CARGO_TARGET_TMPDIR")).join("not_utf8_build.rs");
let mut with_fetch = b"fn main() {\n // stray byte: ".to_vec();
with_fetch.push(0xff);
with_fetch.extend_from_slice(b"\n Command::new(\"curl\");\n}\n");
assert!(
std::str::from_utf8(&with_fetch).is_err(),
"the fixture must really be invalid UTF-8, or this test proves nothing"
);
std::fs::write(&script, &with_fetch).expect("the target tmp dir should be writable");
assert!(
matches!(scan_script(&script), Scan::Inspected(Some("\"curl\""))),
"a fetch behind one invalid byte must still be found"
);
std::fs::write(&script, b"fn main() {\n // stray byte: \xff\n}\n")
.expect("the target tmp dir should be writable");
assert!(
matches!(scan_script(&script), Scan::Inspected(None)),
"a non-UTF-8 script with no fetch must be clean, not an offender"
);
std::fs::remove_file(&script).ok();
}
#[test]
fn a_build_script_that_cannot_be_read_is_not_reported_as_clean() {
let a_directory = Path::new(env!("CARGO_TARGET_TMPDIR"));
assert!(
matches!(scan_script(a_directory), Scan::Unreadable(_)),
"an unopenable path must be Unreadable, not Inspected(None) — that those \
are different claims is the entire fix"
);
let missing = a_directory.join("no_such_build_script.rs");
assert!(
matches!(scan_script(&missing), Scan::Unreadable(_)),
"a path that is not there is unknown, not clean"
);
}
#[test]
fn a_declared_build_script_is_never_silently_dropped() {
let root = Path::new(env!("CARGO_TARGET_TMPDIR"));
let declared = root.join("declared_but_absent_build.rs");
let (scripts, _) = build_scripts(root, std::slice::from_ref(&declared));
assert!(
scripts.contains(&declared),
"a path cargo names must be scanned even when it is absent, so that it \
surfaces as unreadable rather than as a package with no build script"
);
}
#[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
}
#[derive(Debug)]
enum Scan {
Inspected(Option<&'static str>),
Unreadable(String),
}
fn scan_script(path: &Path) -> Scan {
match std::fs::read(path) {
Ok(bytes) => Scan::Inspected(fetch_marker(&String::from_utf8_lossy(&bytes))),
Err(err) => Scan::Unreadable(err.to_string()),
}
}
fn custom_build_sources(package: &serde_json::Value) -> Vec<PathBuf> {
package["targets"]
.as_array()
.expect("cargo metadata should list targets for every package")
.iter()
.filter(|target| {
target["kind"]
.as_array()
.is_some_and(|kinds| kinds.iter().any(|k| k.as_str() == Some("custom-build")))
})
.filter_map(|target| target["src_path"].as_str())
.map(PathBuf::from)
.collect()
}
fn build_scripts(root: &Path, declared: &[PathBuf]) -> (Vec<PathBuf>, Vec<String>) {
let mut found: BTreeSet<PathBuf> = BTreeSet::new();
let mut unlistable = Vec::new();
found.extend(declared.iter().cloned());
let default = root.join("build.rs");
if default.is_file() {
found.insert(default);
}
let dir = root.join("build");
if dir.is_dir() {
collect_rs(&dir, &mut found, &mut unlistable);
}
(found.into_iter().collect(), unlistable)
}
fn collect_rs(dir: &Path, into: &mut BTreeSet<PathBuf>, unlistable: &mut Vec<String>) {
let entries = match std::fs::read_dir(dir) {
Ok(entries) => entries,
Err(err) => {
unlistable.push(format!("{} (directory): {err}", dir.display()));
return;
}
};
for entry in entries {
let path = match entry {
Ok(entry) => entry.path(),
Err(err) => {
unlistable.push(format!("{} (directory entry): {err}", dir.display()));
continue;
}
};
if path.is_dir() {
collect_rs(&path, into, unlistable);
} else if path.extension().is_some_and(|e| e == "rs") {
into.insert(path);
}
}
}
fn expect_str<'a>(package: &'a serde_json::Value, field: &str) -> &'a str {
package[field]
.as_str()
.unwrap_or_else(|| panic!("cargo metadata should give every package a `{field}`"))
}
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")
}