Files
bot-bottle/Dockerfile.cred-proxy
T
didericis 3436d8a68a feat(cred_proxy): add HTTP server + sidecar image (PRD 0010)
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.
2026-05-13 16:05:56 -04:00

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"]