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:
2026-05-25 23:41:04 -04:00
parent cefdc8c6e9
commit a515efb6b4
3 changed files with 29 additions and 52 deletions
+6 -9
View File
@@ -130,21 +130,18 @@ def bottle_plan_to_compose(plan: DockerBottlePlan) -> dict[str, Any]:
def _networks(plan: DockerBottlePlan) -> dict[str, Any]:
"""Both networks are `external: true` — chunk 3 pre-creates them
via `docker network create` so pipelock's yaml can embed the
internal-network CIDR in its SSRF allowlist before compose-up.
Compose just references the pre-existing networks by name.
Network lifecycle (create / remove) is owned by the compose-
lifecycle helpers, not compose itself; `docker compose down`
leaves external networks alone."""
"""Compose-managed networks with explicit `name:` matching the
existing slug-suffixed convention. Compose creates them on `up`
and destroys them on `down`. The internal one is `--internal`
(no default gateway); the egress one is a normal user-defined
bridge."""
return {
"internal": {
"name": plan.proxy_plan.internal_network,
"external": True,
"internal": True,
},
"egress": {
"name": plan.proxy_plan.egress_network,
"external": True,
},
}