Skíðblaðnir — guide (the whole workflow)
Class:
guide· audience: an operator or product author driving Skidbladnir end to end. The what is indesign.md; the why inreasoning.md. Per-function how-tos are the*-guide.mdchapters.
f0 — one deployment across the gap (the whole session)
The end-to-end flow spans several functions. It splits at the gap: everything up to and including archive runs on the internet side; everything from fetch runs on the secure side with zero network.
# ── internet side (build host) ──────────────────────────────────────────
# 1. pack a staging tree into a signed tar.zst bundle + per-entry SHA-256 manifest
nornir airgap pack ./staging --out lake.tar.zst
# …carry lake.tar.zst across the gap — a disk, a one-way diode, a courier…
# ── secure side (target): ZERO network ──────────────────────────────────
# 2. verify-on-receipt against the manifest (nothing changed in transit)
nornir airgap fetch lake.tar.zst
# 3. provision the machine (kvm | terraform | redfish); --run to actually drive it
nornir airgap unfold kvm my-vm
# 4. dependency-ordered start → systemd over D-Bus, no shell
nornir airgap start lake.spec.toml
The declarative spine is a LakeSpec (lib.rs:129): a version, the ComponentSpecs, and one PkiSource. From it, LakeSpec::start_waves() (lib.rs:137) computes the bring-up order — you declare the products and their after edges once; ordering is derived.
As a library, the same session in Rust:
use skidbladnir::{archive::TarZstd, pack, fetch, layout::Layout, install, service::Backend, product};
let eng = TarZstd::new();
// internet side
let staging = pack::Staging::new(&staging_root, "20260704")?;
let manifest = eng.pack(staging.root(), "20260704", &bundle_path)?; // Archive::pack
// secure side — verify BEFORE touching anything
let bundle = fetch::fetch_and_verify(&bundle_path, &eng)?; // fetch.rs:74
let layout = Layout::dated(data_dir, log_dir, software_dir);
let spec = product::ComponentSpec::holger();
let outcome = install::install_product(&spec, &layout, &bundle_path, &eng,
Backend::SystemdSystem, "/")?; // install.rs:88
install::apply(&outcome)?; // runs [enable, start]
f1…f10 — per-function how-tos
Each function has its own guide chapter with its CLI/API and worked examples:
pack-guide.md— build a staging tree, capture deps in a container.archive-guide.md— pickTarZstdvsznippy, delta-pack, selective read.move-guide.md— verify-on-receipt, out-of-band SHA, per-OS unpack.pki-guide.md— self-generated certs vs Vault.layout-guide.md— dated dirs, atomic upgrade swap, rollback.install-guide.md— oneServiceSpec→ any init; install/update/uninstall.unfold-guide.md— KVM / libvirt / Redfish / Terraform.orchestrate-guide.md— dependency waves + telemetry.matrix-guide.md— the live multi-OS install matrix.msi-guide.md— Windows MSI packaging.
Feature flags you choose at build time
The lean core is always available. Turn capabilities on per build (Cargo.toml:91):
| feature | adds | default |
pki |
real ed25519 SelfGenerated certs |
on |
znippy |
REAL znippy-core archive engine (seal/read/verify/delta via ../znippy) | off |
vault |
Vault PKI HTTP client | off |
redfish |
Redfish BMC provisioning | off |
terraform |
drive the terraform binary |
off |
machine / kvm / container |
VM/container lifecycle control | off |
matrix |
the live multi-OS install matrix (implies kvm) |
off |
A build with none of these still packs, archives (tar+zstd), verifies, lays out, installs over systemd/OpenRC, orchestrates, and emits events — fully offline.