diff --git a/CHANGELOG.md b/CHANGELOG.md index ed85af9..fbde0ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,22 @@ which records not just what changed but what each drill run proved. ### Added +- **Server-posture template keys** (#81, carved from #69) — two optional + `box.env` allowlist keys. `BOX_REQUIRE_VM=1` refuses both the silent + container fallback (no `/dev/kvm`, exit 1) and an explicit `--container` + (exit 2): such a template's trust boundary is the VM. `BOX_AUTOSTART=1` + stamps `boot.autostart=true` at launch, per-instance like `limits.*`, so + the box returns from a host reboot without an operator; clones inherit it + via `incus copy`. Still no key for a network or a `security.*` flag, on + purpose. +- **Dynamic template test suite** (#81, carved from #69) — `test/cli.sh` + discovers `templates/*/` instead of hardcoding the list, so a new template + cannot ship unseen. Per template: `box.env` is driven through the real, + extracted `load_template` (unknown keys and missing `BOX_IMAGE`/`BOX_USER` + fail, fixtures proving both dies); `user-data.yaml` exists, declares + `#cloud-config`, parses as YAML, and installs tmux (#65). Grep guards pin + the `cmd_new` half: the `REQUIRE_VM` refusal orders after `pick_mode`, and + `boot.autostart` is stamped only under the `T_AUTOSTART` guard. - **`box export` / `box import`** (#70) — a box's state that survives the box _and_ the host, unblocking #66's humane upgrade flow (down, export, rm, upgrade, re-import). `box export []` wraps `incus export` into diff --git a/test/cli.sh b/test/cli.sh index e569549..fb8ae33 100644 --- a/test/cli.sh +++ b/test/cli.sh @@ -198,25 +198,6 @@ for d in "$ROOT"/templates/*/; do grep -qE '^[[:space:]]*-[[:space:]]+tmux$' "$d/user-data.yaml" done -# --------------------------------------------------------------------------- -# The staging template (#68) — server-class, still creds-free. Its posture in -# full: both boot demands set (proven through the real parser, not a grep), -# docker + rig preinstalled, and NOTHING that joins or admits — tailscale, -# auth keys and ssh in any spelling are rig's to install at bootstrap time, -# inside the guest, so their absence from the shipped cloud-init IS the -# creds-free contract. Comments may name them (to say why they are absent); -# effective lines must not. -# --------------------------------------------------------------------------- -STG="$ROOT/templates/staging" -check "staging: demands VM mode and autostart (via the real parser)" \ - 0 "REQUIRE_VM=1 AUTOSTART=1" tpl "$ROOT" staging -check "staging: installs docker (get.docker.com)" 0 "" \ - grep -qF 'get.docker.com' "$STG/user-data.yaml" -check "staging: preinstalls rig" 0 "" \ - grep -qF 'rig/main/install.sh' "$STG/user-data.yaml" -# shellcheck disable=SC2016 # $1 expands in the child shell, by design -check "staging: no tailscale/authkey/ssh outside comments (creds-free)" 1 "" \ - bash -c 'grep -v "^[[:space:]]*#" "$1" | grep -qiE "tailscale|authkey|ssh"' _ "$STG/user-data.yaml" rm -f "$TPLFN" # The keys' cmd_new half, grepped the way the expose guard is (line order —