@miller-tech/uap 1.179.6 → 1.179.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,27 @@
1
+ """Test package init — keeps importing the proxy from mutating this process.
2
+
3
+ `anthropic_proxy` loads `.uap/proxy.env` into the real `os.environ` at import.
4
+ That is right for a server run and wrong for a test run: it makes tests assert
5
+ the developer's proxy config instead of the shipped defaults, and it leaks
6
+ UAP_DELIVER_* settings into every enforcer subprocess the suite spawns, so
7
+ results depend on module import order.
8
+
9
+ Setting the opt-out here rather than only in `conftest.py` covers every entry
10
+ path, because all of them import this package first:
11
+
12
+ - `python -m unittest tools.agents.tests.test_x` (what CI runs)
13
+ - `python -m unittest discover -s tools/agents/tests`
14
+ - `loadTestsFromNames(...)` in test_enforcer_suite_coverage
15
+ - pytest (which also reads conftest.py)
16
+
17
+ `python3 tools/agents/tests/test_x.py` — running a file directly by path — is
18
+ the one shape that does NOT import the package, which is why conftest.py and
19
+ the `test:enforcers` script both still set it too.
20
+
21
+ `setdefault`, so an explicit `UAP_PROXY_ENV_AUTOLOAD=1` in the environment
22
+ still wins for anyone who deliberately wants the real file loaded.
23
+ """
24
+
25
+ import os
26
+
27
+ os.environ.setdefault("UAP_PROXY_ENV_AUTOLOAD", "0")
@@ -0,0 +1,27 @@
1
+ """Keep importing the proxy from mutating the test process's environment.
2
+
3
+ `anthropic_proxy` loads `.uap/proxy.env` into the real `os.environ` at import
4
+ so a server run gets the operator's recipe/delivery/auth settings without
5
+ hand-exported env. Under test that is a liability, and it produced two real
6
+ failures:
7
+
8
+ 1. Tests that assert shipped defaults (timeouts, retry budgets) instead
9
+ asserted whatever the developer's `.uap/proxy.env` happened to contain —
10
+ green in CI, red locally, for no code reason.
11
+ 2. `UAP_DELIVER_LOCAL_MODE` from that file reached every enforcer subprocess
12
+ the suite spawns, so `test_delivery_enforcement_worktree` passed or failed
13
+ depending on whether a proxy-importing module had run before it.
14
+
15
+ Setting the opt-out here covers every pytest run from one place instead of
16
+ each module defending itself. `npm run test:enforcers` sets the same variable
17
+ for the unittest path, which does not read conftest.py.
18
+
19
+ This must run before any test module imports the proxy — conftest is imported
20
+ at collection time, ahead of the test modules, which is exactly that point.
21
+ Tests that specifically exercise the loader call `_load_proxy_env_file()`
22
+ directly and are unaffected.
23
+ """
24
+
25
+ import os
26
+
27
+ os.environ.setdefault("UAP_PROXY_ENV_AUTOLOAD", "0")
@@ -3,6 +3,7 @@ import importlib.util
3
3
  import os
4
4
  import tempfile
5
5
  import unittest
6
+ import unittest.mock
6
7
  from pathlib import Path
7
8
 
8
9
 
@@ -55,5 +56,144 @@ class ProxyEnvLoaderTest(unittest.TestCase):
55
56
  proxy._load_proxy_env_file() # must not raise
56
57
 
57
58
 
