Files
flowdeck/tests/test_draco_urls_devprod.py
T
Spark 283e226adf
FlowDeck CI / test (push) Successful in 29m39s
FlowDeck CI / lint (push) Successful in 2m18s
FlowDeck CI / docker (push) Successful in 1m41s
fix(draco): URLs sœurs dérivées de l'environnement de l'agent (7.82.3)
Résolution uniforme des quatre sœurs (ObsiGate, Flowdeck, TikTak,
Kanbante) dans app/services/draco_urls.py : explicite prioritaire
(contrat inchangé), sinon dérivation depuis l'hôte de l'agent connu
via AGENT_EVENEMENTS_URL (agent<SUFFIXE>.dracodev.net →
<slug><SUFFIXE>.dracodev.net), sinon défaut officiel. Hors motif
(autre domaine, LAN, IP) : aucune dérivation. Gitea inchangé.
Tests +4 dans test_draco_urls_devprod.py.
2026-10-26 00:46:21 +00:00

191 lines
8.6 KiB
Python

"""URLs publiques dracodev par configuration — chantier dev/prod (v7.82.0).
Règle vérifiée : aucun nom public codé en dur dans le code vivant ;
les défauts sont les noms OFFICIELS (jamais de ``-dev`` en défaut) et
chaque environnement déclare ses noms en ``-dev`` par l'environnement
(``DRACO_SSO_URL``, ``DRACO_AGENT_URL``, ``TIKTAK_URL``,
``KANBANTE_URL``, ``FLOWDECK_URL``/``OAUTH_REDIRECT_URI``…).
"""
import pytest
from app.services import draco_urls
VARS = ("DRACO_SSO_URL", "DRACO_AGENT_URL", "TIKTAK_URL", "KANBANTE_URL",
"FLOWDECK_URL", "OAUTH_REDIRECT_URI", "AGENT_EVENEMENTS_URL")
@pytest.fixture(autouse=True)
def _env_propre(monkeypatch):
for v in VARS:
monkeypatch.delenv(v, raising=False)
def test_defauts_officiels_sans_dev():
urls = draco_urls.toutes()
assert urls["obsigate"] == "https://og.dracodev.net"
assert urls["agent"] == "https://agent.dracodev.net"
assert urls["tiktak"] == "https://tiktak.dracodev.net"
assert urls["kanbante"] == "https://kanbante.dracodev.net"
assert urls["flowdeck"] == "https://flowdeck.dracodev.net"
assert all("-dev" not in u for u in urls.values())
def test_surcharge_dev_par_env(monkeypatch):
monkeypatch.setenv("DRACO_SSO_URL", "https://og-dev.dracodev.net")
monkeypatch.setenv("DRACO_AGENT_URL", "https://agent-dev.dracodev.net")
monkeypatch.setenv("TIKTAK_URL", "https://tiktak-dev.dracodev.net")
monkeypatch.setenv("KANBANTE_URL", "https://kanbante-dev.dracodev.net")
monkeypatch.setenv("FLOWDECK_URL", "https://flowdeck-dev.dracodev.net")
urls = draco_urls.toutes()
assert urls["obsigate"] == "https://og-dev.dracodev.net"
assert urls["agent"] == "https://agent-dev.dracodev.net"
assert urls["tiktak"] == "https://tiktak-dev.dracodev.net"
assert urls["kanbante"] == "https://kanbante-dev.dracodev.net"
assert urls["flowdeck"] == "https://flowdeck-dev.dracodev.net"
def test_flowdeck_url_derivée_oauth_redirect(monkeypatch):
monkeypatch.setenv(
"OAUTH_REDIRECT_URI", "https://flowdeck-dev.dracodev.net/auth/callback")
assert draco_urls.flowdeck_url() == "https://flowdeck-dev.dracodev.net"
def test_evenements_url_derivée_agent(monkeypatch):
from app.services import agent_evenements
monkeypatch.setenv("DRACO_AGENT_URL", "https://agent-dev.dracodev.net")
assert agent_evenements._url() == \
"https://agent-dev.dracodev.net/api/v1/evenements"
monkeypatch.setenv("AGENT_EVENEMENTS_URL", "http://127.0.0.1:9/api/v1/evenements")
assert agent_evenements._url() == "http://127.0.0.1:9/api/v1/evenements"
def test_csp_agent_depuis_config(client, monkeypatch):
monkeypatch.setenv("DRACO_AGENT_URL", "https://agent-dev.dracodev.net")
r = client.get("/")
csp = r.headers.get("content-security-policy", "")
assert "https://agent-dev.dracodev.net" in csp
assert "connect-src 'self' https://agent-dev.dracodev.net" in csp
assert "frame-src 'self' https://agent-dev.dracodev.net" in csp
assert "https://agent.dracodev.net " not in csp.replace(
"https://agent-dev.dracodev.net", "")
def test_parse_deep_link_dev_et_officiel(monkeypatch):
from app.services.external_refs import parse_deep_link
monkeypatch.setenv("TIKTAK_URL", "https://tiktak-dev.dracodev.net")
monkeypatch.setenv("DRACO_SSO_URL", "https://og-dev.dracodev.net")
# Hôte configuré (dev)…
assert parse_deep_link("https://tiktak-dev.dracodev.net/?task=7")[:3] == \
("tiktak", "task", "7")
assert parse_deep_link("https://og-dev.dracodev.net/#file=P:A.md")[:3] == \
("obsigate", "note", "P:A.md")
# …et hôte officiel toujours reconnu (références déjà stockées).
assert parse_deep_link("https://tiktak.dracodev.net/?task=7")[:3] == \
("tiktak", "task", "7")
assert parse_deep_link("https://og.dracodev.net/#file=P:A.md")[:3] == \
("obsigate", "note", "P:A.md")
def test_url_affichage_reecrit_hote_sans_toucher_stockage(monkeypatch):
from app.services.external_refs import url_affichage
monkeypatch.setenv("TIKTAK_URL", "https://tiktak-dev.dracodev.net")
stockee = "https://tiktak.dracodev.net/?task=42"
assert url_affichage(stockee) == "https://tiktak-dev.dracodev.net/?task=42"
# La fonction est pure : la valeur d'entrée (celle en base) ne bouge pas.
assert stockee == "https://tiktak.dracodev.net/?task=42"
assert url_affichage("https://example.com/x") == "https://example.com/x"
def test_preset_tiktak_depuis_config(monkeypatch):
from app.services import connectors
assert connectors.PRESETS["tiktak"]["url"] == \
"https://tiktak.dracodev.net/mcp"
monkeypatch.setenv("TIKTAK_URL", "https://tiktak-dev.dracodev.net")
assert connectors.PRESETS["tiktak"]["url"] == \
"https://tiktak-dev.dracodev.net/mcp"
def test_derivation_dev_depuis_agent_evenements_seul(monkeypatch):
# Cas réel de la dev : seul AGENT_EVENEMENTS_URL est posé —
# les quatre URLs sœurs servies suivent en ``-dev``, sans
# déclarer quatre variables de plus. Gitea ne change pas.
monkeypatch.setenv(
"AGENT_EVENEMENTS_URL",
"https://agent-dev.dracodev.net/api/v1/evenements")
urls = draco_urls.toutes()
assert urls["obsigate"] == "https://og-dev.dracodev.net"
assert urls["flowdeck"] == "https://flowdeck-dev.dracodev.net"
assert urls["tiktak"] == "https://tiktak-dev.dracodev.net"
assert urls["kanbante"] == "https://kanbante-dev.dracodev.net"
assert urls["gitea"] == "https://git.dracodev.net"
# Les accesseurs individuels partagent la même résolution.
assert draco_urls.obsigate_url() == "https://og-dev.dracodev.net"
assert draco_urls.flowdeck_url() == "https://flowdeck-dev.dracodev.net"
assert draco_urls.tiktak_url() == "https://tiktak-dev.dracodev.net"
assert draco_urls.kanbante_url() == "https://kanbante-dev.dracodev.net"
def test_derivation_explicite_gagne_sur_derivation(monkeypatch):
monkeypatch.setenv(
"AGENT_EVENEMENTS_URL",
"https://agent-dev.dracodev.net/api/v1/evenements")
# Explicites (contrat inchangé) : elles priment sur la dérivation,
# y compris quand elles pointent le nom officiel.
monkeypatch.setenv("DRACO_SSO_URL", "https://og.dracodev.net")
monkeypatch.setenv("TIKTAK_URL", "https://tiktak.example.net")
urls = draco_urls.toutes()
assert urls["obsigate"] == "https://og.dracodev.net"
assert urls["tiktak"] == "https://tiktak.example.net"
# Non déclarées : dérivées.
assert urls["flowdeck"] == "https://flowdeck-dev.dracodev.net"
assert urls["kanbante"] == "https://kanbante-dev.dracodev.net"
def test_derivation_hote_agent_hors_motif_defauts_officiels(monkeypatch):
# Autre domaine, LAN, IP : aucune dérivation, jamais un lien deviné.
for url_agent in (
"https://agent.example.com/api/v1/evenements",
"https://agent-dev.example.net/api/v1/evenements",
"https://monagent-dev.dracodev.net/api/v1/evenements",
"https://agent-dev.dracodev.net.evil.com/api/v1/evenements",
"http://192.168.30.101:8790/api/v1/evenements",
"http://127.0.0.1:8790/api/v1/evenements",
"http://agent-dev.local:8790/api/v1/evenements",
):
monkeypatch.setenv("AGENT_EVENEMENTS_URL", url_agent)
urls = draco_urls.toutes()
assert urls["obsigate"] == "https://og.dracodev.net", url_agent
assert urls["flowdeck"] == "https://flowdeck.dracodev.net", url_agent
assert urls["tiktak"] == "https://tiktak.dracodev.net", url_agent
assert urls["kanbante"] == "https://kanbante.dracodev.net", url_agent
def test_derivation_agent_officiel_suffixe_vide(monkeypatch):
# Hôte agent officiel : suffixe vide, les sœurs restent officielles.
monkeypatch.setenv(
"AGENT_EVENEMENTS_URL", "https://agent.dracodev.net/api/v1/evenements")
urls = draco_urls.toutes()
assert urls["obsigate"] == "https://og.dracodev.net"
assert urls["flowdeck"] == "https://flowdeck.dracodev.net"
assert urls["tiktak"] == "https://tiktak.dracodev.net"
assert urls["kanbante"] == "https://kanbante.dracodev.net"
def test_bouton_sso_login_depuis_config(monkeypatch):
from app.routers.auth import _sso_login_url
assert _sso_login_url() == (
"https://og.dracodev.net/sso/authorize?return_to="
"https%3A%2F%2Fflowdeck.dracodev.net%2Fauth%2Fdraco")
monkeypatch.setenv("DRACO_SSO_URL", "https://og-dev.dracodev.net")
monkeypatch.setenv(
"OAUTH_REDIRECT_URI", "https://flowdeck-dev.dracodev.net/auth/callback")
assert _sso_login_url() == (
"https://og-dev.dracodev.net/sso/authorize?return_to="
"https%3A%2F%2Fflowdeck-dev.dracodev.net%2Fauth%2Fdraco")