refactor(git-gate): make GitGate a service class in a git_gate package
test / integration-docker (pull_request) Successful in 15s
tracker-policy-pr / check-pr (pull_request) Successful in 10s
test / unit (pull_request) Successful in 47s
lint / lint (push) Failing after 58s
test / integration-firecracker (pull_request) Successful in 3m17s
test / coverage (pull_request) Successful in 20s
test / publish-infra (pull_request) Has been skipped

Turn the git_gate module into a package with GitGate as a concrete service class
(dropping the ABC), mirroring the Supervisor shape. The host-side git-gate
operations are now methods the backend drives:

  git_gate/
    __init__.py  — thin __getattr__ facade (keeps `from bot_bottle.git_gate
                   import …` working; render/hook names lazily forwarded to
                   gateway.git_gate_render)
    plan.py      — GitGatePlan (the launch DTO the backend contract references)
    service.py   — GitGate: prepare / provision_dynamic_keys /
                   revoke_provisioned_keys / preflight_host_keys
    provision.py — deploy-key lifecycle (was git_gate_provision.py)
    host_key.py  — host-key preflight (was git_gate_host_key.py)

The backend launch + base.py preflight now call GitGate() methods instead of the
free functions. The runtime rendering / in-gateway hook execution stay in
gateway/git_gate_render.py (data plane) — only the host-side service moved.

Because the facade forwards names lazily, the ~25 `from bot_bottle.git_gate
import GitGatePlan` call-sites are unchanged, and importing git_gate.plan (the
contract's dependency) no longer drags in the provisioning / forge-API code.

Full unit suite green (2243).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-24 16:27:56 -04:00
parent 14c28946a7
commit 450037b7e9
13 changed files with 295 additions and 225 deletions
+3 -3
View File
@@ -385,13 +385,13 @@ class TestDynamicKeyProvisioning(unittest.TestCase):
def test_resolve_identity_file_gitea_provisions_key(self):
entry = self._gitea_manifest().bottles["dev"].git[0]
with patch("bot_bottle.git_gate_provision._provision_dynamic_key", return_value="/tmp/provisioned-key") as mock_provision:
with patch("bot_bottle.git_gate.provision._provision_dynamic_key", return_value="/tmp/provisioned-key") as mock_provision:
self.assertEqual("/tmp/provisioned-key", _resolve_identity_file(entry, "demo", self.stage))
mock_provision.assert_called_once()
def test_prepare_defers_gitea_key_provisioning(self):
bottle = self._gitea_manifest().bottles["dev"]
with patch("bot_bottle.git_gate_provision._provision_dynamic_key") as mock_provision:
with patch("bot_bottle.git_gate.provision._provision_dynamic_key") as mock_provision:
plan = _StubGate().prepare(bottle, "demo", self.stage)
mock_provision.assert_not_called()
@@ -402,7 +402,7 @@ class TestDynamicKeyProvisioning(unittest.TestCase):
plan = _StubGate().prepare(bottle, "demo", self.stage)
with patch(
"bot_bottle.git_gate_provision._provision_dynamic_key",
"bot_bottle.git_gate.provision._provision_dynamic_key",
return_value="/tmp/provisioned-key",
) as mock_provision:
updated = provision_git_gate_dynamic_keys(bottle, plan, self.stage)