feat(prd-0081): reprovision CA, git-gate, and egress tokens on gateway bring-up
prd-number-check / require-numbered-prds (pull_request) Successful in 13s
tracker-policy-pr / check-pr (pull_request) Successful in 7s
test / image-input-builds (pull_request) Successful in 41s
test / unit (pull_request) Successful in 51s
test / integration-docker (pull_request) Successful in 58s
test / coverage (pull_request) Successful in 41s
test / image-input-builds (push) Successful in 48s
test / unit (push) Successful in 56s
lint / lint (push) Successful in 1m2s
Update Quality Badges / update-badges (push) Successful in 1m4s
test / integration-docker (push) Failing after 2m53s
test / coverage (push) Has been skipped
prd-number-check / require-numbered-prds (pull_request) Successful in 13s
tracker-policy-pr / check-pr (pull_request) Successful in 7s
test / image-input-builds (pull_request) Successful in 41s
test / unit (pull_request) Successful in 51s
test / integration-docker (pull_request) Successful in 58s
test / coverage (pull_request) Successful in 41s
test / image-input-builds (push) Successful in 48s
test / unit (push) Successful in 56s
lint / lint (push) Successful in 1m2s
Update Quality Badges / update-badges (push) Successful in 1m4s
test / integration-docker (push) Failing after 2m53s
test / coverage (push) Has been skipped
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.
This commit was merged in pull request #517.
This commit is contained in:
@@ -2,9 +2,7 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import subprocess
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace
|
||||
@@ -107,21 +105,6 @@ class TestDockerReprovision(unittest.TestCase):
|
||||
|
||||
|
||||
class TestFirecrackerReprovision(unittest.TestCase):
|
||||
def _run_dir(self, root: Path, ip: str = "10.243.0.3") -> Path:
|
||||
run_dir = root / "demo"
|
||||
run_dir.mkdir()
|
||||
(run_dir / "bottle_id_ed25519").write_text("key")
|
||||
(run_dir / "config.json").write_text(json.dumps({
|
||||
"boot-source": {"boot_args": f"root=/dev/vda ip={ip}::gw:mask::eth0:off"}
|
||||
}))
|
||||
return run_dir
|
||||
|
||||
def test_extracts_guest_ip_from_config(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
run_dir = self._run_dir(Path(tmp))
|
||||
self.assertEqual("10.243.0.3", fc._guest_ip_from_config(run_dir / "config.json"))
|
||||
self.assertEqual("", fc._guest_ip_from_config(run_dir / "missing.json"))
|
||||
|
||||
def test_persists_key_over_stdin_not_argv(self) -> None:
|
||||
with patch.object(fc.util, "ssh_base_argv", return_value=["ssh", "guest"]), \
|
||||
patch.object(fc.subprocess, "run", return_value=_proc()) as run:
|
||||
@@ -135,29 +118,6 @@ class TestFirecrackerReprovision(unittest.TestCase):
|
||||
with self.assertRaisesRegex(fc.ConsolidatedLaunchError, "denied"):
|
||||
fc.persist_env_var_secret(Path("/key"), "10.0.0.1", "secret")
|
||||
|
||||
def test_reads_live_vm_key_and_reprovisions(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
run_dir = self._run_dir(Path(tmp))
|
||||
client = Mock()
|
||||
with patch.object(fc.cleanup, "live_run_dirs", return_value=(run_dir,)), \
|
||||
patch.object(fc.util, "ssh_base_argv", return_value=["ssh", "guest"]), \
|
||||
patch.object(fc.subprocess, "run", return_value=_proc(stdout="secret\n")), \
|
||||
patch.object(fc, "reprovision_bottles", return_value=1) as restore, \
|
||||
patch.object(fc, "info"):
|
||||
fc._reprovision_running_bottles(client)
|
||||
restore.assert_called_once_with(client, {"10.243.0.3": "secret"})
|
||||
|
||||
def test_unreadable_vm_is_skipped(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
run_dir = self._run_dir(Path(tmp))
|
||||
client = Mock()
|
||||
with patch.object(fc.cleanup, "live_run_dirs", return_value=(run_dir,)), \
|
||||
patch.object(fc.util, "ssh_base_argv", return_value=["ssh", "guest"]), \
|
||||
patch.object(fc.subprocess, "run", return_value=_proc(1)), \
|
||||
patch.object(fc, "reprovision_bottles", return_value=0) as restore:
|
||||
fc._reprovision_running_bottles(client)
|
||||
restore.assert_called_once_with(client, {})
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user