Files
felhom.eu/REPORT.md
T
admin a12c6f9730 docs(v1.24.0): R-59/R-60/R-61 SHIPPED — CHANGELOG, README, ROADMAP (+R-62), runbook, capability map, drill evidence, REPORT
Virgin-ISO nested drill closed the train: dead-NIC install baked the
fallback (incl. the dead default gateway), the R-59 screen painted
(capture committed beside the spike doc), the cable move healed +
registered at the hub in 23s unaided, and the build's rootpw file
matched the installed box's shadow hash. R-59 SHIPPED with the recorded
deviation (first-boot gate; installer-initrd abort out of scope by
operator ack). R-60 SHIPPED (spike + drill cited; F-P9 route-flush fix
included). R-61 slice 1 SHIPPED. New R-62 row (hub delete-dialog
cosmetics, XS). Capability map: new PROVEN-LIVE row (nested != metal,
said so). Cleanup verified: felhom-pve interfaces byte-identical,
bridge/VMs/ISO removed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UuFPHmHNrCJj1VhY6QdDMU
2026-07-22 11:45:55 +02:00

6.6 KiB

REPORT — scripts/ISO train v1.24.0: R-59 + R-60 + R-61 (2026-07-22)

Task: the three HP-t740 findings — the box that can never call home (R-59 refuse-loudly gate), the first-boot NIC sweep self-heal (R-60), and the knowable baked root password (R-61 slice 1) — implemented in scripts/iso/, spike-proven, and driven end-to-end on a nested wrong-NIC install. No hub/agent/controller/catalog changes; golden image and floors untouched.

Baselines

  • felhom.eu main at start: 1613bc7 (scripts CHANGELOG head = build-hub.sh v1.23.0); clean-tree gate held before both ISO builds.
  • Target: scripts train v1.24.0 (ISO_VERSION="1.24.0" in build-felhom-iso.sh).

Commits (this train, in order)

Hash What
9e29295 R-61 slice 1: rootpw sibling file (0600) + manifest pointer; test/rootpw-emission.sh; OUT_ISO hoist; FELHOM_ISO_KEEP_WORK escape
ad1d26a Harness catches up with the v1.21.0 in-script pairing wait (old scenarios would hang); assistant image + python3
c043ba9 Phase-0 spike doc — sweep mechanics GO, F-P1..F-P8 (STOP-0 discharged before gate code)
cf1862c R-59+R-60: network_gate + sweep_nics + Hungarian console screen; 4 harness scenarios; 3 red-proofs run
699325b R-60 drill fix (F-P9): flush vmbr0 before the bounded dhclient — the baked fallback default route otherwise poisons the hub probe
(this commit) v1.24.0 CHANGELOG, README, ROADMAP (R-59/60/61 SHIPPED + new R-62), onboarding runbook, capability map, spike-doc drill section + screen capture, this REPORT

Harness results

  • test/bootstrap-modes.sh (in felhom-iso-assistant:trixie): 40/40 green — D (direct, zero appliance calls, G1 zero-new-behavior invariant incl. zero sleeps + fixture untouched), P (v1.21.0 single-invocation pairing loop), 410 crash-window, G2 sweep-success (re-point + persist inet dhcp + .felhom-bak + proceed), G3 sweep-fail (screen content + byte-identical interfaces + no bak), G4 state.json-present (sweep never invoked by fake call-count, interfaces untouched).
  • test/rootpw-emission.sh: 11/11 green — dry-run emission, 0600, plaintext↔answer-hash cross-check (openssl passwd -6 -salt), plaintext absent from build output, manifest-heredoc pointer/no-leak guard.
  • shellcheck -S warning felhom-bootstrap.sh: clean.

