Add RedisRateLimiter using sorted-set sliding window alongside the
existing InMemoryRateLimiter. Users choose via RATE_LIMIT_BACKEND
(memory|redis) with RATE_LIMIT_REDIS_URL falling back to RQ_REDIS_URL.
Redis backend validates connectivity at startup and fails open on
transient errors during requests.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- agent.py: Fail closed when gateway lookup returns None instead of
silently dropping the organization filter (cross-tenant board leak)
- board_webhooks.py: Read request body via streaming chunks so an
oversized payload is rejected before it is fully loaded into memory
- rate_limit.py: Add periodic sweep of expired keys to prevent
unbounded memory growth from inactive clients
- test_rate_limit.py: Add test for the new sweep behavior
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Agent token auth performed O(n) PBKDF2 operations per request with no
rate limiting, enabling CPU exhaustion attacks. Webhook ingest had no
rate limits either. Add an in-memory token-bucket rate limiter:
- Agent auth: 20 requests/minute per IP
- Webhook ingest: 60 requests/minute per IP
Includes unit tests for the rate limiter.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>