feat(B-RL): Rate-Limiting Konsistenz — zentrale Policies für Auth/AI/Upload/Webhook
Check Cross-Plugin Imports / check (push) Has been cancelled

B-RL: Rate-Limiting auf zentrale check_rate_limit() umgestellt
- forgejo_error_reporter: In-Memory → zentrale Redis-Rate-Limit
- ai_proactive: eigene Redis-Logik → zentrale check_rate_limit()
- agent_runner: DB-basiertes Limit bleibt (zählt echte Ausführungen)
- RateLimitPolicy Enum (AUTH/AI/UPLOAD/WEBHOOK) + check_rate_limit_policy()
- 8 neue config.py Settings für Policy-Limits
- 12 Routes mit Policies versehen (login, password-reset, AI, uploads, webhooks)

Tests: 20 Tests in test_rate_limit_policies.py — alle grün
- Policies, check_rate_limit, reset, get_client_ip, forgejo, ai_proactive
- Keine Regression: 116 bestehende Tests grün
This commit is contained in:
Agent Zero
2026-08-13 17:51:04 +02:00
parent 8c04c85d35
commit bb36378494
15 changed files with 516 additions and 84 deletions
+17 -15
View File
@@ -10,7 +10,12 @@ from sqlalchemy.ext.asyncio import AsyncSession
from app.config import get_settings
from app.core.auth import get_redis
from app.core.db import get_auth_db
from app.core.rate_limit import check_rate_limit, get_client_ip, reset_rate_limit
from app.core.rate_limit import (
RateLimitPolicy,
check_rate_limit_policy,
get_client_ip,
reset_rate_limit,
)
from app.schemas.auth import (
AuthResponse,
LoginRequest,
@@ -36,11 +41,10 @@ async def login(
ip = get_client_ip(request)
redis = get_redis()
# Rate limit
await check_rate_limit(
f"auth:login:{ip}:{body.email}",
settings.rate_limit_login_max,
settings.rate_limit_login_window,
# Rate limit — unified AUTH policy
await check_rate_limit_policy(
f"rate:auth:login:{ip}:{body.email}",
RateLimitPolicy.AUTH,
)
result = await auth_service.login(db, redis, body.email, body.password, body.tenant_slug)
@@ -53,7 +57,7 @@ async def login(
session_id, csrf_token, user, tenant, role = result
# Reset rate limit on success
await reset_rate_limit(f"auth:login:{ip}:{body.email}")
await reset_rate_limit(f"rate:auth:login:{ip}:{body.email}")
response = Response(status_code=status.HTTP_200_OK)
response.set_cookie(
@@ -217,10 +221,9 @@ async def password_reset_request(
ip = get_client_ip(request)
redis = get_redis() # noqa: F841
await check_rate_limit(
f"auth:reset:{ip}",
settings.rate_limit_reset_max,
settings.rate_limit_reset_window,
await check_rate_limit_policy(
f"rate:auth:reset:{ip}",
RateLimitPolicy.AUTH,
)
await auth_service.request_password_reset(db, body.email)
@@ -237,10 +240,9 @@ async def password_reset_confirm(
ip = get_client_ip(request)
redis = get_redis() # noqa: F841
await check_rate_limit(
f"auth:reset_confirm:{ip}",
settings.rate_limit_reset_confirm_max,
settings.rate_limit_reset_confirm_window,
await check_rate_limit_policy(
f"rate:auth:reset_confirm:{ip}",
RateLimitPolicy.AUTH,
)
success = await auth_service.confirm_password_reset(db, body.token, body.new_password)