crates/nornir-build-thing/tests/package_door.rs
//! **The whole door, end to end** — `image_build::build_package` over a fake
//! container, asserting on the four files that are left behind.
//!
//! Every other test in this lane checks one layer. This one is the only thing that
//! can catch a defect that lives BETWEEN layers, and it exists because that class of
//! defect is what the lane keeps finding: a `SHA256SUMS` writer that works and a
//! `verify_produced` that works can still add up to a door that can never succeed,
//! if nothing writes the third member both of them assume is there.
//!
//! It uses a fake runner, so it needs no daemon, no network and no python — the
//! same reason the kernel cell's orchestration is testable without compiling a
//! kernel.
use std::path::{Path, PathBuf};
use nornir_build_thing::image_build::build_package;
use nornir_build_thing::package::{
DeclaredStager, PackageBuild, PackageBuilder, PackageFormat, PROVENANCE_FILE, SUMS_FILE,
};
/// A builder that writes exactly what a real one would have produced.
struct FakePip {
wheel: Vec<u8>,
sdist: Vec<u8>,
}
impl PackageBuilder for FakePip {
fn engine(&self) -> &str {
"fake-pip"
}
fn build(&self, pkg: &PackageBuild, repo_root: &Path) -> anyhow::Result<Vec<PathBuf>> {
let dist = pkg.out_dir(repo_root);
std::fs::create_dir_all(&dist)?;
let w = dist.join("facet_wrapped_web-0.1.19-py3-none-any.whl");
let s = dist.join("facet_wrapped_web-0.1.19.tar.gz");
std::fs::write(&w, &self.wheel)?;
std::fs::write(&s, &self.sdist)?;
Ok(vec![w, s])
}
}
fn scratch(tag: &str) -> PathBuf {
let base = std::env::var("CARGO_TARGET_TMPDIR")
.map(PathBuf::from)
.unwrap_or_else(|_| std::env::temp_dir());
let d = base.join(format!("pkgdoor-{tag}"));
let _ = std::fs::remove_dir_all(&d);
std::fs::create_dir_all(&d).unwrap();
d
}
fn a_cell() -> PackageBuild {
PackageBuild {
name: "facet-wrapped-web".into(),
format: PackageFormat::Pip,
distribution: "facet_wrapped_web".into(),
out_dir: "pkg-facet-wrapped/dist".into(),
source: Some("pkg-facet-wrapped".into()),
sdist: true,
image: Some("nordisk-pip-toolchain".into()),
..PackageBuild::default()
}
}
/// **The four files exist, and the provenance is over the PRODUCED BYTES.**
#[test]
fn the_door_leaves_a_complete_checkable_release_behind() {
let root = scratch("complete");
std::fs::create_dir_all(root.join("pkg-facet-wrapped")).unwrap();
let cell = a_cell();
let builder = FakePip { wheel: b"WHEEL BYTES".to_vec(), sdist: b"SDIST BYTES".to_vec() };
let outcome = build_package(&builder, &cell, "facett", &root).expect("the door runs");
assert!(outcome.success, "the build did not succeed: {:?}", outcome.error);
let dist = cell.out_dir(&root);
// ① + ②: the distributions.
assert!(dist.join("facet_wrapped_web-0.1.19-py3-none-any.whl").is_file());
assert!(dist.join("facet_wrapped_web-0.1.19.tar.gz").is_file());
// ③: the manifest a downloader runs `sha256sum -c` against.
let sums = std::fs::read_to_string(dist.join(SUMS_FILE)).expect("SHA256SUMS");
assert_eq!(sums.lines().count(), 2, "{sums}");
// ④: the provenance. THIS is the member that nothing wrote until the door was
// run end to end: `write_sha256sums` worked and `verify_produced` worked, and
// together they were a door that could never succeed, because both assumed the
// other had written this file.
let prov = std::fs::read_to_string(dist.join(PROVENANCE_FILE)).expect("provenance.json");
// THE RULE: the record hashes the bytes that were produced, not the recipe that
// was supposed to produce them. Assert it by hashing independently — a record
// that agreed with the writer's own idea of the hash would prove nothing.
let wheel_bytes = std::fs::read(dist.join("facet_wrapped_web-0.1.19-py3-none-any.whl")).unwrap();
let want = nornir_build_thing::package::sha256_hex(&wheel_bytes);
assert!(
prov.contains(&want),
"the provenance does not carry the wheel's own sha256 ({want}):\n{prov}"
);
// And the attestation the forge files says the same.
let sealed = format!("{:?}", outcome.artifacts);
assert!(sealed.contains(&want), "the attestation does not bind the produced wheel: {sealed}");
assert_eq!(outcome.artifacts.len(), 2, "the sealed set is not the two distributions");
}
/// **A different wheel is a different record.** Without this, everything above
/// would pass for a provenance keyed on the filename or on the declaration.
#[test]
fn one_changed_byte_moves_the_provenance_and_the_manifest() {
let read = |tag: &str, wheel: &[u8]| -> (String, String) {
let root = scratch(tag);
std::fs::create_dir_all(root.join("pkg-facet-wrapped")).unwrap();
let cell = a_cell();
let b = FakePip { wheel: wheel.to_vec(), sdist: b"SDIST".to_vec() };
build_package(&b, &cell, "facett", &root).expect("runs");
let dist = cell.out_dir(&root);
(
std::fs::read_to_string(dist.join(SUMS_FILE)).unwrap(),
std::fs::read_to_string(dist.join(PROVENANCE_FILE)).unwrap(),
)
};
// Same LENGTH, one byte different: a manifest or a record keyed on size or on
// the declaration would be identical here.
let (s1, p1) = read("byte-a", b"AAAA");
let (s2, p2) = read("byte-b", b"AAAB");
assert_ne!(s1, s2, "a one-byte change left SHA256SUMS identical");
assert_ne!(p1, p2, "a one-byte change left the provenance identical");
}
/// **A build that produced nothing is RECORDED as failed, not reported as green.**
///
/// The gunnar-appliance-iso shape: exit 0, no artifact, a digest printed anyway.
/// `capture_target_build` records a builder failure rather than propagating it, so
/// the assertion is on the OUTCOME, not on an `Err`.
#[test]
fn a_build_that_produced_nothing_is_recorded_as_failed_and_names_the_missing_members() {
struct Nothing;
impl PackageBuilder for Nothing {
fn engine(&self) -> &str {
"fake-nothing"
}
fn build(&self, pkg: &PackageBuild, repo_root: &Path) -> anyhow::Result<Vec<PathBuf>> {
std::fs::create_dir_all(pkg.out_dir(repo_root))?;
Ok(Vec::new())
}
}
let root = scratch("nothing");
std::fs::create_dir_all(root.join("pkg-facet-wrapped")).unwrap();
let cell = a_cell();
let outcome = build_package(&Nothing, &cell, "facett", &root).expect("records the failure");
assert!(!outcome.success, "a build that wrote no wheel reported success");
assert!(outcome.artifacts.is_empty(), "a failed build sealed artifacts");
let why = outcome.error.unwrap_or_default();
assert!(
why.contains("wheel") || why.contains("proves nothing"),
"the failure does not name what was missing: {why}"
);
}
/// A declaration naming a source that is not in this checkout is refused BEFORE
/// anything runs — the container-kind precedent.
#[test]
fn a_source_that_is_not_in_this_checkout_is_refused_before_anything_runs() {
let root = scratch("nosource");
let cell = a_cell();
let b = FakePip { wheel: b"W".to_vec(), sdist: b"S".to_vec() };
let e = format!("{:#}", build_package(&b, &cell, "facett", &root).expect_err("must refuse"));
assert!(e.contains("not in this checkout"), "{e}");
assert!(
!cell.out_dir(&root).exists(),
"the refusal happened after the build had already written somewhere"
);
}
/// The declared stager is reachable from here too — a compile-level check that the
/// forge's staging path is public and named, since that is what dwarves injects.
#[test]
fn the_declared_stager_is_what_the_forge_names() {
use nornir_build_thing::package::PackageStager;
assert!(DeclaredStager.describe().contains("declared"));
}