refactor(compose): drop pre-create networks + pipelock CIDR allowlist
PRD 0018 chunk 4 spike: empirically verified that pipelock's SSRF guard checks proxied-request destinations (e.g. api.anthropic.com → public IP) and not source IPs of incoming connections. The bottle's own internal CIDR was being added to ssrf.ip_allowlist defensively, but that defense isn't load-bearing — direct pipelock probe (`curl --proxy http://pipelock https://api.anthropic.com/`) returns 404 from upstream rather than blocking on SSRF. So: - Networks become compose-managed (`internal: true` on the internal network; the egress one is a normal user-defined bridge). Compose creates + removes them via up/down. - launch.py drops the `docker network create` + `network_inspect_cidr` + pipelock yaml re-render dance. - The pre-create/external scaffolding from chunk 3 goes with it. End-to-end `./cli.py start` still works; cleanup leaves no orphans. If real-world use surfaces an SSRF block we hadn't predicted, the allowlist can come back via subnet-pinning rather than pre-create.
This commit is contained in:
@@ -176,20 +176,19 @@ class TestProjectAndNetworks(unittest.TestCase):
|
||||
spec = bottle_plan_to_compose(_plan())
|
||||
self.assertEqual(f"claude-bottle-{SLUG}", spec["name"])
|
||||
|
||||
def test_internal_network_marked_external(self):
|
||||
# Chunk 3 pre-creates networks with `docker network create
|
||||
# --internal` so pipelock can know the CIDR before compose-up.
|
||||
# Compose references the network by name with `external: true`.
|
||||
def test_internal_network_is_internal(self):
|
||||
spec = bottle_plan_to_compose(_plan())
|
||||
net = spec["networks"]["internal"]
|
||||
self.assertEqual(f"claude-bottle-net-{SLUG}", net["name"])
|
||||
self.assertTrue(net["external"])
|
||||
self.assertTrue(net["internal"])
|
||||
|
||||
def test_egress_network_marked_external(self):
|
||||
def test_egress_network_is_external_bridge(self):
|
||||
spec = bottle_plan_to_compose(_plan())
|
||||
net = spec["networks"]["egress"]
|
||||
self.assertEqual(f"claude-bottle-egress-{SLUG}", net["name"])
|
||||
self.assertTrue(net["external"])
|
||||
# No `internal:` key on the egress network — defaults to a
|
||||
# normal user-defined bridge.
|
||||
self.assertNotIn("internal", net)
|
||||
|
||||
|
||||
class TestPipelockAlwaysPresent(unittest.TestCase):
|
||||
|
||||
Reference in New Issue
Block a user