#[path = "../build_validation.rs"]
mod build_validation;
use std::fs;
use std::path::Path;
use build_validation::{discover_embedded_snapshot, DiscoveryError};
fn write_stub_snapshot(dir: &Path, filename: &str) {
fs::write(dir.join(filename), b"{\"stub\":true}\n")
.expect("write stub snapshot for build_validation test");
}
#[test]
fn accepts_unique_valid_regular_file() {
let tmp = tempfile::tempdir().expect("tempdir");
write_stub_snapshot(tmp.path(), "sigstore_trusted_root_2026-05-12.json");
write_stub_snapshot(tmp.path(), "README.md");
let discovery = discover_embedded_snapshot(tmp.path()).expect("happy path");
assert_eq!(discovery.snapshot.date, "2026-05-12");
assert_eq!(
discovery.snapshot.filename,
"sigstore_trusted_root_2026-05-12.json"
);
assert_eq!(
discovery.matched_filenames,
vec!["sigstore_trusted_root_2026-05-12.json".to_string()]
);
}
#[cfg(unix)]
#[test]
fn refuses_symlinked_candidate() {
use std::os::unix::fs::symlink;
let tmp = tempfile::tempdir().expect("tempdir");
let outside = tmp.path().join("attacker.json");
fs::write(&outside, b"{\"attacker\":true}\n").expect("write attacker payload");
let scan_dir = tmp.path().join("embedded");
fs::create_dir(&scan_dir).expect("create scan dir");
symlink(
&outside,
scan_dir.join("sigstore_trusted_root_2026-05-12.json"),
)
.expect("create symlink candidate");
let err = discover_embedded_snapshot(&scan_dir).expect_err("symlink must be refused");
match err {
DiscoveryError::Symlink { path } => {
assert!(
path.ends_with("sigstore_trusted_root_2026-05-12.json"),
"symlink error must name the offending candidate path; got {}",
path.display()
);
}
other => panic!("expected Symlink error, got {other:?}"),
}
}
#[cfg(windows)]
#[test]
fn refuses_symlinked_candidate_windows() {
let tmp = tempfile::tempdir().expect("tempdir");
let outside = tmp.path().join("attacker.json");
fs::write(&outside, b"{\"attacker\":true}\n").expect("write attacker payload");
let scan_dir = tmp.path().join("embedded");
fs::create_dir(&scan_dir).expect("create scan dir");
let link_path = scan_dir.join("sigstore_trusted_root_2026-05-12.json");
if std::os::windows::fs::symlink_file(&outside, &link_path).is_err() {
eprintln!(
"skipping refuses_symlinked_candidate_windows: cannot create symlinks \
on this host (needs Developer Mode or admin)"
);
return;
}
let err = discover_embedded_snapshot(&scan_dir).expect_err("symlink must be refused");
assert!(
matches!(err, DiscoveryError::Symlink { .. }),
"expected Symlink error, got {err:?}"
);
}
#[test]
fn refuses_calendar_invalid_date() {
let tmp = tempfile::tempdir().expect("tempdir");
write_stub_snapshot(tmp.path(), "sigstore_trusted_root_2026-02-30.json");
let err = discover_embedded_snapshot(tmp.path()).expect_err("invalid date must be refused");
match err {
DiscoveryError::InvalidCalendarDate {
filename,
date_segment,
..
} => {
assert_eq!(filename, "sigstore_trusted_root_2026-02-30.json");
assert_eq!(date_segment, "2026-02-30");
}
other => panic!("expected InvalidCalendarDate error, got {other:?}"),
}
}
#[test]
fn refuses_calendar_invalid_month_thirteen() {
let tmp = tempfile::tempdir().expect("tempdir");
write_stub_snapshot(tmp.path(), "sigstore_trusted_root_2026-13-01.json");
let err =
discover_embedded_snapshot(tmp.path()).expect_err("month 13 must be refused as invalid");
assert!(
matches!(err, DiscoveryError::InvalidCalendarDate { .. }),
"expected InvalidCalendarDate, got {err:?}"
);
}
#[test]
fn refuses_multiple_candidates() {
let tmp = tempfile::tempdir().expect("tempdir");
write_stub_snapshot(tmp.path(), "sigstore_trusted_root_2026-05-12.json");
write_stub_snapshot(tmp.path(), "sigstore_trusted_root_2026-08-12.json");
let err =
discover_embedded_snapshot(tmp.path()).expect_err("two valid candidates must be refused");
match err {
DiscoveryError::MultipleCandidates { filenames, .. } => {
assert_eq!(filenames.len(), 2);
assert!(filenames
.iter()
.any(|f| f == "sigstore_trusted_root_2026-05-12.json"));
assert!(filenames
.iter()
.any(|f| f == "sigstore_trusted_root_2026-08-12.json"));
}
other => panic!("expected MultipleCandidates, got {other:?}"),
}
}
#[test]
fn refuses_zero_candidates() {
let tmp = tempfile::tempdir().expect("tempdir");
write_stub_snapshot(tmp.path(), "unrelated.json");
let err = discover_embedded_snapshot(tmp.path()).expect_err("empty must be refused");
assert!(
matches!(err, DiscoveryError::NoCandidates { .. }),
"expected NoCandidates, got {err:?}"
);
}
#[test]
fn error_messages_are_actionable() {
let tmp = tempfile::tempdir().expect("tempdir");
write_stub_snapshot(tmp.path(), "sigstore_trusted_root_2026-02-30.json");
let err = discover_embedded_snapshot(tmp.path()).expect_err("must error");
let rendered = format!("{err}");
assert!(
rendered.contains("sigstore_trusted_root_2026-02-30.json"),
"error must name the offending filename: {rendered}"
);
assert!(
rendered.contains("calendar-invalid"),
"error must explain that the date is calendar-invalid: {rendered}"
);
#[cfg(unix)]
{
use std::os::unix::fs::symlink;
let scan_dir = tmp.path().join("symlink_msg");
fs::create_dir(&scan_dir).expect("create dir");
let target = tmp.path().join("real.json");
fs::write(&target, b"{}").unwrap();
symlink(
&target,
scan_dir.join("sigstore_trusted_root_2026-05-12.json"),
)
.unwrap();
let err = discover_embedded_snapshot(&scan_dir).expect_err("must error");
let rendered = format!("{err}");
assert!(
rendered.contains("Red Team v2 F2-S1"),
"symlink error must cite the originating finding for grep-ability: {rendered}"
);
}
}