Mandatory install profile (no default): byo = a host the operator does not own. Break-glass gated OFF at its call site in byo (root@pam never touched), mandatory --cores/--memory, argv-time refusals (--enable-oob/--rotate-recovery, non-9.x PVE, missing --acl-storages), host-mutation disclosure + typed-hostname ack, byo config asserts (lan_resolver/wg_tunnel/oob off; byo flips the lan_resolver write default to off), pool+ACL verify asserts in BOTH modes (R2), --preflight-only (no state, PASS/FAIL verdict), resume mode-mismatch refusal, FELHOM_INSTALL_STATE_DIR harness override. NEW scripts/hostinstall-mode-harness.sh: static refusal matrix C1-C4 + grep invariants + PVE tier (C5 + A/B dry transcripts). 16/16 PASS on felhom-pve (C5 live); red-proofs RP-1..RP-3 run->fail->revert. shellcheck clean at severity=warning. Docs: day0-install SC.5 byo section + trust model; REUSE row; CONTEXT + REPORT. Live drill = GL-6 (supervised); STOP honored (no non-dry run). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
6.3 KiB
felhom.eu — task reports
Overwrite this file with a summary of the most recent task only (uniform with the other repos; not cumulative). The cumulative hub history lives in hub/CHANGELOG.md; the scripts history lives in scripts/CHANGELOG.md.
TASK GL-2 — BYO-host install profile (--mode appliance|byo) — host-install v1.10.0 (2026-07-07)
Baseline confirmed: felhom.eu @ 1a1e42ad, SCRIPT_VERSION="1.9.1" → 1.10.0.
Implementation + static/dry validation only per spec §0 — the live provision/uninstall runs are
GL-6 (operator-supervised); the §13 STOP was honored (zero non-dry installer invocations anywhere).
Files created / modified (single repo, main)
scripts/felhom-host-install.sh— v1.10.0 (Parts 1–3; see scripts/CHANGELOG.md for the feature list)scripts/hostinstall-mode-harness.sh— NEW (Part 4)documentation/runbooks/day0-install.md—--modein every command, new §C.5 (byo command + trust-model paragraph + preflight-only), §C.6 (pre-v1.10.0 resume note), 4 new troubleshooting rowsscripts/CHANGELOG.md,REUSE.md(install-profile-gate pattern row),CONTEXT.md, this file
Spec deviations / judgment calls (each verified against the real code)
--modecollision: v1.9.1 already used--mode provision|dr. Resolved:appliance|byoare the only install values,provisionretired with a specific die, thedrstub dispatch kept verbatim (the documented 10D seam).- Spec §2 was wrong about the lan-resolver: the config write did
setdefault('lan_resolver', {"enable": True})— default-ON, so the spec's byo assert would have died on every byo install. Fixed by flipping the byo DEFAULT to off (appliance untouched); the assert still dies if a--preserve-fromconfig carries true, which is the intended refusal. - The byo skip line reads
break-glass (step 4b) SKIPPED (byo: …)— NOT the spec's literal"4b/8 …"text, because Scenario B / harness H-B forbid the string4b/8in the byo transcript (an internal spec contradiction; the greppable invariant won). --preflight-onlyskips the byo typed ack (prints the disclosure, logs the skip) — nothing will be mutated, and a mandatory prompt would break its re-runnable/scripted purpose.documentation/pilot/GO-LIVE-PACKAGE.mdis not in the repo and no operator copy arrived with the task — the G2/G4/G5 → "implemented, awaiting GL-6" flip is recorded in CONTEXT.md; add the doc when supplied.
Harness results
Static tier (Windows Git Bash AND felhom-pve, identical): bash -n, C1/C1b/C1c, C2a/C2b, C3/C3b/C3c, C4, C6-static, INV-1 (one appliance-gated break-glass call site), INV-2 (chpasswd unreachable outside step_break_glass), INV-3 (--mode in usage) — all PASS.
PVE tier (felhom-pve, read-only, temp FELHOM_INSTALL_STATE_DIR): C5 PASS live (bogus
--acl-storages entry → die naming it, pre-hub, pre-passphrase). H-A/H-B dry transcripts ran with
the out-of-band demo passphrase (file→file, never printed) but die at step 5 with rc=1 — a
customer-data blocker, not a code bug: demo-felhom's controller.yaml serves EMPTY
git.username/git.token. The transcript span through the break-glass gate was validated manually
instead: appliance transcript contains 4b/8; byo transcript contains no
4b/8/chpasswd/recovery-credential and does contain the disclosure block, the dry ack line,
acl storages all present, and the host-DNS :53 line (it correctly showed the live dnsmasq).
--preflight-only proven live both ways: PASS verdict + rc 0 + zero state entries; bogus-storage
run → specific die + PRE-FLIGHT FAIL (exit 1) verdict.
Red-proofs (run → fail → revert, against mutated scratch copies — the repo file was never mutated):
- RP-1 un-gated the break-glass call site → INV-1 FAIL (13/16). Reverted (scratch deleted).
- RP-2 dropped the byo caps requirement → C1/C1b/C1c FAIL (11/16). Reverted.
- RP-3 dropped the resume mode-mismatch check → C4 FAIL (13/16). Reverted.
§9 rule 9 — the _state_mark dry-run finding
Verified in code: both _state_mark and _state_put begin with $DRY_RUN && return 0 — dry
runs write nothing. Belt on top: the harness points FELHOM_INSTALL_STATE_DIR (new, harness-only
env override — none existed) at a throwaway temp dir for EVERY invocation, so even non-dry refusal
cases can never touch a live state.json. Confirmed live: felhom-pve's real state.json was
byte-untouched (it only ever saw the temp dir) and the preflight-only runs left 0 entries.
Shellcheck
v0.10.0 (build server 180 + felhom-pve; not installed locally). Clean at --severity=warning
on both scripts. Full-severity: 2 pre-existing SC2015 info notes on untouched v1.9.1 lines
(A&&B||C in step_verify) — triaged, not refactored (spec rule 2); 1 new SC2154 false positive on
the EXIT trap (assignment inside the trap string) — targeted disable comment.
NOT yet live-validated — awaiting supervised GL-6
- The full appliance AND byo installs end-to-end (rc=0 transcripts blocked today by the demo-felhom git-creds gap below).
- The uninstall → re-provision drill under both modes.
- C7: the verify pool/ACL asserts firing on real drift (needs a deliberately-broken live box).
- The byo typed-hostname ack answered interactively (only its dry/preflight-only branches ran).
Observations (documented, not acted on)
- demo-felhom has EMPTY
git.username/git.tokenin its served controller.yaml — any step-5 (re)install for that customer dies until real Gitea read creds are set (operator; ties into the standing "scope down + rotate the package-WRITE git token" security follow-up). - felhom-pve's live install predates
_state_put— its state.json has onlycompleted(nocustomer_id/provisioned_vmid/mode); a future--uninstallthere needs an explicit--vmid, and §C.6 of the runbook covers the missing-mode resume. - A
--resumethat skips preflight never recordsmodeinto an old state file (it only writes during a full preflight) — harmless (C4 only fires when a mode IS recorded), noted for GL-6. - The live host-DNS line on felhom-pve shows the agent's own dnsmasq (lan_resolver is ON there — correct for an appliance; it is exactly what byo now refuses).