# Per-bottle sidecar bundle image (PRD 0024). # # Collapses the four prior per-sidecar images (pipelock, egress, # git-gate, supervise) into one. A small stdlib-Python init # supervisor at /app/sidecar_init.py spawns all four daemons, # forwards SIGTERM, and propagates per-daemon stdout/stderr to the # container log with a `[name]` prefix. See PRD 0024 for the # rationale. # # Layout (preserved verbatim from the prior four Dockerfiles so the # compose renderer's bind-mount paths and docker-cp targets keep # working): # # /usr/local/bin/pipelock pipelock binary # /usr/bin/gitleaks gitleaks binary # /app/egress_addon.py + siblings mitmproxy addon (egress) # /app/egress-entrypoint.sh mitmdump launcher # /app/supervise_server.py + .py supervise MCP server # /app/sidecar_init.py PID 1 supervisor # /etc/pipelock.yaml bind-mounted at run time # /etc/egress/routes.yaml bind-mounted at run time # /etc/git-gate/pre-receive docker-cp'd at start time # /git-gate-entrypoint.sh docker-cp'd at start time # /git-gate/creds/* docker-cp'd at start time # /git/* bare repos, populated at runtime # /run/supervise/queue/ bind-mounted at run time # /home/mitmproxy/.mitmproxy/ mitmproxy CA dir # # Exposed ports inside the container: # 8888 pipelock (HTTPS_PROXY) # 9099 egress (mitmproxy, pipelock's upstream — not externally # addressed by the agent) # 9418 git-gate (git-daemon) # 9100 supervise (MCP HTTP) # Stage 1: pipelock binary. The upstream pipelock image is a # scratch image with the binary at /pipelock (entrypoint). # Pinned by digest in lockstep with # claude_bottle/backend/docker/pipelock.py:PIPELOCK_IMAGE. FROM ghcr.io/luckypipewrench/pipelock@sha256:3b1a39417b98406ddc5dc2d8fcb42865ddc0c68a43d355db55f0f8cb06bc6de9 AS pipelock-src # Stage 2: gitleaks binary. The upstream gitleaks image is alpine # with the binary at /usr/bin/gitleaks. Pinned by digest in lockstep # with Dockerfile.git-gate's prior base (now deleted at chunk 3). FROM zricethezav/gitleaks@sha256:c00b6bd0aeb3071cbcb79009cb16a60dd9e0a7c60e2be9ab65d25e6bc8abbb7f AS gitleaks-src # Stage 3: assembly. mitmproxy/mitmproxy is debian-slim-based with # Python + mitmdump pre-installed — heavier than the others, so # this stage starts there and pulls the standalone binaries in. FROM mitmproxy/mitmproxy:11.1.3 # Run as root inside the bundle. The bundle is the isolation # boundary; per-daemon user separation inside it is not load-bearing # and complicates the supervisor's spawn path. USER root # Runtime system deps: # git supplies the `git daemon` subcommand (no separate package) # plus the core `git` binary the pre-receive hook invokes. # openssh-client supplies the upstream SSH transport the # pre-receive hook uses to forward accepted refs. # ca-certificates is needed for both pipelock and mitmdump # upstream TLS (the base image already has it; listed for # explicitness). RUN apt-get update \ && apt-get install -y --no-install-recommends \ git openssh-client ca-certificates \ && rm -rf /var/lib/apt/lists/* # Pull the standalone binaries into the final image. COPY --from=pipelock-src /pipelock /usr/local/bin/pipelock COPY --from=gitleaks-src /usr/bin/gitleaks /usr/bin/gitleaks # Project Python: addon + server modules + the init supervisor. # Kept flat under /app/ so mitmdump's loader resolves them as # top-level siblings (absolute imports), matching the prior # Dockerfile.egress / Dockerfile.supervise layout. COPY claude_bottle/egress_addon_core.py /app/egress_addon_core.py COPY claude_bottle/egress_addon.py /app/egress_addon.py COPY claude_bottle/yaml_subset.py /app/yaml_subset.py COPY claude_bottle/supervise.py /app/supervise.py COPY claude_bottle/supervise_server.py /app/supervise_server.py COPY claude_bottle/sidecar_init.py /app/sidecar_init.py COPY claude_bottle/egress_entrypoint.sh /app/egress-entrypoint.sh RUN chmod +x /app/egress-entrypoint.sh # Pre-create runtime directories the compose renderer + start # step expect to exist. `docker cp` does not create intermediate # dirs, and bind mounts won't either if the parent is missing. RUN mkdir -p \ /etc/egress \ /etc/git-gate \ /git-gate/creds \ /git \ /run/supervise/queue \ /home/mitmproxy/.mitmproxy # WORKDIR matches Dockerfile.supervise's prior layout so the # in-app same-dir import in supervise_server.py stays deterministic. WORKDIR /app # PID 1 is the supervisor. It owns signal handling and exit-code # propagation; no `exec` chain in the entrypoint itself. ENTRYPOINT ["python3", "/app/sidecar_init.py"]