"""Environment Jinja2 partagé (A10 : autoescape activé partout). Une seule instance au lieu de 29 `Environment(loader=FileSystemLoader(...))` sans autoescape — 326 interpolations `{{ … }}` étaient servies crues et tous les `|safe` du codebase étaient des no-op. """ from __future__ import annotations import pathlib from contextvars import ContextVar from jinja2 import Environment, FileSystemLoader, select_autoescape # A20 : nonce de script par requête, posé par le middleware CSP, lu par les # templates via `{{ csp_nonce() }}` (vide hors requête — pas de header CSP # dans ce cas, donc rien n'est bloqué). CSP_NONCE: ContextVar[str] = ContextVar("csp_nonce", default="") ENV = Environment( loader=FileSystemLoader("app/templates"), autoescape=select_autoescape(["html"]), ) # A40 : version des assets statiques première main, lue une seule fois (le # fichier VERSION fait foi ; repli "dev" si l'image ne le contient pas). try: ASSET_VERSION = (pathlib.Path(__file__).resolve().parent.parent / "VERSION").read_text( encoding="utf-8" ).strip() except OSError: # pragma: no cover ASSET_VERSION = "dev" ENV.globals["asset_version"] = ASSET_VERSION ENV.globals["csp_nonce"] = lambda: CSP_NONCE.get()