Conversation
322113e to
6562aec
Compare
6562aec to
3789468
Compare
3789468 to
d4439d8
Compare
|
Holding this until the requirements behind issue #75 are clear; discussing with Ben first. |
|
@stefanwb thanks for the questions. Answers:
The image isn't in scope either. Hash-pinned packages are identical whichever mirror served them. The requirement is about what the running container sends to a model. That makes the deny-all allowlist too strict. It would cost every user the configuration effort you warned about in #75, and a tool the team doesn't adopt proves nothing to the customer. So I've re-scoped #101:
For a colleague it's one env file and one command: Pushed in e162ec7. Does this fit how you see the project? 🤖 Generated with Claude Code |
|
Thanks Ben, that answers it, and the narrower scope fits much better: no allowlist to maintain, and the proxy log is the evidence. Three things before I'd take it in:
Since it's been reshaped a few times, it might help to agree on these three before more code. What do you think? |
Rebased onto #104 (feat/api-endpoint-v2) without the --az base. This is the net result of the earlier d99475a, d4439d8 and e162ec7: the deny-all allowlist from the first commit was dropped by the third, so replaying them one by one would only have resolved conflicts in deleted code. The --az-only hunks (REQUESTS_CA_BUNDLE handling and docs) are gone, because #104 has no --az. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review of #101: most gateway users don't need the sidecar, the internal network and an unrotated log of every connection, so the lock gets its own opt-in that requires --api. Plain --api is back to #104's behaviour. --report and egress_report.py go: the saved .log/.meta files are the evidence, and a PDF for one audit (plus a host python3 dependency) belongs with the team that needs it. OpenSpec: egress-lock-opt-in, archived. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
e162ec7 to
e638ed0
Compare
|
Thanks @stefanwb. I agree with all three, and they're in e638ed0 (with 4b31ca5 as the rebased base):
The three earlier commits are squashed into 4b31ca5, because the first design (deny-all allowlist) was deleted by the third. The OpenSpec change is 🤖 Generated with Claude Code |
Closes #75
What
--egress-lock(with--api) locks Claude Code's model traffic to theANTHROPIC_BASE_URLgateway and logs every connection the session makes. Everything else (git, npm, PyPI, the web) stays reachable, and there is no allowlist to maintain. Plain--apisessions and sessions without--apiare unchanged: no sidecar, no network change, no log.--egress-lockwithout--apirefuses to start.This matches the requirement as clarified in review: only model traffic has to stay in the EU, only Claude Code is in scope, and the proof is network-control logs.
op run --env-file team-eu.env --no-masking -- claude-docker --api --egress-lock ~/repo--internalnetwork. The only way out is a per-session squid sidecar (squid from the agent image, run asproxywith--cap-drop ALL;CapBndstays0xc5).CONNECT, with no TLS interception.ANTHROPIC_BASE_URLhost is allowed;*.anthropic.com,*.claude.aiand*.claude.comare refused;run.shaborts before any container resource exists whenANTHROPIC_BASE_URLis unset, points at a provider host, or isn't a valid hostname/IPv4. The host goes into the squid config, so this is also the injection check..metafile (start/end, user, host, workspaces, image and image ID, endpoint) to$XDG_STATE_HOME/claude-docker/egress/, which is never mounted into a container.run.shdoesn't rotate or delete them. Building a report from them is left to the team that needs one.--ghcomposition: squid resolves the three GitHub hosts to the gh sidecar on the internal network.Changes after the 2026-09-27 review
--apito--egress-lock, which requires--api.--report.egress_report.pyand the--reportflag are gone, and with them the hostpython3dependency.--azbase and every--az-only hunk are gone.The three earlier commits (deny-all allowlist, its archive, the model-only rework) are squashed into one. The first design was deleted by the third, so replaying them only meant resolving conflicts in dead code.
OpenSpec:
2026-09-30-egress-lock-opt-in(on top of2026-09-26-api-egress-policyand2026-09-27-api-egress-model-lock). Theapi-egress-policyPurpose line still mentions--api/--report, because archiving doesn't touch Purpose and specs aren't hand-edited.Stack
Based on #104 (
feat/api-endpoint-v2), next to #105. It is no longer in a GitHub stack; #104 ← #105 is now stack #118.Tests
tests/test_egress_policy.py(stdlib, no docker):--egress-lockwithout--api,--apialone skips the lock, no endpoint, provider endpoints, newline/space injection, valid gateways. The full unit suite passes (122).smoke/egress.sh(CI) drivesrun.sh --api --egress-lock. It checks the endpoint aborts, reachable/refused hosts, no proxy-unaware route or external DNS, metadata/loopback/port denies, the saved log + meta, and teardown. There's also a--ghcell.openspec validate --strictpasses. There's no docker, shellcheck or hadolint here, so CI verifies the build, lint and smoke.🤖 Generated with Claude Code