Skip to content

fix(server): per-IP rate limit on /health endpoint (NET-002) - #236

Closed
imran-siddique wants to merge 8 commits into
mainfrom
fix/net-002-health-rate-limit
Closed

imran-siddique wants to merge 8 commits into
mainfrom
fix/net-002-health-rate-limit

Conversation

@imran-siddique

Copy link
Copy Markdown
Member

Summary

  • Replaces _RateLimitMiddleware (60 req/min, asyncio.Lock) with _HealthRateLimitMiddleware: a 1-second sliding-window token bucket capped at 10 req/sec per IP
  • Returns 429 HEALTH_RATE_LIMIT with Retry-After: 1 when the limit is exceeded
  • MCPServer.__init__ now accepts health_rate_limit_per_second: int = 10; the middleware is applied only to /health before auth middleware runs
  • Tests updated: cover within-limit 200s, over-limit 429 with correct error_code and Retry-After: 1, and confirmation that non-health endpoints are unaffected

Closes #178

Test plan

  • pytest tests/unit/test_mcp_server_auth.py -- all 18 tests pass
  • test_health_rate_limit_returns_429_when_exceeded -- verifies 429, Retry-After: 1, and error_code == "HEALTH_RATE_LIMIT"
  • test_health_rate_limit_non_health_endpoints_not_affected -- verifies /tools/list returns 401 not 429 even after /health is limited

Generated with Claude Code

imran-siddique and others added 8 commits June 7, 2026 13:53
Adds _RateLimitMiddleware (sliding-window, 60 req/min per IP) that wraps
the unauthenticated /health path before auth middleware runs. Returns 429
with Retry-After: 60 when the limit is exceeded. Falls back gracefully
when client IP is unavailable.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
)

Fetches X.509 SVIDs from a local SPIRE agent after TEE attestation.
Falls back to self-signed TLS with a WARNING log if SPIRE is unavailable
or pyspiffe is not installed. GatewayContext gains a `spiffe` field
populated during startup step 5b (non-fatal).

Closes #96

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
python tests/soak/run_soak.py --duration-hours 72 --provider sev-snp
runs alternating 1h active / 1h idle cycles, monitoring all 6 edge cases
from docs/testing/soak-test.md: attestation expiration, SSE stability through
nginx, memory growth bounds, idle-to-active transition latency, signing key
stability, and session orphaning. Outputs benchmarks/soak-YYYY-MM-DD.json.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…-001) (#226)

Closes #171.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…time (POLICY-005, #162) (#225)

Closes #162.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…tribution to result (#229)

INJECT-002: wraps scan_response() and PromptInjectionDetector.detect() in
ThreadPoolExecutor with a configurable timeout (default 5s). A timeout is
treated as deny (fail-safe) so a slow/unresponsive AGT service cannot
exhaust worker slots indefinitely.

INJECT-003: adds injection_scanner and injection_score fields to
InspectionResult and StageResult. Callers writing audit chain entries now
have the specific scanner that triggered the deny ("agt_mcp", "agt_detector",
"regex", "timeout", "utf8_guard") and confidence score if available.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
)

Replace the per-minute _RateLimitMiddleware with _HealthRateLimitMiddleware,
a 1-second sliding-window token bucket that returns 429 HEALTH_RATE_LIMIT
after 10 requests/sec per IP.  MCPServer.__init__ now accepts
health_rate_limit_per_second (default 10).  Tests updated to cover 429
response, Retry-After header, and non-health paths unaffected.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@imran-siddique

Copy link
Copy Markdown
Member Author

Superseded: NET-002 was already implemented and closed via #230. Closing this alternative implementation.

@imran-siddique
imran-siddique deleted the fix/net-002-health-rate-limit branch July 29, 2026 23:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MEDIUM: No rate limiting on unauthenticated /health and /metrics endpoints (NET-002)

1 participant