fix(cred_proxy): close git-push bypass + route through pipelock (PRD 0010)
Three coupled fixes that close a documented bypass of git-gate's gitleaks pre-receive hook: 1. cred-proxy refuses git smart-HTTP push at runtime. Any path ending in /git-receive-pack or /info/refs?service=git-receive-pack returns 403 with a pointer at the bottle.git SSH path. Fetch (upload-pack) is still allowed — the bypass we're closing is push, where gitleaks is the load-bearing scanner. Hard guarantee. 2. The provisioner suppresses the cred-proxy `~/.gitconfig` insteadOf rewrite for any host already declared in bottle.git. git-gate is the canonical git path there; we don't write a competing rule that would let `git clone https://<host>/...` succeed in ways that confuse on push. Defense in depth — (1) is the hard guarantee. 3. cred-proxy routes its outbound HTTPS through pipelock. The sidecar's environ now sets HTTPS_PROXY=<pipelock-url>, and the image's entrypoint runs `update-ca-certificates` over the per-bottle pipelock CA (docker cp'd into /usr/local/share/ca-certificates/pipelock.crt before start) so the proxy's HTTPS client trusts pipelock's bumped certs. Consequence: pipelock's allowlist + body scanner now sit in the cred-proxy egress path the same way they sit in front of direct agent traffic. The cred-proxy upstream hosts (api.github.com, github.com, gitea hosts, registry.npmjs.org) come OFF pipelock's passthrough_domains. Only api.anthropic.com remains on passthrough (LLM body content legitimately trips DLP). PRD 0010 updated to reflect all three. Tests adjusted: the "cred-proxy hosts go on passthrough" assertion in test_pipelock_allowlist flips to "they don't", a new TestIsGitPushRequest exercises the smart-HTTP refusal predicate, and the gitconfig renderer tests cover the per-host suppression matrix.
This commit is contained in:
@@ -83,6 +83,40 @@ class TestRenderGitconfig(unittest.TestCase):
|
||||
self.assertIn("gitea.dideric.is/", out)
|
||||
self.assertIn("gitea.example.com/", out)
|
||||
|
||||
def test_github_suppressed_when_git_gate_covers_host(self):
|
||||
# When bottle.git brokers github.com over SSH, git-gate is the
|
||||
# canonical git path. The cred-proxy https://github.com/
|
||||
# rewrite would let the agent push over HTTPS — bypassing
|
||||
# gitleaks. Suppress it.
|
||||
out = render_cred_proxy_gitconfig(
|
||||
_upstreams([{"Kind": "github", "TokenRef": "GH"}]),
|
||||
{"github.com"},
|
||||
)
|
||||
self.assertEqual("", out)
|
||||
|
||||
def test_gitea_suppressed_when_git_gate_covers_host(self):
|
||||
out = render_cred_proxy_gitconfig(
|
||||
_upstreams([{"Kind": "gitea", "TokenRef": "T",
|
||||
"Url": "https://gitea.dideric.is"}]),
|
||||
{"gitea.dideric.is"},
|
||||
)
|
||||
self.assertEqual("", out)
|
||||
|
||||
def test_partial_suppression_keeps_other_giteas(self):
|
||||
# Two gitea instances; git-gate brokers one. The other still
|
||||
# gets the cred-proxy rewrite.
|
||||
out = render_cred_proxy_gitconfig(
|
||||
_upstreams([
|
||||
{"Kind": "gitea", "TokenRef": "T1",
|
||||
"Url": "https://gitea.dideric.is"},
|
||||
{"Kind": "gitea", "TokenRef": "T2",
|
||||
"Url": "https://gitea.example.com"},
|
||||
]),
|
||||
{"gitea.dideric.is"},
|
||||
)
|
||||
self.assertNotIn("gitea.dideric.is/", out)
|
||||
self.assertIn("gitea.example.com/", out)
|
||||
|
||||
|
||||
class TestRenderTeaConfig(unittest.TestCase):
|
||||
def test_empty_when_no_gitea(self):
|
||||
|
||||
Reference in New Issue
Block a user