Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/facett

facett-ops/tests/release_manifest.rs

//! **Row 10 — a wheel on disk is not a release.**
//!
//! `publish-pip` produces a verified wheel and `publish-holger` serves it, but neither
//! leaves anything a consumer could check the bytes against **away from this machine**.
//! A release is the artefacts plus a statement of what they are: a `SHA256SUMS` a
//! downloader can run `sha256sum -c` on, and a provenance record saying which commit,
//! which toolchain, which host, and — the part that matters — **hashes of the produced
//! bytes rather than of the recipe that was supposed to produce them.**
//!
//! The distinction is the whole point. A provenance record built from the variant
//! declaration describes what was *asked for*; two builds of the same declaration can
//! differ (that is why row 3 measured the wasm growing by 1.7 MB). `capture` is handed
//! the artefact PATHS and hashes what is actually there.
//!
//! ## The door this row could not open, and which is open now
//!
//! This section used to say the row deliberately stopped short:
//!
//! > The brief's door is `dwarves buildthing facett --variant facet-wrapped-web`.
//! > That needs the forge to have an artifact kind for a **package**, and it does
//! > not: `ArtifactKind` is `Lib | Exe | Wasm | Kernel | Container | Service | Vm |
//! > Iso | Installer`. A wheel is none of those, and `Wasm` would make the forge
//! > build a bare `.wasm` — not run wasm-bindgen, not build the wheel, not verify
//! > it. Adding a kind is a change to a shared edda crate that every matcher on it
//! > has to answer, so it is posted rather than made here.
//!
//! It was posted, and on 2026-09-06 (HO-T5) it was made. edda 0.1.13 has
//! `ArtifactKind::Package` and `[[build.package]]`; `facett-build-thing` declares
//! `facet-wrapped-web`; the forge routes it. The paragraph is kept rather than
//! deleted because the reasoning in it is still the reason the kind is `package`
//! and not `wasm`.
//!
//! What changed for THIS file: `write_sha256sums` is edda's now, and these tests run
//! against it through the same thin wrapper `publish-pip` calls. That is the point of
//! leaving them here — they were written for the behaviour, and the behaviour did not
//! move even though the code did. A green run of this file after the move is the
//! evidence that one writer replaced two without changing what either produced.

use std::path::PathBuf;

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!("relman-{tag}"));
    let _ = std::fs::remove_dir_all(&d);
    std::fs::create_dir_all(&d).unwrap();
    d
}

#[test]
fn the_manifest_lists_every_artifact_with_its_real_hash() {
    let d = scratch("hashes");
    std::fs::write(d.join("facet_wrapped_web-0.1.19-py3-none-any.whl"), b"wheel bytes").unwrap();
    std::fs::write(d.join("facet_wrapped_web-0.1.19.tar.gz"), b"sdist bytes").unwrap();

    let sums = facett_ops::pip::write_sha256sums(&d).expect("writes");
    let text = std::fs::read_to_string(&sums).unwrap();

    // `sha256sum -c` format: "<64 hex>  <name>". Two spaces, and the NAME only —
    // a path would make the file uncheckable from the directory it ships in.
    let lines: Vec<&str> = text.lines().collect();
    assert_eq!(lines.len(), 2, "one line per artifact: {text}");
    for l in &lines {
        let (hash, name) = l.split_once("  ").unwrap_or_else(|| panic!("bad line `{l}`"));
        assert_eq!(hash.len(), 64, "sha256 is 64 hex chars: `{l}`");
        assert!(hash.chars().all(|c| c.is_ascii_hexdigit()));
        assert!(!name.contains('/'), "the name must be bare, not a path: `{l}`");
        // The hash must be OF THE BYTES, not of the name or a constant.
        let bytes = std::fs::read(d.join(name)).unwrap();
        let want = facett_ops::pip::sha256_hex(&bytes);
        assert_eq!(hash, want, "`{name}` is listed with a hash that is not its own");
    }
}

#[test]
fn a_changed_byte_changes_the_listed_hash() {
    // The check that makes the one above mean something: if the manifest were keyed on
    // filename or length, everything above would still pass.
    let d = scratch("changed");
    let f = d.join("facet_wrapped_web-0.1.19-py3-none-any.whl");
    std::fs::write(&f, b"aaaa").unwrap();
    let first = std::fs::read_to_string(facett_ops::pip::write_sha256sums(&d).unwrap()).unwrap();

    std::fs::write(&f, b"aaab").unwrap(); // same length, one byte different
    let second = std::fs::read_to_string(facett_ops::pip::write_sha256sums(&d).unwrap()).unwrap();

    assert_ne!(first, second, "a one-byte change left the manifest identical");
}

#[test]
fn the_manifest_does_not_list_itself_or_anything_that_is_not_an_artifact() {
    // SHA256SUMS listing its own (pre-write) hash would be unverifiable, and listing
    // a stray file makes `sha256sum -c` fail for a reason that has nothing to do with
    // the release.
    let d = scratch("selfref");
    std::fs::write(d.join("facet_wrapped_web-0.1.19-py3-none-any.whl"), b"w").unwrap();
    std::fs::write(d.join("notes.txt"), b"scratch").unwrap();
    std::fs::create_dir_all(d.join("subdir")).unwrap();

    let sums = facett_ops::pip::write_sha256sums(&d).unwrap();
    let text = std::fs::read_to_string(&sums).unwrap();
    assert!(!text.contains("SHA256SUMS"), "the manifest lists itself: {text}");
    assert!(!text.contains("notes.txt"), "a non-artifact was listed: {text}");
    assert_eq!(text.lines().count(), 1);
}

#[test]
fn rewriting_the_manifest_is_idempotent() {
    // `publish-pip` is re-run constantly. A manifest that grew a duplicate line per
    // run would still `sha256sum -c` clean, and would quietly stop being a listing.
    let d = scratch("idem");
    std::fs::write(d.join("facet_wrapped_web-0.1.19-py3-none-any.whl"), b"w").unwrap();
    let a = std::fs::read_to_string(facett_ops::pip::write_sha256sums(&d).unwrap()).unwrap();
    let b = std::fs::read_to_string(facett_ops::pip::write_sha256sums(&d).unwrap()).unwrap();
    assert_eq!(a, b);
    assert_eq!(a.lines().count(), 1);
}

#[test]
fn an_empty_dist_is_refused_rather_than_producing_an_empty_manifest() {
    // An empty SHA256SUMS passes `sha256sum -c` trivially — it checks nothing and
    // says so to no one.
    let d = scratch("empty");
    assert!(
        facett_ops::pip::write_sha256sums(&d).is_err(),
        "an empty dist/ must be refused, not manifested"
    );
}