fix: CSP compliance for inline styles and scripts
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
"""Tests E2E de conformité CSP : page de dons, anti-flash de thème et bouton PWA.
|
||||
|
||||
Couvre les corrections COR-4/COR-7 de l'audit : scripts inline noncés,
|
||||
remplacement des `onclick` par des addEventListener, et de
|
||||
`style="display: none;"` par la classe utilitaire `.is-hidden`.
|
||||
"""
|
||||
import pytest
|
||||
from playwright.sync_api import expect
|
||||
|
||||
|
||||
def _aller_page_dons(page, base_url):
|
||||
"""Charge dons.php ; saute le test si les dons sont désactivés sur l'instance."""
|
||||
reponse = page.goto(base_url + "/dons.php", wait_until="domcontentloaded")
|
||||
if reponse is None or reponse.status != 200:
|
||||
pytest.skip(f"dons.php indisponible (HTTP {reponse.status if reponse else '?'})")
|
||||
|
||||
|
||||
def _collecter_erreurs_console(page):
|
||||
"""Installe la collecte des erreurs console/JS ; retourne la liste à vérifier."""
|
||||
erreurs = []
|
||||
page.on("console", lambda msg: erreurs.append(msg.text) if msg.type == "error" else None)
|
||||
page.on("pageerror", lambda exc: erreurs.append(str(exc)))
|
||||
return erreurs
|
||||
|
||||
|
||||
def test_dons_scripts_inline_ont_un_nonce(page, base_url):
|
||||
"""Tous les scripts inline de dons.php portent le nonce CSP (COR-7)."""
|
||||
_aller_page_dons(page, base_url)
|
||||
|
||||
sans_nonce = page.locator("script:not([src]):not([nonce])").evaluate_all(
|
||||
"(els) => els.map(e => e.outerHTML.slice(0, 80))"
|
||||
)
|
||||
assert sans_nonce == [], f"Scripts inline sans nonce : {sans_nonce}"
|
||||
|
||||
onclick = page.locator("[onclick]").count()
|
||||
assert onclick == 0, f"{onclick} élément(s) avec un attribut onclick (bloqué par la CSP)"
|
||||
|
||||
|
||||
def test_dons_anti_flash_theme_sans_erreur(page, base_url):
|
||||
"""Le script anti-flash noncé s'exécute : thème sombre appliqué dès le chargement."""
|
||||
page.add_init_script("localStorage.setItem('theme', 'dark');")
|
||||
erreurs = _collecter_erreurs_console(page)
|
||||
_aller_page_dons(page, base_url)
|
||||
|
||||
assert page.locator("html").get_attribute("data-theme") == "dark", (
|
||||
"data-theme absent : le script anti-flash a été bloqué par la CSP"
|
||||
)
|
||||
assert erreurs == [], f"Erreurs console sur dons.php : {erreurs}"
|
||||
|
||||
|
||||
def test_dons_onglets_stripe(page, base_url):
|
||||
"""Les onglets Don ponctuel / Don mensuel fonctionnent via addEventListener."""
|
||||
_aller_page_dons(page, base_url)
|
||||
|
||||
onglets = page.locator(".donation-tabs .tab-btn")
|
||||
if onglets.count() == 0:
|
||||
pytest.skip("Stripe désactivé sur cette instance (STRIPE_ENABLED=false)")
|
||||
|
||||
onglet_mensuel = page.locator('.tab-btn[data-tab="monthly"]')
|
||||
onglet_ponctuel = page.locator('.tab-btn[data-tab="onetime"]')
|
||||
|
||||
# État initial : don ponctuel actif
|
||||
expect(page.locator("#onetime-tab")).to_have_class("tab-content active")
|
||||
expect(page.locator("#monthly-tab")).to_have_class("tab-content")
|
||||
|
||||
# dispatch_event plutôt que click : les polices chargées depuis cdnjs décalent
|
||||
# la mise en page et rendent le clic aux coordonnées intermittent. Le but est
|
||||
# de vérifier le câblage addEventListener (bloqué avant la correction CSP).
|
||||
onglet_mensuel.dispatch_event("click")
|
||||
expect(page.locator("#monthly-tab")).to_have_class("tab-content active")
|
||||
expect(page.locator("#onetime-tab")).to_have_class("tab-content")
|
||||
expect(onglet_mensuel).to_have_class("tab-btn active")
|
||||
|
||||
# Retour au don ponctuel
|
||||
onglet_ponctuel.dispatch_event("click")
|
||||
expect(page.locator("#onetime-tab")).to_have_class("tab-content active")
|
||||
expect(page.locator("#monthly-tab")).to_have_class("tab-content")
|
||||
|
||||
|
||||
def test_bouton_install_pwa_utilise_is_hidden(page, base_url):
|
||||
"""Le bouton d'installation PWA est masqué par .is-hidden, sans style inline (COR-4)."""
|
||||
_aller_page_dons(page, base_url)
|
||||
|
||||
bouton = page.locator("#install-pwa")
|
||||
assert bouton.count() == 1, "Bouton #install-pwa absent du header"
|
||||
assert bouton.get_attribute("style") is None, "Attribut style résiduel (bloqué par la CSP)"
|
||||
assert bouton.get_attribute("nonce") is None, "Attribut nonce résiduel sur un non-script"
|
||||
assert bouton.evaluate("(e) => e.classList.contains('is-hidden')")
|
||||
assert not bouton.is_visible(), "Le bouton PWA devrait être masqué sans beforeinstallprompt"
|
||||
Reference in New Issue
Block a user