docs: redraw README architecture to show pipelock as HTTP/S chokepoint
test / unit (pull_request) Successful in 15s
test / integration (pull_request) Successful in 22s

The previous diagram showed three parallel egress lanes — agent ↔
pipelock, agent ↔ git-gate, agent ↔ cred-proxy — each going off-box
independently. That was true of an earlier shape but is now wrong on
two counts:

1. cred-proxy's outbound HTTPS routes through pipelock (set when
   the SSRF / CA-trust wiring landed). All cred-proxy upstream
   bytes pass pipelock's allowlist + body scanner.
2. git-gate's SSH push/fetch is direct out the egress network and
   has never gone through pipelock — pipelock is HTTP-only.

Reflect both: the diagram now collapses to one HTTP/HTTPS chokepoint
(pipelock) that the agent and cred-proxy share, plus a separate SSH
lane for git-gate. Prose paragraph above the diagram updated to call
out the "everything except SSH" framing explicitly.

Verified against the current code: HTTPS_PROXY=pipelock set on the
agent in launch.py and on cred-proxy in DockerCredProxy.start;
git-gate's create-args carry no proxy env vars.
This commit is contained in:
2026-05-24 14:23:26 -04:00
parent 77a51702fc
commit 6b91506706
+41 -31
View File
@@ -71,43 +71,53 @@ pieces of v1.
A bottle is the agent container plus up to three per-protocol egress A bottle is the agent container plus up to three per-protocol egress
sidecars on a per-agent Docker `--internal` network. The agent has no sidecars on a per-agent Docker `--internal` network. The agent has no
default route off-box; its only way out is through the pipelock default route off-box. All HTTP and HTTPS egress — from the agent
sidecar (for HTTP/HTTPS), the git-gate sidecar (for git operations *and* from cred-proxy when it dials an upstream — funnels through
against declared upstreams), or the cred-proxy sidecar (for API pipelock, where the egress allowlist, TLS interception, and
calls that need a manifest-declared token — Anthropic OAuth, GitHub request-body DLP scanner enforce the manifest before any byte leaves
PAT, Gitea PAT, npm). Each sidecar also sits on an egress network the host. The only egress that doesn't traverse pipelock is git-gate's
that does have internet access, so the agent's traffic always passes SSH push/fetch to `bottle.git` upstreams — pipelock can't proxy SSH,
through a container that enforces the manifest before it leaves the so git-gate is its own L4-style egress path with gitleaks doing the
host. pre-receive scan.
``` ```
host ( ./cli.py ) host ( ./cli.py )
starts │ stops starts │ stops
┌─────────────────────────── bottle ──────────────────────────┐ ┌─────────────────────────── bottle ──────────────────────────────────
│ │
│ ┌──────────────────┐ │ │ ┌──────────────────┐
│ │ agent image │ HTTPS_PROXY ┌────────────────┐ HTTPS to │ │ agent image │ HTTPS_PROXY
│ │ (claude-code, │ ───────────────► │ pipelock image │──── allowlisted │ │ (claude-code, │ ────────────────────────
│ │ built locally) │ │ (TLS bump, DLP,│ │ hosts │ │ built locally) │ │ │
│ │ │ allowlist) │ │ │ │ plain HTTP
│ │ skills, env, │ ────────────────┘ │ │ skills, env, │ (token injection) ┌─────────────
│ │ ~/.gitconfig, │ │ │ ~/.gitconfig, │ ──────────────────►│ cred-proxy
│ │ ~/.npmrc, tea │ git ops ┌────────────────┐ SSH (push/ │ │ ~/.npmrc, tea │ │ (strips/inj │ │
│ │ │ ───────────────► │ git-gate image │──┼──► fetch) to │ │ │ │ Authoriz.) │ │
│ │ │ │ (gitleaks + │ │ bottle.git │ │ environ: URLs │ └─────┬────────┘ │
│ │ environ: URLs │ git daemon) upstreams │ │ only, no real │ HTTPS_PROXY
│ │ only, no real└────────────────┘ │ │ tokens
│ │ tokensbearer-auth ┌────────────────┐ │ HTTPS to │ │ ┌────────────────┐ │ HTTPS to
│ │ │ ───────────────► │ cred-proxy │──┼──► bottle.tokens │ │ │ │ pipelock image │──────────┼──► allowlisted
│ │ │ HTTP, plain │ (strips/injects│ │ upstreams │ │ │ │ (TLS bump, DLP │ │ hosts (incl.
│ │ │ │ Authorization)│ │ (with the │ │ │ │ body scan, │ │ cred-proxy
└──────────────────┘ └────────────────┘ │ real token) │ │ │ allowlist) │ │ upstreams)
└────────────────┘
agent on internal network (no default route); │ │
sidecars also attached to an egress network. │ │ │ git:// ┌────────────────┐ │ SSH push/fetch
└───────────────────────────────────────────────────────────── │ │ │ ────────────────►│ git-gate image │────────────► to bottle.git
│ │ │ │ (gitleaks + │ │ upstreams
│ └──────────────────┘ │ git daemon) │ │ (direct — not
│ └────────────────┘ │ via pipelock)
│ │
│ agent on internal network (no default route); pipelock, │
│ cred-proxy, and git-gate straddle internal + egress networks. │
│ pipelock is the single HTTP/HTTPS chokepoint — cred-proxy's │
│ outbound traverses it too. git-gate's SSH egress is direct │
│ because pipelock is HTTP-only. │
└─────────────────────────────────────────────────────────────────────┘
``` ```
- **agent image** — built from the repo `Dockerfile` (`node:22-slim` - **agent image** — built from the repo `Dockerfile` (`node:22-slim`