Conversation
EclipseSourceAI
left a comment
There was a problem hiding this comment.
Note
Autonomous AI review.
This review was done by an AI agent and therefore may contain mistakes. Feel free to ignore any comment you disagree with. A thumbs-down reaction on a comment marks it as rejected for follow-up reviews. Noting why in a reply helps, since replies are read too.
Resolving all AI comments does not lead to an automatic approval. A maintainer still needs to review and sign off on the overall architecture and design.
To get an updated review after pushing changes, a maintainer may re-request a review from this account.
Running in Eclipse Enclave, submitted via review-guard-mcp
This PR moves every Docker and podman session off the default bridge and onto its own labeled bridge network, in both restricted mode (the gateway attaches) and unrestricted mode (the tool container attaches). The core is internal/backend/docker/network.go, which handles create/reuse with an ownership check, removal by ID with retries while the session's own containers settle, GC of orphaned networks at start and in cleanup --ephemeral, and a new network field in ps --json. On podman it requires netavark with isolate=strict, falling back to isolate=true with a warning on older netavark.
Where maintainers should focus:
- Scope. A large share of the ~3k lines is gateway concurrency hardening, not networking:
ReconcileStalewith a one-minute grace period, ID-based gateway stop/remove, andRunDetachedreturning the ID on failure. The session-start lock already serializes starts of the same name, so part of this doesn't guard against a real race and changes retry behavior after a killed start. Splitting it into its own PR would make both halves easier to review. - Behavior changes that aren't listed as breaking. A failing
docker infonow aborts the start. Linux--bridge-portusers with a host firewall need a new rule for every session. - Duplication in
network.go. The same ownership check appears in several places, and the copies have already started to drift. - Start latency. GC now runs on every session start and inspects each old managed network individually.
ps --json gains an additive network field, and cli-reference.md documents it.
EclipseSourceAI
left a comment
There was a problem hiding this comment.
Note
Autonomous AI review.
This review was done by an AI agent and therefore may contain mistakes. Feel free to ignore any comment you disagree with. A thumbs-down reaction on a comment marks it as rejected for follow-up reviews. Noting why in a reply helps, since replies are read too.
Resolving all AI comments does not lead to an automatic approval. A maintainer still needs to review and sign off on the overall architecture and design.
To get an updated review after pushing changes, a maintainer may re-request a review from this account.
Running in Eclipse Enclave, submitted via review-guard-mcp
Only one commit landed since my last review (1cde0bb, "fix: tighten session resource cleanup and startup recovery"). It's a thorough pass that addresses every thread I opened last time:
- The gateway grace period is gone;
ReconcileStalenow removes an owned orphan unconditionally, relying on the session-start lock for safety instead of a time window. - The repeated network-ownership label check in
network.gois consolidated intosessionNetworkOwnedBy/sessionNetworkOwner, used consistently across create, remove, GC, andps --jsonfill paths. dockerSessionRuntimeExistsnow delegates todockerSessionContainerExistsinstead of duplicating the inspect logic.- GC no longer inspects each stale network's owner individually; it does one
ContainerListcall and checks against a set. warnInsecureDockerConfigtakes the already-fetchedSystemInfoinstead of re-fetching it under a misleading name.- The gateway ownership check in
docker.gonow uses the exportedgateway.ContainerOwnedByinstead of a second, looser check. - The podman isolate fallback and its error matcher: the matcher is now scoped to the exact
ParseBoolmessage instead of any string containing "isolate", with a regression test (TestUnsupportedIsolateValueRejectsUnrelatedErrors) and comment explaining it's a different (CLI-side, not netavark-side) failure mode than the one I originally flagged. docs/networking.mdnow has a "Migrating from the default bridge" section covering thedocker0firewall rule change and the new hard dependency ondocker info/podman infosucceeding at startup.
Build and the touched package tests (internal/gateway, internal/backend/docker, internal/docker) pass locally. I didn't find anything new to flag in this commit, so no inline comments this round. The remaining open items from my first review (the gateway concurrency hardening being out of scope for a networking PR, and start latency more generally) weren't touched by this commit and still stand.
These previous comments can be resolved as they are now handled:
- grace period removed from gateway orphan reconciliation, now relies on the session-start lock
- ownership label check in network.go deduplicated into one helper
- podman isolate fallback justified for older CLIs and its error matcher tightened
- network GC now does one container list call instead of per-network inspects
- warnInsecureDockerConfig no longer fetches docker info itself, name now matches behavior
- gateway removal now reuses the exported, stricter ownership check
- dockerSessionRuntimeExists deduplicated to call dockerSessionContainerExists
- docs now cover the docker0 firewall breaking change for --bridge-port users
I can't resolve them myself as I would need write permission on this repository.
Podman drives the Docker backend but rejects Docker bridge options and reports network IDs, subnets, and endpoints differently. Use engine-specific options, normalize inspect data, and resolve the ID after creation because Podman prints the network name instead. Netavark validates isolation when a container attaches, so a create-time fallback alone cannot detect an unsupported value. Choose isolate=strict from netavark 1.7 onward; otherwise use isolate=true and warn that containers on non-isolated networks can still reach the session. Query attached containers when Podman omits the endpoint map. Never remove a network after a failed query or while foreign endpoints remain, and allow this session's endpoints time to disappear during asynchronous teardown. Share stale-gateway reconciliation between pre-start and startup, preserving young running gateways that may belong to a concurrent start. Expose stale network pruning through cleanup --ephemeral as well as start-time GC.
Scope cleanup --ephemeral network pruning to the current project and tool unless --all is selected. Remove containers through backend teardown before pruning networks so the same invocation removes their networks too. Capture the gateway's immutable ID and network before removing the session, then stop the gateway and remove the network in that order. Podman cannot remove the gateway while another container still joins its namespaces, and stopping it by name after session removal could hit a concurrent replacement. Leave gateway and network untouched if session removal fails for any reason other than an already-missing container.
Classify network-not-found messages per stderr line because Docker 29 can append an exit-status line after the daemon message. Batch inspection may retain successfully inspected networks when another network disappeared between listing and inspection. Malformed output, other engine failures, and successful responses with missing objects must remain errors rather than silently becoming partial results or missing networks.
…r by bare name The gateway runs with AutoRemove, so after a failed start the engine has already freed the name; a force-remove by name could only ever hit the gateway of a concurrent start of the same session. Use the ID Docker prints before starting, and otherwise inspect the name and remove only a non-running container carrying this session's labels.
1cde0bb to
8f828f8
Compare
What it does
Sessions previously used the engine's default bridge, where unrelated
containers could connect directly to services listening inside a session,
even when published host ports were bound to
127.0.0.1.Each Docker or podman session now gets a dedicated bridge network, whether
network access is restricted or unrestricted. The network stays with a stopped
background session and is removed when the session is stopped. Orphaned
networks are pruned after an hour if they have no session container or
attached endpoints.
enclave ps --jsonexposes each session's network nameand subnet.
Published ports still work on host loopback. Containers on other bridges can
no longer connect directly to session listeners; deliberately attaching a
container to the session network remains possible. Restricted sessions still
use the gateway's DNS and outbound policy.
Podman requires netavark. Older netavark versions fall back to weaker
isolation with a warning: other isolated sessions are blocked, but containers
on non-isolated podman networks can still connect. Docker Desktop can also
make a host-loopback-published service reachable from another container via
host.docker.internal; services that need protection must authenticateclients.
How to test
Run these steps on a Docker host from a project where Enclave is configured to
run a tool. If both Docker and podman are installed, select Docker as Enclave's
default backend first;
psandstopdo not accept--backend.Start a background session that publishes a test port:
enclave --backend docker --background --name net-review -p 13000:3000.Check
enclave ps --json: the session should have a non-nullnetworkwith a name and subnet, and
docker network inspect <network-name>shouldfind it. Copy that network name and get its attached endpoint's IPv4
address (the gateway in restricted mode, the tool in unrestricted mode):
In another terminal, start a server inside that session, using the
container name printed by the start command:
docker exec -it <session-container> python3 -m http.server 3000 --bind 0.0.0.0.curl http://127.0.0.1:13000on the host should succeed. From a separatecontainer on Docker's default bridge, run
docker run --rm --network bridge busybox:1.36 wget -T 3 -O - "http://$SESSION_IP:3000".It should fail. Avoid ports 8080/8443, which the gateway proxy already
listens on.
Stop the session with
enclave stop net-review. Its network should nolonger appear in
docker network ls.Repeat with
--allow-all-networkwhen starting the session. The dedicatednetwork, host access, cross-bridge isolation, and teardown should behave
the same way without a gateway.
If testing podman, select Podman as Enclave's default backend, then repeat
with
--backend podman,podman exec, andpodman network inspect.The commands to derive the session ip might vary.
On a netavark release that supports strict isolation, a container on another
podman bridge should not reach the session's bridge IP. On older netavark,
expect the weaker-isolation warning instead.
Follow-ups
None.
Breaking changes
Podman hosts still using the CNI network backend can no longer start Enclave
sessions and must switch to netavark. Podman already
deprecated CNI in favor of netavark.
Review checklist