Files
felhom.eu/REPORT-universal-iso-spike.md
T
admin bb29186d62 SPIKE 3: [first-boot] does NOT fire on an interactive install
Findings only — no script, profile or build file changed; no release ISO built, nothing published.
documentation/audits/SPIKE-universal-iso-3-2026-07-31.md

MEASURED with a control from the SAME image (one ISO, 15 GRUB entries):
- Automated entry  -> hook fires: ttyS0 marker, marker file,
  /var/lib/proxmox-first-boot/proxmox-first-boot (0700), activation symlink, unit active.
- Terminal-UI entry, normal manual install -> ALL absent, and the proxmox-first-boot PACKAGE is
  not installed at all. A whole-filesystem grep for the marker returns nothing.

Mechanism cited: Config.pm:118 defaults first_boot.enabled=0 and set_first_boot_opt is never
called in the Perl tree; Install.pm:746 returns early without it; Install.pm:1360 skips the
package. proxinstall (graphical) has ZERO occurrences of first-boot. [first-boot] is an
automated-installer feature, unavailable on every interactive path by construction. R-154.

A delivery mechanism DOES exist and is UNTESTED: Install.pm:1343-1372 unpacks every .deb in the
ISO's /proxmox/packages/ into the target on every path (fixed skip-list), then dpkg --configure -a
runs postinsts (:1378) — how PVE ships first-boot itself. Read from source, not measured.

Q5: the public image should carry NO answer.toml at all — that removes the baked root hash, the
disk profile and the whole Spike 1-2 problem space, and makes it a one-line release gate. But
iso-repack.sh:100-106 refuses an ISO without auto-installer-mode.toml. R-155.

Incidental R-153: hub hostInstallVersion=1.19.0 vs SCRIPT_VERSION=1.22.0; hostinstall_gates.py
detects it and exits 1 — the gate works, nothing runs it.

Q3 (real stub at before-network) was NOT reached and is recorded as not reached.
2026-07-31 14:47:18 +02:00

5.2 KiB
Raw Blame History

REPORT — SPIKE 3: on an interactive install, does the ISO deliver anything at all? (2026-07-31)

Written as REPORT-universal-iso-spike.md, not REPORT.md: the shared file belongs to today's hub v0.85.0 session and the second session in a shared clone never touches it. Supersedes this file's Spike 1 and Spike 2 contents.

Class: Spike. Findings only — no production file changed, no release ISO built, nothing published. Evidence: documentation/audits/SPIKE-universal-iso-3-2026-07-31.md.

The answer: no, and more completely than expected

[first-boot] does not fire on an interactive install. Measured, with a control from the same image (one ISO, 15 GRUB entries):

  • Automated entry → hook fires: ttyS0 marker, marker file, /var/lib/proxmox-first-boot/proxmox-first-boot (0700), activation symlink, unit active.
  • Terminal UI entry, normal manual install → every one of those absent, and the proxmox-first-boot package is not installed at all. A whole-filesystem grep for the marker returns nothing.

It is not that the hook fails to run — nothing that could run it is ever placed on the system. The mechanism, cited: Config.pm:118 defaults first_boot.enabled => 0 and set_first_boot_opt is never called anywhere in the Perl tree; Install.pm:746 returns early without the flag; Install.pm:1360 skips the package. And proxinstall, the graphical installer, contains zero occurrences of first-boot. This is a property of the PVE installer, not a Felhom defect — but nothing in our tree records it, which is R-154.

The commercially relevant part

A delivery mechanism does exist. Install.pm:1343-1372 unpacks every .deb in the ISO's /proxmox/packages/ into the target on every install path — a fixed skip-list of known package names, everything else installed — then dpkg --configure -a runs postinsts. That is exactly how PVE ships proxmox-first-boot itself.

It is read from source, not measured, and I have not proven either that our repack preserves an added .deb or that a postinst running in the installer chroot can do the job (it runs inside the installer, not on a booted system). Proving it is the top follow-up, ~45 min. Until then the honest position is: the insert-stick-install-type-claim-code experience is plausible but unvalidated, and the documented one-command manual path is what works today.

Incidentally confirmed: the interactive installer shows the target disk and a summary listing Bootdisk(s) /dev/sda before erasing. Your ruling needs no Felhom work for that warning.

The manual path is already most of the way there

Two of the three things I was asked to look for already exist:

  • The hub already renders the command with the customer-id filled in (customer_unified.html:563-564, plus a JS generator that adjusts the flags per role).
  • The URL is already short, public and always currentfelhom.eu/scripts/felhom-host-install.sh, git-synced from main on a 30-second period.
  • Console display does not exist. Nothing writes /etc/issue; PVE's own banner is what appears after install. That file is the obvious carrier. Reported, not built.

Two things I'd flag

A working gate is red and nobody runs it. configs.go:28 has hostInstallVersion = "1.19.0" against SCRIPT_VERSION = "1.22.0", and scripts/hostinstall_gates.py detects it and exits 1. The comment saying drift "is now gated" is true of the gate's existence and false of its enforcement, so the customer page's install-command generator targets a flag surface three minor versions stale. R-153.

The cleanest public-image posture is currently blocked by our own tooling. §6 of the findings argues the public image should carry no answer.toml at all — which removes the baked root hash, the disk profile, and every question Spikes 12 wrestled with, and makes "no answer.toml" a one-line release gate. But iso-repack.sh:100-106 refuses any ISO lacking auto-installer-mode.toml. That guard is sound for its original case and wrong for this one. R-155.

Not reached

Q3 — the real stub at before-network was not run; driving the interactive install consumed the session. It is recorded as not reached, not inferred. Spike 2's structural case stands unrefuted, and §2 narrows its scope: with no first-boot hook on the interactive path, that question now governs operator-built images only. ~40 min when wanted.

R-rows

R-153 (a working gate is red and unrun) · R-154 ([first-boot] is automated-only and nothing in our tree says so) · R-155 (iso-repack.sh blocks the no-answer.toml posture).

Teardown

All three layers verified positively. demo-hp back to its exact pre-spike state — spike3/ removed, 0 QEMU processes, 0 loop devices, disk usage 6.6 G, identical to pre-spike, 4 storages unchanged, nothing on local-lvm, drill-r50 stopped and 9201 running. demo-felhom: nothing placed, external drive observed only. DooPlex: scratchpad 4.4 GB → 80 K, both throwaway passwords destroyed, felhom-iso/out/ untouched at 17 ISOs, no production file modified. Hub-side: nothing created — verified by fetching and searching the customer list, not asserted. Nothing published.