- gateway: separate config, models, state, audit, guardrail, embeddings, store, metrics, cleanup and routes; keep main.py as FastAPI bootstrap - extension: split client/config, six tools, config command and rules; preserve jiti entrypoint and registrations - Dockerfile copies the complete gateway module set - tests: update monkeypatch boundaries for modular config/state
39 lines
1.1 KiB
Python
39 lines
1.1 KiB
Python
"""Audit e autenticazione del gateway."""
|
|
from __future__ import annotations
|
|
|
|
import time
|
|
from datetime import datetime, timezone
|
|
from typing import Any
|
|
|
|
from fastapi import Header, HTTPException
|
|
|
|
import config
|
|
import state
|
|
|
|
|
|
def require_auth(x_api_key: str = Header(...)) -> str:
|
|
if x_api_key not in config.API_KEYS:
|
|
raise HTTPException(status_code=401, detail="API key non valida")
|
|
now = time.monotonic()
|
|
window = state.ratelimit.setdefault(x_api_key, [])
|
|
window[:] = [t for t in window if now - t < 60]
|
|
if len(window) >= config.RATE_LIMIT_PER_MIN:
|
|
raise HTTPException(status_code=429, detail="Rate limit superato")
|
|
window.append(now)
|
|
return x_api_key
|
|
|
|
|
|
def audit(key: str, action: str, **extra: Any) -> None:
|
|
entry = {
|
|
"ts": datetime.now(timezone.utc).isoformat(),
|
|
"key": key[:8] + "...",
|
|
"action": action,
|
|
"request_id": state.request_id.get(),
|
|
**extra,
|
|
}
|
|
config.log.info(__import__("json").dumps(entry, default=str))
|
|
|
|
|
|
def now_iso() -> str:
|
|
return datetime.now(timezone.utc).isoformat()
|