SPIKE 4: a .deb in the ISO DOES deliver on an interactive install
Findings only — no script, profile or build file changed; no release ISO built, nothing published. documentation/audits/SPIKE-universal-iso-4-2026-07-31.md MEASURED, with a control, and the negative control is in the SAME box. One ISO (15 GRUB entries), a trivial probe .deb injected into /proxmox/packages/, two qm-created VMs on demo-hp (400 interactive / 401 automated control) on a scratch dir storage at the /mnt/nvme-1tb mount ROOT. Interactive (Terminal UI) install: - package installed (ii felhom-spike4-probe 0.0.1) - postinst RAN (marker + content intact) - it enabled a systemd unit, and that unit FIRED ON FIRST BOOT (uptime 7.98s, pid1=systemd) - while on the same machine proxmox-first-boot is NOT installed and /var/lib/proxmox-first-boot does not exist — Spike 3's negative reproduced, not assumed. Postinst environment (identical both paths): pid1=unconfigured.sh, NO running systemd, but 'systemctl enable' SUCCEEDS; /proc+/sys mounted; network+DNS happened to be up (inherited from the installer's DHCP — must NOT be relied on). Constraints: never systemctl start/daemon-reload, never require network, never fail, do the real work in the unit at first boot. Repack preserves it, but a naive 'xorriso -boot_image any replay' fails with 'Overlapping MBR partition entries' — iso-repack.sh:270-292 already documents that exact failure and its fix. R-153 RETRACTED into R-94 leg (b): OPEN-ITEMS.md:15 carries it verbatim at READY (XS), and R-29 says explicitly 'do not mint a new ID for a new instance'. Spike 3's further claim that the drift leaves the generator 'three minor versions stale' was FALSE and is corrected — R-94 retracts that exact reading; the served script is always main, so 1.22.0 is what every install already gets. No new R-rows opened.
This commit is contained in:
@@ -1,88 +1,97 @@
|
||||
# REPORT — SPIKE 3: on an interactive install, does the ISO deliver anything at all? (2026-07-31)
|
||||
# REPORT — SPIKE 4: can a `.deb` in the ISO deliver the stub on an interactive install? (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.
|
||||
> Spike 1–3 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`.
|
||||
Evidence: `documentation/audits/SPIKE-universal-iso-4-2026-07-31.md`.
|
||||
|
||||
## The answer: no, and more completely than expected
|
||||
## The answer is yes, and it was measured with the negative control in the same box
|
||||
|
||||
**`[first-boot]` does not fire on an interactive install.** Measured, with a control from the *same*
|
||||
image (one ISO, 15 GRUB entries):
|
||||
One ISO, 15 GRUB entries, a trivial probe `.deb` injected into `/proxmox/packages/`. Two VMs on
|
||||
demo-hp built with `qm` so the run was visible in the web console: **400 interactive**, **401
|
||||
automated control**.
|
||||
|
||||
- **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.
|
||||
On the **interactive** install (`spikefour.felhom.eu`):
|
||||
|
||||
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 package is installed — `ii felhom-spike4-probe 0.0.1`
|
||||
- its **postinst ran** — marker file present, content intact
|
||||
- it **enabled a systemd unit**, and **that unit fired on first boot** (uptime 7.98 s, `pid1: systemd`)
|
||||
- and on **that same machine**, `proxmox-first-boot` is not installed and `/var/lib/proxmox-first-boot`
|
||||
does not exist — Spike 3's negative reproduced, not assumed
|
||||
|
||||
## The commercially relevant part
|
||||
So the two delivery mechanisms are independent, and the one that survives the path we are actually
|
||||
shipping is the `.deb`. **The product — insert the stick, install Proxmox normally choosing your own
|
||||
disk and password, box sets itself up and waits for a claim code — is now measured rather than hoped
|
||||
for.** With one honest caveat: what was measured is a trivial probe package, not Felhom's real stub.
|
||||
Packaging the real stub and confirming pairing end-to-end is the last step before a spec (~60 min).
|
||||
|
||||
**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.
|
||||
## What a postinst may and may not do
|
||||
|
||||
**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.
|
||||
Identical on both paths: `pid1 = unconfigured.sh`, **no running systemd**, `/proc` and `/sys` mounted,
|
||||
and **`systemctl enable` succeeds** (it wrote the symlink). Network and DNS *happened* to be up —
|
||||
inherited from the installer's own DHCP.
|
||||
|
||||
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.
|
||||
Four constraints for the real postinst, so they get written against rather than discovered:
|
||||
|
||||
## The manual path is already most of the way there
|
||||
1. Never `systemctl start` or `daemon-reload` — there is no systemd running. `enable` is the only verb.
|
||||
2. **Never require the network**, despite it being present here. A box installed with the cable out
|
||||
gives a postinst no route, and a failing postinst breaks the customer's install.
|
||||
3. Never fail — guard everything, `exit 0`.
|
||||
4. Do the real work in the unit at first boot, where systemd, network and a booted kernel exist.
|
||||
|
||||
Two of the three things I was asked to look for already exist:
|
||||
## Two smaller results
|
||||
|
||||
- **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.
|
||||
**The repack preserves the `.deb`, but not naively.** `xorriso … -boot_image any replay` fails with
|
||||
*"Overlapping MBR partition entries"* — and `iso-repack.sh:270-292` already documents that exact
|
||||
failure and its fix. Mirroring it produced a working image (19 El Torito entries; the `.deb` extracted
|
||||
back out is byte-identical). So this is an insertion into an extract→modify→re-master cycle our repack
|
||||
already performs, not a new build stage.
|
||||
|
||||
## Two things I'd flag
|
||||
**Q3:** `iso-repack.sh:100-106` refuses an ISO without `auto-installer-mode.toml`. It is a guard, not
|
||||
a structural requirement, and its reasoning is sound for the shape it was written for — already R-155,
|
||||
cited exactly here. With no mode file the stock grub.cfg does not emit the Automated entry at all; with
|
||||
a mode file but no answer, that entry aborts safely and loudly.
|
||||
|
||||
**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.**
|
||||
## A correction I owe you from last session
|
||||
|
||||
**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.**
|
||||
**R-153 is retracted.** The register grep this task mandated shows R-94 already carries it verbatim at
|
||||
`OPEN-ITEMS.md:15`, status `READY (XS)`, with leg (b) being precisely "the gate fails today and is
|
||||
invoked by nothing" — and R-29, the class, says in terms *"do not mint a new ID for a new instance."*
|
||||
Spike 3 filed a duplicate.
|
||||
|
||||
## Not reached
|
||||
**And the substantive half of that Spike 3 claim was wrong.** I wrote that the drift left the customer
|
||||
page's install-command generator "targeting a flag surface three minor versions stale." R-94 explicitly
|
||||
retracts exactly that reading: the constant selects no script — it renders as a text label, and the
|
||||
command beneath it fetches the script the website git-syncs from `main`, so **1.22.0 is what every
|
||||
install already gets**. It is a wrong number on your screen and nothing more. I overstated it.
|
||||
|
||||
**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.
|
||||
## Still unknown
|
||||
|
||||
**The real stub has not been packaged** — that is the one thing between here and a build spec.
|
||||
Also unproven: `dpkg --configure -a` ordering for a package with dependencies; an ISO that never went
|
||||
through `prepare-iso` (blocked by R-155, which this spike was fenced from changing); and the Graphical
|
||||
installer, where the result should hold *a fortiori* since the `.deb` path is in `Install.pm`, shared
|
||||
by all front-ends — but that is inference, not measurement.
|
||||
|
||||
**Spike 3's Q3** — the real stub at `before-network` — **this session did not touch it.** Note it is
|
||||
now partly superseded: on the `.deb` route the unit's ordering comes from the unit file, not from
|
||||
`[first-boot].ordering`.
|
||||
|
||||
## 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).
|
||||
**None opened.** Each candidate was grepped against the register first: the delivery result is a
|
||||
positive finding, the postinst constraints belong in the build spec, and the repack guard is already
|
||||
R-155. **R-153 retracted** into R-94 leg (b) / R-29.
|
||||
|
||||
## 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.
|
||||
All three layers plus the scratch storage, verified positively. demo-hp: VMs 400/401 purged, **storage
|
||||
`spike4` removed** (`storage.cfg` back to 4, `grep -c spike4` = 0), `/mnt/nvme-1tb/images/` empty,
|
||||
**disk usage 6.6 G — identical to pre-spike**, probe ISO and driver removed, 0 loop devices,
|
||||
`drill-r50` stopped and untouched, 9201 running, `felhom-backup` unmodified, nothing on `local-lvm`.
|
||||
DooPlex: workspace scratch **4.8 GB removed**, scratchpad **3.3 GB → 88 K**, both throwaway passwords
|
||||
destroyed, 17 ISOs in `out/` untouched, no production file modified. **Hub-side: nothing created** —
|
||||
the VMs took LAN DHCP leases but never ran `felhom-host-install.sh` or contacted the hub; verified by
|
||||
fetching and searching the customer list. Nothing published.
|
||||
|
||||
Reference in New Issue
Block a user