diff --git a/bot_bottle/git_gate.py b/bot_bottle/git_gate.py index 5b010f9..e2063c5 100644 --- a/bot_bottle/git_gate.py +++ b/bot_bottle/git_gate.py @@ -41,6 +41,10 @@ from .manifest import Bottle, GitEntry # Short network alias for git-gate inside the sidecar bundle. The # agent's `.gitconfig` insteadOf rewrites resolve through this name. GIT_GATE_HOSTNAME = "git-gate" +# Bound half-open git client sessions. If an agent/tool runner is +# interrupted during push, git daemon should reap the receive-pack +# child instead of keeping the gate wedged indefinitely. +GIT_GATE_DAEMON_TIMEOUT_SECS = 60 def _empty_str_map() -> dict[str, str]: @@ -247,6 +251,8 @@ def git_gate_render_entrypoint(upstreams: tuple[GitGateUpstream, ...]) -> str: "", "exec git daemon \\", " --reuseaddr \\", + f" --timeout={GIT_GATE_DAEMON_TIMEOUT_SECS} \\", + f" --init-timeout={GIT_GATE_DAEMON_TIMEOUT_SECS} \\", " --base-path=/git \\", " --export-all \\", " --enable=receive-pack \\", diff --git a/tests/unit/test_git_gate.py b/tests/unit/test_git_gate.py index 7e7884e..0ad2727 100644 --- a/tests/unit/test_git_gate.py +++ b/tests/unit/test_git_gate.py @@ -170,6 +170,8 @@ class TestEntrypointRender(unittest.TestCase): # Daemon line is what keeps PID 1 alive. self.assertIn("exec git daemon", script) self.assertIn("--enable=receive-pack", script) + self.assertIn("--timeout=60", script) + self.assertIn("--init-timeout=60", script) self.assertIn("--base-path=/git", script) # The access-hook is what makes fetch a mirror operation # against the upstream (PRD 0008 v1.1).