CORS recherche : allowlist soeurs prod+dev explicites (fusion #68/#69) #44
+16
-12
@@ -8,12 +8,16 @@ Ce module n'autorise donc que :
|
|||||||
|
|
||||||
- le chemin ``/api/search`` (jamais les autres routes, jamais les
|
- le chemin ``/api/search`` (jamais les autres routes, jamais les
|
||||||
écritures) ;
|
écritures) ;
|
||||||
- les origines sœurs : celles de ``backend.draco_config``
|
- les origines sœurs : les origines officielles **prod ET dev,
|
||||||
(``urls_publiques()`` : explicite > dérivation par l'hôte de
|
listées explicitement** (``PROD_ORIGINS | DEV_ORIGINS``), **plus**
|
||||||
l'agent > défaut officiel), **plus** les origines prod ou ``-dev``
|
celles de ``backend.draco_config`` (``urls_publiques()`` :
|
||||||
officielles correspondant à l'hôte de la requête — ce second
|
explicite > dérivation par l'hôte de l'agent > défaut officiel)
|
||||||
ensemble couvre le cas où la configuration seule ne déclare pas
|
— jamais ``*``. Correctif 2026-10-28 (fusion #68/#69, matrice
|
||||||
l'environnement courant ;
|
constatée par Bruno) : l'ancienne allowlist ne contenait que
|
||||||
|
l'environnement de la configuration (plus celui de l'hôte de la
|
||||||
|
requête), jamais les deux à la fois — une page de l'autre
|
||||||
|
environnement voyait sa section afficher « Injoignable depuis
|
||||||
|
cet hôte (CORS ou réseau) » ;
|
||||||
- avec credentials (le cookie SSO ``draco_session``, accepté par
|
- avec credentials (le cookie SSO ``draco_session``, accepté par
|
||||||
``/api/search`` via le repli de ``backend.auth.middleware``, ou
|
``/api/search`` via le repli de ``backend.auth.middleware``, ou
|
||||||
le cookie natif ``access_token``).
|
le cookie natif ``access_token``).
|
||||||
@@ -104,12 +108,12 @@ def sister_origins(resolved: dict | None = None, request_host: str | None = None
|
|||||||
origin = origin_of((resolved or {}).get(key))
|
origin = origin_of((resolved or {}).get(key))
|
||||||
if origin:
|
if origin:
|
||||||
origins.add(origin)
|
origins.add(origin)
|
||||||
if is_dev_host(request_host):
|
# Correctif 2026-10-28 : prod ET dev toujours — ``request_host``
|
||||||
origins |= DEV_ORIGINS
|
# ne restreint plus l'allowlist (il ne servait qu'à ajouter
|
||||||
elif is_prod_host(request_host):
|
# l'environnement de la requête, désormais inclus d'office).
|
||||||
origins |= PROD_ORIGINS
|
# ``resolved`` n'ajoute que des origines de configuration sans
|
||||||
if not origins:
|
# jamais retirer une origine officielle.
|
||||||
return PROD_ORIGINS | DEV_ORIGINS
|
origins |= PROD_ORIGINS | DEV_ORIGINS
|
||||||
return frozenset(origins)
|
return frozenset(origins)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,13 @@ def test_origin_of():
|
|||||||
|
|
||||||
|
|
||||||
def test_sister_origins_dev():
|
def test_sister_origins_dev():
|
||||||
|
# Correctif 2026-10-28 : 8 origines officielles, prod ET dev,
|
||||||
|
# quelle que soit la résolution.
|
||||||
assert sister_origins(RESOLVED_DEV) == {
|
assert sister_origins(RESOLVED_DEV) == {
|
||||||
|
"https://og.dracodev.net",
|
||||||
|
"https://flowdeck.dracodev.net",
|
||||||
|
"https://tiktak.dracodev.net",
|
||||||
|
"https://kanbante.dracodev.net",
|
||||||
"https://og-dev.dracodev.net",
|
"https://og-dev.dracodev.net",
|
||||||
"https://flowdeck-dev.dracodev.net",
|
"https://flowdeck-dev.dracodev.net",
|
||||||
"https://tiktak-dev.dracodev.net",
|
"https://tiktak-dev.dracodev.net",
|
||||||
@@ -47,12 +53,18 @@ def test_sister_origins_dev():
|
|||||||
|
|
||||||
|
|
||||||
def test_sister_origins_ajoute_env_de_la_requete():
|
def test_sister_origins_ajoute_env_de_la_requete():
|
||||||
|
# Correctif 2026-10-28 : configuration muette, quel que soit
|
||||||
|
# l'hôte de la requête, prod ET dev passent — l'hôte ne
|
||||||
|
# restreint plus l'allowlist.
|
||||||
assert "https://og-dev.dracodev.net" in sister_origins(
|
assert "https://og-dev.dracodev.net" in sister_origins(
|
||||||
{}, request_host="og-dev.dracodev.net"
|
{}, request_host="og-dev.dracodev.net"
|
||||||
)
|
)
|
||||||
assert "https://og-dev.dracodev.net" not in sister_origins(
|
assert "https://og-dev.dracodev.net" in sister_origins(
|
||||||
{}, request_host="og.dracodev.net"
|
{}, request_host="og.dracodev.net"
|
||||||
)
|
)
|
||||||
|
assert "https://og.dracodev.net" in sister_origins(
|
||||||
|
{}, request_host="og-dev.dracodev.net"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_cors_headers():
|
def test_cors_headers():
|
||||||
@@ -60,7 +72,11 @@ def test_cors_headers():
|
|||||||
assert headers["Access-Control-Allow-Origin"] == "https://tiktak-dev.dracodev.net"
|
assert headers["Access-Control-Allow-Origin"] == "https://tiktak-dev.dracodev.net"
|
||||||
assert headers["Access-Control-Allow-Credentials"] == "true"
|
assert headers["Access-Control-Allow-Credentials"] == "true"
|
||||||
assert cors_headers_for("https://evil.example", RESOLVED_DEV) is None
|
assert cors_headers_for("https://evil.example", RESOLVED_DEV) is None
|
||||||
assert cors_headers_for("https://og.dracodev.net", RESOLVED_DEV) is None
|
assert cors_headers_for("https://og-dev.dracodev.net.evil.example",
|
||||||
|
RESOLVED_DEV) is None
|
||||||
|
# Autre environnement autorisé (correctif 2026-10-28).
|
||||||
|
assert cors_headers_for("https://og.dracodev.net",
|
||||||
|
RESOLVED_DEV) is not None
|
||||||
|
|
||||||
|
|
||||||
def test_preflight_headers():
|
def test_preflight_headers():
|
||||||
|
|||||||
Reference in New Issue
Block a user