fix(stream): cap concurrent SSE streams per tenant (S-5) - #216
Merged
Conversation
Each open /v1/stream/events connection runs a journal scan every second but the rate limiter only charges the request that opened it, so a tenant's scan load grew without bound (security pre-audit S-5). New per-tenant cap on concurrent streams: the (N+1)-th connection is rejected with 429 + Retry-After before the stream opens; already-open streams are never dropped. Cap defaults to 5 and is tunable via AGENTFLOW_SSE_MAX_STREAMS_PER_TENANT. The counter is per process, like the failed-auth throttle (S-7 accepted risk): N replicas give an NxCap effective cap, which still bounds the growth the finding is about. Slot release is idempotent and wired to both the generator's finally (normal close/disconnect) and the response background task (generator never iterated). With auth disabled (tenant_id=None) the cap is skipped, matching the /v1/batch S-4 convention. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
DORA Metrics
|
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.
Closes security pre-audit S-5 (P3, SSE resource exhaustion): each open
/v1/stream/eventsconnection runs a journal scan every second, but the rate limiter only charges the one request that opened it — a 60-rpm tenant could sustain ~60 growing scanners.Semantics (per product decision): the (N+1)-th concurrent stream for a tenant gets an immediate 429 + Retry-After; already-open streams are never dropped. Cap defaults to 5 per tenant, tunable via
AGENTFLOW_SSE_MAX_STREAMS_PER_TENANT.app.state(same accepted per-process trade-off as the S-7 failed-auth throttle: N replicas = N× effective cap, still bounds the growth the finding describes).finally(normal close / client disconnect viaaclose()) and the response's background task (covers a generator the server never iterates).tenant_id=None) → cap skipped, matching the/v1/batchS-4 convention.awaitin between — atomic on the event loop.Tests: 5 new unit tests (reject at cap + no slot consumed by the rejected request; per-tenant isolation; auth-disabled bypass; env override; background-task release path + idempotency). Full unit suite 2028 passed locally; ruff check/format clean.
🤖 Generated with Claude Code