feat(orchestrator): slice 13c(ii) — shared-gateway source-IP allocator #372

Closed
didericis-claude wants to merge 1 commits from orchestrator-gateway-net into orchestrator-gitgate-provision
Collaborator

Sub-slice of slice 13c (docker launch integration). Deterministic per-bottle address assignment on the consolidated gateway's shared docker network — the address the gateway uses as its attribution key.

What it does

next_free_ip(cidr, taken) — the lowest host address in the subnet not reserved and not already assigned:

  • network + broadcast excluded by ipaddress.hosts();
  • docker's router .1 excluded here;
  • taken = the gateway container's own address + every live bottle's (the caller reads these from the registry).
  • NoFreeAddressError when the subnet is exhausted.

Pure ipaddress logic — the docker-specific inputs (subnet CIDR via network_inspect_cidr, the gateway container's address via docker inspect) are gathered by the caller and passed in, so this stays unit-testable without docker.

Why deterministic + pinned

The attribution invariant needs each bottle's source address to be stable and known at registration time; the launch step will docker run --ip <allocated> so the gateway can key policy/supervise/git-gate on it. (On docker the L2 anti-spoof is weaker than Firecracker's /31+nft, which is why the identity token #366 is load-bearing here — tracked separately.)

Verification

pyright 0 errors, pylint 9.83/10 (new files 10.00), unit suite green (1730 tests; the 13 test_sidecar_init /bin/sleep errors are pre-existing NixOS-local noise).

Stacked on #371.

🤖 Generated with Claude Code

Sub-slice of **slice 13c** (docker launch integration). Deterministic per-bottle address assignment on the consolidated gateway's shared docker network — the address the gateway uses as its **attribution key**. ### What it does `next_free_ip(cidr, taken)` — the lowest host address in the subnet not reserved and not already assigned: - network + broadcast excluded by `ipaddress.hosts()`; - docker's router `.1` excluded here; - `taken` = the gateway container's own address + every live bottle's (the caller reads these from the registry). - `NoFreeAddressError` when the subnet is exhausted. Pure `ipaddress` logic — the docker-specific inputs (subnet CIDR via `network_inspect_cidr`, the gateway container's address via `docker inspect`) are gathered by the caller and passed in, so this stays unit-testable without docker. ### Why deterministic + pinned The attribution invariant needs each bottle's source address to be stable and known at registration time; the launch step will `docker run --ip <allocated>` so the gateway can key policy/supervise/git-gate on it. (On docker the L2 anti-spoof is weaker than Firecracker's `/31`+nft, which is why the identity token #366 is load-bearing here — tracked separately.) ### Verification pyright **0 errors**, pylint **9.83/10** (new files 10.00), unit suite green (1730 tests; the 13 `test_sidecar_init` `/bin/sleep` errors are pre-existing NixOS-local noise). Stacked on #371. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
didericis-claude added 1 commit 2026-07-13 21:20:30 -04:00
feat(orchestrator): slice 13c(ii) — shared-gateway source-IP allocator
lint / lint (push) Successful in 2m2s
test / unit (pull_request) Successful in 1m4s
test / integration (pull_request) Successful in 20s
test / coverage (pull_request) Successful in 1m12s
77aaabae63
Deterministic per-bottle address assignment on the consolidated docker
gateway's shared network — the address the gateway uses as its attribution
key. Pure ipaddress logic; the docker-specific inputs (subnet CIDR, the
gateway container's own address) are gathered by the caller and passed as
`taken`, keeping it testable without docker.

- next_free_ip(cidr, taken): lowest host address not reserved (network +
  broadcast excluded by hosts(); docker's router .1 excluded here) and not
  already assigned (gateway container + live bottles from the registry).
  NoFreeAddressError when the subnet is exhausted.

pyright 0 errors; pylint 9.83/10; unit suite green (the 13 test_sidecar_init
/bin/sleep errors are pre-existing NixOS-local noise).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WBMWTEtQdJ4W5UrWuLHCck
didericis approved these changes 2026-07-13 22:06:02 -04:00
Author
Collaborator

Collapsed into the single stack PR #380 (per-host orchestrator, PRD 0070). Closing this slice PR; review + merge happens on #380.

Collapsed into the single stack PR #380 (per-host orchestrator, PRD 0070). Closing this slice PR; review + merge happens on #380.
didericis-claude closed this pull request 2026-07-14 00:57:38 -04:00
Some checks are pending
lint / lint (push) Successful in 2m2s
test / unit (pull_request) Successful in 1m4s
test / integration (pull_request) Successful in 20s
test / coverage (pull_request) Successful in 1m12s

Pull request closed

Sign in to join this conversation.