On a Firecracker gateway cold boot, reconcile every live agent VM against
the fresh gateway: push the new mitmproxy CA into each agent's trust store,
re-provision git-gate repos/creds from the persisted upstreams snapshot,
and restore egress tokens. Per-bottle failures are logged and skipped so
one unreachable VM does not block the rest.
New modules / changes:
- backend/firecracker/reconcile.py: attach_bottled_agents_to_gateway,
_push_ca, _reprovision_git_gate, _guest_ip_from_config
- git_gate/provision.py: write upstreams.json after key provisioning so
the bring-up reconcile can reconstruct the upstream table without the
manifest
- backend/firecracker/infra.py: call attach_bottled_agents_to_gateway in
the cold-boot branch of ensure_running()
- backend/base.py: no-op default on BottleBackend
- backend/firecracker/consolidated_launch.py: remove superseded
_reprovision_running_bottles / _guest_ip_from_config
- orchestrator: OrchestratorCore.update_agent_secret + POST
/bottles/<id>/secret + client.update_agent_secret (single-secret
in-place update, the reusable primitive from the 2026-07-26 hotfix)
- tests: 15 new tests in test_firecracker_reconcile.py; updated
test_firecracker_infra.py cold-boot cases; stale FC reprovision tests
removed from test_backend_secret_reprovision.py
Closes#516.
Now that #469 got the DB off the data plane, the docker backend runs the
control plane and data plane as two containers instead of the combined
`bot-bottle-infra` container:
* bot-bottle-orchestrator — the lean control-plane container (image
Dockerfile.orchestrator, `-m bot_bottle.orchestrator`). Joins the new
`bot-bottle-orchestrator` control network (`--internal`) only, plus a
host-loopback publish for the CLI. Sole opener of bot-bottle.db; holds the
signing key; no CA, no gateway daemons.
* bot-bottle-orch-gateway — the data-plane container (DockerGateway),
dual-homed on the agent `bot-bottle-gateway` network AND the control
network, so it resolves the orchestrator by name
(http://bot-bottle-orchestrator:8099) while agents — never on the control
network — have no route to the control plane (the L3 block, not just the
JWT). Holds the gateway JWT + the mitmproxy CA.
DockerInfraService now orchestrates the pair (builds gateway + orchestrator
images, brings up the orchestrator then the gateway) and exposes gateway_name;
the launch flow attributes agents against the gateway container. DockerGateway
gains a control_network it joins after run. rotate_ca / the CA read target the
gateway container. The combined Dockerfile.infra is no longer built by docker
(firecracker/macOS still use it until their splits).
pyright 0 errors; unit suite green (2273). Integration tests updated for the
two-container shape but need a real-docker run to validate the networking.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>