gates / gates (push) Successful in 8m49s
Closed R-971, R-954, R-1124, R-1012 (174 -> 175 rows); opened R-1139..R-1143; R-895 READY with the design and hub slice 1; R-972 waits on the vouch. [DESIGN] "The catalog allow-list" in 02; the catalog trust line in 01; FELHOM_THINCHECK and unit-forget in 03. Evidence audits/agent-allowlist-rotation-2026-10-17/. Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
12 KiB
12 KiB
REPORT — agent 0.159.1, the catalog allow-list (D2 = A), break-glass rotation (D1 = A), off-site history check (2026-10-17)
Written in ASD-STE100 Simplified Technical English. Evidence: documentation/audits/agent-allowlist-rotation-2026-10-17/
(P1 agent, P2 allow-list, P3 rotation, P4 off-site design, P5 release). Architecture read: 03-host-agent.md,
02-controller-module-map.md, 01-topology-and-trust.md, 07-backup-architecture.md, 06-offsite-connectivity.md,
09-update-architecture.md §3 decision 250, runbooks/break-glass.md.
For the operator — plain words first
Decisions I took myself: none.
- Agent 0.159.1 (0.159.0 is superseded — do not vouch it). New Go. A drive that was decommissioned and then removed is now forgotten: its host mount unit goes away within 20 seconds, so the host no longer waits for it. Before a whole-box backup, and when one fails, the agent checks the thin pool for an orphan snapshot and says so in the failure mail; it never deletes one (the repair is a runbook for you). All of it proven on demo-hp. It runs on demo-hp, Tester 1 and demo-felhom. Your vouch in the hub is still open (the hub names 0.158.1 at 17:58).
- The app list cannot give an app dangerous rights any more (controller 0.328.0, the floor for every box since 17:22 local). Before the box writes any app's settings it checks for dangerous rights. Only homepage's read-only Docker socket is allowed, and only for homepage's own image and start. A refused change writes nothing, the app keeps running, you get a mail, and the app page says one line. Proven on demo-hp 9201 with a test catalog. Three security reviews found eight gaps in the first versions; all eight were fixed before the release.
- New emergency root passwords on demo-hp, Tester 1 and demo-felhom (random, your answer). Each new password works; each old one is refused. Read them in the hub. Tester 2 is off: it gets its new password when it comes back.
- Off-site history: the hub can count a box's off-site copies itself, with the login it already has. Hub 0.157.0 (deployed on your yes) logs that count every morning at 07:10. The alarm on it is the next step.
What needs you:
- Vouch agent 0.159.1 in the hub — all three test hosts already run it; without the vouch a NEW box installs 0.158.1.
- Decide R-1140: keep the hub's access logs for 90 days. Pick A (a small hub-only log, recommended) or B (longer logs for every container on DooPlex). If you do nothing: the next „did anyone use the key?" question has only about 13 hours of logs again.
1. Agent (Part 1)
- Content: Go 1.27.2 + x/crypto v0.58.0 (R-972); R-1124
ForgetRetiredDrives+ root verbfelhom-priv-apply unit-forget; R-1012 read-only root helperfelhom-thin-check+internal/thincheck+BackupRunner.SetThinCheck; 0.159.1: the signed decommission prunes the guest-bind record (found by 0.159.0's own proof). Releases: 0.159.0 (3cfd0a25…, bundle40663c4f…), step bundle0.159.0-step1(1d65edb3…), 0.159.1 (de8f6ad9…aff9, bundle2af3d27d…7cd6). - demo-hp proof (normal delivery: signed
agent_update→ step bundle → release bundle, 75/75 capabilities):- R-1124: a loop-backed test drive on
/mnt/hdd_1enrolled through the agent's local API (the controller's calls); the customer decommission refused it (a loop device reads as „system" — correct), so the operator-signed decommission was used; while present the unit stayed; after the unplug the agent removed the unit and its wants link in 8 s andGET /disksdropped it (5 → 4 rows). On 0.159.1 a second signed decommission pruned the bind record; the 20-second warning stopped (0 lines after, the reconcile tick still running — 3 lines, the control). - R-1012: on a scratch thin pool (loop file on
/mnt/hdd_1, neverpve/data) the helper listed a made orphan (device 7) and refused a metadata snapshot held by someone else; onpve/datait read ids 1, 2 = LVM's and released. A household-press whole-guest backup of 9201 ran the check first (the sudo line) and finished green (6.77 GB). Note on the fence „never write into pve/data": reading a live pool needs a metadata snapshot (reserve_metadata_snap/release_metadata_snap); it changes no data and no mapping. This is what the product now does before every snapshot backup — if you want that stopped, say so (one line in the agent). - Scratch pool, loop devices, test image files, the test drive's folders: removed. One residue kept: the drive's
decommissionedintent line on demo-hp (harmless by design).
- R-1124: a loop-backed test drive on
- Vouch: the operator said yes (STOP, ~17:00). Delivered on that yes by signed jobs: Tester 1 (agent 17:39:31, bundle 17:53:42, 75/75) and demo-felhom (agent 17:40:51, bundle 17:55:00, 75/75), each through the step bundle; the hub has reports from both after. The vouch itself (Configs → Day-0 artifacts) is not done yet — new installs still take 0.158.1 until it is. Tester 2: off; it takes 0.159.1 when it is back (signed jobs, as above).
2. The catalog allow-list (Part 2, R-971 — closed)
- Survey (
P2/survey.md): 123 files (65 templates, 58 ladder steps). The only class member: homepage's read-only Docker socket. That is the whole list. - Built:
felhom-controller internal/privpolicyon the RENDERED compose; wired into every compose writer and env decision point; structural guardTestAllowList_IsWiredIntoEveryComposeWriter(AST). Refusal → nothing written, operator eventapp_definition_refused(hub ≥ 0.157.0), app-page line, plain message on install/settings/restore. The sync never copies a template named like a controller infra stack. Catalog mirror:check-privileges.py(stdlib, in--fast, decoys; the reader equals PyYAML on all 123 files); the two lists are byte-identical, pinned from both sides (boring choice: two copies + one equality check, no network in CI). - Security reviews (three rounds, eight findings, all fixed and red-proved before the release): the entry bound to
its image, entrypoint/command and exact healthcheck; symlinks out of a root (nearest existing ancestor, fail closed);
missed classes (cgroup_parent, runtime, isolation, gpus, device reservations, provider, lifecycle hooks); roots only
under
/mnt/felhom-drives/or the system data path; anyextendsrefused; no variable in a bind's options; YAML anchors refused by the catalog reader; under${HDD_PATH}onlyappdata/(notbackups/). - Live finding on 9201 with rc.4: every not-installed app was refused (placeholder roots do not exist on the box, so the root itself could not be resolved). Fixed in rc.5 (roots resolved through their nearest existing ancestor; no symlink resolve for the placeholder check), red-proved. Its 30 events were dropped by the old hub — no false mail.
- 9201 proof (rc.5, hub 0.157.0): a drill catalog = live +
privileged: trueon privatebin → refused; the compose sha79e7877d…unchanged; the same privatebin container (494270e4…, started 14:34:24Z) still running; the event at the hub at 17:10:34 and an operator mail; the page line on privatebin, not on opengist (control). Restored: live catalog, controller.yaml byte-identical, the drill mirror removed, the drill repo back to the live tree. - Every installed app on the three test boxes still passes: 0 refusals after 0.328.0 started (P5/box-walk.txt).
3. Break-glass rotation (Part 3, R-954 — closed)
| host | how | proof |
|---|---|---|
| demo-hp | installer step 4b ALONE (installer-v1.33.0's own function) |
new value → PVE API 200; old → 401; values differ |
| Tester 1 | the same | the same |
| demo-felhom | the same, on your answer (random) | the same; hub set_at now 2026-10-17T15:10:04Z |
| Tester 2 | offline since 2026-10-04 | R-1139 |
- Why not the full installer re-run (the brief's
--rotate-recovery): it also reinstalls the vouched agent and the root files — on demo-hp it would have moved the candidate agent back. R-1141 asks for a standalone mode. - Found and fixed: the hub kept the FIRST vault's
set_at(demo-hp/Tester 1 still read their old dates, rotated before the fix; demo-felhom shows the new one) — hub v0.157.0. - The passwords were read with the global-key curl (P3/
cred.py, prints only length and time): that path writes NO customer-visible „revealed" line. Nothing was printed or filed. - Log retention: ingress logs cover ≈ 13 h (k3s 10 MiB × 5). Not built: it needs a DooPlex or hub-storage change → R-1140 (cost in the row).
4. Off-site history (Part 4, R-895 — open, READY)
- Measurement: the login the hub already holds (the sealed sub-account password, write-capable) lists the folder; upload times are shown (2026-09-01 evidence on demo-hp's own sub-account). A fresh listing from DooPlex was NOT made: tried the CC store (no Storage Box credential), the box's key (restic REST only, names and sizes, and it is the box's key), the hub (no endpoint); reading the sealed password out of the hub was not done.
- Design:
P4/design-R-895.md— before/after counts from the hub's own listing, files no box run explains, snapshots gone outside a window; a read-only sub-account as the stricter alternative. - Built (slice 1, ~1 h, no new credential): hub v0.157.0 lists
snapshots/in the 07:10 key audit and logs the count, newest and oldest time. Deployed on your yes (17:03, Synced/Healthy, reports from demo-hp and Tester 1, floor read 0.328.0).
5. Versions, commits, fixtures
- felhom-agent:
e15d1d3(code),v0.159.0tag,4a1c07b-line (prune),v0.159.1tag, CHANGELOG…. CI green (job 2025). - felhom-controller:
6d90374,24d937d,36c4aa4,09ac87a,99f9117→ v0.328.0 (rc.1–rc.5 tested on 9201), MinAgent 0.158.1. Global floor 0.328.0 / 0.158.1 at ~17:22 local; per-box floors set and cleared. CI green (job 2032). i18n fixture: newapp_settings_definition_refused; every other fixture byte-identical. - app-catalog-felhom.eu:
d5a443d(gate) + three follow-ups; CI green (job 2033). - felhom.eu:
8f97b800(hub v0.157.0 code, installer uninstall line, runbook),d968f849(hub deploy); docs and register in the final commit.
6. Rows
Before 174, after 175. Closed (4): R-971, R-954, R-1124, R-1012. Opened (5): R-1139, R-1140, R-1141, R-1142, R-1143. Updated: R-895 (READY with the design), R-972.
7. Observations
- Agent v0.159.0's signed decommission left a guest-bind record → a warning every 20 s. NOT-A-FINDING: fixed in the session (agent v0.159.1, the size rule), red-proved.
- Hub kept the first vault's
set_at. NOT-A-FINDING: fixed in the session (hub v0.157.0, the size rule), red-proved. - A full installer re-run is the only
--rotate-recoverypath. FILED: R-1141. - Ingress access logs ≈ 13 h. FILED: R-1140.
- One app can bind another app's
appdata/<name>. FILED: R-1142. - Controller
build.shpushes:lateston every build, rc included. FILED: R-1143. - The first allow-list rc refused every not-installed app on the box. NOT-A-FINDING: found by this session's own live proof on 9201 and fixed before the release (rc.5, red-proved).
- homepage keeps a read-only Docker socket on the list; a read-only mount does not limit the Docker API. NOT-A-FINDING: already R-782's subject (homepage's exposure); the list keeps today's behaviour, it does not bless it.
- Tester 1's ISO-era
--rotate-recoverywarning text („the old one now fails at the PVE web GUI") is printed by the step itself. NOT-A-FINDING: true and intended.
8. Teardown (three layers)
- Machine: demo-hp — scratch VG/pool/loop removed, test image files removed, test drive folders removed; 9201 back on the live catalog (controller.yaml byte-identical), drill mirror removed. Tester 1, demo-felhom: only the releases and the password rotation.
- Host: demo-hp, Tester 1, demo-felhom run controller 0.328.0; demo-hp, Tester 1 and demo-felhom run agent 0.159.1 (bundle 0.159.1).
- Hub: hub 0.157.0; global floor 0.328.0; no per-box floor; signed jobs consumed. Instruction files: none edited. System poster: no fact changed (none of the three).