4fe895eaa4
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
109 lines
6.6 KiB
Markdown
109 lines
6.6 KiB
Markdown
# 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).
|
|
|
|
---
|
|
|
|
# REPORT — S2: box-facing WG registration + `wireguard` desired-state block + /offsite UI (2026-07-04)
|
|
|
|
Doc-06 roadmap row S2 shipped: hub v0.32.1 → **v0.33.0** live on k3s; peersync script v1.0.0 →
|
|
**v1.0.1** redeployed to the dev endpoint. The agent was NOT touched; the S3 contract travels
|
|
via the new golden only.
|
|
|
|
## 1. Baselines
|
|
|
|
Start: felhom.eu @ `740cc42` (hub v0.32.1, peersync v1.0.0), felhom-agent @ `4ba1b14` (v0.63.0,
|
|
read-only). Live baseline captured before validation: `demo-felhom-01` at generation **2**,
|
|
desired-state `{"guests":[]}`, WG registry empty, guest 9201 running (controller 0.98.3
|
|
healthy), agent v0.63.0, poll interval 900 s.
|
|
|
|
## 2. Files created/modified
|
|
|
|
- `hub/internal/store/store.go` (partial unique index `idx_wg_peers_host`; `BumpHostDesired`),
|
|
`hub/internal/store/wg.go` (+`allocateWGPeerTx` extraction, `RegisterWGPeerForHost`,
|
|
`GetWGPeerForHost`, `WGPeer.CreatedAt`), `wg_test.go` (Group A)
|
|
- `hub/internal/api/wg.go` (`handleRegisterHostWG`, `mergeWireguard`, delete-bumps-owner),
|
|
`handler.go` (routing case; merge call in `handleGetDesiredState`; `wireguard`-key rejection
|
|
in `handleAdminSetDesiredState`), `wg_test.go` (Group B), NEW
|
|
`testdata/desired-state-wireguard.golden.json` (**S3 cross-repo contract**)
|
|
- `hub/internal/web/offsite.go` + `templates/offsite.html` + `offsite_test.go` (Group C);
|
|
`server.go` routing; Offsite nav link in all 9 page templates
|
|
- `scripts/felhom-peersync.sh` v1.0.1 (exit-swallow fix)
|
|
- `manifests/hub.yaml` (image 0.33.0), `hub/CHANGELOG.md`, `scripts/CHANGELOG.md`,
|
|
`documentation/architecture/06-offsite-connectivity.md` (§3.2 concrete wire shape + S2 row
|
|
SHIPPED), `CONTEXT.md`, this REPORT
|
|
|
|
## 3. Commits (pushed to `main`)
|
|
|
|
1. `fcf84a0` store: host binding + index + BumpHostDesired
|
|
2. `ba52005` API: registration + merge-at-read + hub-owned-key guard + golden
|
|
3. `13203c2` web: /offsite page + nav
|
|
4. `30d762d` peersync v1.0.1; `99246c3` manifest 0.33.0 bump
|
|
5. `265f46c` docs (+ this hash-fix follow-up)
|
|
|
|
## 4. Tests + the five §10 red-proofs
|
|
|
|
`cd hub && go build ./... && go vet ./... && go test ./...` — all green (12 packages).
|
|
New: 6 store tests (Group A), 5 API tests (Group B), 2 web render tests (Group C).
|
|
`TestDesiredStateGolden_RoundTripsThroughHub` passes **UNMODIFIED**; the S1 suites pass
|
|
unmodified through the allocator extraction.
|
|
|
|
Red-proofs, each run → FAILED as required → reverted:
|
|
- (a) self-scope check dropped → `cross-host register = 200, want 403`
|
|
- (b) merge made unconditional → caught by the no-peer-serves-no-block assertion
|
|
(`GET serves a wireguard block that was never legitimately registered`); the golden test
|
|
itself survived only via the fail-safe unmerged path (endpoint record absent in its setup) —
|
|
the pass-through property is covered either way
|
|
- (c) `wireguard`-key rejection dropped → `PUT with wireguard key = 200, want 400`
|
|
- (d) bump-on-idempotent → both negatives fail (`gen=2 want 1`, `push count 2 want 1`)
|
|
- (e) script exit-swallow (sandbox, stub `wg-quick` exit-1-after-partial + recording stub `wg`):
|
|
pre-fix shape invoked `wg` with rc=0 despite the strip failure; fixed shape errors first,
|
|
`wg` never invoked
|
|
|
|
## 5. Deploy + live validation (real pipeline, secrets redacted)
|
|
|
|
- hub 0.33.0 rolled out via ArgoCD (`deployment "hub" successfully rolled out`, image
|
|
`felhom-hub:0.33.0`, `[INFO] WG peer-sync enabled`); peersync v1.0.1 on the endpoint
|
|
(`head` shows the v1.0.1 header), shellcheck-clean on 180.
|
|
- **Registration through the REAL per-host auth path** (curl run ON felhom-pve; its key never
|
|
left the box; throwaway keypair minted + private key shredded unused):
|
|
`{"assigned_ip":"10.77.0.2/32","existed":false,"generation":3,"sync":"ok"}` — gen 2→3.
|
|
- Served desired-state carried exactly the golden-shaped block (endpoint coords + pubkey +
|
|
assigned_ip) alongside the untouched `guests` key; endpoint `wg show wg0` listed the pubkey
|
|
with `10.77.0.2/32`.
|
|
- **Old-agent tolerance (the S3 fleet-safety gate), verbatim journal:**
|
|
`time=2026-07-04T01:04:29.267+02:00 level=INFO msg="desired: updated from hub" generation=3 guests=0`
|
|
— the v0.63.0 typed parse dropped the unknown key; guest count unchanged; NO error/warn from
|
|
the desired/reconcile path (the only WARN in the window is the pre-existing, documented
|
|
`pbs: cannot read token secret` non-root permission issue — unrelated to S2).
|
|
Guest-state re-capture = byte-identical to baseline (9201 running, controller 0.98.3 healthy).
|
|
- **Removal:** DELETE → `{"status":"ok","sync":"ok"}` → generation 4; desired-state back to the
|
|
pure operator blob (`{"guests":[]}`, no wireguard key); registry `{"peers":[]}`; endpoint
|
|
`wg show` 0 peers. Gen-4 clean fetch by the agent, verbatim:
|
|
`time=2026-07-04T01:19:29.228+02:00 level=INFO msg="desired: updated from hub" generation=4 guests=0`
|
|
— no errors; the box is fully back to baseline except the two expected generation increments.
|
|
- `/offsite` route wired + auth-gated live (302 → /login); page rendering proven by Group C
|
|
unit tests — the live view is operator-password-gated (eyeball on next login).
|
|
|
|
**Generation accounting for demo-felhom-01:** baseline 2 → 3 (registration) → 4 (removal) —
|
|
exactly the two expected increments; desired_json blob never modified (byte-identity asserted
|
|
in tests; live blob returned to the identical `{"guests":[]}`).
|
|
|
|
## 6. NOT yet live-validated — awaiting S3+
|
|
|
|
- Agent keygen/registration/`wg-felhom` service + IdentityBundle escrow join + CGNAT/mobile
|
|
smoke (**S3**, risky/supervised).
|
|
- A real PBS backup over the tunnel into a namespace (**S4**).
|
|
- DR re-establishment consuming the escrowed WG key (**S5**).
|
|
- UI mutations + tunnel-health columns (**S3/S6**).
|
|
|
|
## 7. Observations (noticed, not acted on)
|
|
|
|
- The agent's 900 s poll makes desired-state validation slow-loop (two ≤16-min waits in this
|
|
run) — S3 test plans should budget for it or temporarily shorten the interval on the test box.
|
|
- `hub-config`'s `report_api_key` doubles as the only global admin key; a scoped operator token
|
|
would narrow the blast radius of the endpoint-mutation surface (pre-existing, S6-adjacent).
|
|
- The pre-existing `pbs: cannot read token secret` WARN on felhom-pve (non-root agent vs
|
|
`/etc/pve/priv/storage/felhom-pbs.pw`) fires every cycle — known BUNDLE-slice issue, gets
|
|
resolved naturally when S4 points PBS at the tunnel with per-customer tokens.
|