feat(git-gate): wire DockerGitGate through prepare/launch/plan
test / unit (pull_request) Successful in 12s
test / integration (pull_request) Successful in 14s

DockerBottleBackend now instantiates a DockerGitGate alongside
DockerPipelockProxy and DockerSSHGate; the prepare step lifts
bottle.git into a GitGatePlan stored on DockerBottlePlan, and
launch starts/stops the sidecar in the same ExitStack as the
other two (only when bottle.git is non-empty).

bottle_plan.print now surfaces git remotes and per-upstream gate
forwards in the y/N preflight; to_dict adds git_remotes and
git_gate keys to the dry-run JSON payload for CLI consumers.
PRD: docs/prds/0008-git-gate.md
This commit is contained in:
2026-05-12 21:06:08 -04:00
parent 509b1b61e2
commit f787edb861
5 changed files with 59 additions and 2 deletions
@@ -11,6 +11,7 @@ import sys
from dataclasses import dataclass, field
from pathlib import Path
from ...git_gate import GitGatePlan
from ...log import info
from ...manifest import Agent, Bottle
from ...pipelock import PipelockProxyPlan, pipelock_effective_allowlist
@@ -27,6 +28,7 @@ class _PlanView:
bottle: Bottle
env_names: list[str]
ssh_hosts: list[str]
git_names: list[str]
prompt_first_line: str
@@ -51,6 +53,7 @@ class DockerBottlePlan(BottlePlan):
prompt_file: Path
proxy_plan: PipelockProxyPlan
gate_plan: SSHGatePlan
git_gate_plan: GitGatePlan
allowlist_summary: str
use_runsc: bool
@@ -67,6 +70,7 @@ class DockerBottlePlan(BottlePlan):
bottle=bottle,
env_names=env_names,
ssh_hosts=[e.Host for e in bottle.ssh],
git_names=[e.Name for e in bottle.git],
prompt_first_line=agent.prompt.splitlines()[0] if agent.prompt else "",
)
@@ -100,6 +104,16 @@ class DockerBottlePlan(BottlePlan):
info(f" ssh gate : {'; '.join(gate_lines)}")
else:
info(" ssh hosts : (none)")
if v.git_names:
info(f" git remotes : {', '.join(v.git_names)}")
git_lines = [
f"{u.name} -> {u.upstream_host}:{u.upstream_port} "
f"(gitleaks-scanned)"
for u in self.git_gate_plan.upstreams
]
info(f" git gate : {'; '.join(git_lines)}")
else:
info(" git remotes : (none)")
info(f" egress : {self.allowlist_summary}")
info(" tls intercept : pipelock (per-bottle ephemeral CA, generated at launch)")
info(
@@ -131,6 +145,16 @@ class DockerBottlePlan(BottlePlan):
}
for u in self.gate_plan.upstreams
],
"git_remotes": v.git_names,
"git_gate": [
{
"name": u.name,
"upstream": f"{u.upstream_host}:{u.upstream_port}",
"upstream_url": u.upstream_url,
"known_host_key_pinned": bool(u.known_host_key),
}
for u in self.git_gate_plan.upstreams
],
"egress": {
"host_count": len(hosts),
"hosts": hosts,