fix(git): mount git-gate known hosts
This commit was merged in pull request #91.
This commit is contained in:
@@ -212,6 +212,11 @@ def _sidecar_bundle_service(plan: DockerBottlePlan) -> dict[str, Any]:
|
|||||||
keypath,
|
keypath,
|
||||||
f"{GIT_GATE_CREDS_DIR_IN_CONTAINER}/{u.name}-key",
|
f"{GIT_GATE_CREDS_DIR_IN_CONTAINER}/{u.name}-key",
|
||||||
))
|
))
|
||||||
|
if u.known_hosts_file:
|
||||||
|
volumes.append(_bind(
|
||||||
|
u.known_hosts_file,
|
||||||
|
f"{GIT_GATE_CREDS_DIR_IN_CONTAINER}/{u.name}-known_hosts",
|
||||||
|
))
|
||||||
extra_map = git_gate_aggregate_extra_hosts(gp.upstreams)
|
extra_map = git_gate_aggregate_extra_hosts(gp.upstreams)
|
||||||
extra_hosts = [f"{host}:{ip}" for host, ip in sorted(extra_map.items())]
|
extra_hosts = [f"{host}:{ip}" for host, ip in sorted(extra_map.items())]
|
||||||
|
|
||||||
|
|||||||
@@ -366,6 +366,12 @@ def _bundle_launch_spec(
|
|||||||
f"{GIT_GATE_CREDS_DIR_IN_CONTAINER}/{u.name}-key",
|
f"{GIT_GATE_CREDS_DIR_IN_CONTAINER}/{u.name}-key",
|
||||||
True,
|
True,
|
||||||
))
|
))
|
||||||
|
if u.known_hosts_file:
|
||||||
|
volumes.append((
|
||||||
|
str(u.known_hosts_file),
|
||||||
|
f"{GIT_GATE_CREDS_DIR_IN_CONTAINER}/{u.name}-known_hosts",
|
||||||
|
True,
|
||||||
|
))
|
||||||
|
|
||||||
# --- supervise --------------------------------------------
|
# --- supervise --------------------------------------------
|
||||||
sp = plan.supervise_plan
|
sp = plan.supervise_plan
|
||||||
|
|||||||
+25
-1
@@ -71,6 +71,7 @@ class GitGateUpstream:
|
|||||||
upstream_port: str
|
upstream_port: str
|
||||||
identity_file: str
|
identity_file: str
|
||||||
known_host_key: str
|
known_host_key: str
|
||||||
|
known_hosts_file: Path = Path()
|
||||||
extra_hosts: Mapping[str, str] = field(default_factory=_empty_str_map)
|
extra_hosts: Mapping[str, str] = field(default_factory=_empty_str_map)
|
||||||
|
|
||||||
|
|
||||||
@@ -408,10 +409,33 @@ class GitGate(ABC):
|
|||||||
# not via `sh`, so the script needs the x bit. docker cp
|
# not via `sh`, so the script needs the x bit. docker cp
|
||||||
# preserves source mode into the container.
|
# preserves source mode into the container.
|
||||||
access_hook.chmod(0o700)
|
access_hook.chmod(0o700)
|
||||||
|
upstreams_with_files: list[GitGateUpstream] = []
|
||||||
|
for u in upstreams:
|
||||||
|
known_hosts_file = Path()
|
||||||
|
if u.known_host_key:
|
||||||
|
known_hosts_file = stage_dir / f"{u.name}-known_hosts"
|
||||||
|
known_hosts_file.write_text(
|
||||||
|
git_gate_known_hosts_line(
|
||||||
|
u.upstream_host, u.upstream_port, u.known_host_key,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
known_hosts_file.chmod(0o600)
|
||||||
|
upstreams_with_files.append(
|
||||||
|
GitGateUpstream(
|
||||||
|
name=u.name,
|
||||||
|
upstream_url=u.upstream_url,
|
||||||
|
upstream_host=u.upstream_host,
|
||||||
|
upstream_port=u.upstream_port,
|
||||||
|
identity_file=u.identity_file,
|
||||||
|
known_host_key=u.known_host_key,
|
||||||
|
known_hosts_file=known_hosts_file,
|
||||||
|
extra_hosts=dict(u.extra_hosts),
|
||||||
|
)
|
||||||
|
)
|
||||||
return GitGatePlan(
|
return GitGatePlan(
|
||||||
slug=slug,
|
slug=slug,
|
||||||
entrypoint_script=entrypoint,
|
entrypoint_script=entrypoint,
|
||||||
hook_script=hook,
|
hook_script=hook,
|
||||||
access_hook_script=access_hook,
|
access_hook_script=access_hook,
|
||||||
upstreams=upstreams,
|
upstreams=tuple(upstreams_with_files),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -148,6 +148,7 @@ def _plan(
|
|||||||
upstream_port="22",
|
upstream_port="22",
|
||||||
identity_file="/etc/hostname",
|
identity_file="/etc/hostname",
|
||||||
known_host_key="",
|
known_host_key="",
|
||||||
|
known_hosts_file=STATE / "git-gate" / "upstream-known_hosts",
|
||||||
extra_hosts={"example.com": "10.0.0.1"},
|
extra_hosts={"example.com": "10.0.0.1"},
|
||||||
),)
|
),)
|
||||||
routes: tuple[EgressRoute, ...] = ()
|
routes: tuple[EgressRoute, ...] = ()
|
||||||
@@ -408,6 +409,7 @@ class TestSidecarBundleShape(unittest.TestCase):
|
|||||||
self.assertIn("/etc/pipelock.yaml", targets)
|
self.assertIn("/etc/pipelock.yaml", targets)
|
||||||
self.assertIn("/etc/egress/routes.yaml", targets)
|
self.assertIn("/etc/egress/routes.yaml", targets)
|
||||||
self.assertIn("/git-gate-entrypoint.sh", targets)
|
self.assertIn("/git-gate-entrypoint.sh", targets)
|
||||||
|
self.assertIn("/git-gate/creds/upstream-known_hosts", targets)
|
||||||
# supervise queue dir target = QUEUE_DIR_IN_CONTAINER
|
# supervise queue dir target = QUEUE_DIR_IN_CONTAINER
|
||||||
self.assertTrue(any("supervise/queue" in t or t.startswith("/run/supervise")
|
self.assertTrue(any("supervise/queue" in t or t.startswith("/run/supervise")
|
||||||
for t in targets))
|
for t in targets))
|
||||||
|
|||||||
@@ -257,6 +257,35 @@ class TestPrepare(unittest.TestCase):
|
|||||||
self.assertEqual("", plan.internal_network)
|
self.assertEqual("", plan.internal_network)
|
||||||
self.assertEqual("", plan.egress_network)
|
self.assertEqual("", plan.egress_network)
|
||||||
|
|
||||||
|
def test_prepare_writes_known_hosts_file(self):
|
||||||
|
plan = _StubGate().prepare(
|
||||||
|
fixture_with_git().bottles["dev"], "demo", self.stage
|
||||||
|
)
|
||||||
|
upstream = plan.upstreams[0]
|
||||||
|
self.assertEqual(self.stage / "bot-bottle-known_hosts",
|
||||||
|
upstream.known_hosts_file)
|
||||||
|
self.assertEqual(
|
||||||
|
"[gitea.dideric.is]:30009 ssh-ed25519 AAAA...\n",
|
||||||
|
upstream.known_hosts_file.read_text(),
|
||||||
|
)
|
||||||
|
self.assertEqual(0o600, os.stat(upstream.known_hosts_file).st_mode & 0o777)
|
||||||
|
|
||||||
|
def test_prepare_skips_known_hosts_file_when_key_missing(self):
|
||||||
|
manifest = Manifest.from_json_obj({
|
||||||
|
"bottles": {"dev": {"git": {"remotes": {
|
||||||
|
"github.com": {
|
||||||
|
"Name": "foo",
|
||||||
|
"Upstream": "ssh://git@github.com/didericis/foo.git",
|
||||||
|
"IdentityFile": "/dev/null",
|
||||||
|
},
|
||||||
|
}}}},
|
||||||
|
"agents": {"demo": {"skills": [], "prompt": "", "bottle": "dev"}},
|
||||||
|
})
|
||||||
|
plan = _StubGate().prepare(
|
||||||
|
manifest.bottles["dev"], "demo", self.stage
|
||||||
|
)
|
||||||
|
self.assertEqual(Path(), plan.upstreams[0].known_hosts_file)
|
||||||
|
|
||||||
def test_prepare_with_no_git_writes_minimal_script(self):
|
def test_prepare_with_no_git_writes_minimal_script(self):
|
||||||
plan = _StubGate().prepare(
|
plan = _StubGate().prepare(
|
||||||
fixture_minimal().bottles["dev"], "demo", self.stage
|
fixture_minimal().bottles["dev"], "demo", self.stage
|
||||||
|
|||||||
Reference in New Issue
Block a user