Files
trailofbits-claude-code-dev…/devcontainer.json
T
Akshith G 5a2b92a790 feat: add non-interactive auth via CLAUDE_CODE_OAUTH_TOKEN (#32)
* feat: add non-interactive auth via CLAUDE_CODE_OAUTH_TOKEN

Bypass the interactive onboarding wizard when CLAUDE_CODE_OAUTH_TOKEN is
set. On container create, post_install.py runs `claude -p` to populate
auth state and sets hasCompletedOnboarding so the TUI starts without the
login wizard.

Workaround for https://github.com/anthropics/claude-code/issues/8938.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: use remoteEnv instead of containerEnv for secrets

containerEnv bakes values into the image as ENV instructions, visible
in docker inspect/history. remoteEnv is set at runtime only.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: improve error handling in onboarding bypass

- Handle timeout as expected (claude -p writes config before API call)
- Catch FileNotFoundError/OSError if claude is not installed
- Check returncode explicitly instead of dead CalledProcessError catch
- Guard on ~/.claude.json existence before writing onboarding flag
- Replace contextlib.suppress with explicit try/except that logs
- Update module docstring and README wording

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 06:36:47 -07:00

75 lines
2.6 KiB
JSON

{
"$schema": "https://raw.githubusercontent.com/devcontainers/spec/main/schemas/devContainer.schema.json",
"name": "Claude Code Sandbox",
"build": {
"dockerfile": "Dockerfile",
"args": {
"TZ": "${localEnv:TZ:UTC}",
"GIT_DELTA_VERSION": "0.18.2",
"ZSH_IN_DOCKER_VERSION": "1.2.1"
}
},
"features": {
"ghcr.io/devcontainers/features/github-cli:1": {}
},
"runArgs": [
"--cap-add=NET_ADMIN",
"--cap-add=NET_RAW"
],
"init": true,
"updateRemoteUserUID": true,
"customizations": {
"vscode": {
"extensions": [
"anthropic.claude-code"
],
"settings": {
"terminal.integrated.defaultProfile.linux": "zsh",
"terminal.integrated.profiles.linux": {
"bash": {
"path": "bash",
"icon": "terminal-bash"
},
"zsh": {
"path": "zsh"
}
},
"files.trimTrailingWhitespace": true,
"files.insertFinalNewline": true,
"files.trimFinalNewlines": true
}
}
},
"remoteUser": "vscode",
"mounts": [
"source=devc-${localWorkspaceFolderBasename}-bashhistory-${devcontainerId},target=/commandhistory,type=volume",
"source=devc-${localWorkspaceFolderBasename}-config-${devcontainerId},target=/home/vscode/.claude,type=volume",
"source=devc-${localWorkspaceFolderBasename}-gh-${devcontainerId},target=/home/vscode/.config/gh,type=volume",
"source=${localEnv:HOME}/.gitconfig,target=/home/vscode/.gitconfig,type=bind,readonly",
"source=${localWorkspaceFolder}/.devcontainer,target=/workspace/.devcontainer,type=bind,readonly"
],
"containerEnv": {
"NODE_OPTIONS": "--max-old-space-size=4096",
"CLAUDE_CONFIG_DIR": "/home/vscode/.claude",
"POWERLEVEL9K_DISABLE_GITSTATUS": "true",
"GIT_CONFIG_GLOBAL": "/home/vscode/.gitconfig.local",
"UV_LINK_MODE": "copy",
"NPM_CONFIG_IGNORE_SCRIPTS": "true",
"NPM_CONFIG_AUDIT": "true",
"NPM_CONFIG_FUND": "false",
"NPM_CONFIG_SAVE_EXACT": "true",
"NPM_CONFIG_UPDATE_NOTIFIER": "false",
"NPM_CONFIG_MINIMUM_RELEASE_AGE": "1440",
"PYTHONDONTWRITEBYTECODE": "1",
"PIP_DISABLE_PIP_VERSION_CHECK": "1"
},
"remoteEnv": {
"CLAUDE_CODE_OAUTH_TOKEN": "${localEnv:CLAUDE_CODE_OAUTH_TOKEN:}",
"ANTHROPIC_API_KEY": "${localEnv:ANTHROPIC_API_KEY:}"
},
"initializeCommand": "test -f \"$HOME/.gitconfig\" || touch \"$HOME/.gitconfig\"",
"workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind,consistency=delegated",
"workspaceFolder": "/workspace",
"postCreateCommand": "uv run --no-project /opt/post_install.py"
}