bb29186d62
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.
89 lines
5.2 KiB
Markdown
89 lines
5.2 KiB
Markdown
# 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 current** —
|
||
`felhom.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 1–2 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.
|