carlos / platform Public

host: arm the status-privacy tripwire, and keep a loop panic off the box

The status-publish privacy test iterated store.List("status/") and
passed vacuously if it came back empty — a tripwire across a doorway
nobody walks through. It now fails if the publish tick wrote no status
keys at all.

metricsLoop also recovers at the top of its goroutine: it is always on
and shares a process with the agent serving this box's traffic, so a
panic in it must stop monitoring, not the box.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Paul Campbell 0d6da6890c7e80f11306cab3865baa141191bbc5 parent 6313bc3
2 files changed, +16 −0
  • internal/host/host_test.go +6 −0
  • internal/host/metrics_loop.go +10 −0
diff --git a/internal/host/host_test.go b/internal/host/host_test.go
index d5171d04e..22033ae5d 100644
--- a/internal/host/host_test.go
+++ b/internal/host/host_test.go
@@ -532,6 +532,12 @@ func TestStatusPublishNeverReadsMetricsPrefixes(t *testing.T) {
if err != nil {
t.Fatal(err)
}
+ // Without this the loop below has nothing to inspect and the test passes
+ // no matter what statusTick publishes — a tripwire across a doorway
+ // nobody walks through.
+ if len(keys) == 0 {
+ t.Fatal("no status/ keys after a publish tick — the tripwire is not armed")
+ }
for _, k := range keys {
body, _, err := store.Get(ctx, k)
if err != nil {
diff --git a/internal/host/metrics_loop.go b/internal/host/metrics_loop.go
index f9df3a1a7..a0de7bd66 100644
--- a/internal/host/metrics_loop.go
+++ b/internal/host/metrics_loop.go
@@ -700,6 +700,16 @@ func loadAlertState(path, box string) metrics.AlertState {
// alertTick runs every tick, since a threshold breach deserves faster
// detection than a metrics flush does.
func metricsLoop() {
+ // This loop is always on and shares a process with the agent that serves
+ // this box's traffic, so a panic in it — an unreadable cgroup shape, a
+ // nil no one expected — must not take the box down with it. Monitoring
+ // stopping is a bad day; the box stopping is an outage.
+ defer func() {
+ if r := recover(); r != nil {
+ log.Printf("agent: metrics loop panic, monitoring stopped for this process: %v", r)
+ }
+ }()
+
ctx := context.Background()
bucket := resolveStatusBucket(os.Getenv)
if bucket == "" {