From 639a57ee8b78c980981ec95d9c08eb5e7bc1e827 Mon Sep 17 00:00:00 2001 From: kisfenyo Date: Fri, 3 Jul 2026 13:26:26 +0200 Subject: [PATCH] =?UTF-8?q?felhom-host-install.sh=20v1.9.0=20=E2=80=94=20P?= =?UTF-8?q?ool.Audit=20in=20FelhomAgentGuest=20(audit=20A1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Companion to felhom-agent v0.62.0: the stale-lock reaper reads GET /pools/felhom as its ownership registry. Pool.Allocate does NOT satisfy the read (spike T2). Idempotent upgrade via --rescope-acl (_ensure_role modifies to the exact set). Rescope FIRST, agent second. + REUSE §2 errata: gitea-creds is NOT out-of-band (committed in felhom.secret.yaml, live-consumed — rotation pending). Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6 --- CONTEXT.md | 13 ++++++------- REUSE.md | 4 ++-- scripts/CHANGELOG.md | 12 ++++++++++++ scripts/felhom-host-install.sh | 8 ++++++-- 4 files changed, 26 insertions(+), 11 deletions(-) diff --git a/CONTEXT.md b/CONTEXT.md index 884299b..2fef0b1 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -3,13 +3,12 @@ > Created with the REUSE.md rollout (2026-07-03). Authoritative history: `hub/CHANGELOG.md` (hub), > `website/CHANGELOG.md`, `scripts/CHANGELOG.md`; end-of-task detail in `REPORT.md`. -- **2026-07-03 — SPIKE A1 (pool-membership read) COMPLETE** — - `documentation/audits/SPIKE-a1-pool-membership-read-2026-07-03.md`. **The A1 impl spec is now - unblocked** and must cite it: winner = `Pool.Audit` added to `FelhomAgentGuest` - (`felhom-host-install.sh` L183) + `GET /pools/felhom` cross-check in - `staleLockController.Guests()` (fail-safe skip). Enumeration proven pool-filtered under the - production token; fix is defense-in-depth for the broad-token precondition. Appendix: operator - follow-up to rotate + de-git the 3 committed secrets in `manifests/felhom.secret.yaml`. +- **2026-07-03 — A1 CLOSED (host-install v1.9.0 + agent v0.62.0)** — `Pool.Audit` added to + `FelhomAgentGuest`; the agent's stale-lock reaper now intersects its scan with + `GET /pools/felhom` membership (fail-safe skip on read failure). Spike: + `documentation/audits/SPIKE-a1-pool-membership-read-2026-07-03.md`. Deploy order on any box: + rescope ACL first, then the agent. STILL PENDING (operator): rotate + de-git the 3 committed + secrets in `manifests/felhom.secret.yaml` (spike appendix; REUSE §2 errata added). - **2026-07-03 — hub v0.31.0 LIVE** (critical-severity ingest fix + UI badges; ArgoCD Synced/Healthy; live probe: critical event stored + operator email delivered). - **2026-07-03 — Felhom skills exist**: `skills/{felhom-build-deploy,felhom-ui-design,felhom-testing}`, diff --git a/REUSE.md b/REUSE.md index 60e47f9..ece574e 100644 --- a/REUSE.md +++ b/REUSE.md @@ -99,7 +99,7 @@ | Gate script | scripts/site_gates.py | Byte-level mechanical gates (BOM, emoji codepoint ranges, nav/footer diff, analytics, banned tokens, cache-bust); run `python scripts/site_gates.py` after ANY website change; non-zero exit on failure. | | Fetch-validate-install (shell) | scripts/felhom-host-install.sh `step_agent_install` (~L1108) | `fetch_raw` to mktemp → syntax-check (`bash -n`) → `install -m0755 -o root -g root` → only then activate; guarded-mkfs wrapper installed BEFORE the sudoers that references it (ordering is the safety property). All mutations through `run()` (dry-run aware). | | Website deploy (manifest) | manifests/webpage.yaml | git-sync sidecar (sparse-checkout `/website/` + `/scripts/`, `--link=current`) + init container waits for first sync; nginx serves `current/website`; push to main = deployed, no image build. | -| Secret handling (manifest) | manifests/hub.yaml (env, ~L142) | Secrets via `secretKeyRef` to OUT-OF-BAND secrets (`resend-api`, `gitea-creds`) created per documentation/runbooks/secrets.md — never inline stringData (see §3). | +| Secret handling (manifest) | manifests/hub.yaml (env, ~L142) | Secrets via `secretKeyRef` to OUT-OF-BAND secrets created per documentation/runbooks/secrets.md — never inline stringData (see §3). ERRATA (2026-07-03): only `resend-api` is truly out-of-band today; `gitea-creds` is COMMITTED in manifests/felhom.secret.yaml AND live-consumed by hub.yaml — rotation + de-git is a pending operator task (spike SPIKE-a1 appendix). | | Hub deploy (GitOps) | manifests/hub.yaml `image:` (~L129) | Pinned explicit tag, bumped in git, deliberate ArgoCD sync (auto-sync OFF). Code push alone deploys nothing. | ## 3. Dangerous lookalikes — do NOT reuse @@ -109,7 +109,7 @@ | `(*Handler).handleNotify` + `formatNotificationEmail` + `sendResendEmail` (hub/internal/api/handler.go ~L1289/1624/1589) | Legacy pre-dispatcher notification trio: no cooldowns, no operator channel, no allowedEventTypes gate, duplicate Hungarian formatter. Controller path is FROZEN until slice-10 cutover. | `POST /api/v1/event` → `Dispatcher.ProcessEvent` + `notify.Format*Email` | | Severity `"critical"` POSTed to a PRE-v0.31.0 hub | Fixed in hub v0.31.0 (`handleEvent` now accepts critical). Older hubs coerce `critical` → `"info"`, which never notifies — silent alert loss. Case-variants (`"Critical"`) still coerce on every version. | Against an old hub send `warning`/`error`; otherwise lowercase `critical` is safe | | `compareVersions` for anything security-ish (hub/internal/web/server.go ~L571) | Returns 0 (equal) on unparseable input — a garbage version passes a floor check. `gitea.compareSemver` behaves differently (lexical fallback). | Validate input with `normalizeFloorInput` first; then compareVersions is safe | -| Inline `stringData` secrets à la manifests/felhom.secret.yaml | Commits real credentials to git (healthchecks superuser pw, umami APP_SECRET/POSTGRES_PASSWORD still live there). | Out-of-band `kubectl create secret` + `secretKeyRef` (hub.yaml resend-api pattern; runbook documentation/runbooks/secrets.md) | +| Inline `stringData` secrets à la manifests/felhom.secret.yaml | Commits real credentials to git (healthchecks superuser pw, umami APP_SECRET/POSTGRES_PASSWORD, gitea-creds admin password still live there). | Out-of-band `kubectl create secret` + `secretKeyRef` (hub.yaml resend-api pattern; runbook documentation/runbooks/secrets.md) | | `kubectl apply` / `kubectl set image` on manifests/ | ArgoCD app `felhom` reverts drift on next sync; live state lies about git. | Edit manifest in git → push → ArgoCD sync (CLAUDE.md steps 3–5) | | `:latest` image tag in manifests | Re-push doesn't change the manifest → no redeploy; Synced/Rollback misreport. | Pinned version tag, bumped per deploy | | grep/regex hunting emoji in website HTML | Windows grep false-negatives multibyte emoji (proven in D0). | `python scripts/site_gates.py` (codepoint-range check) | diff --git a/scripts/CHANGELOG.md b/scripts/CHANGELOG.md index fdf30ca..d734837 100644 --- a/scripts/CHANGELOG.md +++ b/scripts/CHANGELOG.md @@ -1,5 +1,17 @@ # Felhom scripts — Changelog +## felhom-host-install.sh v1.9.0 — Pool.Audit for the stale-lock reaper (A1) (2026-07-03) + +Companion to felhom-agent v0.62.0 (audit A1: pool-membership ownership check). `PVE_PRIVS_GUEST` +gains **`Pool.Audit`** (12 → 13 privs, granted at `/pool/felhom` via the existing FelhomAgentGuest +role) so the agent can read `GET /pools/felhom` — its stale-lock reaper's ownership registry. +`Pool.Allocate` does NOT satisfy the read (spike SPIKE-a1-pool-membership-read-2026-07-03 T2). +No structural change: `_ensure_role` already `role modify`s to the exact priv set, so re-running +`--rescope-acl` (or a fresh install) upgrades an existing box idempotently; `remove_scoped_acl` +deletes by role name and needs nothing. **Deploy order on a live box: rescope FIRST, then deploy +agent v0.62.0** — the added read priv is harmless to an older agent, while the new agent on an old +ACL fail-safes its reaper (skips) and reports `pve:pool-read` degraded until the rescope lands. + ## docs — SPIKE: A1 pool-membership read for the stale-lock reaper (2026-07-03) Findings doc `documentation/audits/SPIKE-a1-pool-membership-read-2026-07-03.md`. Live-probed on diff --git a/scripts/felhom-host-install.sh b/scripts/felhom-host-install.sh index 6e3dad9..f96cbbf 100644 --- a/scripts/felhom-host-install.sh +++ b/scripts/felhom-host-install.sh @@ -104,7 +104,7 @@ set -euo pipefail -SCRIPT_VERSION="1.8.0" +SCRIPT_VERSION="1.9.0" #------------------------------------------------------------------------------- # Logging (mirrors felhom-controller/scripts/docker-setup.sh) @@ -177,10 +177,14 @@ PVE_ROLE="FelhomAgent" # the PRE-3b single broad role (removed on rescope/unin # dynamically-enrolled removable drives (felhom-usb/felhom-flash) it observes but never registers — a # per-storage Audit grant hid them → false "drive detached" alerts. Audit is read-only, so box-wide Audit # keeps WRITE containment (Allocate/AllocateSpace stay per-storage). Only Sys.Audit/SDN.Use/Datastore.Audit box-wide. +# `Pool.Audit` (v1.9.0, audit A1): the agent's stale-lock reaper reads GET /pools/felhom as its +# ownership registry (agent v0.62.0+); without it the reaper fail-safes (skips) and reports the +# `pve:pool-read` capability degraded. NOTE: Pool.Allocate does NOT satisfy the read — the spike +# (SPIKE-a1-pool-membership-read-2026-07-03 T2) 403'd with Allocate granted; Audit is required. PVE_ROLE_GUEST="FelhomAgentGuest" PVE_ROLE_STORE="FelhomAgentStore" PVE_ROLE_BASE="FelhomAgentBase" -PVE_PRIVS_GUEST="VM.Allocate VM.Audit VM.Config.Disk VM.Config.CPU VM.Config.Memory VM.Config.Network VM.Config.Options VM.PowerMgmt VM.Snapshot VM.Snapshot.Rollback VM.Backup Pool.Allocate" +PVE_PRIVS_GUEST="VM.Allocate VM.Audit VM.Config.Disk VM.Config.CPU VM.Config.Memory VM.Config.Network VM.Config.Options VM.PowerMgmt VM.Snapshot VM.Snapshot.Rollback VM.Backup Pool.Allocate Pool.Audit" PVE_PRIVS_STORE="Datastore.Allocate Datastore.AllocateSpace" PVE_PRIVS_BASE="Sys.Audit SDN.Use Datastore.Audit" # Storages the agent reads/writes (archive+dump=local, restore=local-lvm, offsite DR=felhom-pbs). The