feat(devcontainer): autonomous-agent sandbox with egress lockdown + scoped tokens#107
Open
karlkfi wants to merge 3 commits into
Open
feat(devcontainer): autonomous-agent sandbox with egress lockdown + scoped tokens#107karlkfi wants to merge 3 commits into
karlkfi wants to merge 3 commits into
Conversation
… + scoped tokens
Add a containerized sandbox so Claude Code agents can run autonomously
(--dangerously-skip-permissions) without host risk or credential
exfiltration. The container is the boundary; three layers cover its gaps:
- .devcontainer/init-firewall.sh — default-drop egress, allowlisting only
the Anthropic API and GitHub's published CIDRs (from api.github.com/meta).
Go builds need no egress because the repo vendors its deps. Self-verifies
(GitHub reachable, example.com blocked) and exits non-zero otherwise.
- .devcontainer/claude-settings.json — deny rules (secret-file reads, sudo,
Keychain) baked into the container user's settings so repo settings can't
relax them. Closes the GitHub exfil channel the firewall can't (GitHub is
an allowed host).
- scripts/mint-installation-token.sh — host-side; reads the App PEM from the
macOS Keychain via process substitution (never on disk), mints a <=1h
repo-scoped installation token with minimal permissions. Verified
end-to-end.
- .devcontainer/{Dockerfile,devcontainer.json,README.md} — image, wiring,
and the security model + one-time agent-App setup steps.
The agent commits as a separate least-privilege identity, not the
actions-gateway-test runner App (which lacks contents/pull_requests and
carries administration:write).
Capture the autonomous-agent workflow initiative kicked off by the .devcontainer sandbox: goal, the four levers (approval prompts, parallelism, PR/CI/merge automation, orchestration glue), what's done vs in-flight vs open, and the decisions made (dedicated least-privilege agent App; minimal Anthropic+GitHub egress allowlist). Remaining work tracked as Q62/Q63.
bddf140 to
0d77cb2
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds a containerized sandbox so Claude Code agents can run autonomously (
--dangerously-skip-permissions) without host risk or credential exfiltration. New files only — no existing behavior changes..devcontainer/init-firewall.sh— default-drop container egress, allowlisting only the Anthropic API and GitHub's published CIDR ranges (fetched fromapi.github.com/meta). Self-verifies at the end (GitHub reachable,example.comblocked) and exits non-zero if the lockdown didn't take..devcontainer/claude-settings.json—denyrules (secret-file reads,sudo, Keychain) baked into the container user's~/.claude/settings.jsonso repo-level settings can't relax them.scripts/mint-installation-token.sh— host-side; reads the App PEM from the macOS Keychain via process substitution (never written to disk), mints a ≤1h, single-repo-scoped installation token with minimal permissions. Prints only the token to stdout..devcontainer/{Dockerfile,devcontainer.json,README.md}— the image (golang:1.26, matching the repo builder), wiring (NET_ADMIN, firewall aspostStartCommand), and the security model + one-time agent-App setup steps.Why
Enables running many parallel worktree agents with far fewer approval prompts. Full-bypass mode consults no permission rules, so the container must be the boundary — but the container still holds push credentials, so "the container is the sandbox" only protects the host. Three layers cover the gaps:
Reviewer notes
go build/go testrun offline, so egress is just Anthropic + GitHub — no fragile CDN/module-proxy allowlisting.actions-gateway-testApp returned HTTP 422: that App is the runner control plane (actions:write,administration:write,organization_self_hosted_runners:write,metadata:read) — it has nocontents/pull_requestsand is too powerful to hand an agent. The README documents creating a dedicated App with onlycontents:write+pull_requests:write; the mint script targets it via env overrides, no code change.denyglobs are defense-in-depth, not the primary control. They can't reliably gate agit pushby target branch and can't hide an env-var token fromprintenv. The real guards are the short-lived scoped token + server-side branch protection onmain(called out in the README).bash -n; the JWT RS256 signing path was verified against a generated keypair (signature Verified OK); the Keychain hex store/read round-trips byte-for-byte; the mint script minted a realghs_…token scoped to exactly this repo.Tracking
This PR also adds the initiative's plan doc and backlog entries so the work is pickable cold:
docs/plan/agent-workflow-automation.md— goal, the four levers, done/in-flight/open, decisions made.docs/STATUS.md— Progress row + Q62 (go-live: dedicated agent App + branch protection) and Q63 (auto-merge + CI auto-fix, blocked by Q62).