chore: correct body-cap comments, dockerignore licence posture, stale log copy

- workouts/batch + safeJson: the body cap is a DoS ceiling, not a bound
  the worst-case payload always fits under; an extreme GPS-heavy backlog
  can exceed it and falls back to smaller batches client-side. Note that
  request.text() still buffers the raw body, so the cap bounds the parse
  cost, not the initial read.
- .dockerignore: keep LICENSE / LICENSE.md in the image — AGPL-3.0
  conveys with the software.
- reminder-worker: the dense walk flag is an operator kill-switch now
  that the fold is reworked, not a pending-rework gate.
This commit is contained in:
Marc-André Bombeck committed 2026-06-03 09:10:46 +02:00
1 parent 33358c7960
commit 8456d3bbc3
4 files changed
+24 -21

No files matched your search

+11 -11
View File
@@ -87,13 +87,13 @@ const PR_DETECTION_SILENT_THRESHOLD = 50;
const BATCH_RATE_LIMIT_MAX = 60;
const BATCH_RATE_LIMIT_WINDOW_MS = 60 * 1000;
// 5 MB request-body ceiling. The route geometry is the largest tail in
// a workout payload; with the 20 000-point cap on a single LineString
// AND the 100-workout cap per batch, the worst-case body is bounded
// well below this ceiling for typical lon/lat encodings. A request
// above this ceiling almost certainly indicates a misbehaving client
// or an attempted DoS — return 413 so the iOS client falls back to
// one-workout-per-call.
// 5 MB request-body ceiling (pre-existing). The route geometry is the
// largest tail in a workout payload; a typical batch sits comfortably
// under this, but the 20 000-point LineString cap combined with the
// 100-workout batch cap allows a theoretical tens-of-MB body for an
// extreme GPS-heavy backlog. Such a body returns 413 so the iOS client
// falls back to smaller / one-workout-per-call batches — which is also
// the correct response to a misbehaving client or an attempted DoS.
const MAX_BODY_BYTES = 5 * 1024 * 1024;
/**
@@ -178,10 +178,10 @@ async function postBatch(request: NextRequest): Promise<Response> {
// The Content-Length pre-flight above bounds the common case, but a
// chunked upload carries no Content-Length. The `safeJson` body cap
// backstops that gap: the raw text is measured before `JSON.parse`,
// so an over-limit chunked body returns a clean 413 rather than
// buffering an unbounded payload onto the heap. Reuses the same 5 MB
// ceiling — the route's 100-workout × 20 000-point worst case sits
// well below it, so a real iOS batch is never rejected.
// so an over-limit chunked body returns a clean 413 before the parse
// cost. Reuses the same 5 MB ceiling — a typical iOS batch sits under
// it; an extreme GPS-heavy backlog that exceeds it falls back to
// smaller batches client-side.
const { data: rawBody, error: jsonError } = await safeJson<unknown>(request, {
maxBytes: MAX_BODY_BYTES,
});