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

Model: opus-5-5
2026-09-28 17:29:08 +00:00
+7 -10
View File
@@ -163,10 +163,7 @@ func TestHandleReportLogsClientIDCutToBound(t *testing.T) {
h.HandleReport().ServeHTTP(rec, req)
var logged struct {
ClientID string `json:"client_id"`
Timestamp string `json:"timestamp"`
}
var logged map[string]any
err := json.Unmarshal(logbuf.Bytes(), &logged)
if err != nil {
@@ -175,14 +172,14 @@ func TestHandleReportLogsClientIDCutToBound(t *testing.T) {
want := long[:handlers.MaxLoggedFieldBytes]
if logged.ClientID != want {
t.Fatalf("logged client_id is %d bytes, want %d",
len(logged.ClientID), len(want))
if logged["client_id"] != want {
t.Fatalf("logged client_id not cut to %d bytes: %q",
handlers.MaxLoggedFieldBytes, logged["client_id"])
}
if logged.Timestamp != want {
t.Fatalf("logged timestamp is %d bytes, want %d",
len(logged.Timestamp), len(want))
if logged["timestamp"] != want {
t.Fatalf("logged timestamp not cut to %d bytes: %q",
handlers.MaxLoggedFieldBytes, logged["timestamp"])
}
}