Files
felhom-agent/CONTEXT.md
T
admin 567cf9f401 docs: REPORT + CONTEXT for S4.1 (tier-aware deadline + teardown phantom confirmed)
Live diagnosis on the agent-token path: offsite restore-test pass:true,
verified:boot+running, teardown succeeded (no 403), scratch band clean. The
VM.Allocate follow-up was a PHANTOM — the earlier 403 was the 10m-timeout firing
teardown against a not-yet-pool-associated guest; with the timeout fixed the
guest is in /pool/felhom and teardown is authorized. No ACL/host-install change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
2026-07-04 19:54:46 +02:00

108 lines
9.5 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.
# CONTEXT — felhom-agent working state
> Snapshot of the current state + open threads. Authoritative history lives in `CHANGELOG.md` (top
> entry = current); the end-of-task detail lives in `REPORT.md`.
## Current
- **v0.68.0** (2026-07-04, live on felhom-pve) — **S4.1: unattended offsite restore-test**.
**Tier-aware restore-task deadline:** `RestoreTestSpec.RestoreTaskTimeout` (0→10m default) from
`config.RestoreTestPBSRestoreTimeoutSeconds` (accessor default **120m**), set only when
`SourceTier=="pbs"` (`main.restoreTaskTimeout`); local tier UNCHANGED. Fixes the WAN restore being
killed at 10m → mid-restore teardown → leaked scratch. **Teardown "VM.Allocate" follow-up =
PHANTOM (diagnosed, not blind-fixed):** ran the restore-test on the AGENT-TOKEN path sourcing the
offsite (pbs) backup → `pass:true verified:boot+running`, teardown succeeded (`torn down
vmid=990000`, no 403), scratch band clean. The earlier 403 was the 10m-timeout consequence (guest
not yet pool-associated); the scratch is restored INTO `/pool/felhom` (ACL already grants
VM.Allocate) so teardown is authorized once the restore completes. **No ACL/host-install change.**
OPEN: publish 0.68.0 + Day-0 vouch; Tier-1/Tier-2 split for offsite-as-default; S5 DR consume.
Rollback `felhom-agent.bak-0.67.0`. Detail: REPORT.md.
- **v0.66.0 + v0.67.0** (2026-07-04, live on felhom-pve) — **S4: PBS over the tunnel**. **v0.66.0**:
wgtunnel **v4-pin** (renderConf writes the resolved A LITERAL, never DNS/AAAA; `Resolver` seam,
lowest addr; cached → steady-state zero-DNS/zero-exec) + **re-resolve watchdog** (`Manager.Watchdog`,
loop-only; handshake stale > `stale_after_seconds`=180 → re-resolve → IP-changed re-render+restart)
+ FELHOM_WG **Critical** flips (conf-install/enable/restart/handshake-read). **v0.67.0**:
**namespace-aware PBS client** (Config.Namespace → `Snapshots ?ns=`, `Verify ns=`; root-ns
unchanged) — the operator-approved fix after Phase-1 showed the ns-unaware datastore-root 403s a
per-tenant token. **Live Scenario-D (all green):** real vzdump of 9201 → **ciphertext** in ns
`demo-felhom-01` over the tunnel; ns-scoped verify=ok under the box's own `felhom@pbs!demo-felhom-01`
token; WARN gone; restore round-tripped (decrypt with box-born key → boot → teardown).
**Confirmed tenant ACL (felhom-hetzner):** `DatastoreBackup` on `/datastore/felhom-offsite/<ns>`
(NOT `/ns/<ns>`) to BOTH user `felhom@pbs` AND token (privsep=intersection; cross-ns 403);
DatastoreBackup can't prune (safety). **FINDINGS:** retarget field is `local_backup_target` (not
`backup_target`); retarget REVERTED to `local` (controller backs up ~every 30 min → single-target
offsite = near-continuous 20-min uploads; needs Tier-1/Tier-2 split); restore-test scheduler needs
a WAN restore deadline + scratch-band `VM.Allocate` before it runs offsite unattended. **OPEN:**
escrow-create (OPERATOR-PRESENT, new R); publish 0.66/0.67 + Day-0 vouch; S5 DR consume. Rollback:
`felhom-agent.bak-0.65.0`/`.bak-0.66.0`. Detail: REPORT.md + doc-06 §3.4/§4.2 + runbook §4a/§4b.
- **v0.65.0** (2026-07-04, live on felhom-pve) — **S3.1 offsite-tunnel client MTU 1420 → 1280**:
resolves `06 §4.3`'s OPEN DECISION left by the CGNAT smoke test. 1420 **silently black-holed bulk
TCP** on sub-~1480 paths (mobile ~1400, DS-Lite ~1452) — handshake+ping healthy, PBS TLS page
(and at S4 the backup itself) drops. New `const clientMTU = 1280` (RFC 8200 IPv6-minimum floor;
outer 1340 v4 / 1360 v6 fits every realistic path), **permanent + fleet-wide + family-agnostic**.
**Client-only by construction** — interface MTU caps box→PBS, advertised MSS caps PBS→box, so the
endpoint's `wg0` is untouched (zero live-endpoint risk). Golden pins exact `MTU = 1280`
(red-proofed vs a 1420 flip); no wire/JSON change. Live: agent re-rendered on restart (hash-gated
apply), conf + live iface both 1280, PBS page loads at 1280 (no regression on wired). OPEN:
true-CGNAT-SIM retest (low risk); publish 0.65.0 + Day-0 vouch (operator); S4 PBS-over-tunnel.
Rollback: `felhom-agent.bak-0.64.0` on the box. The v4-pin (§4.2 determinism) is a separate,
optional future note — NOT needed for MTU correctness.
- **v0.64.0** (2026-07-04, live on felhom-pve) — **S3 offsite WG tunnel**: new `internal/wgtunnel`
(keygen 0600/0700, marker-gated one-shot registration, agent-managed `wg-quick@wg-felhom` from
the hub's desired-state `wireguard` block via the new `desired.Syncer.AddConsumer` seam,
revoked-stays-revoked teardown, report stanza) + `FELHOM_WG` sudoers/capabilities +
`IdentityBundle.WGPrivateKey` escrow auto-inject. **`wg_tunnel.enabled` DEFAULTS FALSE** (safety
gate — rollout to Peti's box is a no-op until the production endpoint exists; enabled explicitly
on felhom-pve only). Live: tunnel to ep0.felhom.eu:443 up 3 s after enable (PBS page through
10.77.0.1:8007), reboot-persistent, revocation drill clean, 30-min keepalive soak. GOTCHAS:
hub envelope poll_interval_seconds (hub-side const 900 s) silently overrides agent poll_seconds
on cycle 1; `wg show <if> dump` leaks the PRIVATE key (forbidden everywhere — sudoers only
grants `latest-handshakes`). OPEN: CGNAT/mobile-hotspot smoke (operator-assisted appendix);
publish 0.64.0 to Gitea + Day-0 vouch (operator); S4 points PBS at the tunnel.
- **configs: build-golden.sh v2.0.0** (2026-07-03, @ `ceca355`; no agent version change) — **drill
findings B5 + B1 FIXED** (`DRILL-golden-098-2026-07-03.md`): the controller tag is a MANDATORY
argument (the default rotted twice — a fresh install booted a pre-floor controller, forcing the
guide's manual D.1b update) and the golden now bakes a `felhom-controller-bootstrap.path` unit
(controller deploys the moment the back-half hot-plugs the bootstrap mount — no reboot; installer
v1.9.1's reboot is a redundant belt, kept). **Golden 0.98.3** baked on the drill VM, clean-room
validated (bake integrity → isolated hot-plug proof → local-golden Day-0 → published-artifact
Day-0), published (sha256 b9a02ef1…fd01) + operator-vouched — Day-0 manifest now vouches
**agent 0.63.0 + golden 0.98.3** (the v0.63.0 vouch follow-up below is DONE). Fresh installs land
current and self-manage. NEW operator follow-up (SECURITY): the customer-config `git.token` has
Gitea package-WRITE rights — scope down + rotate (evidence-doc observation O1).
- **v0.63.0** (2026-07-03, live on felhom-pve + Gitea-published sha256 b4a89c81…) — **drill findings
B3 + B2 FIXED** (`DRILL-day0-cleanroom-2026-07-03.md`): `TokenStore.Lookup` reloads the append-only
store once on a miss (cross-process coherence with the one-shot provisioner — no more fresh-install
`/controller/swap` 401 / manual restart; size short-circuit bounds the cost; behind the
`TokenAuthority` seam) + `guesthook.InstallSnippet` issues a fenced `mkdir -p /var/lib/vz/snippets`
first (fresh boxes lacked the dir → the self-heal hook silently never installed). Sudoers gained
exactly that one grant — **ship sudoers WITH the binary** (done on felhom-pve). Red-proofed both;
Scenario-E method: compiled test suite run ON felhom-pve + live channel-health hit-path.
**OPERATOR FOLLOW-UP: bump the hub Day-0 manifest to agent 0.63.0** — until then fresh installs get
0.62.0 and the guide's D.1b restart-first step still applies (narrowed to "< v0.63.0" in the guide).
- **v0.62.0** (2026-07-03) — **audit A1 RESOLVED**: the stale-lock reaper's scan is now
pool-intersected (`staleLockController.Guests()` = `ListLXC``Client.Pool("felhom")` members),
fail-safe skip on pool-read failure; `pve:pool-read` capability (non-critical) + `--selftest`
"pool read" line. Companion host-install **v1.9.0** adds `Pool.Audit` to `FelhomAgentGuest`
**deploy order on any box: rescope ACL first, then this agent.** Per
`SPIKE-a1-pool-membership-read-2026-07-03.md`; red-proofed tests in stalelock_pool_test.go.
- **2026-07-03 — CLAUDE.md refreshed**: version narrative removed (state lives HERE + CHANGELOG top), layout completed (all 17 internal packages + cmd/felhom-opsign); deploy runbook now in the `felhom-build-deploy` skill (`felhom.eu/skills/`).
- **2026-07-03 — `REUSE.md` exists at the repo root** (canonical helpers / format-safety guards / traps / seams, code-verified); maintenance rule active: update it in the same commit that changes a shared helper.
- **v0.61.0** (2026-07-03) — blast-radius audit fixes **B1 + D1 + D2 + D3** from
`felhom.eu/documentation/audits/AUDIT-blast-radius-hostroot-localapi-2026-07-02.md`: random temp
staging for root-installed scripts (+ sudoers/manifest glob updates), mkfs-wrapper member/RO
re-checks (validated by `scripts/mkfs-guarded-harness.sh`), classifyClaim empty-lsblk fail-safe,
and the blank-format anti-retarget (durable-id-bound, AGENT-001's benign-branch twin).
- Deployed on demo host `felhom-pve` (node `demo-felhom`), non-root `felhom-agent` service user,
pool-scoped token (`felhom` pool).
## Open threads
- Deferred audit items (housekeeping/design, all INFO): C1 (controller-swap version floor), C2 (NAS
server allowlist), A2 (gate journal cross-check), B2B5, E1/E2.
- Drive-enrollment leftovers: (a) `runStorageInit` slow-device detached-format polling; (b) Impl-3
shared-box operator format gate.
- BUNDLE leftover: non-root agent can't read the PBS key; migration must preserve cert/key/tokens.
- Not run (needs a supervised session): the destructive D1/D3 live proofs (real mkfs on a crafted
member; a live /dev re-enumeration race during a real format).