use std::fs;
const REQUIRED_PATHS: &[&str] = &[
"spec/src/lib.rs",
"spec/**",
"conform/src/reference/**",
"conform/src/harnesses/**",
"conform/src/algebra/laws/**",
"mutations.toml",
"test-infra/test_catalog.toml",
".github/CODEOWNERS",
".github/workflows/**",
"scripts/apply-branch-protection.sh",
"scripts/mutants.sh",
"scripts/append-only.sh",
"Cargo.toml",
"coordination/adversary-threat-model.md",
];
const MAINTAINER_TEAM: &str = "@santhsecurity/core-maintainers";
#[test]
fn codeowners_coverage_for_trust_boundary() {
let codeowners =
fs::read_to_string(".github/CODEOWNERS").expect("failed to read .github/CODEOWNERS");
let mut missing = Vec::new();
for required in REQUIRED_PATHS {
let mut found = false;
for line in codeowners.lines() {
let trimmed = line.trim();
if trimmed.is_empty() || trimmed.starts_with('#') {
continue;
}
let parts: Vec<&str> = trimmed.split_whitespace().collect();
if parts.len() < 2 {
continue;
}
let pattern = parts[0];
let owners = &parts[1..];
if pattern == *required && owners.contains(&MAINTAINER_TEAM) {
found = true;
break;
}
}
if !found {
missing.push(*required);
}
}
assert!(
missing.is_empty(),
"CODEOWNERS coverage test FAILED. Missing rules for maintainer-only paths:\n{}\n\
Fix: add `<path> {MAINTAINER_TEAM}` to .github/CODEOWNERS",
missing
.iter()
.map(|p| format!(" - {p}"))
.collect::<Vec<_>>()
.join("\n")
);
}