Consolidate required CI gate (#115)
Some checks failed
CI / required (push) Failing after 15m43s

This commit is contained in:
2026-08-12 16:46:45 +00:00
parent b9415bedaa
commit eaf9358baa
44 changed files with 1945 additions and 2041 deletions

View File

@@ -917,7 +917,7 @@ fn parse_lock_string(value: &str) -> Result<String> {
fn package_notices(root: &Path, explicit: Option<&str>) -> Result<Vec<(String, String)>> {
let mut candidates = Vec::new();
collect_notice_files(root, 0, &mut candidates)?;
collect_notice_files(root, &mut candidates)?;
if let Some(explicit) = explicit {
let path = root.join(explicit);
if path.is_file() {
@@ -946,10 +946,10 @@ fn package_notices(root: &Path, explicit: Option<&str>) -> Result<Vec<(String, S
Ok(notices)
}
fn collect_notice_files(directory: &Path, depth: u8, output: &mut Vec<PathBuf>) -> Result<()> {
if depth > 2 {
return Ok(());
}
fn collect_notice_files(directory: &Path, output: &mut Vec<PathBuf>) -> Result<()> {
// Cargo build scripts may populate nested source directories (rust-skia
// creates `skia/` in its registry checkout). Only package-root notices and
// Cargo's explicit `license_file` are immutable package metadata.
let mut entries = fs::read_dir(directory)?.collect::<std::io::Result<Vec<_>>>()?;
entries.sort_by_key(std::fs::DirEntry::file_name);
for entry in entries {
@@ -969,8 +969,6 @@ fn collect_notice_files(directory: &Path, depth: u8, output: &mut Vec<PathBuf>)
.any(|prefix| name.starts_with(prefix))
{
output.push(path);
} else if kind.is_dir() && depth < 2 {
collect_notice_files(&path, depth + 1, output)?;
}
}
Ok(())
@@ -1095,6 +1093,10 @@ fn source_paths(root: &Path) -> Result<Vec<String>> {
.map_err(|_| MatrixError::new("source archive contains a non-UTF-8 path"))
})
.collect::<Result<Vec<_>>>()?;
// `git ls-files --cached` retains index entries for working-tree deletions
// until the consolidation commit is created. A source distribution always
// describes files that actually exist, including during a pre-commit audit.
paths.retain(|path| root.join(path).is_file());
for path in &paths {
validate_relative(path)?;
}
@@ -1126,8 +1128,18 @@ fn compare_report(root: &Path, relative: &str, expected: &[u8]) -> Result<()> {
MatrixError::new(format!("generated report {}: {error}", path.display()))
})?;
if actual != expected {
if let Some(directory) = std::env::var_os("METACRATE_PROVENANCE_DIAGNOSTICS_DIR") {
let directory = PathBuf::from(directory);
fs::create_dir_all(&directory)?;
let name = path
.file_name()
.ok_or_else(|| MatrixError::new("generated report path has no file name"))?;
fs::write(directory.join(name), expected)?;
}
return Err(MatrixError::new(format!(
"{relative} is stale; run `cargo run --locked -p metacrate-ci-matrix -- provenance-report`"
"{relative} is stale (checked-in sha256 {}, generated sha256 {}); run `cargo run --locked -p metacrate-ci-matrix -- provenance-report`",
sha256(&actual),
sha256(expected),
)));
}
Ok(())
@@ -1253,6 +1265,27 @@ version = "0.0.1"
);
}
#[test]
fn package_notice_scan_ignores_build_generated_subtrees() {
let root =
std::env::temp_dir().join(format!("metacrate-package-notices-{}", std::process::id()));
let _ = fs::remove_dir_all(&root);
fs::create_dir_all(root.join("generated")).unwrap();
fs::write(root.join("LICENSE"), "package license\n").unwrap();
fs::write(root.join("generated/LICENSE"), "generated license\n").unwrap();
fs::write(root.join("generated/NOTICE.explicit"), "explicit notice\n").unwrap();
let notices = package_notices(&root, Some("generated/NOTICE.explicit")).unwrap();
assert_eq!(
notices
.iter()
.map(|(path, _)| path.as_str())
.collect::<Vec<_>>(),
["LICENSE", "generated/NOTICE.explicit"]
);
fs::remove_dir_all(root).unwrap();
}
#[test]
fn unsafe_paths_are_rejected() {
for path in ["", "../escape", "a/../b", "/absolute"] {