Files
felhom.eu/REPORT.md
T
admin 02d63ed070 GL-2: --mode appliance|byo install profile (host-install v1.10.0) + harness
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
2026-07-07 20:26:32 +02:00

94 lines
6.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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](hub/CHANGELOG.md); the scripts history lives in [scripts/CHANGELOG.md](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 13; see scripts/CHANGELOG.md for the feature list)
- `scripts/hostinstall-mode-harness.sh` — NEW (Part 4)
- `documentation/runbooks/day0-install.md``--mode` in every command, new §C.5 (byo command +
trust-model paragraph + preflight-only), §C.6 (pre-v1.10.0 resume note), 4 new troubleshooting rows
- `scripts/CHANGELOG.md`, `REUSE.md` (install-profile-gate pattern row), `CONTEXT.md`, this file
### Spec deviations / judgment calls (each verified against the real code)
1. **`--mode` collision:** v1.9.1 already used `--mode provision|dr`. Resolved: `appliance|byo` are
the only install values, `provision` retired with a specific die, the `dr` stub dispatch kept
verbatim (the documented 10D seam).
2. **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-from` config carries true, which is the intended refusal.
3. 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 string `4b/8` in the byo transcript
(an internal spec contradiction; the greppable invariant won).
4. `--preflight-only` skips 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.
5. `documentation/pilot/GO-LIVE-PACKAGE.md` is 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.token`** in 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 only `completed` (no
`customer_id`/`provisioned_vmid`/`mode`); a future `--uninstall` there needs an explicit `--vmid`,
and §C.6 of the runbook covers the missing-mode resume.
- A `--resume` that skips preflight never records `mode` into 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).