"""对齐 Muse P4 测试:浏览器完全对齐。
只测本轨交付物(chv-guest/chv_browser_guard.py、
chv-cdp-broker.py、chv-browser.py、browser-blocklist.txt、
build.sh 干跑、buildinfo.py 内容项)。全部用假 socket/假进程/
假 playwright,绝不连真实网络、不起真实 VM、不改生产行为。
"""
import ast
import importlib.util
import json
import os
import shutil
import socket
import subprocess
import sys
import tempfile
import threading
import unittest
from pathlib import Path
from unittest import mock
ROOT = Path(__file__).resolve().parents[2]
def _load_script(name):
"""把 chv-guest 下的独立脚本当模块加载(无包结构)。"""
path = ROOT / "chv-guest" / name
spec = importlib.util.spec_from_file_location(
"chv_guest_p4_" + name[:-3].replace("-", "_"), str(path))
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
return module
GUARD = _load_script("chv_browser_guard.py")
CDP = _load_script("chv-cdp-broker.py")
BROWSER = _load_script("chv-browser.py")
BUILDINFO = _load_script("buildinfo.py")
class GuardTest(unittest.TestCase):
def test_validate_url(self):
self.assertTrue(GUARD.validate_url("https://example.com")[0])
self.assertTrue(GUARD.validate_url("http://example.com/x")[0])
for bad in ("ftp://example.com", "file:///etc/passwd",
"https://localhost:8080/", "http://127.0.0.1/",
"https://192.168.1.1/", "https://10.0.0.5/",
"https://172.17.0.2/", "", None):
ok, _ = GUARD.validate_url(bad)
self.assertFalse(ok, bad)
def test_blocklist_load_and_match(self):
with tempfile.TemporaryDirectory() as tmp:
path = os.path.join(tmp, "blocklist.txt")
with open(path, "w") as fh:
fh.write("# comment\n\nmalware.test\n.phishing.test\n")
entries = GUARD.load_blocklist(path)
self.assertEqual(entries, {"malware.test",
".phishing.test"})
self.assertTrue(GUARD.check_blocklist("malware.test",
entries))
self.assertTrue(GUARD.check_blocklist("a.malware.test",
entries))
self.assertTrue(GUARD.check_blocklist("x.phishing.test",
entries))
self.assertFalse(GUARD.check_blocklist("example.com",
entries))
self.assertFalse(GUARD.check_blocklist("notmalware.test",
entries))
self.assertEqual(GUARD.load_blocklist("/nonexistent/x"), set())
def test_truncate_a11y_small_tree_untouched(self):
tree = {"role": "WebArea", "name": "Example",
"children": [{"role": "heading", "name": "Hi"}]}
out, truncated = GUARD.truncate_a11y(tree)
self.assertFalse(truncated)
self.assertEqual(out, tree)
def test_truncate_a11y_char_cap(self):
tree = {"role": "WebArea", "name": "x" * 70000, "children": []}
out, truncated = GUARD.truncate_a11y(tree)
self.assertTrue(truncated)
self.assertTrue(out.get("truncated_chars"))
def test_sanitize_error_strips_html_and_secrets(self):
err = RuntimeError(
"timeout token=sk-secret-abc")
clean = GUARD.sanitize_error(err)
self.assertIn("RuntimeError", clean)
self.assertNotIn(" sk-secret-abc")
resp = broker.open("https://example.com")
self.assertFalse(resp["ok"])
self.assertNotIn("