59
+ class ProxyEnvWalkStopsAtRepoRootTest(unittest.TestCase):
60
+ """The upward walk must stop at the repository, not the filesystem root.
61
+
62
+ It used to run to "/", so a checkout nested under an unrelated checkout
63
+ loaded the outer repo's proxy.env, PROXY_AUTH_TOKEN included. A WORKTREE is
64
+ not that case — its .git file names the same repository — so it must still
65
+ reach its own repo's config rather than start tokenless.
66
+ """
67
+
68
+ KEY = "UAP_WALK_PROBE_KEY"
69
+
70
+ def tearDown(self):
71
+ os.environ.pop(self.KEY, None)
72
+ os.environ.pop("UAP_PROXY_ENV_FILE", None)
73
+
74
+ def _tree(self, td):
75
+ # outer/ is the "parent checkout" and holds the env file; outer/inner/
76
+ # is the "worktree" — it has a .git FILE (as real worktrees do) and no
77
+ # .uap/ of its own.
78
+ outer = Path(td) / "outer"
79
+ (outer / ".uap").mkdir(parents=True)
80
+ (outer / ".git").mkdir()
81
+ (outer / ".uap" / "proxy.env").write_text(f"{self.KEY}=from_the_repo\n")
82
+ inner = outer / "inner"
83
+ inner.mkdir()
84
+ (inner / ".git").write_text("gitdir: ../.git/worktrees/inner\n")
85
+ return outer, inner
86
+
87
+ def _load_from(self, path):
88
+ # cwd is process-global; restore it even if the loader raises. Safe
89
+ # under unittest (serial) and pytest-xdist (separate processes); would
90
+ # not be under a thread-parallel runner, and nothing here runs threaded.
91
+ cwd = os.getcwd()
92
+ os.chdir(path)
93
+ try:
94
+ os.environ.pop(self.KEY, None)
95
+ proxy._load_proxy_env_file()
96
+ finally:
97
+ os.chdir(cwd)
98
+ return os.environ.get(self.KEY)
99
+
100
+ def test_a_worktree_still_reaches_its_own_repository_config(self):
101
+ # A worktree's .git is a FILE naming the same repository. Stopping there
102
+ # would leave the proxy with an empty PROXY_AUTH_TOKEN, and since the
103
+ # auth middleware treats empty as "no auth configured", a non-loopback
104
+ # bind would then be wide open. Same repo => follow the pointer home.
105
+ with tempfile.TemporaryDirectory() as td:
106
+ _outer, inner = self._tree(td)
107
+ self.assertEqual(self._load_from(inner), "from_the_repo")
108
+
109
+ def test_still_finds_the_env_file_at_the_repo_root_itself(self):
110
+ # The bound is inclusive — stopping AT the repo root must not stop
111
+ # BEFORE reading it, or the proxy loses its own config.
112
+ with tempfile.TemporaryDirectory() as td:
113
+ outer, _inner = self._tree(td)
114
+ self.assertEqual(self._load_from(outer), "from_the_repo")
115
+
116
+ def test_the_walk_actually_ascends(self):
117
+ # Both cases above sit ON a boundary directory, so an implementation
118
+ # that only ever looked at Path.cwd() would pass them. Start well below
119
+ # the root, in a dir with neither .git nor .uap.
120
+ with tempfile.TemporaryDirectory() as td:
121
+ outer, _inner = self._tree(td)
122
+ deep = outer / "a" / "b" / "c"
123
+ deep.mkdir(parents=True)
124
+ self.assertEqual(self._load_from(deep), "from_the_repo")
125
+
126
+ def test_does_not_climb_out_of_one_repository_into_another(self):
127
+ # The genuine cross-repo case the bound exists for: a checkout nested
128
+ # under an unrelated checkout must not inherit the outer repo's secret.
129
+ with tempfile.TemporaryDirectory() as td:
130
+ outer, _inner = self._tree(td)
131
+ nested = outer / "vendored"
132
+ (nested / ".git").mkdir(parents=True) # a real repo root, not a worktree
133
+ self.assertIsNone(
134
+ self._load_from(nested),
135
+ "walk escaped a nested repository into the enclosing checkout",
136
+ )
137
+
138
+
139
+ class ProxyBindAuthGuardTest(unittest.TestCase):
140
+ """A non-loopback bind with no token must fail closed.
141
+
142
+ PROXY_AUTH_TOKEN comes from .uap/proxy.env; PROXY_HOST commonly comes from
143
+ the systemd EnvironmentFile. So any failure to find the former leaves the
144
+ latter intact — bind-all survives, require-a-credential does not — and the
145
+ middleware reads an empty token as "no auth configured". Without this guard
146
+ a config-discovery bug silently produces an open LLM proxy on the LAN.
147
+ """
148
+
149
+ def test_loopback_without_a_token_is_allowed(self):
150
+ for host in ("127.0.0.1", "::1", "localhost"):
151
+ with self.subTest(host=host):
152
+ proxy._assert_bind_is_authenticated(host, "") # must not raise
153
+
154
+ def test_any_bind_with_a_token_is_allowed(self):
155
+ proxy._assert_bind_is_authenticated("0.0.0.0", "a-real-token")
156
+
157
+ def test_non_loopback_without_a_token_refuses_to_start(self):
158
+ for host in ("0.0.0.0", "192.168.1.50", "::"):
159
+ with self.subTest(host=host):
160
+ with unittest.mock.patch.dict(os.environ, {}, clear=False):
161
+ os.environ.pop("PROXY_ALLOW_UNAUTHENTICATED_BIND", None)
162
+ with self.assertRaises(SystemExit) as ctx:
163
+ proxy._assert_bind_is_authenticated(host, "")
164
+ self.assertIn("unauthenticated", str(ctx.exception))
165
+
166
+ def test_explicit_override_permits_an_open_listener(self):
167
+ with unittest.mock.patch.dict(
168
+ os.environ, {"PROXY_ALLOW_UNAUTHENTICATED_BIND": "1"}
169
+ ):
170
+ proxy._assert_bind_is_authenticated("0.0.0.0", "") # must not raise
171
+
172
+
173
+ class ProxyEnvAutoloadOptOutTest(unittest.TestCase):
174
+ """Importing the module must be inert when the opt-out is set."""
175
+
176
+ def test_autoload_enabled_by_default(self):
177
+ with unittest.mock.patch.dict(os.environ, {}, clear=False):
178
+ os.environ.pop("UAP_PROXY_ENV_AUTOLOAD", None)
179
+ self.assertTrue(proxy._proxy_env_autoload_enabled())
180
+
181
+ def test_opt_out_values_disable_autoload(self):
182
+ for val in ("0", "off", "false", "no", "OFF", " 0 "):
183
+ with self.subTest(val=val):
184
+ with unittest.mock.patch.dict(
185
+ os.environ, {"UAP_PROXY_ENV_AUTOLOAD": val}
186
+ ):
187
+ self.assertFalse(proxy._proxy_env_autoload_enabled())
188
+
189
+ def test_other_values_leave_autoload_on(self):
190
+ for val in ("1", "on", "true", "yes"):
191
+ with self.subTest(val=val):
192
+ with unittest.mock.patch.dict(
193
+ os.environ, {"UAP_PROXY_ENV_AUTOLOAD": val}
194
+ ):
195
+ self.assertTrue(proxy._proxy_env_autoload_enabled())
196
+
197
+
58
198
  if __name__ == "__main__":
59
199
  unittest.main()