# Skidbladnir — complete overview

> The **real** README: the full pitch, quickstart, capabilities and design. The
> repo-root [`README.md`](../README.md) is the slim face (title · mashup ·
> pointers); this chapter is the heavy detail, and it is also folded into the
> manual [`docs/book.pdf`](../docs/book.pdf) by `nornir docs book`.

> 100% Rust — airgap a **whole system** (the infrastructure *and* the software on it)
> across a gap with no network, no shell, no manual steps: pack everything into one sealed,
> content-addressed bundle, carry it across, and on the far side it provisions the machine,
> sets up PKI + systemd, and starts every component in dependency order.

**Why Skíðblaðnir** — it carries the *whole* deployment (infra **and** software) over an
airgap in one bundle and brings it up with no agent on the target — the rows marked **NA**
are categories the rivals have no concept for:

| capability | **Skidbladnir** | Ansible | Packer | cloud-init |
|---|:--:|:--:|:--:|:--:|
| One sealed, content-addressed bundle — infra **+** software + images + config + data, verify-on-receipt | **✅** | ✗ | ◐ (image only) | ✗ |
| **Zero network, zero shell** on the target — drives systemd over D-Bus, no SSH/agent | **✅** | ✗ (SSH + Python) | ✗ | ◐ (first-boot shell) |
| **Provision the machine** (Redfish BMC · Terraform · KVM) **and** install the software, one tool | **✅** | ◐ | ✗ | ✗ |
| Typed **`ServiceSpec` → renderer tree** — PKI + user + systemd unit + ports + dated layout from one declaration | **✅** | **NA** | **NA** | **NA** |
| Dependency-ordered bring-up with atomic version-swap + rollback | **✅** | ◐ | ✗ | ✗ |
| 100% **Rust**, builds & runs fully offline (lean core pulls no network client) | **✅** | ✗ (Python) | ◐ (Go) | ✗ |
| Mature module ecosystem / huge community / multi-distro coverage | ◐ | **✅** | ✅ | ✅ |

*Rows marked **NA**: the rival has no such category — not a missing feature, a missing concept.*

Think of it as a **moving company for a deployment**. The flyttbil (moving van)
packs *all your belongings* — every binary, config, container image and data
file — into one sealed crate. But unlike a normal mover, it also brings the
**cement mixer**: on the far side it pours the foundation first (provisions the
machine, the OS, the network) and *then* unpacks the furniture (installs,
configures and starts each component) — in the right order. You roll the crate
across the airgap; the far side comes up running.

## What it does — pack, move, unfold

- **pack** — gather everything the target needs: artifacts, target-identical
  dependencies (it can build a component in a container so it is byte-alike with
  the destination), images, config, data.
- **archive** — seal it into one movable bundle with a content-addressed
  manifest (SHA-256 per entry), so the far side can **verify-on-receipt** that
  nothing changed in transit.
- **move** — carry the single bundle across the gap by any means (it is just
  bytes — a disk, a one-way diode, a courier).
- **unfold** — on arrival: lay the foundation (provision hardware/VMs), unpack
  into a versioned software dir, set up the PKI, create the service user and
  systemd unit, open the firewall, and **start every component in dependency
  order**. No shell scripts — it talks to systemd over D-Bus directly.

It packs **and** unpacks: the same crate goes both ways.

> **Named for Skíðblaðnir**, the ship in Norse myth that always has a fair wind
> and folds up small enough to fit in a pouch. The bundle folds an entire
> deployment into one thing you can carry.

## Quickstart

```sh
# internet side — 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 — ZERO network on the target:
nornir airgap fetch  lake.tar.zst     # verify-on-receipt against the manifest
nornir airgap unfold kvm my-vm        # show the provisioning plan (kvm | terraform | redfish; --run to drive)
nornir airgap start  lake.spec.toml   # dependency-ordered start waves → systemd over D-Bus
```

## The packet format — tar + zstd default, znippy behind a feature

The default archive is **tar + zstd**: pure Rust, always works offline, the
dependable fallback. **znippy** — the content-cache + delta packet format (read
without full decompress, ship only what changed) — is **fully implemented behind
the `znippy` cargo feature** (`--features znippy`), not the default. Turn it on to
use it; the tar+zstd path keeps working regardless.

## Capabilities

- **platform** — per-OS prep, verify-on-receipt, unpack into the software dir.
- **pki** — `SelfGenerated` ed25519 certs (pure Rust, offline) or a Vault source.
- **layout** — version-dated `software/<date>/<product>` dirs with an atomic
  symlink swap on upgrade (and rollback).
- **product** — service user + systemd unit + configure + open ports.
- **unfold backends** — Redfish (bare-metal BMC) · Terraform (cloud/VM) · KVM
  (local test).
- **orchestrate** — dependency-ordered bring-up, emitting `airgap_events`.

## Design

Lean by default: the offline core (pack · archive · layout · orchestrate ·
events) needs only a small always-offline dep set
(`anyhow`/`serde`/tar/zstd/sha2/chrono/tempfile/zbus), so it **always builds
offline**. PKI, the znippy engine, and the Redfish/Terraform/KVM backends sit behind cargo
features — the lean core never pulls a network client it doesn't use.

Part of the [nornir](https://codeberg.org/nordisk/nornir) ecosystem. See
`nornir/.nornir/airgap-install.md` for the full design + guide.

## License

MIT OR Apache-2.0
