# Felhom scripts — Changelog ## felhom-host-install.sh v1.1.0 — self-install the agent + fetch the golden from Gitea (2026-06-28) The script now **installs the agent itself** (the last big manual Day-0 prerequisite is gone). It fetches the agent binary + golden from Gitea generic packages and **verifies each against the hub-vouched artifact manifest** before installing/using it. BUNDLE slice; pairs with hub v0.16.0 (artifact manifest endpoint + operator UI) and felhom-agent v0.43.0 (canonical unit + publish). - **New step `5/8 agent install`** (before agent-config): resolves the manifest (`GET /api/v1/artifacts/{id}`, passphrase) + the git fetch token (from the customer's `controller.yaml` via config-retrieve — **NO new credential**); fetches `/api/packages/admin/generic/felhom-agent//felhom-agent`, **verifies sha256 vs the hub manifest** (aborts on mismatch — verify-before-use), backs up any existing binary, installs `0755 /usr/local/bin/felhom-agent`; ensures the non-root `felhom-agent` system user; installs the canonical sudoers (`0440`, `visudo -cf`-validated) + systemd unit; `daemon-reload` + enable. Idempotent: same version already installed + service active → skip. - **New step `7/8 golden`:** local auto-discovery stays the default/fallback; otherwise fetches `/api/packages/admin/generic/felhom-golden//golden.tar.zst`, **verifies sha256**, and imports it into the archive storage's dump dir for the restore. `--force-gitea-golden` forces the Gitea path. - **Non-root agent model:** the agent now runs as `felhom-agent` with `privileged.mode: "sudo"` (was the dev/CI `direct`+root shortcut). The config is `chown`ed to the service user (0600) so the daemon can read it; `systemctl is-active` after restart is the real proof the non-root user can read the config. - **Pre-flight relaxed:** a missing agent binary is no longer fatal (step 5 installs it); the local golden requirement is deferred to step 7. - **Trust model:** checksum **trust root = the hub** (manifest), not Gitea; the fetch credential is the existing config-retrieve git token; artifacts are pinned to a version (never `:latest`). - **Secrets:** the git token is a never-logged runtime carrier (cleared on EXIT alongside the passphrase / pve-token / hub api_key); the sudoers is `0440` and `visudo -cf`-validated before install. - `bash -n` + `shellcheck` clean. ## felhom-host-install.sh v1.0.0 — Day-0 host bootstrap (provision mode) (2026-06-26) First release. A single operator-run script that automates Day-0 on a freshly-PVE-installed host: Proxmox API token → hub host enrollment (option C, single secret) → agent config → guest provision → verify. Composes proven mechanisms (the `pveum` role/token sequence, hub `POST /host-enroll`, `felhom-agent --selftest=provision`); grounded by `documentation/audits/SPIKE-day0-firstboot-handshake-2026-06-26.md`. - **7 steps, idempotent + resumable** via `/var/lib/felhom-install/state.json`: pre-flight → Proxmox token → compute grows → host-enroll → agent config → provision → verify. - **Single-secret** (the retrieval passphrase): read no-echo or from a 0600 file, never on argv/logs/state. The global operator key never touches the box. - **pveum automation:** 16-priv `FelhomAgent` role (create-or-modify), `felhom-agent@pve` user, privsep token (reuse-if-working else rotate), and **both** ACL grants applied **after** the token exists (token-remove purges the token ACL). - **Auto-discovery:** golden archive (newest `vzdump-lxc-`), PVE node name, vmbr0 bridge IP for the local-api, and the served-leaf TLS fingerprint pin. - **Safety:** pre-flight fails fast (root, PVE 9.x, local-lvm headroom, hub reachable, customer+passphrase valid via read-only `GET /config/{id}`, golden resolvable); refuses to clobber an existing `--vmid` without `--force`; `--dry-run` previews every mutation; `--preserve-from` keeps operator infra (PBS/local_api/privileged/authz) on re-deploys. - **`--mode dr`:** documented 10D stub (restore customer PBS snapshot instead of golden) — not implemented. - **Live-validated** end-to-end on `felhom-pve`: authorized wipe of demo guest 9201 → re-provision from the golden → controller config-pull + public tunnel `HTTP 200` → host-report of guest 9201 → idempotent `--resume` no-op. (One ordering bug — token ACL applied before rotation — was found and fixed during the live run.)