securite: #87 T6-T8 fin dette — deps qualifiées, semgrep, Secure auto, CORS
This commit is contained in:
@@ -1,31 +1,34 @@
|
||||
"""Tests — cookies Secure, CORS same-origin implicite, avertissement bind (ROADMAP #87 T3).
|
||||
"""Tests — cookies Secure, CORS same-origin explicite, avertissement bind (ROADMAP #87 T3/T8).
|
||||
|
||||
- `is_secure_cookies()` suit `OBSIGATE_SECURE_COOKIES` (défaut `false` :
|
||||
compatibilité logins en HTTP local — les navigateurs ignorent les cookies
|
||||
`Secure` en clair).
|
||||
- Aucun en-tête CORS permissif n'est émis : sans `CORSMiddleware`, les
|
||||
navigateurs appliquent le same-origin par défaut (politique explicite par
|
||||
l'absence — vérifiée ici pour qu'un ajout futur de CORS soit conscient).
|
||||
- `is_secure_cookies()` : `OBSIGATE_SECURE_COOKIES=true|false|auto` (défaut
|
||||
`auto` : Secure si la requête arrive en https, sinon pas de flag — les
|
||||
navigateurs ignorent les cookies `Secure` en clair).
|
||||
- CORS same-origin EXPLICITE : `CORSMiddleware(allow_origins=[])` — aucun
|
||||
`Access-Control-Allow-*` n'est émis même avec un `Origin` cross-origin,
|
||||
et les preflights sont rejetés (400).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
def test_secure_cookies_default_false(monkeypatch):
|
||||
"""Défaut `false` (logins HTTP locaux préservés)."""
|
||||
def test_secure_cookies_default_auto(monkeypatch):
|
||||
"""Défaut `auto` : sans requête → pas de flag (logins HTTP locaux préservés)."""
|
||||
from backend.auth.router import is_secure_cookies
|
||||
|
||||
monkeypatch.delenv("OBSIGATE_SECURE_COOKIES", raising=False)
|
||||
assert is_secure_cookies() is False
|
||||
|
||||
|
||||
def test_secure_cookies_opt_in(monkeypatch):
|
||||
"""`OBSIGATE_SECURE_COOKIES=true` → flag actif (insensible à la casse)."""
|
||||
def test_secure_cookies_forced_values(monkeypatch):
|
||||
"""`true`/`1`/`yes` → flag ; `false`/`0`/`no` → pas de flag (insensible à la casse)."""
|
||||
from backend.auth.router import is_secure_cookies
|
||||
|
||||
for value in ("true", "True", "TRUE", "1", "yes"):
|
||||
for value in ("true", "True", "TRUE", "1", "yes", "on"):
|
||||
monkeypatch.setenv("OBSIGATE_SECURE_COOKIES", value)
|
||||
assert is_secure_cookies() is (value.lower() == "true")
|
||||
assert is_secure_cookies() is True
|
||||
for value in ("false", "False", "FALSE", "0", "no", "off"):
|
||||
monkeypatch.setenv("OBSIGATE_SECURE_COOKIES", value)
|
||||
assert is_secure_cookies() is False
|
||||
|
||||
|
||||
def test_no_cors_headers_on_api(client):
|
||||
@@ -42,6 +45,25 @@ def test_no_cors_headers_on_public_share(client):
|
||||
assert "access-control-allow-origin" not in {k.lower() for k in resp.headers}
|
||||
|
||||
|
||||
def test_cross_origin_get_emits_no_acao(client):
|
||||
"""#87 T8 : même avec un `Origin` cross-origin, aucun ACAO (refus explicite)."""
|
||||
resp = client.get("/api/health", headers={"Origin": "http://evil.example"})
|
||||
assert resp.status_code == 200
|
||||
assert "access-control-allow-origin" not in {k.lower() for k in resp.headers}
|
||||
|
||||
|
||||
def test_cross_origin_preflight_rejected(client):
|
||||
"""#87 T8 : preflight cross-origin → 400 (origine non autorisée)."""
|
||||
resp = client.options(
|
||||
"/api/health",
|
||||
headers={
|
||||
"Origin": "http://evil.example",
|
||||
"Access-Control-Request-Method": "GET",
|
||||
},
|
||||
)
|
||||
assert resp.status_code == 400
|
||||
|
||||
|
||||
def test_security_headers_present(client):
|
||||
"""En-têtes de durcissement posés par le middleware (non-régression)."""
|
||||
resp = client.get("/api/health")
|
||||
|
||||
Reference in New Issue
Block a user