fix(workers-bridge): refuse a subnet that swallows the default gateway (#74) #79
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "fix/subnet"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Fixes #74.
Problem
When Nexus bootstraps inside a DinD worker that is itself attached to the outer
nexus-workersbridge (172.30.0.0/16, gw172.30.0.1), the inner daemon creates a bridge with the identical name and subnet. Because the subnet is pinned explicitly (IPAM.Config[0].Subnet) rather than IPAM-auto-allocated, Docker's own pool-collision avoidance never engages. The outer default gateway172.30.0.1gets claimed by the new inner bridge, two172.30.0.0/16routes compete, and egress dies — silently, since DNS keeps resolving so it doesn't look like a network-layer failure.Fix
The minimal guardrail from the issue (option #4 — "that single check would have prevented this outage"): on the create path only, read the container's default gateway from
/proc/net/routeand refuse to create a bridge whose subnet contains it, throwing an actionable error that names the two escape hatches (WORKERS_BRIDGE_SUBNET,WORKER_NETWORK).if (!network)block, so the steady state (bridge already exists) and theWORKER_NETWORKreuse path are untouched.ensureWorkersBridgeis only reached once per daemon lifetime (the caller caches in aWeakMap), so the tiny synchronous proc read is off any hot path.New pure helpers (
parseRouteTable,subnetContains,ipToInt) live beside their sole caller — no IP/CIDR library is installed and no shared net-utils module exists, so a first-of-kind is correct here.Tests
parseRouteTable(little-endian parse, no-default-route) andsubnetContains(containment, prefix length, malformed input).Verification
pnpm test→ 735 passed (75 files)tsc --noEmit→ cleanpnpm dev: booted cleanly, ran migrations, served the app,/api/state→200 needs-unlock, no errors in the log.Reviewed with a 4-angle
/simplifypass (reuse / simplification / efficiency / altitude); applied the one finding (split a pureparseRouteTableout ofreadDefaultGateway, dropping all temp-file machinery from the tests).