nornir 0.5.2

Companion to cargo: dependency tracking, release gating, deploy, benchmarks, and documentation assembly. Project-agnostic.
//! Declarative **build variants** (task #19) + the **build-thing** UI surface,
//! **build-provenance** attestation, and warehouse sink (task #36).
//!
//! EXTRACTED (task #36) into the reusable, dependency-light
//! [`nornir_build_thing`] leaf crate — mirroring how the test-matrix engine lives
//! in `nornir-testmatrix`. This module is now a thin **re-export** so every
//! existing path keeps working:
//!
//! * `nornir::build::variant::{BuildVariant, BuildVariantSet, Profile, …}`
//! * `nornir::build::surface::BuildSurface` — the data-driven build-thing UI model
//! * `nornir::build::provenance::{BuildProvenance, Attestation, build_variant, …}`
//! * `nornir::build::sink::BuildProvenanceSink` — the warehouse seam
//! * `nornir::build::elm::BuildThing` — the facett-Elm UI component (pure core)
//!
//! A repo like holger ships **three split executables from one tree**
//! (`embedded`, `minimal`, `full`); it declares them as data and nornir drives
//! `cargo` from the descriptor. Building one (with `--attest`) captures a
//! content-addressed provenance record → writes it to the warehouse
//! ([`crate::warehouse::build_provenance`]) → then dumps a znippy archive beside
//! the artifact ([`seal`], feature `build-provenance`).

// Re-export the leaf crate's modules verbatim so `nornir::build::variant::*`,
// `::surface::*`, `::provenance::*`, `::sink::*`, `::elm::*`, `::container::*`
// all resolve.
pub use nornir_build_thing::{
    container, elm, image_build, provenance, sink, surface, variant, vm,
};

// Flat re-exports of the headline API (mirrors the crate's own prelude).
pub use nornir_build_thing::{
    build_variant, Attestation, BuildOutcome, BuildProvenance, BuildProvenanceSink, BuildSurface,
    BuildThing, ContainerBuild, ImageFormat, ImageLayer, ProvenanceSealer,
};

// Flat re-exports of the IMAGE/VM build-target API — the peer of `build_variant`
// for `ContainerBuild` images and `VmBuild` appliances. The heavy real container
// builder (`BollardImageBuilder`) is forwarded behind the `build-image` feature.
pub use nornir_build_thing::{
    build_container, build_vm, BuiltImage, ImageBuilder, PrebuiltVmBuilder, TargetAttestation,
    TargetBuildOutcome, TargetKind, TargetProvenance, VmBuild, VmFormat, VmImageBuilder,
};

/// The real bollard-backed container image builder — only linked when the main
/// crate is built with `--features build-image` (which forwards
/// `nornir-build-thing/image-build`).
#[cfg(feature = "build-image")]
pub use nornir_build_thing::image_build::BollardImageBuilder;

/// The real **znippy-sealed** attestation path (feature `build-provenance`): a
/// detached CMS signature over the attestation digest, and the znippy-archive
/// dump placed beside the released artifact.
#[cfg(feature = "build-provenance")]
pub mod seal;

#[cfg(test)]
mod reexport_tests {
    //! Compile-level proof that the IMAGE/VM build-target API is reachable through
    //! the `nornir::build::` re-export (not only the leaf crate).

    /// The `vm` + `image_build` modules and the flat `build_vm`/`PrebuiltVmBuilder`
    /// re-exports resolve, and the dep-light VM path seals a produced-artifact
    /// attestation whose digest is 64 hex chars.
    #[test]
    fn build_vm_reachable_via_reexport_and_seals_a_digest() {
        use crate::build::image_build::build_vm;
        use crate::build::vm::VmBuild;
        use crate::build::PrebuiltVmBuilder;

        let dir = tempfile::tempdir().unwrap();
        let root = dir.path();
        std::fs::create_dir_all(root.join("artifacts")).unwrap();
        std::fs::write(root.join("artifacts/bzImage"), b"KERNEL bytes").unwrap();
        std::fs::write(root.join("artifacts/rootfs.cpio.gz"), b"ROOTFS bytes").unwrap();

        let vm = VmBuild {
            name: "appliance".into(),
            kernel: "artifacts/bzImage".into(),
            rootfs: "artifacts/rootfs.cpio.gz".into(),
            ..Default::default()
        };
        let out = build_vm(&PrebuiltVmBuilder, &vm, "repo", root).unwrap();

        // A TargetAttestation over the produced kernel+rootfs hashes.
        assert_eq!(out.kind, crate::build::TargetKind::Vm);
        let hex = out.attestation.digest_hex();
        assert_eq!(hex.len(), 64, "sha-256 digest is 64 hex chars: {hex}");
        assert!(hex.chars().all(|c| c.is_ascii_hexdigit()));
        assert!(out.attestation.digest_matches_record().unwrap());
    }
}