mirror of
https://github.com/kevinveenbirkenbach/homepage.veen.world.git
synced 2026-09-23 19:03:18 +00:00
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:
@@ -6,6 +6,7 @@ import subprocess
|
|||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
import unittest
|
import unittest
|
||||||
|
from html.parser import HTMLParser
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from unittest.mock import Mock, patch
|
from unittest.mock import Mock, patch
|
||||||
|
|
||||||
@@ -112,18 +113,29 @@ class TestEscaping(AppRouteMixin, unittest.TestCase):
|
|||||||
self.assertIn("<script>alert('config')", body)
|
self.assertIn("<script>alert('config')", 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):
|
class TestContentSecurityPolicy(AppRouteMixin, unittest.TestCase):
|
||||||
def test_page_ships_no_executable_inline_script(self):
|
def test_page_ships_no_executable_inline_script(self):
|
||||||
body = self.client.get("/de/").get_data(as_text=True)
|
body = self.client.get("/de/").get_data(as_text=True)
|
||||||
|
|
||||||
inline = [
|
collector = InlineScriptCollector()
|
||||||
tag
|
collector.feed(body)
|
||||||
for tag in re.findall(r"<script\b[^>]*>", body)
|
|
||||||
if "src=" not in tag and 'type="application/json"' not in tag
|
|
||||||
]
|
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
inline,
|
collector.inline,
|
||||||
[],
|
[],
|
||||||
"a host CSP can only hash an inline script whose content it knows, "
|
"a host CSP can only hash an inline script whose content it knows, "
|
||||||
"and this one changes with every language",
|
"and this one changes with every language",
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ import re
|
|||||||
import shutil
|
import shutil
|
||||||
import tempfile
|
import tempfile
|
||||||
import unittest
|
import unittest
|
||||||
|
import unittest.mock
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from unittest import mock
|
|
||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
@@ -170,7 +170,7 @@ class TestCatalogMerge(unittest.TestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def test_an_unsupported_code_never_becomes_a_path(self):
|
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"), {})
|
self.assertEqual(i18n.catalog("../content/de"), {})
|
||||||
|
|
||||||
read.assert_not_called()
|
read.assert_not_called()
|
||||||
|
|||||||
Reference in New Issue
Block a user