Findings security-review P1/P2 (2026-07-03): - headere de securitate pe toate raspunsurile (nosniff, X-Frame-Options, Referrer-Policy, HSTS doar pe HTTPS) + teste - body-cap global 10MB ca middleware ASGI pur (413 inainte de parserul multipart/JSON; verificarea per-endpoint ramane strat 2) - imagine Docker non-root (uid 10001), port 8010 aliniat, loguri pe volumul /data - fail-fast la boot cu rar_env=prod fara AUTOPASS_REQUIRE_API_KEY sau AUTOPASS_SESSION_SECRET - compose: env-uri critice obligatorii (:?) ca api/worker sa nu diverga tacit; FORWARDED_ALLOW_IPS ca rate-limit-ul sa vada IP-ul real dupa Traefik - signup fara PII in stdout: log_event in loc de print cu email (idem notify degradat) - ratelimit: sterge cheile fara timestamp-uri valide (crestere monotona a memoriei pe IP-uri reale) - backup criptat SQLite (backup online API, gpg AES256) + verificare restore + docs/backup.md Suita completa verde: 1557 passed, 1 skipped (live). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
65 lines
1.8 KiB
Python
65 lines
1.8 KiB
Python
"""Teste P1-5 (hardening 2026-07-03): plafon global corp cerere (BodyCapMiddleware)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import io
|
|
import json
|
|
import os
|
|
import tempfile
|
|
|
|
import pytest
|
|
from fastapi.testclient import TestClient
|
|
|
|
|
|
@pytest.fixture()
|
|
def client(monkeypatch):
|
|
tmp = tempfile.mkdtemp()
|
|
monkeypatch.setenv("AUTOPASS_DB_PATH", os.path.join(tmp, "bc.db"))
|
|
monkeypatch.setenv("AUTOPASS_LOG_DIR", os.path.join(tmp, "logs"))
|
|
# Prag mic ca sa nu generam MB-uri reale in test.
|
|
monkeypatch.setenv("AUTOPASS_MAX_REQUEST_BYTES", "1000")
|
|
from app.config import get_settings
|
|
get_settings.cache_clear()
|
|
from app.main import app
|
|
with TestClient(app) as c:
|
|
yield c
|
|
get_settings.cache_clear()
|
|
|
|
|
|
def test_multipart_peste_limita_413(client):
|
|
data = b"x" * 5000
|
|
r = client.post(
|
|
"/v1/import",
|
|
files={"file": ("mare.csv", io.BytesIO(data), "text/csv")},
|
|
)
|
|
assert r.status_code == 413
|
|
assert r.json()["cod"] == "CERERE_PREA_MARE"
|
|
|
|
|
|
def test_json_peste_limita_413(client):
|
|
payload = {"blob": "x" * 5000}
|
|
r = client.post(
|
|
"/v1/prezentari",
|
|
content=json.dumps(payload),
|
|
headers={"content-type": "application/json"},
|
|
)
|
|
assert r.status_code == 413
|
|
assert r.json()["cod"] == "CERERE_PREA_MARE"
|
|
|
|
|
|
def test_cerere_normala_sub_limita_trece(client):
|
|
r = client.get("/healthz")
|
|
assert r.status_code == 200
|
|
|
|
|
|
def test_content_length_mare_body_mic_413_devreme(client):
|
|
"""Content-Length declarat peste limita respinge inainte sa citeasca body-ul,
|
|
chiar daca body-ul trimis efectiv e mic (client "mincinos")."""
|
|
r = client.post(
|
|
"/v1/prezentari",
|
|
content=b"{}",
|
|
headers={"content-type": "application/json", "content-length": "999999"},
|
|
)
|
|
assert r.status_code == 413
|
|
assert r.json()["cod"] == "CERERE_PREA_MARE"
|