refactor(gateway): fail closed without an orchestrator URL; drop stale single-tenant comments
Follow-ups from the #402 review of the single-tenant data-plane teardown. - egress_entrypoint.sh: refuse to launch mitmdump when BOT_BOTTLE_ORCHESTRATOR_URL is unset, so the fail-closed guarantee no longer rests solely on mitmproxy's errorcheck addon exiting on the addon's load-time raise. A misconfigured gateway can never come up as a bare TLS-bumping open proxy with no policy. - orchestrator/gateway.py: ensure_running() raises GatewayError on an empty orchestrator URL — a URL-less launch would only crash-loop the now-resolver-only daemons (egress raises, git-http exits 1, supervise exits 2). The env-injection branch is now unconditional. - Drop stale "single-tenant" / "reads routes.yaml" comments in gateway.py and egress_entrypoint.sh, and the /etc/egress/routes.yaml layout line in Dockerfile.gateway. - Tests: gateway fixtures supply an orchestrator URL; add a refuse-without-URL test and assert the URL env is injected. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UoEZHDjv84ChoZbozQERhJ
This commit is contained in:
@@ -22,13 +22,27 @@ def _proc(returncode: int = 0, stdout: str = "", stderr: str = "") -> Mock:
|
||||
return Mock(returncode=returncode, stdout=stdout, stderr=stderr)
|
||||
|
||||
|
||||
_ORCH_URL = "http://orchestrator:9000"
|
||||
|
||||
|
||||
class TestDockerGateway(unittest.TestCase):
|
||||
def setUp(self) -> None:
|
||||
self.sc = DockerGateway("bot-bottle-gateway:latest")
|
||||
# Resolver-only data plane (PRD 0070): running the gateway requires an
|
||||
# orchestrator URL, so the fixture supplies one.
|
||||
self.sc = DockerGateway("bot-bottle-gateway:latest", orchestrator_url=_ORCH_URL)
|
||||
|
||||
def test_default_name(self) -> None:
|
||||
self.assertEqual(GATEWAY_NAME, self.sc.name)
|
||||
|
||||
def test_ensure_running_refuses_without_orchestrator_url(self) -> None:
|
||||
# No policy source → the data-plane daemons would only crash-loop, so
|
||||
# the launch must fail closed with a clear error rather than start one.
|
||||
sc = DockerGateway("bot-bottle-gateway:latest")
|
||||
with patch(_RUN_DOCKER) as m:
|
||||
with self.assertRaises(GatewayError):
|
||||
sc.ensure_running()
|
||||
m.assert_not_called()
|
||||
|
||||
def test_is_running_reads_docker_ps(self) -> None:
|
||||
with patch(_RUN_DOCKER, return_value=_proc(stdout=self.sc.name + "\n")):
|
||||
self.assertTrue(self.sc.is_running())
|
||||
@@ -98,6 +112,8 @@ class TestDockerGateway(unittest.TestCase):
|
||||
for a in runs[0]))
|
||||
self.assertTrue(any(
|
||||
a.endswith(":/run/supervise") for a in runs[0]))
|
||||
# Data plane resolves policy against the orchestrator control plane.
|
||||
self.assertIn(f"BOT_BOTTLE_ORCHESTRATOR_URL={_ORCH_URL}", runs[0])
|
||||
|
||||
def test_ensure_running_creates_network_when_missing(self) -> None:
|
||||
calls: list[list[str]] = []
|
||||
|
||||
Reference in New Issue
Block a user