From a7633977de50d9e7db0e3ee579fbfd9f9d569a08 Mon Sep 17 00:00:00 2001 From: didericis Date: Tue, 12 May 2026 16:09:53 -0400 Subject: [PATCH] test(ssh-gate): assert SSHGate.stop is no-op on missing sidecar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PRD 0007: the launch ExitStack calls gate.stop on every failure path, so an early bring-up error (where the gate container was never created) must not raise from teardown. Mirrors the existing DockerPipelockProxy.stop assertion. The orphan-container enumeration in cleanup.py already covers ssh-gate containers via its `claude-bottle-` name prefix filter — no code change there. --- tests/integration/test_orphan_cleanup.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/tests/integration/test_orphan_cleanup.py b/tests/integration/test_orphan_cleanup.py index 4aff79b..2462120 100644 --- a/tests/integration/test_orphan_cleanup.py +++ b/tests/integration/test_orphan_cleanup.py @@ -1,8 +1,8 @@ """Integration: the cleanup primitives the start-flow trap depends on are idempotent. The original orphan-network bug was a trap-ordering issue; the fix moved the install earlier. The trap is only safe if -network_remove and PipelockProxy.stop are no-ops against missing -resources.""" +network_remove, PipelockProxy.stop, and SSHGate.stop are no-ops +against missing resources.""" import os import subprocess @@ -17,6 +17,10 @@ from claude_bottle.backend.docker.pipelock import ( DockerPipelockProxy, pipelock_container_name, ) +from claude_bottle.backend.docker.ssh_gate import ( + DockerSSHGate, + ssh_gate_container_name, +) from tests._docker import skip_unless_docker @@ -75,6 +79,13 @@ class TestOrphanCleanup(unittest.TestCase): # Should not raise. DockerPipelockProxy().stop(pipelock_container_name(f"missing-{self.slug}")) + def test_ssh_gate_stop_missing_sidecar(self): + # Same trap-safety requirement for the gate (PRD 0007). The + # launch ExitStack calls gate.stop on every error path; if + # the container was never created (early failure), stop must + # still no-op. + DockerSSHGate().stop(ssh_gate_container_name(f"missing-{self.slug}")) + if __name__ == "__main__": unittest.main()