fix(supervise): provision MCP via claude mcp add #25
@@ -18,6 +18,7 @@ from pathlib import Path
|
||||
from typing import cast
|
||||
|
||||
from .cred_proxy import CRED_PROXY_HOSTNAME
|
||||
from .supervise import SUPERVISE_HOSTNAME
|
||||
from .manifest import Bottle
|
||||
|
||||
# Baked-in default allowlist for hosts Claude Code itself needs.
|
||||
@@ -76,16 +77,18 @@ def pipelock_token_hosts(bottle: Bottle) -> list[str]:
|
||||
def pipelock_effective_allowlist(bottle: Bottle) -> list[str]:
|
||||
"""Deduplicated union of: baked-in defaults, bottle.egress.allowlist,
|
||||
the cred-proxy upstream hosts derived from bottle.cred_proxy.routes,
|
||||
and the cred-proxy sidecar's own hostname when any cred_proxy route
|
||||
is declared. Sorted for stability. Git upstreams declared in
|
||||
the cred-proxy sidecar's own hostname when any cred_proxy route is
|
||||
declared, and the supervise sidecar's hostname when bottle.supervise
|
||||
is enabled. Sorted for stability. Git upstreams declared in
|
||||
`bottle.git` do NOT contribute here — git traffic flows through the
|
||||
per-agent git-gate sidecar (PRD 0008), not pipelock.
|
||||
|
||||
The cred-proxy hostname is auto-added because the agent's
|
||||
HTTP_PROXY points at pipelock, so a manifest-driven URL like
|
||||
`http://cred-proxy:9099/anthropic/...` arrives at pipelock as a
|
||||
request for hostname `cred-proxy`. Without this auto-allow,
|
||||
pipelock would 403 the request before it reached the sidecar."""
|
||||
The cred-proxy + supervise hostnames are auto-added because the
|
||||
agent's HTTP_PROXY points at pipelock, so a manifest-driven URL
|
||||
like `http://cred-proxy:9099/anthropic/...` or
|
||||
`http://supervise:9100/` arrives at pipelock as a request for the
|
||||
sidecar hostname. Without this auto-allow, pipelock would 403 the
|
||||
request before it reached the sidecar."""
|
||||
seen: dict[str, None] = {}
|
||||
for h in DEFAULT_ALLOWLIST:
|
||||
seen.setdefault(h, None)
|
||||
@@ -96,6 +99,8 @@ def pipelock_effective_allowlist(bottle: Bottle) -> list[str]:
|
||||
seen.setdefault(h, None)
|
||||
if bottle.cred_proxy.routes:
|
||||
seen.setdefault(CRED_PROXY_HOSTNAME, None)
|
||||
if bottle.supervise:
|
||||
seen.setdefault(SUPERVISE_HOSTNAME, None)
|
||||
return sorted(seen.keys())
|
||||
|
||||
|
||||
|
||||
@@ -91,6 +91,21 @@ class TestAllowlistWithTokens(unittest.TestCase):
|
||||
eff = pipelock_effective_allowlist(_bottle({}))
|
||||
self.assertNotIn("cred-proxy", eff)
|
||||
|
||||
def test_supervise_hostname_auto_added_when_supervise_enabled(self):
|
||||
# Same reasoning as cred-proxy: the agent's HTTP_PROXY points
|
||||
# at pipelock, so http://supervise:9100/ (the MCP endpoint)
|
||||
# arrives at pipelock as hostname `supervise`. Without this
|
||||
# auto-allow, claude-code's MCP client gets a 403 and the
|
||||
# supervise server shows up as "failed" in /mcp.
|
||||
eff = pipelock_effective_allowlist(_bottle({"supervise": True}))
|
||||
self.assertIn("supervise", eff)
|
||||
|
||||
def test_supervise_hostname_NOT_added_when_disabled(self):
|
||||
eff = pipelock_effective_allowlist(_bottle({}))
|
||||
self.assertNotIn("supervise", eff)
|
||||
eff_explicit = pipelock_effective_allowlist(_bottle({"supervise": False}))
|
||||
self.assertNotIn("supervise", eff_explicit)
|
||||
|
||||
|
||||
class TestTlsPassthrough(unittest.TestCase):
|
||||
def test_default_includes_api_anthropic(self):
|
||||
|
||||
Reference in New Issue
Block a user