feat(cred_proxy): wire DockerCredProxy through backend (PRD 0010)

- DockerBottleBackend instantiates DockerCredProxy alongside pipelock
  and git-gate; threads it through prepare and launch.
- DockerBottlePlan gains cred_proxy_plan; preflight rendering shows
  the declared kinds + TokenRefs and to_dict emits a cred_proxy
  array matching the routing table.
- prepare.py: when bottle.tokens has an anthropic entry, route the
  agent at the proxy via ANTHROPIC_BASE_URL, drop the agent-side
  CLAUDE_CODE_OAUTH_TOKEN forward (the token goes to the sidecar's
  environ instead, set a non-secret placeholder so claude-code's
  startup check passes), and default the telemetry-off env vars.
- launch.py: bring up the cred-proxy sidecar in ExitStack before the
  agent container so DNS resolution for `cred-proxy` succeeds on the
  agent's first call.
- backend/__init__.py: add provision_cred_proxy to the provision
  template (runs after provision_git so it can append to ~/.gitconfig).
- bottle_plan _view: env_names is derived from the forwarded_env dict,
  so the preflight reflects the PRD 0010 switch without ad-hoc
  branching on spec.forward_oauth_token.
This commit is contained in:
2026-05-13 16:20:42 -04:00
parent b3529b27a5
commit 8334f51268
5 changed files with 98 additions and 12 deletions
+13 -5
View File
@@ -214,15 +214,17 @@ class BottleBackend(ABC, Generic[PlanT, CleanupT]):
decide whether to add --append-system-prompt-file to claude's
argv.
Default orchestration: ca → prompt → skills → git. CA install
runs first so the agent's trust store is rebuilt before
anything inside the agent makes a TLS call. Subclasses
typically don't override this; they implement the sub-methods
below."""
Default orchestration: ca → prompt → skills → git
cred_proxy. CA install runs first so the agent's trust store
is rebuilt before anything inside the agent makes a TLS call.
cred_proxy runs last because it appends to ~/.gitconfig (which
provision_git writes). Subclasses typically don't override
this; they implement the sub-methods below."""
self.provision_ca(plan, target)
prompt_path = self.provision_prompt(plan, target)
self.provision_skills(plan, target)
self.provision_git(plan, target)
self.provision_cred_proxy(plan, target)
return prompt_path
def provision_ca(self, plan: PlanT, target: str) -> None:
@@ -251,6 +253,12 @@ class BottleBackend(ABC, Generic[PlanT, CleanupT]):
"""Copy the host's cwd `.git` directory into the running
bottle if the user requested --cwd. No-op otherwise."""
def provision_cred_proxy(self, plan: PlanT, target: str) -> None:
"""Drop the cred-proxy agent-side dotfiles (.npmrc,
.gitconfig insteadOf, ~/.config/tea/config.yml) per PRD 0010.
Default impl is a no-op for backends that don't yet support
the cred-proxy sidecar; the Docker backend overrides."""
@abstractmethod
def prepare_cleanup(self) -> CleanupT:
"""Enumerate orphaned resources from previous bottles. No side