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).
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
"""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"
|
||||
Reference in New Issue
Block a user