mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-09-29 01:41:42 +00:00
Extend the host bind-mount surface so coding agents inside the container inherit cloud + container-registry auth from the host without any per-container setup: - ~/.docker (read-write) — Docker registry auth (config.json) + buildx config. Container-registry pushes (ghcr.io, docker.io) from inside the container pick up host `docker login` state. Read-write because the Docker CLI refreshes credential-helper tokens. - ~/.aws (read-only) — AWS CLI / SDK credentials. Read-only because rotating creds typically happens via the host. Empty on this dev box, so forward-compatible: the moment you `aws configure` on the host the container picks it up on the next rebuild. - ~/.azure (read-only) — Azure CLI credentials. Same pattern as ~/.aws. `ensure-host-config-dirs.cjs` extends to mkdir these three on init so the bind mounts always have a valid source even if a CLI has never been used on this host. The Docker CLI itself isn't installed in the container by default — the ~/.docker/ mount is inert until you add `docker-outside-of-docker:1` or similar Feature. README now calls this out under "What you still don't have inside the container" so it's obvious which CLIs are agent-ready and which need a feature add to become useful. README updates: - Bind-mount table gains a "Why" column and rows for the three new mounts, making it clear at a glance what each one enables. - Trust-boundary section lists Docker registry tokens, AWS, and Azure creds in the read-side exfil path so the threat model stays honest as the credential surface grows. - New subsection lists not-included CLIs (Docker, AWS, Azure, gcloud, kubectl, private-npm) with the exact Feature ID or mount snippet needed to enable each — turns "I want my agent to do X" into a one-line config change. Verified locally: `npx @devcontainers/cli read-configuration` resolves all 9 host bind mounts to valid C:\Users\<name>/* paths on Windows.
147 lines
6.7 KiB
JSON
147 lines
6.7 KiB
JSON
// Devcontainer for GitNexus. Pre-installs Claude Code, OpenAI Codex CLI,
|
|
// and Cursor CLI alongside the Node.js native build chain. Cross-platform
|
|
// across macOS, Linux, and Windows-via-WSL2 (Windows-native is unsupported
|
|
// — see .devcontainer/README.md § Windows 11 setup). Opens via the VS Code
|
|
// Dev Containers extension.
|
|
//
|
|
// First-time setup, auth flows, and troubleshooting: .devcontainer/README.md.
|
|
{
|
|
"name": "GitNexus AI CLI Devcontainer",
|
|
|
|
"build": {
|
|
"dockerfile": "Dockerfile",
|
|
"context": ".",
|
|
"args": {
|
|
"CLAUDE_CODE_VERSION": "2.1.153",
|
|
"CODEX_VERSION": "0.134.0",
|
|
"CURSOR_VERSION": "latest",
|
|
"TZ": "${localEnv:TZ:UTC}"
|
|
}
|
|
},
|
|
|
|
// Runs on the HOST (not the container) before container create. The
|
|
// single-string form is the spec-canonical shape for cross-platform
|
|
// command-property dispatch; the object form is "named parallel tasks",
|
|
// not OS dispatch. We use Node so the same command works in cmd.exe on
|
|
// Windows and bash/zsh on Linux/macOS/WSL — the script reads `os.homedir()`
|
|
// (which respects $HOME on POSIX and %USERPROFILE% on Windows) and creates
|
|
// the host-side bind mount sources idempotently. Host prerequisite: Node
|
|
// on PATH (the only host-side toolchain dependency beyond Docker Desktop
|
|
// and the VS Code Dev Containers extension).
|
|
"initializeCommand": "node .devcontainer/ensure-host-config-dirs.cjs",
|
|
|
|
"features": {
|
|
"ghcr.io/devcontainers/features/github-cli:1": {}
|
|
},
|
|
|
|
"remoteUser": "node",
|
|
"updateRemoteUserUID": true,
|
|
|
|
"workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind,consistency=delegated",
|
|
"workspaceFolder": "/workspace",
|
|
|
|
// Mount topology, by group:
|
|
//
|
|
// 1. CLI config dirs — bind-mounted from the host so the developer's
|
|
// existing plugins, skills, agents, memory, settings, and credentials
|
|
// for Claude Code / Codex / Cursor + git identity + gh auth are
|
|
// immediately available inside the container, and changes inside the
|
|
// container flow back to the host. ~/.gitconfig is read-only so
|
|
// container-side `git config --global` doesn't leak to host config.
|
|
// For high-trust environments where host and container should NOT
|
|
// share credentials, swap these three CLI bind mounts for
|
|
// per-devcontainer named volumes (Anthropic's reference pattern).
|
|
//
|
|
// 2. Per-instance state — `${devcontainerId}` scoped: history and npm
|
|
// cache survive container rebuilds but stay isolated between
|
|
// sibling devcontainer instances.
|
|
//
|
|
// 3. Per-workspace-name AND per-instance state — workspace `node_modules`
|
|
// volumes use both `${localWorkspaceFolderBasename}` (debuggable in
|
|
// `docker volume ls`) and `${devcontainerId}` (collision-free between
|
|
// sibling instances of the same repo, e.g., ~/work/GitNexus vs
|
|
// ~/projects/GitNexus). Keeps tree-sitter native binaries and
|
|
// onnxruntime off the workspace bind mount (the real Win/Mac perf win).
|
|
"mounts": [
|
|
"source=${localEnv:HOME}/.claude,target=/home/node/.claude,type=bind",
|
|
"source=${localEnv:HOME}/.codex,target=/home/node/.codex,type=bind",
|
|
"source=${localEnv:HOME}/.cursor,target=/home/node/.cursor,type=bind",
|
|
"source=${localEnv:HOME}/.config/git,target=/home/node/.config/git,type=bind,readonly",
|
|
"source=${localEnv:HOME}/.ssh,target=/home/node/.ssh,type=bind,readonly",
|
|
"source=${localEnv:HOME}/.config/gh,target=/home/node/.config/gh,type=bind",
|
|
"source=${localEnv:HOME}/.docker,target=/home/node/.docker,type=bind",
|
|
"source=${localEnv:HOME}/.aws,target=/home/node/.aws,type=bind,readonly",
|
|
"source=${localEnv:HOME}/.azure,target=/home/node/.azure,type=bind,readonly",
|
|
"source=commandhistory-${devcontainerId},target=/commandhistory,type=volume",
|
|
"source=npm-cache-${devcontainerId},target=/home/node/.npm,type=volume",
|
|
"source=${localWorkspaceFolderBasename}-root-node-modules-${devcontainerId},target=/workspace/node_modules,type=volume",
|
|
"source=${localWorkspaceFolderBasename}-gitnexus-node-modules-${devcontainerId},target=/workspace/gitnexus/node_modules,type=volume",
|
|
"source=${localWorkspaceFolderBasename}-gitnexus-web-node-modules-${devcontainerId},target=/workspace/gitnexus-web/node_modules,type=volume",
|
|
"source=${localWorkspaceFolderBasename}-gitnexus-shared-node-modules-${devcontainerId},target=/workspace/gitnexus-shared/node_modules,type=volume"
|
|
],
|
|
|
|
// Interactive login is the default auth path for all three CLIs;
|
|
// credentials persist in the host-bind-mounted directories (~/.claude,
|
|
// ~/.codex, ~/.cursor) declared in the mounts block above.
|
|
// API keys (ANTHROPIC_API_KEY / OPENAI_API_KEY / CURSOR_API_KEY) are NOT
|
|
// injected via containerEnv — `${localEnv:VAR}` resolves an unset host var
|
|
// to an empty string, and Cursor in particular treats `CURSOR_API_KEY=""`
|
|
// as "use this empty key" rather than "fall back to stored login", which
|
|
// would silently break `cursor-agent login`. Users who need API key auth
|
|
// should `export` the var in their container shell or carry it via their
|
|
// VS Code dotfiles repo (see .devcontainer/README.md).
|
|
"containerEnv": {
|
|
"CLAUDE_CONFIG_DIR": "/home/node/.claude",
|
|
"DISABLE_AUTOUPDATER": "1",
|
|
"HISTFILE": "/commandhistory/.zsh_history"
|
|
},
|
|
|
|
"customizations": {
|
|
"vscode": {
|
|
"extensions": [
|
|
"anthropic.claude-code",
|
|
"dbaeumer.vscode-eslint",
|
|
"esbenp.prettier-vscode",
|
|
"eamodio.gitlens"
|
|
],
|
|
"settings": {
|
|
"editor.formatOnSave": true,
|
|
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
|
"editor.codeActionsOnSave": {
|
|
"source.fixAll.eslint": "explicit"
|
|
},
|
|
"files.eol": "\n",
|
|
"terminal.integrated.defaultProfile.linux": "zsh",
|
|
"terminal.integrated.profiles.linux": {
|
|
"bash": { "path": "bash", "icon": "terminal-bash" },
|
|
"zsh": { "path": "zsh" }
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
// 4747 (gitnexus serve) must not be remapped: gitnexus-web hardcodes
|
|
// http://localhost:4747 as the default backend URL.
|
|
"forwardPorts": [5173, 4747, 4173],
|
|
"portsAttributes": {
|
|
"5173": {
|
|
"label": "Vite dev (gitnexus-web)",
|
|
"onAutoForward": "notify"
|
|
},
|
|
"4747": {
|
|
"label": "gitnexus serve HTTP API",
|
|
"onAutoForward": "notify",
|
|
"requireLocalPort": true
|
|
},
|
|
"4173": {
|
|
"label": "Static web (Vite preview)",
|
|
"onAutoForward": "silent"
|
|
}
|
|
},
|
|
|
|
// Driver script with labeled steps lives at .devcontainer/post-create.sh
|
|
// so each step's success/failure is visible in the log without parsing
|
|
// an &&-chain. Run via `bash` explicitly so the script doesn't depend
|
|
// on its executable bit surviving the workspace bind mount.
|
|
"postCreateCommand": "bash .devcontainer/post-create.sh"
|
|
}
|