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
+8
View File
@@ -23,9 +23,11 @@ from . import prepare as _prepare
from .bottle import DockerBottle
from .bottle_cleanup_plan import DockerBottleCleanupPlan
from .bottle_plan import DockerBottlePlan
from .cred_proxy import DockerCredProxy
from .git_gate import DockerGitGate
from .pipelock import DockerPipelockProxy
from .provision import ca as _ca
from .provision import cred_proxy as _cred_proxy
from .provision import git as _git
from .provision import prompt as _prompt
from .provision import skills as _skills
@@ -40,6 +42,7 @@ class DockerBottleBackend(BottleBackend["DockerBottlePlan", "DockerBottleCleanup
def __init__(self) -> None:
self._proxy = DockerPipelockProxy()
self._git_gate = DockerGitGate()
self._cred_proxy = DockerCredProxy()
def _resolve_plan(self, spec: BottleSpec, *, stage_dir: Path) -> DockerBottlePlan:
return _prepare.resolve_plan(
@@ -47,6 +50,7 @@ class DockerBottleBackend(BottleBackend["DockerBottlePlan", "DockerBottleCleanup
stage_dir=stage_dir,
proxy=self._proxy,
git_gate=self._git_gate,
cred_proxy=self._cred_proxy,
)
@contextmanager
@@ -55,6 +59,7 @@ class DockerBottleBackend(BottleBackend["DockerBottlePlan", "DockerBottleCleanup
plan,
proxy=self._proxy,
git_gate=self._git_gate,
cred_proxy=self._cred_proxy,
provision=self.provision,
) as bottle:
yield bottle
@@ -71,6 +76,9 @@ class DockerBottleBackend(BottleBackend["DockerBottlePlan", "DockerBottleCleanup
def provision_git(self, plan: DockerBottlePlan, target: str) -> None:
_git.provision_git(plan, target)
def provision_cred_proxy(self, plan: DockerBottlePlan, target: str) -> None:
_cred_proxy.provision_cred_proxy(plan, target)
def prepare_cleanup(self) -> DockerBottleCleanupPlan:
return _cleanup.prepare_cleanup()