gabriel / muse public
test_phase7_no_msgpack_in_storage.py python
119 lines 4.7 KB
Raw
1 """TDD — Phase 7: msgpack confined to wire-protocol files only.
2
3 Phase 7 requirements (issue #12):
4 - `import msgpack` must appear ONLY in wire-protocol files (transport, object
5 store, gc, migration, bundle, pack/unpack commands).
6 - Every file in the allowlist must exist (guard against stale allowlist).
7 - No file under muse/core/, muse/plugins/, or muse/cli/commands/ outside the
8 allowlist may import the msgpack library.
9 """
10
11 from __future__ import annotations
12
13 import ast
14 import pathlib
15
16 # ---------------------------------------------------------------------------
17 # Wire-only allowlist — files that legitimately import msgpack
18 # ---------------------------------------------------------------------------
19
20 _REPO_ROOT = pathlib.Path(__file__).parent.parent
21
22 _WIRE_ALLOWLIST: frozenset[pathlib.Path] = frozenset({
23 _REPO_ROOT / "muse" / "core" / "io.py",
24 _REPO_ROOT / "muse" / "core" / "gc.py",
25 _REPO_ROOT / "muse" / "core" / "transport.py",
26 _REPO_ROOT / "muse" / "core" / "migrate.py",
27 _REPO_ROOT / "muse" / "core" / "mpack.py",
28 _REPO_ROOT / "muse" / "cli" / "commands" / "bundle.py",
29 _REPO_ROOT / "muse" / "cli" / "commands" / "pack_objects.py",
30 _REPO_ROOT / "muse" / "cli" / "commands" / "unpack_objects.py",
31 _REPO_ROOT / "muse" / "cli" / "commands" / "verify_pack.py",
32 })
33
34
35 def _imports_msgpack(path: pathlib.Path) -> bool:
36 """Return True if *path* contains any import of the msgpack library."""
37 try:
38 tree = ast.parse(path.read_text(encoding="utf-8"), filename=str(path))
39 except SyntaxError:
40 return False
41 for node in ast.walk(tree):
42 if isinstance(node, ast.Import):
43 for alias in node.names:
44 if alias.name == "msgpack" or alias.name.startswith("msgpack."):
45 return True
46 elif isinstance(node, ast.ImportFrom):
47 if node.module and (
48 node.module == "msgpack" or node.module.startswith("msgpack.")
49 ):
50 return True
51 return False
52
53
54 # ---------------------------------------------------------------------------
55 # Test: allowlist files all exist
56 # ---------------------------------------------------------------------------
57
58
59 class TestWireAllowlistFilesExist:
60 def test_all_allowlist_files_exist(self) -> None:
61 """Every file in the wire allowlist must actually exist on disk."""
62 missing = [p for p in _WIRE_ALLOWLIST if not p.is_file()]
63 assert missing == [], (
64 f"Stale allowlist — these files no longer exist: "
65 + ", ".join(str(p.relative_to(_REPO_ROOT)) for p in missing)
66 )
67
68
69 # ---------------------------------------------------------------------------
70 # Test: no msgpack in muse/core/ (except allowlist)
71 # ---------------------------------------------------------------------------
72
73
74 class TestNoMsgpackInCore:
75 def test_no_msgpack_import_in_core_storage(self) -> None:
76 """No file in muse/core/ outside the allowlist may import msgpack."""
77 violations: list[str] = []
78 for path in (_REPO_ROOT / "muse" / "core").rglob("*.py"):
79 if path in _WIRE_ALLOWLIST:
80 continue
81 if _imports_msgpack(path):
82 violations.append(str(path.relative_to(_REPO_ROOT)))
83 assert violations == [], (
84 "Non-wire muse/core/ files import msgpack:\n "
85 + "\n ".join(sorted(violations))
86 )
87
88 def test_no_msgpack_import_in_plugins(self) -> None:
89 """No file in muse/plugins/ may import msgpack."""
90 violations: list[str] = []
91 for path in (_REPO_ROOT / "muse" / "plugins").rglob("*.py"):
92 if path in _WIRE_ALLOWLIST:
93 continue
94 if _imports_msgpack(path):
95 violations.append(str(path.relative_to(_REPO_ROOT)))
96 assert violations == [], (
97 "Plugin files import msgpack:\n "
98 + "\n ".join(sorted(violations))
99 )
100
101
102 # ---------------------------------------------------------------------------
103 # Test: no msgpack in muse/cli/commands/ (except allowlist)
104 # ---------------------------------------------------------------------------
105
106
107 class TestNoMsgpackInCliCommands:
108 def test_no_msgpack_import_in_cli_storage(self) -> None:
109 """No cli/commands/ file outside the wire allowlist may import msgpack."""
110 violations: list[str] = []
111 for path in (_REPO_ROOT / "muse" / "cli" / "commands").rglob("*.py"):
112 if path in _WIRE_ALLOWLIST:
113 continue
114 if _imports_msgpack(path):
115 violations.append(str(path.relative_to(_REPO_ROOT)))
116 assert violations == [], (
117 "Non-wire cli/commands/ files import msgpack:\n "
118 + "\n ".join(sorted(violations))
119 )
File History 1 commit