⚠️ Definition of Done: this issue must be completed in full, in a single PR. Do not split this
work across multiple PRs, and do not defer any Deliverable below to a follow-up issue. A PR that
satisfies only some of the Deliverables, stubs a required test, or leaves a checkbox
partially-done does NOT resolve this issue and will be closed.
Context
src/github/webhook.ts:83-106's handleGitHubWebhook checks content-length against GITHUB_WEBHOOK_MAX_BODY_BYTES and returns 413 before touching the body (added in #197, "Harden GitHub webhook endpoint against large-body DoS"). handleOrbRelay (lines 233-246, added later in #1354/#1639) goes straight to readBodyWithLimit(c.req.raw, maxBodyBytes) with no Content-Length pre-check -- it still enforces the byte cap while streaming, but only after buffering up to the cap, and only after doing so does it 413. The two receivers process an identical GitHub payload shape but diverge on this bound with no comment explaining why.
Requirements
Add the same content-length header check (413 fast-path, before touching the body) to handleOrbRelay, matching handleGitHubWebhook's existing pattern exactly.
Deliverables
All of the above Deliverables are required in the same PR unless the deliverable text itself states otherwise.
Test Coverage Requirements
src/** -- 99%+ patch coverage, branch-counted, on the new pre-check.
Expected Outcome
handleOrbRelay rejects an oversized request at the header-check stage, matching handleGitHubWebhook's existing DoS-hardening pattern, instead of buffering up to the cap first.
Links & Resources
src/github/webhook.ts:83-106,233-246
Context
src/github/webhook.ts:83-106'shandleGitHubWebhookcheckscontent-lengthagainstGITHUB_WEBHOOK_MAX_BODY_BYTESand returns 413 before touching the body (added in #197, "Harden GitHub webhook endpoint against large-body DoS").handleOrbRelay(lines 233-246, added later in #1354/#1639) goes straight toreadBodyWithLimit(c.req.raw, maxBodyBytes)with no Content-Length pre-check -- it still enforces the byte cap while streaming, but only after buffering up to the cap, and only after doing so does it 413. The two receivers process an identical GitHub payload shape but diverge on this bound with no comment explaining why.Requirements
Add the same
content-lengthheader check (413 fast-path, before touching the body) tohandleOrbRelay, matchinghandleGitHubWebhook's existing pattern exactly.Deliverables
handleOrbRelayrejects an oversized request via acontent-lengthheader pre-check, before callingreadBodyWithLimitcontent-lengthheader is rejected with 413 before the body is readAll of the above Deliverables are required in the same PR unless the deliverable text itself states otherwise.
Test Coverage Requirements
src/**-- 99%+ patch coverage, branch-counted, on the new pre-check.Expected Outcome
handleOrbRelayrejects an oversized request at the header-check stage, matchinghandleGitHubWebhook's existing DoS-hardening pattern, instead of buffering up to the cap first.Links & Resources
src/github/webhook.ts:83-106,233-246