9.4 KiB
REPORT — Hub v0.85.0: the Network card (2026-07-31)
Overwritten per the standing rule. Pairs with agent v0.119.0 (see felhom-agent/REPORT.md);
neither half is useful alone. Live evidence:
documentation/audits/host-addresses-visible-2026-07-31.md.
The earlier v0.84.0 work this file previously described (break-glass Console access card) shipped, deployed and validated in the same session; its durable record is
hub/CHANGELOG.mdv0.84.0 plusCONTEXT.mdruling S-4 anddocumentation/backlog/R-133.
0. Follow-up shipped the same session — hub v0.86.0 (Copy without reveal)
The operator hit a real defect in the v0.84.0 Console access card and it cost a login. Copy was
disabled until a Reveal, so clicking it did nothing, silently; the clipboard kept its previous
contents — another host's console password — which was pasted into demo-hp's PVE login. It failed
with password check failed for user (root), which reads exactly like a stale credential and sends
you diagnosing the wrong thing.
Diagnosis, read-only first: the vaulted password matched the box's /etc/shadow hash, the account
was unlocked and non-expiring, no TFA, no pam_faillock — and then it minted a real PVE ticket
(POST /api2/json/access/ticket → HTTP 200, root@pam, 367-char ticket). So the credential was
always good; only the clipboard was wrong. That also closes the leg §7 of this report listed as
operator-only — the capability-map row now records it.
v0.86.0 makes Copy work without revealing (the safer default — the secret never renders, so it
cannot be shoulder-surfed or screenshotted) and closes three silent-failure branches in one eight-line
function: the disabled no-op, a missing navigator.clipboard, and an ignored writeText()
rejection that let the operator believe a refused write had succeeded. The success message now names
the host, because the clipboard is fleet-wide and "copied" alone cannot say for which box.
Tests 566 → 568, both pinning the regression; red-proof: re-adding disabled reproduces the shipped
bug. Deployed and live-verified (Synced/Healthy, image :0.86.0, button served without disabled,
retrieval URL defined exactly once, all four outcome messages present). Commits 670ec35 + 80f4739.
1. Baselines
| Repo | main @ start of this half |
Version before → after |
|---|---|---|
| felhom.eu (hub) | b4edc087fa9a |
hub v0.84.0 → v0.85.0 |
| felhom-agent | 6b5dade4dcc5 |
agent 0.118.1 → 0.119.0 |
2. The ask, and what it turned out to be
"Show the LAN and WireGuard IPs on the hosts page — it looks like it is not visible anywhere." Nearly exact, and the two halves were very different jobs:
- WireGuard — the hub already had it (
wg_peers.assigned_ip,GetWGPeerForHost, no UI consumer). It was visible in exactly one place,/offsite's peer table keyed by pubkey, so you could go peer→host and never host→peer. - LAN — not renderable at all.
HostReport/HostMetricscarried no address of any kind, so this needed a cross-repo agent release, not an edit. Confirmed against the struct and against a live box before proposing anything.
Operator chose: both together as one arc, with the addresses[] (iface + cidr) shape.
3. Files (hub half)
hub/internal/web/hosts.go—parseHostAddresses,hostAddressView,hostNetworkView,hostNetwork,minAgentForAddresses,hostDetailData+1 keyhub/internal/web/templates/host_detail_body.html— the Network cardhub/internal/web/hosts_network_test.go(new)hub/internal/api/testdata/host-report.golden.json— the cross-repo contract, moved in lockstephub/CHANGELOG.md,REUSE.md,manifests/hub.yamldocumentation/architecture/00-capability-map.md(new row),documentation/audits/host-addresses-visible-2026-07-31.md(new)
4. Commits pushed to main
| Repo | Commit | What |
|---|---|---|
| felhom-agent | 14642e3 |
v0.119.0 — the host report carries the box's addresses |
| felhom-agent | 4663df7 |
REPORT |
| felhom.eu | e07d90f |
hub v0.85.0 — Network card |
| felhom.eu | 37f7ff6 |
manifests: hub 0.84.0 → 0.85.0 |
5. Tests + red-proofs (hub half)
Suite 559 → 566 (+7). go build ./... && go vet ./... && go test ./... rc=0, run separately
from the commit per standing rule 1.
| Test | Asserts | Result |
|---|---|---|
TestNetwork_A_LANAddressRendered |
the LAN address + its interface reach the page | PASS |
TestNetwork_B_WireGuardAllocatedAndConfirmed |
WG shown once, marked confirmed, not duplicated as a plain row | PASS |
TestNetwork_C_AllocatedButBoxDoesNotHoldIt |
the drift case renders not confirmed by the box |
PASS |
TestNetwork_D_OldAgentSaysUnknownNotNone |
an old agent renders UNKNOWN, never "no addresses" | PASS |
TestNetwork_E_NoPeerAllocated |
no peer → says so; the box's wg address is not silently dropped | PASS |
TestNetwork_F_NoReportYet |
never-reported host says "waiting", not "no addresses" | PASS |
TestParseHostAddresses_RealWire |
parses the real wire; empty/malformed degrade without panic | PASS |
The report fixture is the REAL wire — the addresses block copied out of
felhom-agent --selftest=hub on demo-felhom running 0.119.0. A hand-written shape would have proved
only that the parser matches my own idea of the format.
| # | Mutation | Observed | Reverted |
|---|---|---|---|
| A | hostDetailData ships an empty hostNetworkView{} (the inert-seam shape) |
FAIL … the LAN address is not on the host page — the feature shows nothing |
yes |
| B | WGConfirmed set unconditionally from the allocation |
FAIL … an allocated-but-unheld peer renders as healthy — the drift is invisible |
yes |
| D | delete the AgentTooOld branch |
FAIL … an old agent's silence is not explained |
yes |
Red-proof A took two attempts, and the first one proved nothing. The initial mutation
(_ = network inside a map literal) did not compile, so the "failure" was a build error, not a test
result. Recorded because a red-proof that fails to build is indistinguishable from one that lands if
you only read the exit code.
6. Deployed
Image gitea.dooplex.hu/admin/felhom-hub:0.85.0 built on DooPlex and pushed; manifests/hub.yaml
bumped in git; ArgoCD hard-refreshed and deliberately synced (never kubectl set image).
- ArgoCD app
felhom: Synced / Healthy deploy/hubimage:gitea.dooplex.hu/admin/felhom-hub:0.85.0- Rollout:
deployment "hub" successfully rolled out(rc=0) - Startup log:
2026/07/31 08:50:57 [INFO] felhom-hub 0.85.0 starting
One sequencing note worth keeping: the first sync fired before ArgoCD had re-read git, so it
reported Synced/Healthy while still running 0.84.0 — a green pair that meant nothing. The fix is to
wait until .status.sync.revision equals the pushed commit before trusting the sync, which the
final run did.
7. Live validation
Method: endpoint-level (no browser on DooPlex), against the deployed hub, cross-checked
against ip addr read directly over SSH on both boxes.
| Host | Agent | Network card, live | Matches ground truth? |
|---|---|---|---|
demo-felhom-8363b5 |
0.119.0 | WG 10.77.0.2 confirmed; vmbr0 192.168.0.162/24, tailscale0 100.70.170.35/32 + ULA |
yes, exactly |
demo-hp-bb76ea |
0.119.0 | WG 10.77.0.3 confirmed; vmbr0 192.168.0.87/24, tailscale0 100.76.96.79/32 + ULA |
yes, exactly |
drill-r50-0a4f9a |
0.113.0 | WG 10.77.0.4 allocated; "agent (0.113.0) does not report its addresses — they are unknown, not absent. Needs 0.119.0 or newer." | correct UNKNOWN rendering |
sess-f-2670b5 |
old | same UNKNOWN rendering | correct |
Correctly absent from every card: lo, vmbr9's 169.254.253.1 island literal, every fe80::.
A fifth host 404'd and it was not a bug. sess-g-e687c3 appeared in a host list I read 30
minutes earlier and returned 404 when I fetched its page; the concurrent session had deleted it as
part of its scratch-customer cleanup. Chased to ground before reporting rather than filed as a defect.
8. Not yet validated / not covered
- A box with two LAN bridges — handled by design (one row per interface) and unit-tested; no such box exists to observe.
- A real WireGuard drift — the
not confirmedbranch is unit-tested and red-proofed but never seen in production, because no live peer is currently unapplied. - IPv4-only / IPv6-only hosts — every box here is dual-stacked via tailscale's ULA.
9. Teardown
This run provisioned nothing — no guest, no VM, no scratch customer, no external resource. The only
mutations are two in-place agent upgrades (previous binaries retained as .bak-0.118.1 on both
boxes), the Day-0 manifest agent vouch, and the hub image bump.
10. Backlog
- Opened: none. Closed: none.
- R-115 / R-121 touched, not closed. This release walked all three legs deliberately — deployed, published (round-trip verified) and vouched (read back) — so no new drift instance was created. The finding those rows record is that nothing notices when the legs diverge, which is unchanged. One small contribution: the Network card now surfaces "this host's agent is older than 0.119.0" per host, which is a per-field hint, not the installed-vs-vouched checker R-121 asks for.
- Concurrent session: every path was staged explicitly; no foreign WIP was swept into any commit.