refactor(orchestrator): rename Sidecar -> Gateway for the consolidated data plane

Retire "sidecar" for the consolidated per-host path (PRD 0070 naming
decision): the orchestrator is the umbrella/control plane, and the
egress/git/supervise data-plane unit it runs is the "gateway".

- git mv sidecar.py -> gateway.py and the two integration + one unit test
  files; DockerSidecar->DockerGateway, Sidecar->Gateway,
  SidecarError->GatewayError, SIDECAR_*->GATEWAY_*, ensure_sidecar->
  ensure_gateway, sidecar_status->gateway_status, container name
  bot-bottle-orch-sidecar->bot-bottle-orch-gateway.
- Prose rename across broker/registry/egress/policy_resolver + PRD 0070.
- Preserved: the image name bot-bottle-sidecars, the
  BOT_BOTTLE_SIDECAR_IMAGE env var, Dockerfile.sidecars, and PRD 0069's
  own stage-name cross-references (that doc still uses "sidecar").

No behavior change. Full unit suite green (1679 tests; the 13
test_sidecar_init /bin/sleep errors are pre-existing NixOS-local noise).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WBMWTEtQdJ4W5UrWuLHCck
This commit is contained in:
2026-07-13 18:12:17 -04:00
parent 47268f6fd6
commit 3178453f83
17 changed files with 151 additions and 151 deletions
@@ -118,8 +118,8 @@ class TestDispatch(unittest.TestCase):
status, _ = dispatch(self.orch, "GET", "/health/", b"")
self.assertEqual(200, status)
def test_sidecar_status_unconfigured(self) -> None:
status, payload = dispatch(self.orch, "GET", "/sidecar", b"")
def test_gateway_status_unconfigured(self) -> None:
status, payload = dispatch(self.orch, "GET", "/gateway", b"")
self.assertEqual(200, status)
self.assertEqual(False, payload["configured"])
@@ -1,29 +1,29 @@
"""Unit tests for the consolidated Docker sidecar (PRD 0070). Docker mocked."""
"""Unit tests for the consolidated Docker gateway (PRD 0070). Docker mocked."""
from __future__ import annotations
import unittest
from unittest.mock import Mock, patch
from bot_bottle.orchestrator.sidecar import (
SIDECAR_NAME,
DockerSidecar,
SidecarError,
from bot_bottle.orchestrator.gateway import (
GATEWAY_NAME,
DockerGateway,
GatewayError,
)
_RUN_DOCKER = "bot_bottle.orchestrator.sidecar.run_docker"
_RUN_DOCKER = "bot_bottle.orchestrator.gateway.run_docker"
def _proc(returncode: int = 0, stdout: str = "", stderr: str = "") -> Mock:
return Mock(returncode=returncode, stdout=stdout, stderr=stderr)
class TestDockerSidecar(unittest.TestCase):
class TestDockerGateway(unittest.TestCase):
def setUp(self) -> None:
self.sc = DockerSidecar("bot-bottle-sidecars:latest")
self.sc = DockerGateway("bot-bottle-sidecars:latest")
def test_default_name(self) -> None:
self.assertEqual(SIDECAR_NAME, self.sc.name)
self.assertEqual(GATEWAY_NAME, self.sc.name)
def test_is_running_reads_docker_ps(self) -> None:
with patch(_RUN_DOCKER, return_value=_proc(stdout=self.sc.name + "\n")):
@@ -61,7 +61,7 @@ class TestDockerSidecar(unittest.TestCase):
return _proc()
with patch(_RUN_DOCKER, side_effect=fake):
with self.assertRaises(SidecarError):
with self.assertRaises(GatewayError):
self.sc.ensure_running()
def test_stop_is_idempotent_on_missing(self) -> None:
@@ -71,13 +71,13 @@ class TestDockerSidecar(unittest.TestCase):
def test_stop_raises_on_other_failure(self) -> None:
with patch(_RUN_DOCKER, return_value=_proc(returncode=1, stderr="daemon down")):
with self.assertRaises(SidecarError):
with self.assertRaises(GatewayError):
self.sc.stop()
class TestDockerSidecarBuild(unittest.TestCase):
class TestDockerGatewayBuild(unittest.TestCase):
def setUp(self) -> None:
self.sc = DockerSidecar() # defaults to the real bundle image + dockerfile
self.sc = DockerGateway() # defaults to the real bundle image + dockerfile
def test_image_exists_reads_docker_inspect(self) -> None:
with patch(_RUN_DOCKER, return_value=_proc(returncode=0)):
@@ -109,7 +109,7 @@ class TestDockerSidecarBuild(unittest.TestCase):
self.assertTrue(any(a.endswith("Dockerfile.sidecars") for a in builds[0]))
def test_ensure_built_noop_when_no_dockerfile(self) -> None:
sc = DockerSidecar("busybox", dockerfile=None)
sc = DockerGateway("busybox", dockerfile=None)
with patch(_RUN_DOCKER) as m:
sc.ensure_built()
m.assert_not_called()
@@ -121,7 +121,7 @@ class TestDockerSidecarBuild(unittest.TestCase):
return _proc(returncode=1, stderr="build boom")
with patch(_RUN_DOCKER, side_effect=fake):
with self.assertRaises(SidecarError):
with self.assertRaises(GatewayError):
self.sc.ensure_built()
+16 -16
View File
@@ -10,7 +10,7 @@ from pathlib import Path
from bot_bottle.orchestrator.broker import LaunchBroker, LaunchRequest, StubBroker
from bot_bottle.orchestrator.registry import RegistryStore
from bot_bottle.orchestrator.service import Orchestrator
from bot_bottle.orchestrator.sidecar import Sidecar
from bot_bottle.orchestrator.gateway import Gateway
class _FailingBroker(LaunchBroker):
@@ -24,11 +24,11 @@ class _FailingBroker(LaunchBroker):
pass
class _FakeSidecar(Sidecar):
"""In-memory sidecar for wiring tests."""
class _FakeGateway(Gateway):
"""In-memory gateway for wiring tests."""
def __init__(self) -> None:
self.name = "fake-sidecar"
self.name = "fake-gateway"
self.ensured = 0
self.built = 0
self._running = False
@@ -120,23 +120,23 @@ class TestOrchestrator(unittest.TestCase):
orch.launch_bottle("10.243.0.9")
self.assertEqual([], self.store.all()) # no orphan
def test_sidecar_unconfigured_by_default(self) -> None:
self.assertEqual({"configured": False}, self.orch.sidecar_status())
self.orch.ensure_sidecar() # no-op, must not raise
def test_gateway_unconfigured_by_default(self) -> None:
self.assertEqual({"configured": False}, self.orch.gateway_status())
self.orch.ensure_gateway() # no-op, must not raise
def test_sidecar_wired_and_ensured(self) -> None:
sc = _FakeSidecar()
orch = Orchestrator(self.store, self.broker, self.secret, sidecar=sc)
def test_gateway_wired_and_ensured(self) -> None:
sc = _FakeGateway()
orch = Orchestrator(self.store, self.broker, self.secret, gateway=sc)
self.assertEqual(
{"configured": True, "name": "fake-sidecar", "running": False},
orch.sidecar_status(),
{"configured": True, "name": "fake-gateway", "running": False},
orch.gateway_status(),
)
orch.ensure_sidecar()
self.assertEqual(1, sc.built) # ensure_sidecar builds first,
orch.ensure_gateway()
self.assertEqual(1, sc.built) # ensure_gateway builds first,
self.assertEqual(1, sc.ensured) # then runs
self.assertEqual(
{"configured": True, "name": "fake-sidecar", "running": True},
orch.sidecar_status(),
{"configured": True, "name": "fake-gateway", "running": True},
orch.gateway_status(),
)
+1 -1
View File
@@ -1,4 +1,4 @@
"""Unit tests for the sidecar-side PolicyResolver (PRD 0070). HTTP mocked."""
"""Unit tests for the gateway-side PolicyResolver (PRD 0070). HTTP mocked."""
from __future__ import annotations