refactor(cred_proxy): flat routes, role-driven provisioning (PRD 0010)
Replace bottle.tokens (with Kind enum and hardcoded per-kind
route/auth tables) with bottle.cred_proxy.routes — each route
declares its own path, upstream, auth_scheme, token_ref, and
optional role[]. The manifest is now the source of truth for the
proxy's runtime route table; adding an upstream is a manifest edit,
not a code change.
Agent-side rewrites move from per-kind dispatch to per-role tags
on routes:
anthropic-base-url -> set ANTHROPIC_BASE_URL=<proxy><path>
npm-registry -> write ~/.npmrc registry=
git-insteadof -> write ~/.gitconfig [url] insteadOf, keyed
off route.upstream (suppressed when
bottle.git brokers the same host)
tea-login -> add a ~/.config/tea/config.yml login
Roles are a list (string accepted as sugar). A gitea route
typically carries ["git-insteadof", "tea-login"]. Singleton roles
(anthropic-base-url, npm-registry) appear on at most one route.
token_env slots are assigned per distinct TokenRef in declaration
order — two routes sharing a token_ref (e.g. github API + git
endpoints) share a slot.
Drops: TOKEN_KINDS, _KIND_ROUTES, _KIND_AUTH_SCHEME, _TOKEN_DEFAULT_HOST,
cred_proxy_route_path_for_gitea, the kind field on CredProxyUpstream,
and the kind-based hardcoding in pipelock_token_hosts (now derives
from route.UpstreamHost).
Legacy bottle.tokens manifests now die with a hint pointing at
bottle.cred_proxy.routes + this PRD. Tests rewritten end-to-end.
Docs + example.json + the dev ~/claude-bottle.json updated to match.
This commit is contained in:
@@ -57,27 +57,18 @@ def pipelock_bottle_allowlist(bottle: Bottle) -> list[str]:
|
||||
|
||||
def pipelock_token_hosts(bottle: Bottle) -> list[str]:
|
||||
"""Hostnames the cred-proxy sidecar (PRD 0010) talks to upstream
|
||||
on the agent's behalf. Derived from `bottle.tokens[]`. Returned
|
||||
on the agent's behalf. Derived from each route's
|
||||
`upstream.UpstreamHost` in `bottle.cred_proxy.routes`. Returned
|
||||
sorted+deduped.
|
||||
|
||||
These hosts must be on pipelock's allowlist so cred-proxy's
|
||||
outbound HTTPS traffic can leave the egress network, and on
|
||||
pipelock's TLS-passthrough list so pipelock does not MITM them —
|
||||
cred-proxy validates real upstream certs with the system CA store,
|
||||
so a pipelock-bumped cert would fail trust."""
|
||||
hosts: set[str] = set()
|
||||
for t in bottle.tokens:
|
||||
if t.Kind == "github":
|
||||
hosts.add("api.github.com")
|
||||
hosts.add("github.com")
|
||||
elif t.Kind == "gitea":
|
||||
if t.UpstreamHost:
|
||||
hosts.add(t.UpstreamHost)
|
||||
elif t.Kind == "npm":
|
||||
hosts.add("registry.npmjs.org")
|
||||
elif t.Kind == "anthropic":
|
||||
# Already on DEFAULT_ALLOWLIST + DEFAULT_TLS_PASSTHROUGH.
|
||||
hosts.add("api.anthropic.com")
|
||||
outbound HTTPS traffic can leave the egress network. They are
|
||||
NOT auto-added to passthrough_domains: cred-proxy's HTTPS client
|
||||
trusts pipelock's per-bottle CA at runtime (installed via
|
||||
docker cp + update-ca-certificates in the cred-proxy image),
|
||||
so pipelock MITMs and body-scans the cred-proxy → upstream leg
|
||||
the same way it does direct agent traffic."""
|
||||
hosts = {r.UpstreamHost for r in bottle.cred_proxy.routes if r.UpstreamHost}
|
||||
return sorted(hosts)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user