返回 CodeWhale
check-command-session-proof.py
根目录 / scripts / check-command-session-proof.py
1 #!/usr/bin/env python3
2 """Require the actual whole session group and a normal graph without host services.
3
4 Source inclusion compiles all transitive helpers and inline tests, without stubs.
5 Cargo compilation remains the authority for Rust name/type resolution. This guard
6 also catches architecture drift which compiles but imports runtime infrastructure.
7 """
8 from pathlib import Path
9 import argparse
10 import re
11
12 ROOT = Path(__file__).resolve().parent.parent
13 GROUP = "crates/tui/src/commands/groups/session/mod.rs"
14 PROOF = "tests/portable-session/src/commands/groups/mod.rs"
15 ALLOWED_WORKSPACE = {
16 "codewhale-portable-session", "codewhale-command-contract",
17 "codewhale-protocol", "codewhale-sanitize",
18 }
19 FORBIDDEN_SERVICES = {
20 "tokio", "reqwest", "hyper", "rusqlite", "sqlx", "keyring", "dbus",
21 "zbus", "secret-service", "ratatui", "crossterm",
22 }
23
24
25 def graph_violations(graph):
26 names = {line.split()[0] for line in graph.splitlines() if line.strip()}
27 return [f"unapproved normal dependency: {name}" for name in sorted(names)
28 if (name.startswith("codewhale-") and name not in ALLOWED_WORKSPACE)
29 or name in FORBIDDEN_SERVICES]
30
31
32 def violations(root):
33 errors = []
34 wrapper = root / PROOF
35 text = wrapper.read_text()
36 includes = re.findall(r'#\[path\s*=\s*"([^"]+)"\]\s*pub mod session;', text)
37 if len(includes) != 1 or (wrapper.parent / includes[0]).resolve() != (root / GROUP).resolve():
38 errors.append("proof must include the actual session group root, not a selected leaf or stub")
39 for path in sorted((root / GROUP).parent.rglob("*.rs")):
40 # Exclude comments, but retain cfg(test) code: its dependency closure matters.
41 source = "\n".join(line.split("//")[0] for line in path.read_text().splitlines())
42 if re.search(r'\b(?:crate::(?:tui|remote_control|commands::(?:traits|contract|CommandResult))|AppAction|codewhale_(?:core|secrets|tui|runtime))\b', source):
43 errors.append(f"host dependency in session closure: {path.relative_to(root)}")
44 return errors
45
46
47 def main():
48 parser = argparse.ArgumentParser(description=__doc__)
49 parser.add_argument("--graph", type=Path)
50 args = parser.parse_args()
51 errors = violations(ROOT)
52 if args.graph:
53 errors += graph_violations(args.graph.read_text())
54 for error in errors:
55 print(f"[session-proof] FAIL: {error}")
56 if not errors:
57 print("[session-proof] PASS: actual complete group and approved dependency boundary")
58 return bool(errors)
59
60
61 if __name__ == "__main__":
62 raise SystemExit(main())
63
63 lines PYTHON