3436d8a68a
Stdlib-only Python proxy: reads /run/cred-proxy/routes.json on boot, listens on 0.0.0.0:9099, strips inbound Authorization, injects the configured header (Bearer or token) using the route's token_env env var, forwards over HTTPS to the upstream, and streams the response back chunk-by-chunk (SSE-safe). Hop-by-hop headers are stripped per RFC 7230, including anything listed in `Connection:`. Content-Length is dropped so http.client recomputes it on the upstream leg. Tokens never reach routes.json — they arrive via the container's environ. Dockerfile.cred-proxy builds on python:3.13-alpine pinned by digest; mkdir /run/cred-proxy is baked in so docker cp can drop the route table at start time. No pip install layer. Smoke-tested: container boots, logs listen line, returns 404 for unmatched paths. Full request/response cycle covered by the integration tests in a follow-up commit.
36 lines
1.6 KiB
Docker
36 lines
1.6 KiB
Docker
# Per-bottle cred-proxy sidecar image (PRD 0010).
|
|
#
|
|
# Holds API tokens (Anthropic OAuth, GitHub PAT, Gitea PAT, npm) in
|
|
# this container's environ, strips inbound Authorization headers, and
|
|
# injects the configured one before forwarding to the real upstream
|
|
# over HTTPS. The agent's environ carries only URLs pointing at this
|
|
# sidecar — the upstream credentials never reach the agent container.
|
|
#
|
|
# Stdlib-only Python; no pip install layer. The route table lands at
|
|
# /run/cred-proxy/routes.json via `docker cp` from the backend's
|
|
# start step.
|
|
|
|
# python:3.13-alpine. Pinned by digest for reproducibility — the
|
|
# proxy script is stdlib-only so a Python minor-version drift would
|
|
# only affect the runtime, not API surface, but pinning makes the
|
|
# image bytes deterministic.
|
|
FROM python@sha256:420cd0bf0f3998275875e02ecd5808168cf0843cbb4d3c536432f729247b2acc
|
|
|
|
# The proxy script ships as a single file. Tests in tests/unit/ import
|
|
# it as `claude_bottle.cred_proxy_server`; the container runs it
|
|
# directly as a script. No package install, no other modules pulled.
|
|
COPY claude_bottle/cred_proxy_server.py /app/cred_proxy_server.py
|
|
|
|
# Pre-create the runtime directory the backend's start step will
|
|
# `docker cp` routes.json into. docker cp does not create
|
|
# intermediate dirs, so the mkdir must be baked into the image.
|
|
RUN mkdir -p /run/cred-proxy
|
|
|
|
# Listening port. The agent's environ resolves the cred-proxy host
|
|
# via Docker's embedded DNS on the per-bottle internal network and
|
|
# dials this port. Surfaced as EXPOSE for documentation; not required
|
|
# for the internal network to route to it.
|
|
EXPOSE 9099
|
|
|
|
ENTRYPOINT ["python3", "/app/cred_proxy_server.py"]
|