docs: S1 shipped — hub v0.32.0/0.32.1 CHANGELOG, peersync v1.0.0, 06 S1 status, CONTEXT, REPORT
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
This commit is contained in:
@@ -1,5 +1,44 @@
|
||||
# Felhom Hub — Changelog
|
||||
|
||||
## v0.32.0 + v0.32.1 — S1 offsite connectivity: WG endpoint record + peer registry + pinned-SSH peer-sync (2026-07-04)
|
||||
|
||||
The hub side of doc 06's roadmap row S1 (`documentation/architecture/06-offsite-connectivity.md`),
|
||||
resolving the slice-1 design point: **peer-sync = hub pushes over SSH** to a forced-command
|
||||
reconcile script on the endpoint (pull/signed-manifest rejected — weakens immediate revocation;
|
||||
HTTPS push API rejected — a new versioned binary + third public port for nothing).
|
||||
|
||||
- **Store** (`internal/store/wg.go` + migration in `store.go`, commit `b18f6ae`): `wg_endpoints`
|
||||
(single expected row "ep0") + `wg_peers` (presence = desired state; no status column — that's
|
||||
the S2 host-join). `AddWGPeer` = one tx, idempotent on pubkey, lowest-free-host `/32` allocation
|
||||
skipping network/`pbs_tunnel_ip`/broadcast, `UNIQUE(assigned_ip)` race backstop + one internal
|
||||
retry; typed `ErrWGEndpointUnset`/`ErrWGSubnetExhausted`.
|
||||
- **wgsync** (`internal/wgsync/`, commits `fbeeacb` + `0fa7ea1`): `x/crypto/ssh` push client with
|
||||
`ssh.FixedHostKey` pin (no insecure fallback, ever) **+ `HostKeyAlgorithms` constrained to the
|
||||
pinned key's type** — the live validation caught a stock multi-hostkey sshd presenting ECDSA
|
||||
against the ed25519 pin (legitimate server refused); regression-tested with an in-process
|
||||
dual-hostkey SSH server. Reconciler pushes the FULL peer list (never deltas — drift repair by
|
||||
construction) on `Trigger()` or a 5-min tick; payload
|
||||
`{"version":1,"interface":"wg0","peers":[{pubkey, allowed_ip}]}`, deterministic order.
|
||||
- **API** (`internal/api/wg.go`): `PUT/GET /admin/wg/endpoint`, `POST/DELETE/GET /admin/wg/peers`
|
||||
— GLOBAL key only (the `handleAdminSetDesiredState` gate); pubkey validated 44-b64/32-byte;
|
||||
**DELETE takes the pubkey in the JSON body** (base64 `/`+`+` keep pubkeys out of URL paths);
|
||||
mutation responses carry `sync: ok | deferred: <err> | disabled` — the DB is the source of
|
||||
truth, a failed push defers to the reconciler.
|
||||
- **Wiring** (`cmd/hub/main.go`): `WG_ENDPOINT_SSH_{ADDR,USER,KEY_FILE,HOSTKEY}` env (key from
|
||||
the mounted `Secret/wg-endpoint-ssh`, host key non-secret plain env); any piece missing →
|
||||
`[INFO] WG peer-sync disabled` and mutations still work DB-only.
|
||||
- **Tests:** allocator (exact IPs, freed-IP reuse, /30 exhaustion), API auth/validation with a
|
||||
fake syncer, SSH client against an in-process server (exact payload bytes, stderr surfacing,
|
||||
wrong-host-key refusal, multi-hostkey pin), reconciler (full-list, retry-on-tick, no-mutation
|
||||
drift push, removed-peer-absent negative). Four red-proofs run and reverted (allocator-ignores-
|
||||
rows, gate removal, InsecureIgnoreHostKey, delta-only push) — each failed its test.
|
||||
- **Live-validated** end-to-end on the dev endpoint (`felhom-hetzner`, runbook
|
||||
`documentation/runbooks/offsite-endpoint.md`): add → `wg show` on the box; delete → gone
|
||||
(+404/403 paths); malformed payloads leave wg state byte-identical; endpoint reboot → persisted
|
||||
set + hub push converges; client tunnel `ep0.felhom.eu:443` → PBS login page via the wg0-only
|
||||
8007 rule; public 8007 unreachable. v0.32.1 = the HostKeyAlgorithms fix (0.32.0 image was
|
||||
already pulled by the cluster; tag kept immutable).
|
||||
|
||||
## docs — Felhom skills introduced + CLAUDE.md refresh (2026-07-03)
|
||||
|
||||
Repo-level docs work alongside v0.31.0 (no hub code in this entry):
|
||||
|
||||
Reference in New Issue
Block a user