Files
CIAgent/apps/api/tests/unit/test_rate_limit.py
T
saksham 1a4c80958f Initial commit: CI Agent competitive-intelligence monitoring app
FastAPI + Celery + Next.js + Postgres/Redis app with company monitoring,
source collection, LLM-based change analysis, enrichment, and account
security (Turnstile, escalating lockout, email verification).
2026-08-05 10:48:20 -04:00

90 lines
3.2 KiB
Python

"""The suite disables the rate limiter globally (see conftest.py) so the many
auth calls other tests make don't trip real limits. This test re-enables it
temporarily to verify the limiter itself actually works."""
from __future__ import annotations
import uuid
from fastapi import Request
from app.core.config import get_settings
from app.core.rate_limit import _client_ip_key, limiter
def _build_request(headers: dict[str, str], client_ip: str) -> Request:
scope = {
"type": "http",
"headers": [(k.lower().encode(), v.encode()) for k, v in headers.items()],
"client": (client_ip, 12345),
}
return Request(scope)
def test_client_ip_key_uses_direct_peer_when_no_proxy_header_configured():
# Default test settings have trusted_proxy_ip_header="" - the header
# must be ignored even if a client sends it, or a spoofed header could
# forge any rate-limit identity with no proxy actually in front.
request = _build_request({"CF-Connecting-IP": "203.0.113.5"}, client_ip="10.0.0.9")
assert _client_ip_key(request) == "10.0.0.9"
def test_client_ip_key_honors_configured_proxy_header(monkeypatch):
# Once deployed behind Cloudflare, trusted_proxy_ip_header="CF-Connecting-IP"
# must make the limiter key off the real visitor, not Nginx's own address -
# this is the exact bug slowapi's default get_remote_address had.
settings = get_settings().model_copy(update={"trusted_proxy_ip_header": "CF-Connecting-IP"})
monkeypatch.setattr("app.core.rate_limit.get_settings", lambda: settings)
request = _build_request({"CF-Connecting-IP": "203.0.113.5"}, client_ip="10.0.0.9")
assert _client_ip_key(request) == "203.0.113.5"
def test_register_endpoint_enforces_rate_limit(client):
limiter.enabled = True
try:
responses = [
client.post(
"/api/v1/auth/register",
json={
"email": f"rl-{uuid.uuid4().hex[:10]}@example.com",
"password": "correct-horse-1",
"display_name": "Rate Limit Test",
},
)
for _ in range(6)
]
finally:
limiter.enabled = False
statuses = [r.status_code for r in responses]
assert 429 in statuses, f"Expected a 429 among {statuses} after 6 rapid registrations"
def test_create_company_enforces_rate_limit(client):
email = f"rl-company-{uuid.uuid4().hex[:10]}@example.com"
client.post(
"/api/v1/auth/register",
json={"email": email, "password": "correct-horse-1", "display_name": "RL Test"},
)
tokens = client.post(
"/api/v1/auth/login", json={"email": email, "password": "correct-horse-1"}
).json()
headers = {"Authorization": f"Bearer {tokens['access_token']}"}
limiter.enabled = True
try:
responses = [
client.post(
"/api/v1/companies",
json={"name": f"RL Co {i}", "frequency_type": "weekly"},
headers=headers,
)
for i in range(22)
]
finally:
limiter.enabled = False
statuses = [r.status_code for r in responses]
assert 429 in statuses, f"Expected a 429 among {statuses} after 22 rapid company creations"