Red-proofs (all four run, failed exactly on their guarding assertion, restored)

  1. Manifest plaintext leak (R-61): root-password-plain : ${ROOT_PLAIN} injected into the manifest heredoc → manifest never references ROOT_PLAIN FAILED → restored.
  2. Restore-on-failure dropped (R-60): sweep's byte-identical restore removed → G3 interfaces BYTE-IDENTICAL after failed sweep FAILED → restored.
  3. State gate removed (R-60): [[ ! -e $STATE_FILE ]]true → G4 zero-ifreload/zero- dhclient FAILED → restored.
  4. Hub-reachable early return removed (R-59): all five G1 invariants FAILED → restored.

Phase-0 spike (STOP-0 honored)

documentation/audits/SPIKE-firstboot-nic-sweep-2026-07-22.md — written and committed BEFORE the gate code. Verdict GO; key inputs: success leg ≈ 4 s, dead candidate = exactly its DHCP bound; unused NICs are admin-DOWN (raise before carrier read); ANY HTTP status = reachable (hub answers 302); trigger on hub-unreachable, never the fallback signature (the drill found the second wrong-NIC variant: the installer picks the NIC that LEASES and bakes the lease as static).

Nested end-to-end drill (evidence in the spike doc)

  • Round 1 caught a real defect the harness could not: the fallback bake includes a default route via 192.168.100.1, and dhclient-script never replaces an existing default route → the sweep's hub probe rode the dead gateway and the gate oscillated. Fixed (699325b, flush before dhclient), validated by hot-patch (heal in 33 s), then the ISO was rebuilt.
  • Round 2, virgin final ISO, zero patching: dead-NIC install → fallback baked → R-59 screen on the console (capture committed: SPIKE-firstboot-nic-sweep-2026-07-22-screen.png) → failed-sweep restore proven safe (flushed static re-applied by ifreload) → cable move → self-heal + hub registration in 23 s unaided (persisted inet dhcp + winner port, original in interfaces.felhom-bak, box at a proper DHCP address, pairing banner + code on console).
  • R-61 lockout closed, proven: the build's .rootpw.txt password recomputed against the installed box's /etc/shadow root hash → exact match (computed on the build host; the plaintext never left it). Value NOT included here by design.
  • Validation method note: no browser on DooPlex — console proof is QEMU screendump; hub-side proof is the box's own registration/pairing-code delivery (endpoint-level).

Artifacts

  • Final drill ISO: felhom-pve-9.2-1-v1.24.0-nested-probe-generic.iso, sha256 c25cdbbf35d2134b0bf278c4b069a3d5849c0960cf0a5e4500e52638489c8947, built from clean tree at 699325b with an uncommitted key-bearing probe profile (nested-vm + ops SSH key — never committed, per the armed-profile rule). Its .rootpw.txt exists beside it (0600) — verified, value stored out-of-band only.
  • Shipping rebuilds for real profiles (hp/n100/generic) happen at next need; the committed pipeline builds them from main as usual.

Cleanup verification

Nested VMs 9310/9311/9312 destroyed; throwaway vmbr9 (+ its temporary host address) deleted; transferred ISO + screendumps removed from felhom-pve; brctl show back to exactly enp1s0 + veth9201i0 on vmbr0; /etc/network/interfaces on felhom-pve diffed BYTE-IDENTICAL against the pre-task copy (sha c7ace087…). Residue by design: three unclaimed-appliance registrations at the production hub (all three source machines destroyed) — operator may discard them from the Unclaimed list.

Observations / follow-ups

  • F-P8 (out of scope, noted): the pairing loop's register-failure line prints every ~42 s on a no-network box; v1.21.0 quieted the 204 wait but not this path. The gate makes it mostly moot (it holds before register), but the line exists for a box that loses network AFTER install start (state.json present → screen + retry, register never reached).
  • The console font renders Hungarian long vowels (ő/ű) approximately on the text console — same behavior as the existing pairing banner; acceptable.
  • qm screendump (qm monitorscreendump) is a serviceable no-browser console-capture method for nested drills — worth remembering for future runbooks.
  • R-62 (hub delete-dialog cosmetics) filed on the ROADMAP as agreed — docs-only here.