"""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"