test: parse the page instead of matching tags with a regex

The inline-script check matched <script\b[^>]*> and then filtered the matched text, so a > inside an attribute value split one tag into a fragment that had already lost the attribute the filter looks for. An html.parser subclass decides on the parsed attributes instead. The i18n test imported unittest twice, once plain and once as a from-import.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-23 02:09:23 +02:00
parent 87c4405aa4
commit 4cc8052a88
2 changed files with 20 additions and 8 deletions

View File

@@ -6,6 +6,7 @@ import subprocess
import sys
import tempfile
import unittest
from html.parser import HTMLParser
from pathlib import Path
from unittest.mock import Mock, patch
@@ -112,18 +113,29 @@ class TestEscaping(AppRouteMixin, unittest.TestCase):
self.assertIn("&lt;script&gt;alert(&#39;config&#39;)", body)
class InlineScriptCollector(HTMLParser):
def __init__(self):
super().__init__()
self.inline = []
def handle_starttag(self, tag, attrs):
if tag != "script":
return
attributes = dict(attrs)
if "src" in attributes or attributes.get("type") == "application/json":
return
self.inline.append(self.get_starttag_text())
class TestContentSecurityPolicy(AppRouteMixin, unittest.TestCase):
def test_page_ships_no_executable_inline_script(self):
body = self.client.get("/de/").get_data(as_text=True)
inline = [
tag
for tag in re.findall(r"<script\b[^>]*>", body)
if "src=" not in tag and 'type="application/json"' not in tag
]
collector = InlineScriptCollector()
collector.feed(body)
self.assertEqual(
inline,
collector.inline,
[],
"a host CSP can only hash an inline script whose content it knows, "
"and this one changes with every language",

View File

@@ -2,8 +2,8 @@ import re
import shutil
import tempfile
import unittest
import unittest.mock
from pathlib import Path
from unittest import mock
import yaml
@@ -170,7 +170,7 @@ class TestCatalogMerge(unittest.TestCase):
)
def test_an_unsupported_code_never_becomes_a_path(self):
with mock.patch.object(i18n, "read_catalog") as read:
with unittest.mock.patch.object(i18n, "read_catalog") as read:
self.assertEqual(i18n.catalog("../content/de"), {})
read.assert_not_called()