diff --git a/bot_bottle/agent_provider.py b/bot_bottle/agent_provider.py index ca2a6ab..8174ef1 100644 --- a/bot_bottle/agent_provider.py +++ b/bot_bottle/agent_provider.py @@ -207,8 +207,7 @@ class AgentProvider(ABC): ) -> None: """Register the per-bottle supervise sidecar as an MCP server in the provider's in-guest config. Called by the backend after - the supervise sidecar is reachable. No-op when - `plan.supervise_plan is None`.""" + the supervise sidecar is reachable.""" def provision_ca(self, bottle: "Bottle", plan: "BottlePlan") -> None: """Install the egress MITM CA into the agent's trust store. diff --git a/bot_bottle/backend/__init__.py b/bot_bottle/backend/__init__.py index 06b279e..9258f53 100644 --- a/bot_bottle/backend/__init__.py +++ b/bot_bottle/backend/__init__.py @@ -102,7 +102,7 @@ class BottlePlan(ABC): over a published host port).""" return "git" egress_plan: EgressPlan - supervise_plan: SupervisePlan | None + supervise_plan: SupervisePlan agent_provision: AgentProvisionPlan @property @@ -332,7 +332,7 @@ class BottleBackend(ABC, Generic[PlanT, CleanupT]): ) agent_provision_plan = merge_provision_env_vars(agent_provision_plan) egress_plan = prepare_egress(manifest_bottle, slug, agent_provision_plan) - supervise_plan = prepare_supervise(manifest_bottle, slug) + supervise_plan = prepare_supervise(slug) git_gate_plan = prepare_git_gate(manifest_bottle, slug) return self._resolve_plan( @@ -405,7 +405,7 @@ class BottleBackend(ABC, Generic[PlanT, CleanupT]): agent_provision_plan: AgentProvisionPlan, egress_plan: EgressPlan, git_gate_plan: GitGatePlan, - supervise_plan: SupervisePlan | None, + supervise_plan: SupervisePlan, stage_dir: Path) -> PlanT: """Backend-specific plan resolution: image/container names, env-file, prompt-file, proxy plan, runtime detection. Called by diff --git a/bot_bottle/backend/docker/backend.py b/bot_bottle/backend/docker/backend.py index b3b9e3f..cfc05ae 100644 --- a/bot_bottle/backend/docker/backend.py +++ b/bot_bottle/backend/docker/backend.py @@ -70,7 +70,7 @@ class DockerBottleBackend(BottleBackend["DockerBottlePlan", "DockerBottleCleanup agent_provision_plan: AgentProvisionPlan, egress_plan: EgressPlan, git_gate_plan: GitGatePlan, - supervise_plan: SupervisePlan | None, + supervise_plan: SupervisePlan, stage_dir: Path, ) -> DockerBottlePlan: return _resolve_plan.resolve_plan( @@ -94,8 +94,6 @@ class DockerBottleBackend(BottleBackend["DockerBottlePlan", "DockerBottleCleanup """Docker bottles reach the supervise sidecar via the compose-network alias `supervise:9100`. No per-bottle URL plumbing needed; the alias resolves inside the bridge.""" - if plan.supervise_plan is None: - return "" return f"http://{SUPERVISE_HOSTNAME}:{SUPERVISE_PORT}/" def prepare_cleanup(self) -> DockerBottleCleanupPlan: diff --git a/bot_bottle/backend/docker/compose.py b/bot_bottle/backend/docker/compose.py index 9ad0011..b230a4c 100644 --- a/bot_bottle/backend/docker/compose.py +++ b/bot_bottle/backend/docker/compose.py @@ -14,7 +14,7 @@ Conditional services follow the plan content: - agent + sidecars bundle: always. - git-gate: iff plan.git_gate_plan.upstreams. - egress: iff plan.egress_plan.routes. - - supervise: iff plan.supervise_plan is not None. + - supervise: always (every bottle is supervised, issue #249). """ from __future__ import annotations @@ -119,13 +119,11 @@ def _sidecar_bundle_service(plan: DockerBottlePlan) -> dict[str, Any]: image, all daemons under a Python init supervisor. Daemon subset narrows via `BOT_BOTTLE_SIDECAR_DAEMONS` env. - egress is always present; git-gate / supervise are conditional. + egress and supervise are always present; git-gate is conditional. """ - daemons: list[str] = ["egress"] + daemons: list[str] = ["egress", "supervise"] if plan.git_gate_plan.upstreams: daemons.append("git-gate") - if plan.supervise_plan is not None: - daemons.append("supervise") env: list[str] = [f"BOT_BOTTLE_SIDECAR_DAEMONS={','.join(daemons)}"] volumes: list[dict[str, Any]] = [] @@ -160,24 +158,21 @@ def _sidecar_bundle_service(plan: DockerBottlePlan) -> dict[str, Any]: # --- supervise ---------------------------------------------------- sp = plan.supervise_plan - if sp is not None: - env += [ - f"SUPERVISE_BOTTLE_SLUG={plan.slug}", - f"SUPERVISE_QUEUE_DIR={QUEUE_DIR_IN_CONTAINER}", - f"SUPERVISE_PORT={SUPERVISE_PORT}", - ] - volumes.append({ - "type": "bind", - "source": str(sp.queue_dir), - "target": QUEUE_DIR_IN_CONTAINER, - "read_only": False, - }) + env += [ + f"SUPERVISE_BOTTLE_SLUG={plan.slug}", + f"SUPERVISE_QUEUE_DIR={QUEUE_DIR_IN_CONTAINER}", + f"SUPERVISE_PORT={SUPERVISE_PORT}", + ] + volumes.append({ + "type": "bind", + "source": str(sp.queue_dir), + "target": QUEUE_DIR_IN_CONTAINER, + "read_only": False, + }) - internal_aliases = [EGRESS_HOSTNAME] + internal_aliases = [EGRESS_HOSTNAME, SUPERVISE_HOSTNAME] if gp.upstreams: internal_aliases.append(GIT_GATE_HOSTNAME) - if sp is not None: - internal_aliases.append(SUPERVISE_HOSTNAME) service: dict[str, Any] = { "image": SIDECAR_BUNDLE_IMAGE, @@ -231,14 +226,10 @@ def _agent_service(plan: DockerBottlePlan) -> dict[str, Any]: if plan.use_runsc: service["runtime"] = "runsc" - volumes: list[dict[str, Any]] = [] - if plan.supervise_plan is not None: - volumes.append(_bind( - plan.supervise_plan.current_config_dir, - CURRENT_CONFIG_DIR_IN_AGENT, - )) - if volumes: - service["volumes"] = volumes + service["volumes"] = [_bind( + plan.supervise_plan.current_config_dir, + CURRENT_CONFIG_DIR_IN_AGENT, + )] # The init supervisor inside the bundle owns intra-bundle # daemon ordering, so the agent only waits for the bundle @@ -254,12 +245,9 @@ def _agent_proxy_url(plan: DockerBottlePlan) -> str: def _agent_no_proxy(plan: DockerBottlePlan) -> str: - """NO_PROXY for the agent: loopback always; supervise hostname - when the supervise sidecar is up (MCP long-poll must bypass - the egress proxy).""" - hosts = ["localhost", "127.0.0.1"] - if plan.supervise_plan is not None: - hosts.append(SUPERVISE_HOSTNAME) + """NO_PROXY for the agent: loopback plus the supervise hostname + (MCP long-poll must bypass the egress proxy).""" + hosts = ["localhost", "127.0.0.1", SUPERVISE_HOSTNAME] return ",".join(hosts) diff --git a/bot_bottle/backend/docker/launch.py b/bot_bottle/backend/docker/launch.py index 03ab619..6da3c5c 100644 --- a/bot_bottle/backend/docker/launch.py +++ b/bot_bottle/backend/docker/launch.py @@ -130,12 +130,10 @@ def launch( mitmproxy_ca_host_path=egress_ca_host, mitmproxy_ca_cert_only_host_path=egress_ca_cert_only, ) - supervise_plan = plan.supervise_plan - if supervise_plan is not None: - supervise_plan = dataclasses.replace( - supervise_plan, - internal_network=internal_network, - ) + supervise_plan = dataclasses.replace( + plan.supervise_plan, + internal_network=internal_network, + ) plan = dataclasses.replace( plan, git_gate_plan=git_gate_plan, diff --git a/bot_bottle/backend/docker/resolve_plan.py b/bot_bottle/backend/docker/resolve_plan.py index c48e3ac..02b971c 100644 --- a/bot_bottle/backend/docker/resolve_plan.py +++ b/bot_bottle/backend/docker/resolve_plan.py @@ -37,7 +37,7 @@ def resolve_plan( resolved_env: ResolvedEnv, agent_provision_plan: AgentProvisionPlan, egress_plan: EgressPlan, - supervise_plan: SupervisePlan | None, + supervise_plan: SupervisePlan, git_gate_plan: GitGatePlan, stage_dir: Path, ) -> DockerBottlePlan: diff --git a/bot_bottle/backend/macos_container/backend.py b/bot_bottle/backend/macos_container/backend.py index bd43ed8..a205d30 100644 --- a/bot_bottle/backend/macos_container/backend.py +++ b/bot_bottle/backend/macos_container/backend.py @@ -52,7 +52,7 @@ class MacosContainerBottleBackend( agent_provision_plan: AgentProvisionPlan, egress_plan: EgressPlan, git_gate_plan: GitGatePlan, - supervise_plan: SupervisePlan | None, + supervise_plan: SupervisePlan, stage_dir: Path, ) -> MacosContainerBottlePlan: return _resolve_plan.resolve_plan( diff --git a/bot_bottle/backend/macos_container/launch.py b/bot_bottle/backend/macos_container/launch.py index 8de4385..95f67e9 100644 --- a/bot_bottle/backend/macos_container/launch.py +++ b/bot_bottle/backend/macos_container/launch.py @@ -222,9 +222,7 @@ def _stamp_agent_urls( sidecar_ip: str, ) -> MacosContainerBottlePlan: proxy_url = f"http://{sidecar_ip}:{EGRESS_PORT}" - supervise_url = "" - if plan.supervise_plan is not None: - supervise_url = f"http://{sidecar_ip}:{SUPERVISE_PORT}/" + supervise_url = f"http://{sidecar_ip}:{SUPERVISE_PORT}/" git_gate_url = "" if plan.git_gate_plan.upstreams: git_gate_url = f"http://{sidecar_ip}:{_GIT_HTTP_PORT}" @@ -341,11 +339,9 @@ def _sidecar_dns() -> str: def _sidecar_daemons(plan: MacosContainerBottlePlan) -> tuple[str, ...]: - daemons = ["egress"] + daemons = ["egress", "supervise"] if plan.git_gate_plan.upstreams: daemons += ["git-gate", "git-http"] - if plan.supervise_plan is not None: - daemons.append("supervise") return tuple(daemons) @@ -355,12 +351,11 @@ def _sidecar_env_entries(plan: MacosContainerBottlePlan) -> tuple[str, ...]: env.extend(sorted(plan.egress_plan.token_env_map.keys())) if plan.git_gate_plan.upstreams: env.append(f"BOT_BOTTLE_GIT_GATE_READY_FILE={_GIT_GATE_READY_FILE}") - if plan.supervise_plan is not None: - env += [ - f"SUPERVISE_BOTTLE_SLUG={plan.slug}", - f"SUPERVISE_QUEUE_DIR={QUEUE_DIR_IN_CONTAINER}", - f"SUPERVISE_PORT={SUPERVISE_PORT}", - ] + env += [ + f"SUPERVISE_BOTTLE_SLUG={plan.slug}", + f"SUPERVISE_QUEUE_DIR={QUEUE_DIR_IN_CONTAINER}", + f"SUPERVISE_PORT={SUPERVISE_PORT}", + ] return tuple(env) @@ -383,8 +378,7 @@ def _sidecar_mounts( )) sp = plan.supervise_plan - if sp is not None: - mounts.append((str(sp.queue_dir), QUEUE_DIR_IN_CONTAINER, False)) + mounts.append((str(sp.queue_dir), QUEUE_DIR_IN_CONTAINER, False)) return tuple(mounts) diff --git a/bot_bottle/backend/macos_container/resolve_plan.py b/bot_bottle/backend/macos_container/resolve_plan.py index 9a9eb28..229e3d4 100644 --- a/bot_bottle/backend/macos_container/resolve_plan.py +++ b/bot_bottle/backend/macos_container/resolve_plan.py @@ -30,7 +30,7 @@ def resolve_plan( resolved_env: ResolvedEnv, agent_provision_plan: AgentProvisionPlan, egress_plan: EgressPlan, - supervise_plan: SupervisePlan | None, + supervise_plan: SupervisePlan, git_gate_plan: GitGatePlan, stage_dir: Path, ) -> MacosContainerBottlePlan: diff --git a/bot_bottle/backend/resolve_common.py b/bot_bottle/backend/resolve_common.py index cb9322f..55c9572 100644 --- a/bot_bottle/backend/resolve_common.py +++ b/bot_bottle/backend/resolve_common.py @@ -92,11 +92,9 @@ def prepare_egress( return Egress().prepare(bottle, slug, egress_dir, provision.egress_routes) -def prepare_supervise(bottle: ManifestBottle, slug: str) -> SupervisePlan | None: - """Prepare the supervise sidecar state dir. Returns None when - bottle.supervise is falsy.""" - if not bottle.supervise: - return None +def prepare_supervise(slug: str) -> SupervisePlan: + """Prepare the supervise sidecar state dir. Every bottle is + supervised (issue #249), so this always returns a plan.""" supervise_dir = supervise_state_dir(slug) supervise_dir.mkdir(parents=True, exist_ok=True) return Supervise().prepare(slug, supervise_dir) diff --git a/bot_bottle/backend/smolmachines/backend.py b/bot_bottle/backend/smolmachines/backend.py index f24be61..3ca0252 100644 --- a/bot_bottle/backend/smolmachines/backend.py +++ b/bot_bottle/backend/smolmachines/backend.py @@ -62,7 +62,7 @@ class SmolmachinesBottleBackend( agent_provision_plan: AgentProvisionPlan, egress_plan: EgressPlan, git_gate_plan: GitGatePlan, - supervise_plan: SupervisePlan | None, + supervise_plan: SupervisePlan, stage_dir: Path, ) -> SmolmachinesBottlePlan: return _resolve_plan.resolve_plan( diff --git a/bot_bottle/backend/smolmachines/launch.py b/bot_bottle/backend/smolmachines/launch.py index e45fbbb..355bd13 100644 --- a/bot_bottle/backend/smolmachines/launch.py +++ b/bot_bottle/backend/smolmachines/launch.py @@ -206,12 +206,10 @@ def _discover_urls( ) agent_git_gate_host = f"{loopback_ip}:{git_gate_host_port}" - agent_supervise_url = "" - if plan.supervise_plan is not None: - supervise_host_port = _bundle.bundle_host_port( - plan.slug, _SUPERVISE_PORT, host_ip=loopback_ip, - ) - agent_supervise_url = f"http://{loopback_ip}:{supervise_host_port}/" + supervise_host_port = _bundle.bundle_host_port( + plan.slug, _SUPERVISE_PORT, host_ip=loopback_ip, + ) + agent_supervise_url = f"http://{loopback_ip}:{supervise_host_port}/" existing_no_proxy = plan.guest_env.get("NO_PROXY", "localhost,127.0.0.1") no_proxy = f"{existing_no_proxy},{loopback_ip}" @@ -299,15 +297,14 @@ def _bundle_launch_spec( """Build a BundleLaunchSpec from the resolved inner Plans. Daemons in the CSV: - - egress is always present. + - egress and supervise are always present. - git-gate + git-http are conditional on plan.git_gate_plan.upstreams. - - supervise is conditional on plan.supervise_plan. Env + volumes are the union of the sidecar daemons' needs, with daemon-private values only (HTTPS_PROXY is scoped to the egress process by egress_entrypoint.sh — see PRD 0024's bundle bind-address PR).""" - daemons: list[str] = ["egress"] + daemons: list[str] = ["egress", "supervise"] env: list[str] = [] volumes: list[tuple[str, str, bool]] = [] @@ -347,23 +344,19 @@ def _bundle_launch_spec( # --- supervise -------------------------------------------- sp = plan.supervise_plan - if sp is not None: - daemons.append("supervise") - env += [ - f"SUPERVISE_BOTTLE_SLUG={plan.slug}", - f"SUPERVISE_QUEUE_DIR={QUEUE_DIR_IN_CONTAINER}", - f"SUPERVISE_PORT={SUPERVISE_PORT}", - ] - volumes.append((str(sp.queue_dir), QUEUE_DIR_IN_CONTAINER, False)) + env += [ + f"SUPERVISE_BOTTLE_SLUG={plan.slug}", + f"SUPERVISE_QUEUE_DIR={QUEUE_DIR_IN_CONTAINER}", + f"SUPERVISE_PORT={SUPERVISE_PORT}", + ] + volumes.append((str(sp.queue_dir), QUEUE_DIR_IN_CONTAINER, False)) # Container ports the agent reaches from the smolvm guest — # published on host loopback so the guest can dial via TSI + # macOS networking. Egress is always the agent's HTTP/HTTPS proxy. - ports_to_publish: list[int] = [_EGRESS_PORT] + ports_to_publish: list[int] = [_EGRESS_PORT, _SUPERVISE_PORT] if gp.upstreams: ports_to_publish.append(_GIT_HTTP_PORT) - if sp is not None: - ports_to_publish.append(_SUPERVISE_PORT) return _bundle.BundleLaunchSpec( slug=plan.slug, diff --git a/bot_bottle/backend/smolmachines/resolve_plan.py b/bot_bottle/backend/smolmachines/resolve_plan.py index 8d8dfcb..904c6fd 100644 --- a/bot_bottle/backend/smolmachines/resolve_plan.py +++ b/bot_bottle/backend/smolmachines/resolve_plan.py @@ -52,7 +52,7 @@ def resolve_plan( resolved_env: ResolvedEnv, agent_provision_plan: AgentProvisionPlan, egress_plan: EgressPlan, - supervise_plan: SupervisePlan | None, + supervise_plan: SupervisePlan, git_gate_plan: GitGatePlan, stage_dir: Path, ) -> SmolmachinesBottlePlan: diff --git a/bot_bottle/backend/smolmachines/sidecar_bundle.py b/bot_bottle/backend/smolmachines/sidecar_bundle.py index 60b3413..6b56886 100644 --- a/bot_bottle/backend/smolmachines/sidecar_bundle.py +++ b/bot_bottle/backend/smolmachines/sidecar_bundle.py @@ -68,7 +68,8 @@ class BundleLaunchSpec: image: str = SIDECAR_BUNDLE_IMAGE # Daemon subset CSV for BOT_BOTTLE_SIDECAR_DAEMONS. The # supervisor inside the bundle reads it to skip - # bottle-irrelevant daemons (e.g. supervise=False bottles). + # bottle-irrelevant daemons (e.g. git-gate when a bottle + # declares no upstreams). daemons_csv: str = "egress" # Plain "KEY=VALUE" strings + "KEY" bare names (the bare-name # form inherits the value from the docker-run subprocess env, diff --git a/bot_bottle/contrib/claude/agent_provider.py b/bot_bottle/contrib/claude/agent_provider.py index 198d1dd..1f38702 100644 --- a/bot_bottle/contrib/claude/agent_provider.py +++ b/bot_bottle/contrib/claude/agent_provider.py @@ -291,8 +291,6 @@ class ClaudeAgentProvider(AgentProvider): Failure is logged but not fatal — the bottle still works without the entry; the operator can register it manually.""" - if plan.supervise_plan is None: - return info(f"registering supervise MCP server in agent claude config → {supervise_url}") r = bottle.exec( f"claude mcp add --scope user --transport http " diff --git a/bot_bottle/contrib/codex/agent_provider.py b/bot_bottle/contrib/codex/agent_provider.py index 57f7e82..c8a457d 100644 --- a/bot_bottle/contrib/codex/agent_provider.py +++ b/bot_bottle/contrib/codex/agent_provider.py @@ -257,8 +257,6 @@ class CodexAgentProvider(AgentProvider): Mirrors the Claude provider's `claude mcp add` flow — failure is logged but not fatal.""" - if plan.supervise_plan is None: - return info(f"registering supervise MCP server in agent codex config → {supervise_url}") r = bottle.exec( f"codex mcp add {_SUPERVISE_MCP_NAME} --url " diff --git a/bot_bottle/manifest.py b/bot_bottle/manifest.py index 224e7ea..43e30ae 100644 --- a/bot_bottle/manifest.py +++ b/bot_bottle/manifest.py @@ -19,7 +19,6 @@ Bottle schema (frontmatter): repos: { : , ... } # optional egress: { routes: [ , ... ] } # route keys: host, matches, auth, role, dlp - supervise: # optional Agent schema (frontmatter): bottle: # required @@ -111,13 +110,6 @@ class ManifestBottle: # identity without any git-gate.repos upstreams, and vice versa. git_user: ManifestGitUser = field(default_factory=ManifestGitUser) egress: ManifestEgressConfig = field(default_factory=ManifestEgressConfig) - # Opt-in per-bottle stuck-recovery sidecar (PRD 0013). When true, - # the launch step brings up a supervise sidecar that exposes MCP - # tools to the agent (egress-block, capability-block) plus mounts - # the current-config dir read-only into the agent at - # /etc/bot-bottle/current-config. False (the default) skips the - # sidecar and mount. - supervise: bool = False @classmethod def from_dict(cls, name: str, raw: object) -> "ManifestBottle": @@ -152,6 +144,13 @@ class ManifestBottle: f"removed. Move it under 'git-gate.user'." ) + if "supervise" in d: + raise ManifestError( + f"bottle '{name}' has a 'supervise' field, which has been " + f"removed (issue #249). All bottles are now supervised; the " + f"flag was always-on in practice. Delete the field." + ) + unknown = set(d.keys()) - BOTTLE_KEYS if unknown: allowed = ", ".join(sorted(BOTTLE_KEYS)) @@ -190,16 +189,9 @@ class ManifestBottle: else ManifestEgressConfig() ) - supervise_raw = d.get("supervise", False) - if not isinstance(supervise_raw, bool): - raise ManifestError( - f"bottle '{name}' supervise must be a boolean " - f"(was {type(supervise_raw).__name__})" - ) - return cls( env=env, agent_provider=agent_provider, git=git, - git_user=git_user, egress=egress, supervise=supervise_raw, + git_user=git_user, egress=egress, ) diff --git a/bot_bottle/manifest_extends.py b/bot_bottle/manifest_extends.py index 3432f64..de74fbb 100644 --- a/bot_bottle/manifest_extends.py +++ b/bot_bottle/manifest_extends.py @@ -134,9 +134,6 @@ def _merge_bottles( if "agent_provider" in child_raw else parent.agent_provider ) - merged_supervise = ( - child.supervise if "supervise" in child_raw else parent.supervise - ) validate_egress_routes(name, merged_egress.routes) return ManifestBottle( @@ -145,7 +142,6 @@ def _merge_bottles( git=merged_git, git_user=merged_git_user, egress=merged_egress, - supervise=merged_supervise, ) diff --git a/bot_bottle/manifest_schema.py b/bot_bottle/manifest_schema.py index 1925cf8..366018e 100644 --- a/bot_bottle/manifest_schema.py +++ b/bot_bottle/manifest_schema.py @@ -16,7 +16,7 @@ _FILENAME_RX = re.compile(r"^[a-z][a-z0-9-]*$") # sets dies with a "did you mean" pointer: typos should not silently # ghost into an empty config. BOTTLE_KEYS = frozenset( - {"env", "extends", "agent_provider", "git-gate", "egress", "supervise"} + {"env", "extends", "agent_provider", "git-gate", "egress"} ) AGENT_KEYS_REQUIRED = frozenset({"bottle"}) AGENT_KEYS_OPTIONAL = frozenset({"skills", "git-gate"}) diff --git a/tests/integration/test_sidecar_bundle_compose.py b/tests/integration/test_sidecar_bundle_compose.py index b57600e..9e4ec7c 100644 --- a/tests/integration/test_sidecar_bundle_compose.py +++ b/tests/integration/test_sidecar_bundle_compose.py @@ -27,14 +27,13 @@ from tests._docker import skip_unless_docker def _manifest() -> ManifestIndex: - """Bottle with supervise on so the bundle exercises egress + - supervise. Git is off because a meaningful git-gate test needs - a real upstream and SSH keys — out of scope for a bundle smoke.""" + """Minimal bottle so the bundle exercises egress + supervise + (every bottle is supervised, issue #249). Git is off because a + meaningful git-gate test needs a real upstream and SSH keys — + out of scope for a bundle smoke.""" return ManifestIndex.from_json_obj({ "bottles": { - "dev": { - "supervise": True, - }, + "dev": {}, }, "agents": { "demo": {"skills": [], "prompt": "", "bottle": "dev"}, diff --git a/tests/unit/test_compose.py b/tests/unit/test_compose.py index 8b10eec..255632c 100644 --- a/tests/unit/test_compose.py +++ b/tests/unit/test_compose.py @@ -40,13 +40,11 @@ STAGE = Path("/tmp/cb-stage") STATE = Path("/tmp/cb-state") -def _manifest(*, supervise: bool, with_git: bool, with_egress: bool) -> ManifestIndex: +def _manifest(*, with_git: bool, with_egress: bool) -> ManifestIndex: """Minimal manifest with the toggles the chunk-1 matrix needs. The renderer only reads from the plan, not the manifest, so this is just here to back BottleSpec.""" bottle: dict[str, object] = {} - if supervise: - bottle["supervise"] = True if with_git: bottle["git-gate"] = {"repos": { "upstream": { @@ -111,10 +109,11 @@ def _plan( *, with_git: bool = False, with_egress: bool = False, - supervise: bool = False, ) -> DockerBottlePlan: """Build a fully-resolved DockerBottlePlan. Toggles cover the - matrix the renderer's conditional-service logic branches on.""" + matrix the renderer's conditional-service logic branches on. + Every bottle is supervised (issue #249), so the supervise plan + is always present.""" upstreams: tuple[GitGateUpstream, ...] = () if with_git: upstreams = (GitGateUpstream( @@ -136,7 +135,7 @@ def _plan( roles=(), ),) - index = _manifest(supervise=supervise, with_git=with_git, with_egress=with_egress) + index = _manifest(with_git=with_git, with_egress=with_egress) spec = BottleSpec( manifest=index, agent_name="demo", @@ -151,7 +150,7 @@ def _plan( forwarded_env={"CLAUDE_CODE_OAUTH_TOKEN": "x"}, git_gate_plan=_git_gate_plan(upstreams), egress_plan=_egress_plan(routes), - supervise_plan=_supervise_plan() if supervise else None, + supervise_plan=_supervise_plan(), use_runsc=False, agent_provision=AgentProvisionPlan( template="claude", @@ -220,10 +219,8 @@ class TestAgentAlwaysPresent(unittest.TestCase): proxy = [e for e in s["environment"] if e.startswith("HTTPS_PROXY=")][0] self.assertEqual("HTTPS_PROXY=http://egress:9099", proxy) - def test_agent_no_proxy_adds_supervise_when_enabled(self): - s = bottle_plan_to_compose( - _plan(supervise=True) - )["services"]["agent"] + def test_agent_no_proxy_includes_supervise(self): + s = bottle_plan_to_compose(_plan())["services"]["agent"] no_proxy = [e for e in s["environment"] if e.startswith("NO_PROXY=")][0] self.assertIn("supervise", no_proxy) @@ -259,22 +256,18 @@ class TestAgentAlwaysPresent(unittest.TestCase): def test_agent_depends_only_on_sidecars(self): # Bundle shape: the init supervisor owns intra-bundle daemon # ordering, so the agent waits on the bundle container alone. - for kwargs in [{}, {"with_git": True, "with_egress": True, "supervise": True}]: + for kwargs in [{}, {"with_git": True, "with_egress": True}]: with self.subTest(**kwargs): s = bottle_plan_to_compose(_plan(**kwargs))["services"]["agent"] self.assertEqual(["sidecars"], s["depends_on"]) - def test_agent_current_config_mount_only_with_supervise(self): - with_sv = bottle_plan_to_compose(_plan(supervise=True))["services"]["agent"] + def test_agent_current_config_always_mounted(self): + # Every bottle is supervised (issue #249), so the read-only + # current-config mount is always present in the agent. + agent = bottle_plan_to_compose(_plan())["services"]["agent"] self.assertTrue(any( v["target"] == "/etc/bot-bottle/current-config" - for v in with_sv.get("volumes", []) - )) - without_sv = bottle_plan_to_compose(_plan(supervise=False))["services"]["agent"] - # Either no volumes key at all, or no current-config target. - self.assertFalse(any( - v["target"] == "/etc/bot-bottle/current-config" - for v in without_sv.get("volumes", []) + for v in agent.get("volumes", []) )) @@ -292,7 +285,7 @@ class TestSidecarBundleShape(unittest.TestCase): self.assertEqual({"sidecars", "agent"}, set(spec["services"].keys())) def test_emits_two_services_full_matrix(self): - spec = self._render(with_git=True, with_egress=True, supervise=True) + spec = self._render(with_git=True, with_egress=True) # Still two services — the bundle absorbs git-gate/egress/supervise. self.assertEqual({"sidecars", "agent"}, set(spec["services"].keys())) @@ -315,16 +308,16 @@ class TestSidecarBundleShape(unittest.TestCase): self.assertIn("egress", aliases) def test_internal_aliases_omit_inactive_sidecars(self): - # With no git-gate / supervise, those names are NOT aliased - # — keeps the alias list honest about what's actually - # listening inside the bundle. + # With no git-gate, that name is NOT aliased — keeps the alias + # list honest about what's actually listening inside the bundle. + # supervise is always present (issue #249). sc = self._render()["services"]["sidecars"] aliases = set(sc["networks"]["internal"]["aliases"]) self.assertNotIn("git-gate", aliases) - self.assertNotIn("supervise", aliases) + self.assertIn("supervise", aliases) def test_internal_aliases_include_active_sidecars(self): - sc = self._render(with_git=True, supervise=True)["services"]["sidecars"] + sc = self._render(with_git=True)["services"]["sidecars"] aliases = set(sc["networks"]["internal"]["aliases"]) self.assertIn("git-gate", aliases) self.assertIn("supervise", aliases) @@ -336,10 +329,11 @@ class TestSidecarBundleShape(unittest.TestCase): for line in sc["environment"] if line.startswith("BOT_BOTTLE_SIDECAR_DAEMONS=") } - self.assertEqual({"egress"}, daemons) + # egress + supervise are always present (issue #249). + self.assertEqual({"egress,supervise"}, daemons) def test_daemons_csv_expands_with_optional_sidecars(self): - sc = self._render(with_git=True, supervise=True)["services"]["sidecars"] + sc = self._render(with_git=True)["services"]["sidecars"] for line in sc["environment"]: if line.startswith("BOT_BOTTLE_SIDECAR_DAEMONS="): csv = line.split("=", 1)[1] @@ -347,7 +341,7 @@ class TestSidecarBundleShape(unittest.TestCase): else: self.fail("BOT_BOTTLE_SIDECAR_DAEMONS not in env") self.assertEqual( - ["egress", "git-gate", "supervise"], + ["egress", "supervise", "git-gate"], csv.split(","), ) @@ -376,7 +370,7 @@ class TestSidecarBundleShape(unittest.TestCase): self.assertNotIn("EGRESS_TOKEN_0", env_strings) def test_supervise_env_present_when_active(self): - sc = self._render(supervise=True)["services"]["sidecars"] + sc = self._render()["services"]["sidecars"] env_strings = sc["environment"] self.assertIn(f"SUPERVISE_BOTTLE_SLUG={SLUG}", env_strings) self.assertTrue(any(e.startswith("SUPERVISE_QUEUE_DIR=") for e in env_strings)) @@ -388,7 +382,7 @@ class TestSidecarBundleShape(unittest.TestCase): self.assertIn("/home/mitmproxy/.mitmproxy/mitmproxy-ca.pem", targets) def test_volumes_union_full_matrix(self): - sc = self._render(with_git=True, with_egress=True, supervise=True)[ + sc = self._render(with_git=True, with_egress=True)[ "services"]["sidecars"] targets = {v["target"] for v in sc["volumes"]} self.assertIn("/home/mitmproxy/.mitmproxy/mitmproxy-ca.pem", targets) @@ -403,7 +397,7 @@ class TestSidecarBundleShape(unittest.TestCase): self.assertNotIn("extra_hosts", sc) def test_agent_depends_on_bundle_only(self): - sc = self._render(with_git=True, with_egress=True, supervise=True)[ + sc = self._render(with_git=True, with_egress=True)[ "services"]["agent"] self.assertEqual(["sidecars"], sc["depends_on"]) diff --git a/tests/unit/test_contrib_claude_provider.py b/tests/unit/test_contrib_claude_provider.py index 1f6bdbc..fef6a02 100644 --- a/tests/unit/test_contrib_claude_provider.py +++ b/tests/unit/test_contrib_claude_provider.py @@ -50,11 +50,8 @@ def _plan( agent_prompt: str = "", skills: list[str] | None = None, agent_provision: AgentProvisionPlan | None = None, - supervise: bool = False, ) -> DockerBottlePlan: bottle_json: dict = {"agent_provider": {"template": "claude"}} # type: ignore - if supervise: - bottle_json["supervise"] = True index = ManifestIndex.from_json_obj({ "bottles": {"dev": bottle_json}, "agents": { @@ -70,13 +67,11 @@ def _plan( manifest=index, agent_name="demo", copy_cwd=False, user_cwd="/tmp/x", ) - supervise_plan = None - if supervise: - supervise_plan = SupervisePlan( - slug="demo-abc12", - queue_dir=Path("/tmp/queue"), - current_config_dir=Path("/tmp/current-config"), - ) + supervise_plan = SupervisePlan( + slug="demo-abc12", + queue_dir=Path("/tmp/queue"), + current_config_dir=Path("/tmp/current-config"), + ) return DockerBottlePlan( spec=spec, manifest=manifest, @@ -314,17 +309,10 @@ class TestClaudeUiProvision(unittest.TestCase): class TestClaudeSuperviseMcp(unittest.TestCase): - def test_noop_when_supervise_disabled(self): - bottle = _make_bottle() - ClaudeAgentProvider().provision_supervise_mcp( - _plan(supervise=False), bottle, _URL, - ) - bottle.exec.assert_not_called() - def test_runs_claude_mcp_add_as_node(self): bottle = _make_bottle() ClaudeAgentProvider().provision_supervise_mcp( - _plan(supervise=True), bottle, _URL, + _plan(), bottle, _URL, ) bottle.exec.assert_called_once() script = bottle.exec.call_args.args[0] @@ -340,7 +328,7 @@ class TestClaudeSuperviseMcp(unittest.TestCase): exec_result=ExecResult(returncode=1, stdout="", stderr="boom"), ) ClaudeAgentProvider().provision_supervise_mcp( - _plan(supervise=True), bottle, _URL, + _plan(), bottle, _URL, ) diff --git a/tests/unit/test_contrib_codex_provider.py b/tests/unit/test_contrib_codex_provider.py index 54e2b2c..fd574ee 100644 --- a/tests/unit/test_contrib_codex_provider.py +++ b/tests/unit/test_contrib_codex_provider.py @@ -50,11 +50,8 @@ def _plan( agent_prompt: str = "", skills: list[str] | None = None, agent_provision: AgentProvisionPlan | None = None, - supervise: bool = False, ) -> DockerBottlePlan: bottle_json: dict = {"agent_provider": {"template": "codex"}} # type: ignore - if supervise: - bottle_json["supervise"] = True index = ManifestIndex.from_json_obj({ "bottles": {"dev": bottle_json}, "agents": { @@ -70,13 +67,11 @@ def _plan( manifest=index, agent_name="demo", copy_cwd=False, user_cwd="/tmp/x", ) - supervise_plan = None - if supervise: - supervise_plan = SupervisePlan( - slug="demo-abc12", - queue_dir=Path("/tmp/queue"), - current_config_dir=Path("/tmp/current-config"), - ) + supervise_plan = SupervisePlan( + slug="demo-abc12", + queue_dir=Path("/tmp/queue"), + current_config_dir=Path("/tmp/current-config"), + ) return DockerBottlePlan( spec=spec, manifest=manifest, @@ -277,17 +272,10 @@ class TestCodexProvision(unittest.TestCase): class TestCodexSuperviseMcp(unittest.TestCase): - def test_noop_when_supervise_disabled(self): - bottle = _make_bottle() - CodexAgentProvider().provision_supervise_mcp( - _plan(supervise=False), bottle, _URL, - ) - bottle.exec.assert_not_called() - def test_runs_codex_mcp_add_as_node(self): bottle = _make_bottle() CodexAgentProvider().provision_supervise_mcp( - _plan(supervise=True), bottle, _URL, + _plan(), bottle, _URL, ) bottle.exec.assert_called_once() script = bottle.exec.call_args.args[0] @@ -302,7 +290,7 @@ class TestCodexSuperviseMcp(unittest.TestCase): exec_result=ExecResult(returncode=1, stdout="", stderr="boom"), ) CodexAgentProvider().provision_supervise_mcp( - _plan(supervise=True), bottle, _URL, + _plan(), bottle, _URL, ) diff --git a/tests/unit/test_contrib_pi_provider.py b/tests/unit/test_contrib_pi_provider.py index 0abe959..5971bb5 100644 --- a/tests/unit/test_contrib_pi_provider.py +++ b/tests/unit/test_contrib_pi_provider.py @@ -16,6 +16,7 @@ from bot_bottle.backend.docker.bottle_plan import DockerBottlePlan from bot_bottle.contrib.pi.agent_provider import PiAgentProvider from bot_bottle.egress import EgressPlan from bot_bottle.git_gate import GitGatePlan +from bot_bottle.supervise import SupervisePlan from bot_bottle.manifest import ManifestIndex @@ -77,7 +78,11 @@ def _plan( routes=(), token_env_map={}, ), - supervise_plan=None, + supervise_plan=SupervisePlan( + slug="demo-abc12", + queue_dir=Path("/tmp/queue"), + current_config_dir=Path("/tmp/current-config"), + ), use_runsc=False, agent_provision=agent_provision or AgentProvisionPlan( template="pi", command="pi", prompt_mode="append_system_prompt", diff --git a/tests/unit/test_docker_launch_committed_image.py b/tests/unit/test_docker_launch_committed_image.py index 1152e63..341177f 100644 --- a/tests/unit/test_docker_launch_committed_image.py +++ b/tests/unit/test_docker_launch_committed_image.py @@ -16,6 +16,7 @@ from bot_bottle.backend.docker import launch as launch_mod from bot_bottle.backend.docker.bottle_plan import DockerBottlePlan from bot_bottle.egress import EgressPlan from bot_bottle.git_gate import GitGatePlan +from bot_bottle.supervise import SupervisePlan from bot_bottle.manifest import ManifestIndex @@ -55,7 +56,11 @@ def _plan(tmp: str) -> DockerBottlePlan: routes=(), token_env_map={}, ), - supervise_plan=None, + supervise_plan=SupervisePlan( + slug=_SLUG, + queue_dir=stage / "supervise" / "queue", + current_config_dir=stage / "supervise" / "current-config", + ), agent_provision=AgentProvisionPlan( template="claude", command="claude", diff --git a/tests/unit/test_docker_launch_teardown.py b/tests/unit/test_docker_launch_teardown.py index 983bbc6..0f19d5b 100644 --- a/tests/unit/test_docker_launch_teardown.py +++ b/tests/unit/test_docker_launch_teardown.py @@ -21,6 +21,7 @@ from bot_bottle.backend.docker import launch as launch_mod from bot_bottle.backend.docker.bottle_plan import DockerBottlePlan from bot_bottle.egress import EgressPlan from bot_bottle.git_gate import GitGatePlan +from bot_bottle.supervise import SupervisePlan from bot_bottle.manifest import ManifestIndex _INDEX = ManifestIndex.from_json_obj({ @@ -56,7 +57,11 @@ def _plan(tmp: str) -> DockerBottlePlan: routes=(), token_env_map={}, ), - supervise_plan=None, + supervise_plan=SupervisePlan( + slug="test-teardown-00001", + queue_dir=stage / "supervise" / "queue", + current_config_dir=stage / "supervise" / "current-config", + ), agent_provision=AgentProvisionPlan( template="claude", command="claude", diff --git a/tests/unit/test_docker_provision_git_user.py b/tests/unit/test_docker_provision_git_user.py index 2fb7466..3dcfde0 100644 --- a/tests/unit/test_docker_provision_git_user.py +++ b/tests/unit/test_docker_provision_git_user.py @@ -21,6 +21,7 @@ from bot_bottle.backend import Bottle, BottleSpec, ExecResult from bot_bottle.backend.docker.bottle_plan import DockerBottlePlan from bot_bottle.egress import EgressPlan from bot_bottle.git_gate import GitGatePlan +from bot_bottle.supervise import SupervisePlan from bot_bottle.manifest import ManifestIndex @@ -79,7 +80,11 @@ def _plan(*, git_user: dict | None = None, # type: ignore routes=(), token_env_map={}, ), - supervise_plan=None, + supervise_plan=SupervisePlan( + slug="demo-abc12", + queue_dir=Path("/tmp/queue"), + current_config_dir=Path("/tmp/current-config"), + ), use_runsc=False, agent_provision=AgentProvisionPlan( template="claude", diff --git a/tests/unit/test_macos_container_launch.py b/tests/unit/test_macos_container_launch.py index d9ae81c..0455fdd 100644 --- a/tests/unit/test_macos_container_launch.py +++ b/tests/unit/test_macos_container_launch.py @@ -15,6 +15,7 @@ from bot_bottle.backend.macos_container import launch from bot_bottle.backend.macos_container.bottle_plan import MacosContainerBottlePlan from bot_bottle.egress import EgressPlan from bot_bottle.git_gate import GitGatePlan +from bot_bottle.supervise import SupervisePlan from bot_bottle.manifest import ManifestIndex _MANIFEST = ManifestIndex.from_json_obj({ @@ -27,7 +28,6 @@ def _plan( *, stage_dir: Path, git: bool = False, - supervise: bool = False, agent_git_gate_url: str = "", agent_supervise_url: str = "", ) -> MacosContainerBottlePlan: @@ -67,10 +67,8 @@ def _plan( ) else: git_gate_plan = SimpleNamespace(upstreams=()) - supervise_plan = ( - SimpleNamespace(queue_dir=Path("/state/supervise/queue")) - if supervise else None - ) + # Every bottle is supervised (issue #249). + supervise_plan = SimpleNamespace(queue_dir=Path("/state/supervise/queue")) agent_provision = SimpleNamespace( guest_env={"LITERAL": "value"}, provisioned_env={"CODEX_HOME": "/run/codex-home"}, @@ -101,7 +99,7 @@ class TestMacosContainerLaunchArgv(unittest.TestCase): self._tmp.cleanup() def test_sidecar_argv_uses_egress_network_first_and_explicit_dns(self): - plan = _plan(stage_dir=self.stage_dir, supervise=True) + plan = _plan(stage_dir=self.stage_dir) with patch.object(launch.os, "environ", { "BOT_BOTTLE_MACOS_CONTAINER_DNS": "9.9.9.9", }): @@ -172,7 +170,7 @@ class TestMacosContainerLaunchArgv(unittest.TestCase): def test_git_gate_daemons_are_ready_gated(self): plan = _plan(stage_dir=self.stage_dir, git=True) self.assertEqual( - ("egress", "git-gate", "git-http"), + ("egress", "supervise", "git-gate", "git-http"), launch._sidecar_daemons(plan), ) self.assertIn( @@ -181,7 +179,7 @@ class TestMacosContainerLaunchArgv(unittest.TestCase): ) def test_stamp_agent_urls_includes_git_http_when_git_gate_exists(self): - plan = _plan(stage_dir=self.stage_dir, git=True, supervise=True) + plan = _plan(stage_dir=self.stage_dir, git=True) with patch.object(launch.dataclasses, "replace") as replace: launch._stamp_agent_urls(plan, "192.168.128.2") replace.assert_called_once_with( @@ -272,7 +270,10 @@ def _build_plan(stage_dir: Path) -> MacosContainerBottlePlan: stage_dir=stage_dir, git_gate_plan=cast(GitGatePlan, SimpleNamespace(upstreams=())), egress_plan=cast(EgressPlan, SimpleNamespace()), - supervise_plan=None, + supervise_plan=cast( + SupervisePlan, + SimpleNamespace(queue_dir=Path("/state/supervise/queue")), + ), agent_provision=AgentProvisionPlan( template="claude", command="claude", diff --git a/tests/unit/test_manifest_agent_git_user.py b/tests/unit/test_manifest_agent_git_user.py index c9ccd26..d564e16 100644 --- a/tests/unit/test_manifest_agent_git_user.py +++ b/tests/unit/test_manifest_agent_git_user.py @@ -116,7 +116,6 @@ class TestAgentGitUserOverlay(unittest.TestCase): idx = ManifestIndex.from_json_obj({ "bottles": {"dev": { "env": {"FOO": "bar"}, - "supervise": True, "git-gate": {"user": {"name": "B"}}, }}, "agents": {"impl": { @@ -127,7 +126,6 @@ class TestAgentGitUserOverlay(unittest.TestCase): b = idx.load_for_agent("impl").bottle self.assertEqual("a", b.git_user.name) self.assertEqual({"FOO": "bar"}, dict(b.env)) - self.assertTrue(b.supervise) class TestAgentGitUserRejections(unittest.TestCase): diff --git a/tests/unit/test_manifest_extends.py b/tests/unit/test_manifest_extends.py index b96ea8b..5c79899 100644 --- a/tests/unit/test_manifest_extends.py +++ b/tests/unit/test_manifest_extends.py @@ -42,38 +42,26 @@ class TestExtendsBasic(unittest.TestCase): # same way they did before the resolver landed. m = _build(dev={ "env": {"FOO": "bar"}, - "supervise": True, }) b = m.bottles["dev"] self.assertEqual({"FOO": "bar"}, dict(b.env)) - self.assertTrue(b.supervise) def test_child_inherits_parent_fields_unchanged(self): m = _build( base={ "env": {"BASE": "1"}, - "supervise": True, }, child={"extends": "base"}, ) c = m.bottles["child"] self.assertEqual({"BASE": "1"}, dict(c.env)) - self.assertTrue(c.supervise) - - def test_child_overrides_supervise_scalar(self): - m = _build( - base={"supervise": True}, - off={"extends": "base", "supervise": False}, - ) - self.assertTrue(m.bottles["base"].supervise) - self.assertFalse(m.bottles["off"].supervise) def test_parent_resolved_once_for_multiple_children(self): # Two children sharing one parent: both inherit; the parent # is resolved once + cached. (Cache behavior is internal; we # observe correctness on both children.) m = _build( - base={"env": {"BASE": "1"}, "supervise": True}, + base={"env": {"BASE": "1"}}, a={"extends": "base", "env": {"A": "1"}}, b={"extends": "base", "env": {"B": "1"}}, ) @@ -366,7 +354,6 @@ class TestExtendsChain(unittest.TestCase): m = _build( grandparent={ "env": {"GP": "1"}, - "supervise": True, }, parent={ "extends": "grandparent", @@ -381,8 +368,6 @@ class TestExtendsChain(unittest.TestCase): {"GP": "1", "P": "1", "C": "1"}, dict(m.bottles["child"].env), ) - # supervise threads through unchanged. - self.assertTrue(m.bottles["child"].supervise) def test_intermediate_can_override(self): m = _build( diff --git a/tests/unit/test_plan_print_parity.py b/tests/unit/test_plan_print_parity.py index f8b5648..4bc3299 100644 --- a/tests/unit/test_plan_print_parity.py +++ b/tests/unit/test_plan_print_parity.py @@ -19,6 +19,7 @@ from bot_bottle.backend.docker.bottle_plan import DockerBottlePlan from bot_bottle.backend.smolmachines.bottle_plan import SmolmachinesBottlePlan from bot_bottle.egress import EgressPlan, EgressRoute from bot_bottle.git_gate import GitGatePlan, GitGateUpstream +from bot_bottle.supervise import SupervisePlan from bot_bottle.manifest import Manifest, ManifestIndex @@ -77,6 +78,15 @@ def _egress_plan(tmp: str) -> EgressPlan: ) +def _supervise_plan(tmp: str) -> SupervisePlan: + stage = Path(tmp) + return SupervisePlan( + slug="test-00001", + queue_dir=stage / "supervise" / "queue", + current_config_dir=stage / "supervise" / "current-config", + ) + + def _agent_provision(tmp: str) -> AgentProvisionPlan: return AgentProvisionPlan( template="claude", @@ -99,7 +109,7 @@ def _docker_plan(spec: BottleSpec, manifest: Manifest, tmp: str) -> DockerBottle stage_dir=stage, git_gate_plan=_git_gate_plan(tmp), egress_plan=_egress_plan(tmp), - supervise_plan=None, + supervise_plan=_supervise_plan(tmp), agent_provision=_agent_provision(tmp), slug="test-00001", forwarded_env={}, @@ -115,7 +125,7 @@ def _smolmachines_plan(spec: BottleSpec, manifest: Manifest, tmp: str) -> Smolma stage_dir=stage, git_gate_plan=_git_gate_plan(tmp), egress_plan=_egress_plan(tmp), - supervise_plan=None, + supervise_plan=_supervise_plan(tmp), agent_provision=_agent_provision(tmp), slug="test-00001", bundle_subnet="10.99.0.0/24", diff --git a/tests/unit/test_smolmachines_provision.py b/tests/unit/test_smolmachines_provision.py index e3fbbfc..1f6a6af 100644 --- a/tests/unit/test_smolmachines_provision.py +++ b/tests/unit/test_smolmachines_provision.py @@ -86,7 +86,6 @@ def _plan( stage_dir: Path | None = None, egress_routes: tuple[EgressRoute, ...] = (), egress_ca_path: Path = Path(), - supervise: bool = False, bundle_ip: str = "192.168.50.2", agent_git_gate_host: str = "127.0.0.1:55555", agent_supervise_url: str = "http://127.0.0.1:55556/", @@ -108,8 +107,6 @@ def _plan( git_gate_json["user"] = git_user if git_gate_json: bottle_json["git-gate"] = git_gate_json - if supervise: - bottle_json["supervise"] = True index = ManifestIndex.from_json_obj({ "bottles": {"dev": bottle_json}, "agents": { @@ -127,13 +124,11 @@ def _plan( copy_cwd=copy_cwd, user_cwd=user_cwd, ) - supervise_plan = None - if supervise: - supervise_plan = SupervisePlan( - slug="demo-abc12", - queue_dir=Path("/tmp/queue"), - current_config_dir=Path("/tmp/current-config"), - ) + supervise_plan = SupervisePlan( + slug="demo-abc12", + queue_dir=Path("/tmp/queue"), + current_config_dir=Path("/tmp/current-config"), + ) return SmolmachinesBottlePlan( spec=spec, manifest=manifest, @@ -405,7 +400,7 @@ class TestBundleLaunchSpec(unittest.TestCase): spec = _bundle_launch_spec(plan, "net", "127.0.0.16") self.assertEqual( - "egress,git-gate,git-http", + "egress,supervise,git-gate,git-http", spec.daemons_csv, ) self.assertIn(9420, spec.ports_to_publish)