test_model_routing_security.py python
122 lines 3.1 KB
Raw
sha256:a78e7e5a8740e03315f325d19edeb3aa1b306b3337d04abbaa9a9e0f3bbeb7a1 docs: MuseHub-first before ISR #74 — staging solidify NEXT Human 1 day ago
1 """Security tests for Track P / P-route (§PR.8)."""
2
3 from __future__ import annotations
4
5 import inspect
6 import json
7 import socket
8 from pathlib import Path
9 from unittest.mock import patch
10
11 import pytest
12
13 from cli.kit_root import kit_root
14 from tests.fixtures.model_routing import seed_routing_repo, write_routing_policy
15 from tests.support import git_status_runner, run_cli
16 from tools.model_routing import policy as routing_policy_module
17 from tools.model_routing import resolve as routing_resolve_module
18
19
20 class _SocketBlockedError(RuntimeError):
21 pass
22
23
24 @pytest.fixture
25 def block_network():
26 real_socket = socket.socket
27
28 def _guard(*args, **kwargs):
29 raise _SocketBlockedError("network connections forbidden in routing code paths")
30
31 with patch.object(socket, "socket", side_effect=_guard):
32 yield
33
34
35 def test_route_makes_no_network_connections(tmp_path, block_network) -> None:
36 seed_routing_repo(tmp_path)
37 code = run_cli(
38 ["route", "--position", "overseer", "--json"],
39 cwd=tmp_path,
40 runner=git_status_runner(),
41 kit=kit_root(),
42 json_mode=True,
43 )
44 assert code == 0
45
46
47 def test_injection_shaped_selector_strings_are_opaque(tmp_path, capsys, block_network) -> None:
48 seed_routing_repo(tmp_path)
49 payload = "'; DROP TABLE routes; --"
50 code = run_cli(
51 ["route", "--position", payload, "--json"],
52 cwd=tmp_path,
53 runner=git_status_runner(),
54 kit=kit_root(),
55 json_mode=True,
56 )
57 assert code == 0
58 out = json.loads(capsys.readouterr().out)
59 assert out["query"]["position"] == payload
60 assert out["route_id"] == "defaults"
61
62
63 def test_route_output_has_no_vendor_slugs(tmp_path, capsys) -> None:
64 seed_routing_repo(tmp_path)
65 run_cli(
66 ["route", "--phase-tier", "auto", "--json"],
67 cwd=tmp_path,
68 runner=git_status_runner(),
69 kit=kit_root(),
70 json_mode=True,
71 )
72 text = capsys.readouterr().out.lower()
73 for marker in ("gpt-", "claude-", "openrouter", "api_key", "sk-"):
74 assert marker not in text
75
76
77 def test_malformed_policy_exit_30_missing_human_terminal(tmp_path) -> None:
78 seed_routing_repo(tmp_path)
79 write_routing_policy(
80 tmp_path,
81 """
82 version: 1
83 defaults:
84 model_tier: standard
85 fallback: [standard, fast]
86 """,
87 )
88 assert (
89 run_cli(
90 ["route", "--validate"],
91 cwd=tmp_path,
92 runner=git_status_runner(),
93 kit=kit_root(),
94 )
95 == 30
96 )
97
98
99 def test_missing_policy_exit_31(tmp_path) -> None:
100 from tests.support import write_config
101
102 write_config(tmp_path, "config-git-only.yaml")
103 assert (
104 run_cli(
105 ["route"],
106 cwd=tmp_path,
107 runner=git_status_runner(),
108 kit=kit_root(),
109 )
110 == 31
111 )
112
113
114 def test_routing_modules_avoid_http_clients() -> None:
115 sources = (
116 inspect.getsource(routing_policy_module),
117 inspect.getsource(routing_resolve_module),
118 )
119 joined = "\n".join(sources).lower()
120 assert "urllib" not in joined
121 assert "requests." not in joined
122 assert "httpx" not in joined
File History 1 commit
sha256:a78e7e5a8740e03315f325d19edeb3aa1b306b3337d04abbaa9a9e0f3bbeb7a1 docs: MuseHub-first before ISR #74 — staging solidify NEXT Human 1 day ago