xtask/tests/ossf_scorecard.rs
//! **What OpenSSF Scorecard reads in this tree, held here** (lane OSSF-NEXT, 2026-10-30).
//!
//! Scorecard runs nightly in local mode on the dwarves forge (`scorecard-holger`, results in
//! nordisk/ci-status). Two of its checks read files this repository controls:
//!
//! * **Vulnerabilities** runs osv-scanner over every `Cargo.lock` and honours an
//! `osv-scanner.toml` in the lock's OWN directory (`[[IgnoredVulns]]`). That file is a
//! second reader of the one triage policy, `deny.toml`'s `[advisories] ignore`, which the
//! 0-known-CVE gate (`cargo deny check advisories`) obeys. So every id an
//! `osv-scanner.toml` ignores is ignored in `deny.toml` too, with a dated reason, and
//! every `deny.toml` ignore is carried to the locks: one policy, never two that drift.
//! Each entry also carries an `ignoreUntil`, so a triage expires and is looked at again.
//! * **Binary-Artifacts** flags a tracked file whose magic says executable or archive of
//! code (ELF, PE, Mach-O, wasm, Java class, dex, crx, rpm, deb) or whose extension is one
//! of its binary list (jar, whl, so, exe, …) when the content is not text. A fixture the
//! tests need is made at test time from committed text instead.
use std::collections::BTreeSet;
use std::path::{Path, PathBuf};
use std::process::Command;
fn root() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR"))
.parent()
.expect("xtask has a parent")
.to_path_buf()
}
/// The tracked files of the checkout (`git ls-files`), relative to the root.
fn tracked(root: &Path) -> Vec<String> {
// A test of the tree it runs in: git is the authority on what is tracked.
let out = Command::new("git")
.arg("-C")
.arg(root)
.args(["ls-files", "-z"])
.output()
.expect("git ls-files runs");
assert!(
out.status.success(),
"git ls-files: {}",
String::from_utf8_lossy(&out.stderr)
);
out.stdout
.split(|b| *b == 0)
.filter(|s| !s.is_empty())
.map(|s| String::from_utf8_lossy(s).into_owned())
.collect()
}
/// The value of `key = "…"` on a line, if the line holds it.
fn quoted(line: &str, key: &str) -> Option<String> {
let at = line.find(&format!("{key} ="))? + key.len() + 2;
let rest = line[at..].trim_start().strip_prefix('"')?;
Some(rest[..rest.find('"')?].to_owned())
}
/// `deny.toml`'s `[advisories] ignore` entries: (id, reason).
fn deny_ignores(text: &str) -> Vec<(String, String)> {
let adv = text
.split("[advisories]")
.nth(1)
.expect("deny.toml has [advisories]");
let adv = adv.split("\n[").next().unwrap();
adv.lines()
.map(str::trim)
.filter(|l| l.starts_with('{'))
.filter_map(|l| Some((quoted(l, "id")?, quoted(l, "reason").unwrap_or_default())))
.collect()
}
#[derive(Debug, Default)]
struct OsvIgnore {
id: String,
until: Option<String>,
reason: Option<String>,
}
/// An `osv-scanner.toml`'s `[[IgnoredVulns]]` entries.
fn osv_ignores(text: &str) -> Vec<OsvIgnore> {
let mut all: Vec<OsvIgnore> = Vec::new();
for l in text.lines().map(str::trim) {
if l.starts_with('#') {
continue;
}
if l == "[[IgnoredVulns]]" {
all.push(OsvIgnore::default());
continue;
}
let Some(cur) = all.last_mut() else { continue };
if let Some(v) = quoted(l, "id") {
cur.id = v;
} else if let Some(v) = quoted(l, "reason") {
cur.reason = Some(v);
} else if let Some(v) = l.strip_prefix("ignoreUntil =") {
cur.until = Some(v.trim().to_owned());
}
}
all
}
/// "YYYY-MM-DD" somewhere in `s`.
fn has_date(s: &str) -> bool {
let b = s.as_bytes();
b.windows(10).any(|w| {
w.iter().enumerate().all(|(i, c)| {
if i == 4 || i == 7 {
*c == b'-'
} else {
c.is_ascii_digit()
}
}) && w.starts_with(b"20")
})
}
/// ★ **The osv-scanner triage beside each lock is `deny.toml`'s triage, dated, and complete.**
#[test]
fn osv_scanner_triage_is_the_deny_toml_policy() {
let root = root();
let files = tracked(&root);
let deny = deny_ignores(&std::fs::read_to_string(root.join("deny.toml")).expect("deny.toml"));
let mut bad = Vec::new();
for (id, reason) in &deny {
if reason.trim().is_empty() || !has_date(reason) {
bad.push(format!(
"deny.toml ignores {id} without a dated reason (\"… Triaged YYYY-MM-DD …\")"
));
}
}
let deny_ids: BTreeSet<&str> = deny.iter().map(|(i, _)| i.as_str()).collect();
let locks: BTreeSet<&str> = files
.iter()
.filter(|f| f.ends_with("Cargo.lock"))
.map(String::as_str)
.collect();
let mut carried: BTreeSet<String> = BTreeSet::new();
let mut seen = 0;
for f in files.iter().filter(|f| f.ends_with("osv-scanner.toml")) {
seen += 1;
let dir = f.strip_suffix("osv-scanner.toml").unwrap();
if !locks.contains(format!("{dir}Cargo.lock").as_str()) {
bad.push(format!("{f} sits beside no tracked Cargo.lock: osv-scanner reads it only in the lock's own directory"));
}
let text = std::fs::read_to_string(root.join(f)).unwrap();
let entries = osv_ignores(&text);
if entries.is_empty() {
bad.push(format!("{f} ignores nothing"));
}
for e in entries {
if !deny_ids.contains(e.id.as_str()) {
bad.push(format!("{f} ignores {} but deny.toml does not: the cargo-deny gate and Scorecard would disagree", e.id));
}
if e.until.as_deref().is_none_or(|u| !has_date(u)) {
bad.push(format!("{f}: {} has no ignoreUntil date", e.id));
}
if e.reason.as_deref().is_none_or(|r| r.trim().len() < 20) {
bad.push(format!("{f}: {} has no reason", e.id));
}
carried.insert(e.id);
}
}
if seen == 0 {
bad.push(
"no osv-scanner.toml is tracked: Scorecard counts every triaged advisory as open"
.into(),
);
}
for id in &deny_ids {
if !carried.contains(*id) {
bad.push(format!(
"deny.toml ignores {id}, but no osv-scanner.toml beside a lock carries it"
));
}
}
assert!(
bad.is_empty(),
"the triage policy has drifted:\n {}",
bad.join("\n ")
);
}
/// Scorecard's binary list (checks/raw/binary_artifact.go, v5.6.0).
const BINARY_EXT: &[&str] = &[
"crx", "deb", "dex", "dey", "elf", "o", "a", "so", "macho", "iso", "class", "jar", "bundle",
"dylib", "lib", "msi", "dll", "drv", "efi", "exe", "ocx", "pyc", "pyo", "par", "rpm", "wasm",
"whl",
];
/// The magic numbers of the executable kinds on that list.
fn binary_magic(b: &[u8]) -> Option<&'static str> {
let m: &[(&[u8], &str)] = &[
(b"\x7fELF", "ELF"),
(b"MZ", "PE/exe"),
(b"\0asm", "wasm"),
(b"\xca\xfe\xba\xbe", "Java class / Mach-O fat"),
(b"\xfe\xed\xfa\xce", "Mach-O"),
(b"\xfe\xed\xfa\xcf", "Mach-O"),
(b"\xce\xfa\xed\xfe", "Mach-O"),
(b"\xcf\xfa\xed\xfe", "Mach-O"),
(b"dex\n", "dex"),
(b"Cr24", "crx"),
(b"\xed\xab\xee\xdb", "rpm"),
(b"!<arch>\ndebian", "deb"),
];
m.iter()
.find(|(magic, _)| b.starts_with(magic))
.map(|(_, k)| *k)
}
/// Scorecard's `isText`: no control byte but tab, CR and LF in the first KiB.
fn is_text(b: &[u8]) -> bool {
let b = &b[..b.len().min(1024)];
match std::str::from_utf8(b) {
Ok(s) => s
.chars()
.all(|c| c >= ' ' || matches!(c, '\n' | '\t' | '\r')),
Err(e) => {
let ok = &b[..e.valid_up_to()];
e.valid_up_to() + 4 > b.len()
&& std::str::from_utf8(ok)
.unwrap()
.chars()
.all(|c| c >= ' ' || matches!(c, '\n' | '\t' | '\r'))
}
}
}
/// ★ **The tree carries no binary artifact** (Scorecard Binary-Artifacts). The one exception
/// is named here with its reason: upstream bytes whose real signature is the test.
#[test]
fn the_tree_carries_no_binary_artifact() {
// `sampleproject 4.0.0`'s wheel as PyPI serves it: its PEP 740 attestation (Sigstore,
// pypa's release workflow) signs THESE bytes, and the pull-through and upload tests prove
// a real wheel against it (and refuse it under the sdist's attestation). Rebuilt bytes
// would carry no valid signature. One copy, in server-lib's pull-through fixtures.
const KEPT: &[&str] = &[
"server/lib/tests/fixtures/pull_through/pypi/files/sampleproject-4.0.0-py3-none-any.whl",
];
let root = root();
let mut bad = Vec::new();
for f in tracked(&root) {
if KEPT.contains(&f.as_str()) {
continue;
}
let Ok(mut file) = std::fs::File::open(root.join(&f)) else {
continue;
};
let mut head = vec![0u8; 1024];
let n = std::io::Read::read(&mut file, &mut head).unwrap_or(0);
head.truncate(n);
if head.is_empty() {
continue;
}
let ext = Path::new(&f)
.extension()
.and_then(|e| e.to_str())
.unwrap_or("")
.to_ascii_lowercase();
if let Some(kind) = binary_magic(&head) {
bad.push(format!("{f}: {kind}"));
} else if BINARY_EXT.contains(&ext.as_str()) && !is_text(&head) {
bad.push(format!("{f}: a .{ext} that is not text"));
}
}
assert!(
bad.is_empty(),
"binary artifacts in the tree (make them at test time from text):\n {}",
bad.join("\n ")
);
}