feat: rate limit leggero (30/min per IP) su /v1/status pubblico

- endpoint pubblico per healthcheck, protetto da abusi
- verificato sul server: 36 richieste → 30x200 + 6x429 (istanza di test)
This commit is contained in:
Matteo Benedetto
2026-08-16 19:22:18 +02:00
parent 87d59ccb5c
commit f30966a77c
+14 -1
View File
@@ -94,6 +94,10 @@ qdrant = QdrantClient(url=QDRANT_URL, api_key=QDRANT_API_KEY)
# Rate limit in-memory: {key: [timestamps]}
_ratelimit: dict[str, list[float]] = {}
# Rate limit /v1/status (pubblico, per IP): {ip: [timestamps]}
_STATUS_RATE_LIMIT_PER_MIN = 30
_status_ratelimit: dict[str, list[float]] = {}
# Idempotency in-memory: {api_key:key: {hash, response, ts}} (TTL 24h)
_IDEMPOTENCY_TTL_SECONDS = 24 * 3600
_idempotency: dict[str, dict[str, Any]] = {}
@@ -416,7 +420,16 @@ async def meta_overview(key: str = Depends(require_auth)) -> dict:
@app.get("/v1/status")
async def status() -> dict:
async def status(request: Request) -> dict:
# Endpoint pubblico (healthcheck): rate limit leggero per IP
ip = request.client.host if request.client else "unknown"
now = time.monotonic()
window = _status_ratelimit.setdefault(ip, [])
window[:] = [t for t in window if now - t < 60]
if len(window) >= _STATUS_RATE_LIMIT_PER_MIN:
raise HTTPException(status_code=429, detail="Rate limit superato")
window.append(now)
info = qdrant.get_collection(COLLECTION)
return {
"status": "ok",