diff --git a/scripts/deploy_local_main.py b/scripts/deploy_local_main.py index 9987f3f8d..a4a9e444e 100755 --- a/scripts/deploy_local_main.py +++ b/scripts/deploy_local_main.py @@ -262,7 +262,11 @@ def redirect_request(self, req, fp, code, msg, headers, newurl): def _read_health(url: str, headers: dict[str, str] | None = None) -> dict[str, Any]: try: opener = urllib.request.build_opener(_NoHealthRedirect()) - request = urllib.request.Request(url, headers=headers or {}) + # Identify this authorised client explicitly: the public edge rejects + # urllib's generic bot identifier before evaluating Service Auth. + request = urllib.request.Request( + url, headers={"User-Agent": "Von-Deployment/1", **(headers or {})} + ) with opener.open(request, timeout=5) as response: payload = json.load(response) except urllib.error.HTTPError as exc: diff --git a/tests/test_codex_von_deploy.py b/tests/test_codex_von_deploy.py index 6ee35e203..72d064019 100644 --- a/tests/test_codex_von_deploy.py +++ b/tests/test_codex_von_deploy.py @@ -10,6 +10,35 @@ from scripts import codex_von_deploy as deployer +def test_public_health_identifies_client_and_preserves_service_credentials(): + seen = [] + + class Handler(BaseHTTPRequestHandler): + def log_message(self, *args): + pass + + def do_GET(self): + agent = self.headers.get("User-Agent", "") + seen.append((agent, self.headers.get("CF-Access-Client-Secret"))) + self.send_response(403 if agent.startswith("Python-urllib") else 200) + self.end_headers() + self.wfile.write(b'{"status":"healthy"}') + + server = HTTPServer(("127.0.0.1", 0), Handler) + thread = threading.Thread(target=server.serve_forever, daemon=True) + thread.start() + try: + assert deployer.runtime._read_health( + f"http://127.0.0.1:{server.server_port}/health", + {"CF-Access-Client-Secret": "fixture-only"}, + ) == {"status": "healthy"} + assert seen == [("Von-Deployment/1", "fixture-only")] + finally: + server.shutdown() + server.server_close() + thread.join() + + def test_public_credentials_are_not_forwarded_through_redirects(): paths = []