fix(app): bound Redis rate-limiter socket timeout#47
Merged
Conversation
Limiter's storage_uri pointed at Redis with no socket_timeout / socket_connect_timeout, so redis-py defaulted to blocking indefinitely. Since the limiter runs as a before_request hook for every route (not just /login), a Redis instance that's up but not responding (network stall, overload) would hang every Gunicorn worker on any request -- turning a Redis-side stall into a full panel outage. Added a 2s socket_timeout/socket_connect_timeout via storage_options (a no-op for the in-memory test backend). Found while independently reviewing the new shared Redis rate-limiter added in 38bc33f/9fa5e83/2860249/4b19d6b; everything else checked (fail-closed on Redis outage, atomic Lua-script increment, counting before password comparison) held up. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01U7XvmEneuMexTJGbvC1EQR
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughThe Flask-Limiter configuration now sets two-second Redis socket and connection timeouts. The bug-scan progress document records the rate-limiter review and completed scan items, while the changelog documents the timeout change. ChangesRedis limiter timeouts
Estimated code review effort: 2 (Simple) | ~10 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
|
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.



Summary
Independent bug-scan pass focused on the new Redis-backed shared login rate limiter (
38bc33f,9fa5e83,2860249,4b19d6b), which landed after the last documented full-module scan (.cursor/bug-scan-progress.md, 2026-07-10) and hadn't had a manual review pass yet (only automated CodeRabbit/Codex review).Verified against the actual
Flask-Limiter==4.1.1/limits==5.8.0source (not from memory):/loginrequest is counted before password comparison — no uncounted bypass path.One real bug found and fixed:
Limiter(...)passed nostorage_options, so the underlyingredis.Redisclient used redis-py's defaultNonesocket timeout. Since the limiter runs as abefore_requesthook for every route (not just/login—default_limits=["100 per minute"]is global), a Redis instance that's up but not responding (network stall, overload) would hang every Gunicorn worker indefinitely on any request — a Redis-side stall becomes a full panel DoS. Fixed by addingstorage_options={"socket_timeout": 2, "socket_connect_timeout": 2}(a no-op for the in-memory test backend, verified vialimits'MemoryStorage.__init__which accepts and ignores extra kwargs).Other things reviewed and found sound (documented in
.cursor/bug-scan-progress.md): fail-closed blast radius (whole panel, not just login, on Redis outage — an accepted tradeoff since an in-memory fallback would reopen the original multi-worker bypass this PR fixed), IP-only rate-limit keying (pre-existing, not a regression), Redis network exposure (internal-only, no host port mapping), and CSRF/rate-limit hook ordering (no bypass).Test plan
pytest tests/ --ignore=tests/test_integration_server.py(58 passed)pytest tests/test_login_routes.py tests/test_app.pyspecifically (48 passed, includes the rate-limiter tests)Generated by Claude Code
Need help on this PR? Tag
/codesmithwith what you need. Autofix is disabled.Summary by CodeRabbit
Bug Fixes
Documentation