"""Fusion #69 — Alertes unifiées (chantier 2, Flowdeck). Source réelle de Flowdeck : GET /api/notifications (non lues = actives, `url` relative pour le lien profond), déjà exposée et inchangée ici. Couverts : placeholder Alertes disparu, module servi, CSP connect-src avec les origines soeurs, CORS (origines soeurs ajoutées à allow_origins ; tiers sans en-tête). """ SOEURS = ("https://og.dracodev.net", "https://flowdeck.dracodev.net", "https://tiktak.dracodev.net", "https://kanbante.dracodev.net") def test_barre_alertes_sans_placeholder_et_module_servi(client): # Les pages applicatives authentifiées ne sont pas atteignables # telles quelles dans la sandbox (l'écran de connexion est servi # pour "/" comme pour "/dashboard") : on vérifie donc le gabarit # livré lui-même, plus les fichiers statiques servis. from pathlib import Path gabarit = Path("app/templates/_draco_bar.html").read_text() assert "Alertes unifiées : arrive avec la fédération" not in gabarit assert "draco-alertes.js" in gabarit assert "draco-alertes.css" in gabarit assert "DRACO_ALERTES.open()" in gabarit js = client.get("/static/js/draco-alertes.js") assert js.status_code == 200 assert "DRACO_ALERTES" in js.text assert "api/notifications" in js.text css = client.get("/static/css/draco-alertes.css") assert css.status_code == 200 assert "draco-alertes-overlay" in css.text def test_csp_connect_src_contient_les_soeurs(client): # La CSP est posée sur toute réponse HTML, y compris l'écran de # connexion servi ici : elle prouve les origines soeurs en # connect-src pour les pages de l'hôte. r = client.get("/") csp = r.headers.get("content-security-policy", "") assert "connect-src" in csp for origine in SOEURS: assert origine in csp, csp def test_notifications_api_et_cors_soeur(client): r = client.get("/api/notifications") assert r.status_code == 200 body = r.json() assert isinstance(body["notifications"], list) assert "unread" in body r2 = client.options("/api/notifications", headers={"Origin": "https://tiktak.dracodev.net", "Access-Control-Request-Method": "GET"}) assert r2.headers.get("access-control-allow-origin") == "https://tiktak.dracodev.net" assert r2.headers.get("access-control-allow-credentials") == "true" r3 = client.get("/api/notifications", headers={"Origin": "https://tiktak.dracodev.net"}) assert r3.headers.get("access-control-allow-origin") == "https://tiktak.dracodev.net" r4 = client.options("/api/notifications", headers={"Origin": "https://evil.example", "Access-Control-Request-Method": "GET"}) assert "access-control-allow-origin" not in r4.headers