from __future__ import annotations import json import re import subprocess import time import unittest from hub_case import HubCase from hub_support import AMBIENCE, SPACE, VOICE from kvb_hub import exchange class TestHubPage(HubCase): def test_review_page_is_sandboxed_and_the_index_allows_only_its_own_inline_code(self): review_id = self.request("feat: csp", "") status, headers, _ = self.get(f"/reviews/{review_id}/page") self.assertEqual(status, 200) self.assertEqual(headers["content-security-policy"], "sandbox allow-scripts") self.assertEqual(headers["x-content-type-options"], "nosniff") status, headers, body = self.get("/") csp = headers["content-security-policy"] nonce = re.search(r"script-src 'nonce-([^']+)'", csp).group(1) self.assertIn(f"style-src 'nonce-{nonce}'", csp) self.assertNotIn("unsafe", csp) self.assertIn("default-src 'none'", csp) html = body.decode("utf-8") tags = re.findall(r"<(script|style)\b([^>]*)>", html) self.assertEqual(sorted({tag for tag, _ in tags}), ["script", "style"]) self.assertGreaterEqual(len(tags), 3) for tag, attributes in tags: with self.subTest(tag=tag, attributes=attributes): self.assertIn(f'nonce="{nonce}"', attributes) self.assertNotIn(nonce, self.get("/")[1]["content-security-policy"]) status, headers, _ = self.get(f"/reviews/{review_id}/files") self.assertEqual((status, headers["content-type"]), (200, "application/json")) self.assertEqual(headers["content-security-policy"], exchange.PLAIN_CSP) def test_markup_from_agents_is_escaped(self): self.request("", "") register = {"work/x": {"title": "", "status": "running", "roles": {"One": "RA"}}} news = {"ts": time.time(), "from": "", "to": [], "text": ""} self.write_council({"rasci.json": register, "news.jsonl": self.jsonl([news])}) html = self.index() for n in range(1, 5): with self.subTest(n=n): self.assertNotIn(f"', html, re.DOTALL).group(1) state = json.loads(embedded) self.assertEqual((state["reviews"][0]["title"], state["reviews"][0]["notes"]), ("", "")) self.assertEqual((state["register"][0]["title"], state["radio"][0]["from"]), ("", "")) def test_the_index_scripts_parse_and_embed_the_ambience_voice_and_space_modules(self): html = self.index() for module in (AMBIENCE, VOICE, SPACE): with self.subTest(module=module.name): self.assertIn(module.read_text(encoding="utf-8").strip(), html) scripts = re.findall(r'', html, re.DOTALL) self.assertEqual(len(scripts), 4) page = self.state / "page.js" page.write_text("\n;\n".join(scripts), encoding="utf-8") done = subprocess.run(["node", "--check", str(page)], capture_output=True, text=True, timeout=60, check=False) self.assertEqual(done.returncode, 0, done.stderr) for module in (AMBIENCE, VOICE, SPACE): with self.subTest(module=module.name): done = subprocess.run(["node", "--check", str(module)], capture_output=True, text=True, timeout=60, check=False) self.assertEqual(done.returncode, 0, done.stderr) if __name__ == "__main__": unittest.main()