The receiver's 1 MB body cap lives in the handler, not the middleware the other route groups use #173

Open
opened 2026-08-18 00:41:49 +02:00 by clawbot · 0 comments
Collaborator

Found by the independent review of #167 while verifying the premise that route's memory bound rests on. Not a defect — the cap is real and effective — so deliberately NOT milestoned 1.0.0.

/webhook/{uuid} carries only ReceiverRateLimit(). Unlike the four page route groups, it has no MaxBodySize middleware. Its 1 MB cap is enforced inside the handler instead, at internal/handlers/webhook.go:145-166, via io.LimitReader plus a length check.

That works today and the reviewer confirmed it. The problem is the asymmetry is undocumented and invisible at the routing layer: someone reading internal/server/routes.go sees four groups with an explicit body-size middleware and one without, and would reasonably conclude the receiver is uncapped — or, worse, edit the handler assuming middleware coverage that is not there and silently remove the only bound on the one unauthenticated, internet-facing endpoint.

Several units this cycle have depended on that 1 MB cap being real: #135 sized the event-log render bound from it, and #157's whole memory argument rests on it.

Definition of done

Either:

  • Move the receiver onto the same MaxBodySize middleware the page groups use, so the cap is visible where every other route's cap is — checking first that this does not change the 413 semantics or the error the handler currently returns, since the receiver's response shape is part of its contract with senders; or
  • Keep it in the handler and add a comment at the route registration in internal/server/routes.go saying where the cap actually lives and why, so the omission reads as deliberate rather than forgotten.

State which you chose and why. If you move it, add a test asserting an oversized body is rejected at the middleware rather than the handler; if you document it, add a test that pins the handler-level cap so it cannot be removed silently.

Implementation requirements

  • Branch from next, PR based on next, single commit, title ending (closes #N).
  • Do not modify TODO.md (see #112).
  • Run make bootstrap in a fresh clone before gating — browser assets are fetched at build time and not committed.
  • Gate on make check plus the Docker lint path with the cache defeated. All linting runs in Docker, never on the host.
Found by the independent review of https://git.eeqj.de/sneak/webhooker/pulls/167 while verifying the premise that route's memory bound rests on. Not a defect — the cap is real and effective — so deliberately NOT milestoned 1.0.0. `/webhook/{uuid}` carries only `ReceiverRateLimit()`. Unlike the four page route groups, it has **no `MaxBodySize` middleware**. Its 1 MB cap is enforced inside the handler instead, at `internal/handlers/webhook.go:145-166`, via `io.LimitReader` plus a length check. That works today and the reviewer confirmed it. The problem is the asymmetry is undocumented and invisible at the routing layer: someone reading `internal/server/routes.go` sees four groups with an explicit body-size middleware and one without, and would reasonably conclude the receiver is uncapped — or, worse, edit the handler assuming middleware coverage that is not there and silently remove the only bound on the one unauthenticated, internet-facing endpoint. Several units this cycle have depended on that 1 MB cap being real: https://git.eeqj.de/sneak/webhooker/issues/135 sized the event-log render bound from it, and https://git.eeqj.de/sneak/webhooker/issues/157's whole memory argument rests on it. ## Definition of done Either: - Move the receiver onto the same `MaxBodySize` middleware the page groups use, so the cap is visible where every other route's cap is — checking first that this does not change the 413 semantics or the error the handler currently returns, since the receiver's response shape is part of its contract with senders; or - Keep it in the handler and add a comment at the route registration in `internal/server/routes.go` saying where the cap actually lives and why, so the omission reads as deliberate rather than forgotten. State which you chose and why. If you move it, add a test asserting an oversized body is rejected at the middleware rather than the handler; if you document it, add a test that pins the handler-level cap so it cannot be removed silently. ## Implementation requirements - Branch from `next`, PR based on `next`, single commit, title ending ` (closes #N)`. - Do not modify `TODO.md` (see https://git.eeqj.de/sneak/webhooker/issues/112). - Run `make bootstrap` in a fresh clone before gating — browser assets are fetched at build time and not committed. - Gate on `make check` plus the Docker lint path with the cache defeated. All linting runs in Docker, never on the host.
clawbot self-assigned this 2026-08-18 00:41:49 +02:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/webhooker#173