Conversation
Signed-off-by: Tal Weiss <major.tal@gmail.com>
🔐 Codex Security Review
|
Git sends the same unauthenticated four-byte flush-packet probe before any smart HTTP POST whose body exceeds http.postBuffer — not just large pushes. Fetch negotiations cross the 1 MiB decoded threshold when the client's divergent local history contributes enough have lines (an in-limit repo plus ~21k unpushed divergent branches suffices; measured live at MAX_MANIFEST_REFS = 10_000 with divergent client history: 1.46 MiB decoded negotiation, probe fired, fetch got 401). Parameterize the receive-pack probe middleware over the service's (request MIME, result MIME) pair — the predicate was already otherwise service-agnostic — and mount it on the upload-pack POST route as well. All other predicate legs are unchanged: no Authorization / Content-Encoding / Transfer-Encoding headers, a single exact Content-Length of 4, and an exact 0000 body; near misses fall through to the normal authenticated path. Tests: the existing exactness/path-independence matrix now runs against both services (2 path shapes + 11 near-misses each), plus a cross-service case proving each route rejects the other service's request MIME. Fixes block#4423 Co-authored-by: npub1qyvc0c5kl4gqv2fd97fsk46tu378sqgy35vc83rvgfwne90sel7s0ed67d <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@buzz.block.builderlab.xyz> Signed-off-by: npub1qyvc0c5kl4gqv2fd97fsk46tu378sqgy35vc83rvgfwne90sel7s0ed67d <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@buzz.block.builderlab.xyz> Signed-off-by: Tal Weiss <major.tal@gmail.com>
Admitting the 0000 probe means reading four unauthenticated body bytes. Give that read its own 60 s deadline that fails closed into the normal authenticated path, so a client that sends the probe headers and then withholds the body cannot park a task. The wider request-time policy for the API and media routers is a separate change (block#4424). Co-authored-by: npub1qyvc0c5kl4gqv2fd97fsk46tu378sqgy35vc83rvgfwne90sel7s0ed67d <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@buzz.block.builderlab.xyz> Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Tal Weiss <major.tal@gmail.com>
The unit lane selects buzz-relay tests by explicit nextest expression, and none of its terms matched api::git::transport::track_c_tests, so the four compatibility-probe tests were compiled by clippy but executed by no hosted job. They need no database or storage, so they belong in the infra-free lane. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Tal Weiss <major.tal@gmail.com>
buzz-relay bounded request bytes but never request time (block#4424): valid headers followed by a withheld body parked a task per socket, before authentication, on the API and media routers. API router: a middleware collects the whole request body up front under a 60 s idle deadline, a 300 s reception ceiling and the existing 1 MiB limit, answers 408 for a body that does not arrive in time and 413 for an oversized one before any handler runs (an over-limit Content-Length is refused without reading a byte), and hands a buffered body to the handler. Handlers themselves run with no deadline: ingest_event inserts, dispatch_persistent_event awaits the bounded audit queue and only then spawns fanout, so a wall deadline around that future could strand a committed event with no audit and no delivery while a retry is answered duplicate. A test pins that a slow handler after a complete body is never cancelled. Media uploads: an idle body timeout (60 s between frames) so a slow but progressing upload finishes while a withheld body fails closed with 408, plus a 3600 s reception ceiling, matching the Blossom auth window, that bounds how long a trickling client can hold an upload permit. Both surface as body read errors and neither is a timer around the handler: once the last frame is in, the storage writes, upload record, sidecar publish and audit enqueue cannot be dropped, and a test pins that too. Media reads: a 300 s wall deadline answered 504; no body, no mutation. Body errors are classified (reception deadline, length limit, other) so 408 and 413 are never reported as storage failures. The guard tests need no infrastructure and run in the unit lane. Unchanged: admin router, git policy router, SPA fallback, health listener. Header-read deadlines before routing remain open on block#4424. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Tal Weiss <major.tal@gmail.com>
MajorTal
force-pushed
the
codex/issue-4424-body-timeouts
branch
from
September 19, 2026 12:29
f3382e2 to
b2dca8f
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #4401, split out per Carl's review there.
buzz-relaybounds request bytes but not request time (#4424): valid headers followed by a withheld body parks a task per socket, pre-auth, on the API and media routers.What changes
One principle: bound reception, never the handler. Every deadline in this PR is a body read error. No timer wraps a handler future that writes.
API router. A middleware collects the whole request body up front under a 60 s idle deadline (resets on every frame), a 300 s reception ceiling (so a client trickling one byte per idle window cannot hold a pre-auth task forever) and the existing 1 MiB limit. It answers
408for a body that does not arrive in time and413for an oversized one before any handler runs. An over-limitContent-Lengthis refused without reading a byte, as the old limit layer did. The handler gets a buffered body; every API write handler extracts its body in full already (Bytes, orJsonfor the mesh demo echo), so handlers see what they saw before.That is the fix for the P1 in #4401:
ingest_eventinserts,dispatch_persistent_eventawaits the bounded audit queue, and only then spawns fanout. There is no deadline around that anymore. A test pins it: a handler that outlives both deadlines tenfold after a complete body still completes.Media uploads. Same idle bound (60 s between frames, so a slow but progressing upload finishes) plus a 3600 s reception ceiling matching the Blossom auth window, which bounds how long a trickling client can hold an upload permit. The ceiling used to be a
TimeoutLayeraround the whole upload future; that could drop the future after the blob and sidecar were published and before the audit entry was enqueued. It is now enforced only while body frames are still being read, so once the last frame is in, the storage writes, upload record, sidecar publish and audit enqueue cannot be cancelled. A test pins that as well.Media reads. 300 s wall deadline, answered
504. No body, no mutation; a hung storage read no longer parks a task.504and not408because nothing on that path waits on the client.Unchanged: admin router, git policy router, SPA fallback, health listener. Header-read deadlines before routing (hyper level) remain open on #4424.
Tests
/media/uploadalias stays under the upload guards; the body error classifier and the video-stream timeout conversion are pinned in buzz-media.just test-unitnow (router::tests::body_guards::and the two buzz-media tests are added to its nextest expressions). Before, no hosted lane executed them.Review done before this push
Block's gates and reviews, run locally on this exact head, macOS Apple Silicon:
just fmt-check,just clippy(workspace,-D warnings),just test-unit(cargo-nextest),cargo-deny check,just file-size-check,just security-review-check: clean.scripts/postgres-test-run.shagainst Postgres and Redis containers): 390 passed.ingest_eventanddispatch_persistent_event: the old P1 does not apply to this design. Its non-blocking items (API trickle, 408 for server-side read stalls, stall tests that hang instead of fail, guard tests outside every CI lane, comments citing notes that are not in the repository) are all fixed here.Hosted Rust CI needs a maintainer to approve the workflow for this fork branch.
Stacked on #4401 (its four commits appear here until it merges).
Refs #4424
🤖 Generated with Claude Code