Skip to content

refactor(server): move rate limiter - #383

Merged
delete-cloud merged 1 commit into
mainfrom
refactor/server-rate-limit
May 25, 2026
Merged

delete-cloud merged 1 commit into
mainfrom
refactor/server-rate-limit

Conversation

@delete-cloud

@delete-cloud delete-cloud commented May 25, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • move rate limiting implementation to coding_agent.server.rate_limit
  • update HTTP server to import the canonical server rate limiter
  • keep coding_agent.ui.rate_limit as a strong compatibility alias for old imports and reload-oriented tests
  • add identity tests for old/new rate_limit paths and HTTP app limiter binding

Verification

  • uv run ruff check src/coding_agent/server/rate_limit.py src/coding_agent/ui/rate_limit.py src/coding_agent/server/http_server.py tests/ui/test_rate_limit.py tests/ui/test_http_server.py
  • uv run pytest tests/ui/test_rate_limit.py tests/ui/test_security.py tests/ui/test_http_server.py tests/ui/test_http_server_failover.py -v
  • git diff --check

Summary by CodeRabbit

  • New Features

    • Added Redis support for rate limiting in distributed deployments.
  • Chores

    • Consolidated rate-limiting configuration with per-endpoint rate limits.
    • Set default rate limit to 100 requests per minute.
    • Automatic fallback to in-memory storage when Redis is unavailable.

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 25, 2026 •

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Rate-limiting logic is consolidated into a canonical server module that manages Redis-backed or in-memory storage selection, creates a shared slowapi Limiter instance, and defines endpoint rate-limit constants. The UI module becomes a re-export shim for backward compatibility, the HTTP server imports from the server module, and tests validate module equivalence and functionality.

Changes

Rate-Limit Module Consolidation

