Files
felhom.eu/REPORT.md
T

3.5 KiB

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-side agent leaf-fingerprint change detection (HostLeafChecker) — hub v0.22.1

Date: 2026-06-29. Companion: felhom-agent v0.48.0 (Part A — reports the served leaf fp). This repo = Part B (hub). The last self-health leg: a proactive, fleet-wide agent-re-key alert.

Implementation

  • monitor.HostLeafChecker (NEW): sibling of HostCapabilityChecker. Trust-on-first-report — the first leaf fp seen per host is the baseline; a later change emits host_leaf_changed (operator-only, English; details carry old+new fp) and advances the baseline. First-obs seeds silently (a change needs a prior value → no F2 issue). An empty reported fp (pre-v0.48.0 / local-API-disabled) is unknown — never seeds, never alerts, never overwrites a baseline. Customer-blocked hosts dropped; unseen pruned. Same 60s sweep.
  • store.GetHostLeafFingerprints (NEW): latest reported fp per host, parsed from report_json (mirrors GetHostCapabilitiesMAX(id), no schema migration; chose the report_json read over a denorm column to avoid an ALTER TABLE).
  • No allowlist change: host_leaf_changed is hub-generated (SaveEvent + dispatcher.ProcessEvent), not controller-pushed, so it bypasses the /api/v1/event allowedEventTypes gate (same as host_*). The generic operator template relays it.
  • Known limitation (documented): trust-on-first-report can't detect a re-key that happened before the hub's first report — but the controller channel-check catches the downstream pin mismatch, so this is defense-in-depth, not the sole guard. (The served-fp-vs-pinned-fp authoritative cross-check is a deliberate future enhancement.)

Tests (green: go build/vet/test ./...)

Change red-proof (A→B → one host_leaf_changed + baseline advanced; companion: unchanged → none), first-obs seeds silently, change-back re-alerts, empty fp skipped, customer-blocked dropped. Cross-repo golden mirrors leaf_fingerprint.

Live validation — PASS (+ a wiring bug the live test caught)

  • v0.22.0 shipped the checker but the cmd/hub/main.go goroutine wiring never applied (a concurrent file-touch made me wrongly assume the edit landed). The live test caught it: a leaf regen produced no host_leaf_changed — only the controller's complementary agent_channel_pin_mismatch. Fixed in v0.22.1 (wired + redeployed). A good example of live validation catching what the build/test couldn't.
  • After v0.22.1: Host leaf checker initialized: 1 host fingerprint(s) seeded; then restoring the leaf (a change from the seeded baseline) → [WARN] Host leaf: demo-felhom-01 fp 82078fab77ea… → 60b5974d586f… (host_leaf_changed) (~8 s, one sweep), event saved (no error) + dispatched to the operator. Independent of the controller's channel-check, which also fired agent_channel_pin_mismatch during the regen — the two are complementary. Final state: leaf == pin 60b5974d…, channel recovered, capabilities 45/45, controller healthy.

Self-health arc — complete

Agent watches its own privileged capabilities (v0.44.0) + the controller watches its link to the agent (controller v0.90.0/F2) + the hub proactively watches every agent's leaf fp fleet-wide (this). The original silent-multi-day-outage incident class is now caught from three independent angles.