Commit Graph
4 Commits
Author SHA1 Message Date
sneak e5d708cefa fix(backend): report ingest correctness — propagate storage failure, 413 on oversize, global body cap (closes #23)
check / check (push) Successful in 45s
A buffer failure on POST /api/v1/reports now returns 500 instead of a
false `ok`, so clients can retry. Decode errors split: an over-limit
body returns 413 (via errors.As on `*http.MaxBytesError`), malformed
JSON stays 400. A new MaxBodyBytes middleware (1 MiB default) caps
every route — rejecting an oversized Content-Length up front and
capping the read otherwise — so the health check and future routes are
bounded too. The raw attacker-controlled geo blob is no longer logged,
only its length; client_id and timestamp are length-bounded before
logging. A decodeJSON handler helper is added. Panic recovery is now a
local middleware routing the stack through slog as structured JSON.
Storage failure uses 500: a full buffer or write error is server-side
and retryable.

Model: opus-4-8
2026-09-21 17:02:37 +00:00
clawbot d7cf010e00 fix(server): shut down through fx so buffered reports flush (closes #22)
check / check (push) Successful in 1m11s
The server ran os.Exit at the end of its own goroutine, racing fx's
teardown and sometimes killing the process before reportbuf's OnStop
flushed — silently losing a full flush window of telemetry on every
restart, at exit 0. Shutdown now goes through fx.Shutdowner, so every
OnStop runs in order.

The http.Server is built synchronously in OnStart before the serving
goroutine, so shutdown can no longer race or nil-deref it. A listen
failure exits non-zero via fx.ExitCode(1). reportbuf's OnStop is guarded
by sync.Once. writeTimeout now exceeds the chi per-request budget so that
budget is reachable. Dead startupTime, exitCode, and cancelFunc fields
are gone. A new test asserts a buffered report reaches disk after the
lifecycle stops.

Model: opus-4-8
2026-09-21 18:47:12 +02:00
clawbot f3895789d2 feat(backend): server hardening: timeouts, security headers, trusted-proxy client IP (closes #19)
check / check (push) Failing after 1s
Add ReadHeaderTimeout and IdleTimeout to the http.Server as named constants beside the existing timeouts. Add a SecurityHeaders middleware (HSTS, a JSON-API CSP of default-src 'none'; frame-ancestors 'none', X-Frame-Options DENY, nosniff, Referrer-Policy, Permissions-Policy), registered before CORS so preflight responses carry it. Resolve the client IP from X-Forwarded-For / X-Real-IP only when the direct peer is in the trusted-proxy allowlist (loopback plus RFC1918 by default, configurable via TRUSTED_PROXIES); an untrusted peer's forwarded headers are ignored. Uses net/netip; no new dependency.

Model: opus-4-8 (implementation and review); claude-fable-5 (merge)
2026-09-21 15:05:25 +02:00
sneak b57afeddbd Add backend with buffered zstd-compressed report storage
Introduce the Go backend (netwatch-server) with an HTTP API that
accepts telemetry reports and persists them as zstd-compressed JSONL
files. Reports are buffered in memory and flushed to disk when the
buffer reaches 10 MiB or every 60 seconds.
2026-02-27 12:14:34 +07:00