Layer / File(s) Summary
Server rate-limit module implementation
coding-agent/src/coding_agent/server/rate_limit.py
A new rate_limit.py module implements HTTP rate limiting with slowapi. It provides _get_storage_uri() to select Redis storage from AGENT_SESSION_REDIS_URL or default to in-memory, _create_limiter() to construct a slowapi Limiter with IP-based keys and 100/minute default limit (with fallback to memory if Redis init fails), a module-level limiter instance, and RateLimits class defining per-endpoint rate-limit strings (sessions, prompts, approvals, operations, health, events).
UI shim and HTTP server integration
coding-agent/src/coding_agent/ui/rate_limit.py, coding-agent/src/coding_agent/server/http_server.py
The UI rate_limit.py is transformed into a compatibility shim that imports server.rate_limit, re-exports its namespace via globals().update(), and registers module aliasing in sys.modules. HTTP server updates its import to use coding_agent.server.rate_limit instead of the UI module, establishing the canonical import path.
Test validation of module structure and functionality
coding-agent/tests/ui/test_rate_limit.py, coding-agent/tests/ui/test_http_server.py
Tests verify that ui.rate_limit is the same module object as server.rate_limit with shared limiter instance. HTTP server consistency is validated by checking app.state.limiter references the canonical limiter. Storage URI tests confirm default memory:// behavior, Redis URL passthrough from AGENT_SESSION_REDIS_URL, and fallback to memory:// when the env var is empty.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐇 Hopping modules to the right place,
Rate limits now in their proper space,
UI shim keeps old paths alive,
While tests make sure the code will thrive! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main objective: moving the rate limiter implementation from the UI module to the server module as the canonical location.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/server-rate-limit

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@delete-cloud
delete-cloud marked this pull request as ready for review May 25, 2026 02:42

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@coding-agent/src/coding_agent/server/rate_limit.py`:
- Around line 17-20: The code treats whitespace-only AGENT_SESSION_REDIS_URL as
a valid backend; fix by normalizing the env var with .strip() before the truthy
check so blank/padded values fall back to memory. Update the assignment of
redis_url (in coding_agent.server.rate_limit.py) to strip whitespace (e.g.,
redis_url = os.environ.get("AGENT_SESSION_REDIS_URL", "").strip()) and then use
the existing if redis_url: return redis_url else return "memory://".
- Around line 32-35: The warning currently logs the raw storage_uri which can
contain credentials; update the logger.warning call in rate_limit.py to never
emit raw URIs by redacting credentials before logging (e.g., parse storage_uri
in the same scope as the existing logger.warning and reconstruct a masked_uri
that removes or replaces username/password, or log only scheme/host), then pass
masked_uri (not storage_uri) into the logger.warning message where
logger.warning("Rate limiter storage unavailable at %s; ...", storage_uri, exc)
is called; ensure the redaction handles both URLs with userinfo and edge cases
so secrets cannot be logged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 17e3bfc3-21f8-4010-8ae0-426242f22a3c

📥 Commits

Reviewing files that changed from the base of the PR and between 07d9e8e and b347497.

📒 Files selected for processing (5)
  • coding-agent/src/coding_agent/server/http_server.py
  • coding-agent/src/coding_agent/server/rate_limit.py
  • coding-agent/src/coding_agent/ui/rate_limit.py
  • coding-agent/tests/ui/test_http_server.py
  • coding-agent/tests/ui/test_rate_limit.py

Comment on lines +17 to +20
redis_url = os.environ.get("AGENT_SESSION_REDIS_URL", "")
if redis_url:
return redis_url
return "memory://"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Trim AGENT_SESSION_REDIS_URL before backend selection.

Whitespace-only or padded values are currently treated as configured Redis URIs and can trigger avoidable fallback behavior. Normalize with .strip() before the truthy check.

💡 Suggested patch
 def _get_storage_uri() -> str:
-    redis_url = os.environ.get("AGENT_SESSION_REDIS_URL", "")
+    redis_url = os.environ.get("AGENT_SESSION_REDIS_URL", "").strip()
     if redis_url:
         return redis_url
     return "memory://"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
redis_url = os.environ.get("AGENT_SESSION_REDIS_URL", "")
if redis_url:
return redis_url
return "memory://"
redis_url = os.environ.get("AGENT_SESSION_REDIS_URL", "").strip()
if redis_url:
return redis_url
return "memory://"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@coding-agent/src/coding_agent/server/rate_limit.py` around lines 17 - 20, The
code treats whitespace-only AGENT_SESSION_REDIS_URL as a valid backend; fix by
normalizing the env var with .strip() before the truthy check so blank/padded
values fall back to memory. Update the assignment of redis_url (in
coding_agent.server.rate_limit.py) to strip whitespace (e.g., redis_url =
os.environ.get("AGENT_SESSION_REDIS_URL", "").strip()) and then use the existing
if redis_url: return redis_url else return "memory://".

Comment on lines +32 to +35
logger.warning(
"Rate limiter storage unavailable at %s; falling back to memory: %s",
storage_uri,
exc,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid logging raw storage URIs (credentials can leak).

If AGENT_SESSION_REDIS_URL contains credentials, the warning currently writes secrets to logs.

🔐 Suggested patch
         logger.warning(
-            "Rate limiter storage unavailable at %s; falling back to memory: %s",
-            storage_uri,
+            "Rate limiter storage unavailable; falling back to memory: %s",
             exc,
         )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@coding-agent/src/coding_agent/server/rate_limit.py` around lines 32 - 35, The
warning currently logs the raw storage_uri which can contain credentials; update
the logger.warning call in rate_limit.py to never emit raw URIs by redacting
credentials before logging (e.g., parse storage_uri in the same scope as the
existing logger.warning and reconstruct a masked_uri that removes or replaces
username/password, or log only scheme/host), then pass masked_uri (not
storage_uri) into the logger.warning message where logger.warning("Rate limiter
storage unavailable at %s; ...", storage_uri, exc) is called; ensure the
redaction handles both URLs with userinfo and edge cases so secrets cannot be
logged.

@delete-cloud
delete-cloud merged commit 3c8439f into main May 25, 2026
1 check passed
@delete-cloud
delete-cloud deleted the refactor/server-rate-limit branch May 25, 2026 02:50
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.

1 participant