-
Notifications
You must be signed in to change notification settings - Fork 9
Add claude sandbox #337
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add claude sandbox #337
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -113,6 +113,30 @@ docker_debug: | |
| be useful if debugging the service inside of the cluster | ||
| infrastructure is required. | ||
|
|
||
| add_claude: | ||
| type: bool | ||
| help: | | ||
| Add a Claude Code sandbox to the devcontainer? | ||
| Disables host SSH agent / VS Code git credential injection inside | ||
| the container, mounts ~/.claude from the host, installs Claude Code | ||
| CLI, and enables `--dangerously-skip-permissions` autopilot mode. | ||
|
|
||
| install_gh: | ||
| type: bool | ||
| when: "{{ add_claude }}" | ||
| help: | | ||
| Install the GitHub CLI (gh) so Claude can push/pull via PAT auth? | ||
| Only useful inside the Claude sandbox — ordinary users typically | ||
| rely on SSH keys or VS Code git credentials. | ||
|
|
||
| install_glab: | ||
| type: bool | ||
| when: "{{ add_claude }}" | ||
| help: | | ||
| Install the GitLab CLI (glab) for projects that talk to a GitLab | ||
| instance (e.g. gitlab.diamond.ac.uk submodules)? | ||
| Only useful inside the Claude sandbox. | ||
|
Comment on lines
+124
to
+138
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again, I reckon we should probably just include these in the ubuntu devcontainer unconditionally
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That was my first instinct and then I thought people would push back on it especially since glab would be a less common requirement. But if you like always including then I do to. |
||
|
|
||
| docs_type: | ||
| type: str | ||
| help: | | ||
|
|
||
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,115 @@ | ||
| // For format details, see https://containers.dev/implementors/json_reference/ | ||
| { | ||
| "name": "Python 3 Developer Container", | ||
| "build": { | ||
| "dockerfile": "../Dockerfile", | ||
| "target": "developer" | ||
| },{% if add_claude %} | ||
| // Tell VS Code the remote user is root so copyGitConfig writes to | ||
| // /root/.gitconfig (matching $HOME in the shell); otherwise it falls back | ||
| // to the base image's USER and the copy lands in the wrong home. | ||
| "remoteUser": "root",{% endif %} | ||
| "remoteEnv": { | ||
| // Allow X11 apps to run inside the container | ||
| "DISPLAY": "${localEnv:DISPLAY}",{% if add_claude %} | ||
| // Disable SSH agent forwarding — prevents Claude from using host SSH keys | ||
| "SSH_AUTH_SOCK": "", | ||
| // Disable VS Code git credential injection — prevents askpass from | ||
| // relaying host GitHub credentials into the container over the IPC socket | ||
| "GIT_ASKPASS": "", | ||
| "VSCODE_GIT_IPC_HANDLE": "", | ||
| "VSCODE_GIT_ASKPASS_MAIN": "", | ||
| "VSCODE_GIT_ASKPASS_NODE": "", | ||
| "VSCODE_GIT_ASKPASS_EXTRA_ARGS": "",{% endif %} | ||
| // Mark this shell as running inside the devcontainer | ||
| "IN_DEVCONTAINER": "1", | ||
| // Put things that allow it in the persistent cache | ||
| "PRE_COMMIT_HOME": "/cache/pre-commit", | ||
| "UV_CACHE_DIR": "/cache/uv", | ||
| "UV_PYTHON_CACHE_DIR": "/cache/uv-python", | ||
| // Make a venv that is specific for this workspace path as the cache is shared | ||
| "UV_PROJECT_ENVIRONMENT": "/cache/venv-for${localWorkspaceFolder}", | ||
| // Do the equivalent of "activate" the venv so we don't have to "uv run" everything | ||
| "VIRTUAL_ENV": "/cache/venv-for${localWorkspaceFolder}", | ||
| "PATH": "/cache/venv-for${localWorkspaceFolder}/bin:${containerEnv:PATH}" | ||
| }, | ||
| "customizations": { | ||
| "vscode": { | ||
| // Set *default* container specific settings.json values on container create. | ||
| "settings": { | ||
| // Use the container's python by default | ||
| "python.defaultInterpreterPath": "/cache/venv-for${localWorkspaceFolder}/bin/python", | ||
| // Don't activate the venv as it is already in the PATH | ||
| "python.terminal.activateEnvInCurrentTerminal": false, | ||
| "python.terminal.activateEnvironment": false, | ||
| // Workaround to prevent garbled python REPL in the terminal | ||
| // https://github.com/microsoft/vscode-python/issues/25505 | ||
| "python.terminal.shellIntegration.enabled": false{% if sphinx %}, | ||
| // Only forward explicitly listed ports — auto-detection races with | ||
| // sphinx-autobuild and steals the port on restart | ||
| "remote.autoForwardPorts": false{% endif %} | ||
| }, | ||
| // Add the IDs of extensions you want installed when the container is created. | ||
| "extensions": [ | ||
| "ms-python.python", | ||
| "github.vscode-github-actions", | ||
| "tamasfe.even-better-toml", | ||
| "redhat.vscode-yaml", | ||
| "ryanluker.vscode-coverage-gutters", | ||
| "charliermarsh.ruff", | ||
| "ms-azuretools.vscode-docker"{% if add_claude %}, | ||
| "anthropic.claude-code"{% endif %} | ||
| ] | ||
| } | ||
| },{% if sphinx %} | ||
| // Explicitly forward sphinx-autobuild port (auto-detection disabled above) | ||
| "forwardPorts": [ | ||
| 8000 | ||
| ],{% endif %} | ||
| // Create host-side dirs needed for bind mounts before the container starts | ||
| "initializeCommand": "mkdir -p ${localEnv:HOME}/.config/terminal-config{% if add_claude %} ${localEnv:HOME}/.claude{% endif %}", | ||
| "runArgs": [ | ||
| // Allow the container to access the host X11 display and EPICS CA | ||
| "--net=host", | ||
| // Make sure SELinux does not disable with access to host filesystems like tmp | ||
| "--security-opt=label=disable" | ||
| ], | ||
| "mounts": [ | ||
| // Mount in the user terminal config folder so it can be edited | ||
| { | ||
| "source": "${localEnv:HOME}/.config/terminal-config", | ||
| "target": "/user-terminal-config", | ||
| "type": "bind" | ||
| }, | ||
| // Keep a persistent cross container cache for uv, pre-commit, and the venvs | ||
| { | ||
| "source": "devcontainer-shared-cache", | ||
| "target": "/cache", | ||
| "type": "volume" | ||
| }{% if install_gh %}, | ||
| // Persist gh auth across container rebuilds with per-repo scoped PAT | ||
| { | ||
| "source": "gh-auth-${localWorkspaceFolderBasename}", | ||
| "target": "/root/.config/gh", | ||
| "type": "volume" | ||
| }{% endif %}{% if install_glab %}, | ||
| // Persist glab auth across container rebuilds (GitLab CLI) | ||
| { | ||
| "source": "glab-auth-${localWorkspaceFolderBasename}", | ||
| "target": "/root/.config/glab-cli", | ||
| "type": "volume" | ||
| }{% endif %}{% if add_claude %}, | ||
| // Mount Claude config from host (settings, memory, skills) | ||
| { | ||
| "source": "${localEnv:HOME}/.claude", | ||
| "target": "/root/.claude", | ||
| "type": "bind" | ||
| }{% endif %} | ||
| ], | ||
| // Mount the parent as /workspaces so we can pip install peers as editable | ||
| "workspaceMount": "source=${localWorkspaceFolder}/..,target=/workspaces,type=bind",{% if add_claude %} | ||
| "postCreateCommand": ".devcontainer/postCreate.sh", | ||
| "postStartCommand": ".devcontainer/postStart.sh"{% else %} | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we always put a postCreate in and jinja template just the claude bits?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think yes - its tidier than long bash entries embedded in the devcontainer.json |
||
| // After the container is created, recreate the venv then make pre-commit first run faster | ||
| "postCreateCommand": "uv venv --clear && uv sync && pre-commit install --install-hooks"{% endif %} | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| #!/bin/bash | ||
| set -euo pipefail | ||
|
|
||
| # Install Claude Code CLI | ||
| curl -fsSL https://claude.ai/install.sh | bash | ||
|
|
||
| # Install Python dependencies and pre-commit hooks | ||
| uv venv --clear | ||
| uv sync | ||
| pre-commit install --install-hooks | ||
|
|
||
| # Initialise git submodules if any are declared | ||
| [ -f .gitmodules ] && git submodule update --init || true | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this line is useful in the non-claude case too.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah - I thought I had dropped that. It is useful for first opening a devcontainer that needs submodules to build, but ...... if you rebuild your container while you are in progress with submodule changes they disapear. I think that cost outweighs the benefit. So I vote to take this back out. |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| #!/bin/bash | ||
| set -euo pipefail | ||
|
|
||
| # Wipe any credential helpers and SSH URL rewrites injected by VS Code's | ||
| # Dev Containers extension when it copies the host gitconfig. An empty-string | ||
| # value resets the helper list so only an explicit PAT via `just gh-auth` | ||
| # can authenticate to remotes. | ||
| git config --global credential.helper '' | ||
| git config --global --unset-all url.ssh://git@github.com/.insteadOf 2>/dev/null || true | ||
|
|
||
| # Force all SSH-style remotes to use HTTPS so the gh/glab credential helpers | ||
| # handle auth. This keeps the container SSH-key-free (Claude stays sandboxed) | ||
| # while still allowing push/pull on repos whose remotes are set to git@...:. | ||
| git config --global url."https://github.com/".insteadOf "git@github.com:" | ||
| {%- if install_glab %} | ||
| git config --global url."https://gitlab.diamond.ac.uk/".insteadOf "git@gitlab.diamond.ac.uk:" | ||
| {%- endif %} | ||
|
|
||
| {% if install_gh -%} | ||
| # If gh CLI has cached credentials (survive container rebuild), re-register | ||
| # its git credential helper so HTTPS remotes authenticate automatically. | ||
| if gh auth status &>/dev/null; then | ||
| gh auth setup-git | ||
| fi | ||
| {%- endif %} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,7 +5,29 @@ FROM ghcr.io/diamondlightsource/ubuntu-devcontainer:noble AS developer | |
| # Add any system dependencies for the developer/build environment here | ||
| RUN apt-get update -y && apt-get install -y --no-install-recommends \ | ||
| graphviz \ | ||
| && apt-get dist-clean{% if docker %} | ||
| && apt-get dist-clean{% if add_claude %} | ||
|
|
||
| # Node is required by Claude Code's hook runtime | ||
| RUN apt-get update -y && apt-get install -y --no-install-recommends \ | ||
| nodejs \ | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this plus gh plus glab be in the ubuntu devcontainer base?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes. |
||
| && apt-get dist-clean{% endif %}{% if install_gh %} | ||
|
|
||
| # GitHub CLI — used by Claude to authenticate to github.com via PAT | ||
| RUN curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | \ | ||
| dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg && \ | ||
| chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg && \ | ||
| echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" \ | ||
| | tee /etc/apt/sources.list.d/github-cli.list > /dev/null && \ | ||
| apt-get update && apt-get install -y --no-install-recommends gh && \ | ||
| apt-get dist-clean{% endif %}{% if install_glab %} | ||
|
Comment on lines
+15
to
+22
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I should think yes - so lets do as you suggest below and put these in the base container from 26.04 onwards and claude enabled PCT will use that. |
||
|
|
||
| # GitLab CLI — used by Claude to authenticate to gitlab instances via PAT. | ||
| # No apt repo, so install from the upstream release tarball. | ||
| ARG GLAB_VERSION=1.92.1 | ||
| RUN curl -fsSL "https://gitlab.com/gitlab-org/cli/-/releases/v${GLAB_VERSION}/downloads/glab_${GLAB_VERSION}_linux_amd64.tar.gz" \ | ||
| | tar -xz -C /tmp bin/glab && \ | ||
| install -m 0755 /tmp/bin/glab /usr/local/bin/glab && \ | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. see above. |
||
| rm -rf /tmp/bin{% endif %}{% if docker %} | ||
|
|
||
| # The build stage installs the context into the venv | ||
| FROM developer AS build | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| # Start Claude Code in sandbox mode (no SSH agent, skip permission prompts) | ||
| claude: | ||
| SSH_AUTH_SOCK= IS_SANDBOX=1 claude --dangerously-skip-permissions{% if install_gh %} | ||
|
|
||
|
|
||
| # Authenticate gh CLI with a GitHub PAT (token not stored in shell history) | ||
| gh-auth: | ||
| #!/bin/bash | ||
| read -sp "GitHub PAT: " t && echo | ||
| echo "$t" | gh auth login --with-token | ||
| unset t | ||
| gh auth setup-git | ||
| gh auth status{% endif %}{% if install_glab %} | ||
|
|
||
|
|
||
| # Authenticate glab CLI with a GitLab PAT (token not stored in shell history). | ||
| # --git-protocol https prevents glab's SSH insteadOf rewrite. | ||
| glab-auth hostname="gitlab.com": | ||
| #!/bin/bash | ||
| read -sp "GitLab PAT for {{ '{{' }} hostname {{ '}}' }}: " t && echo | ||
| echo "$t" | glab auth login --stdin --hostname {{ '{{' }} hostname {{ '}}' }} --git-protocol https | ||
| unset t | ||
| glab auth status{% endif %} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need this? When you click on the link it autoforwards the port anyway...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This got pulled in from my project that was having issues with sphinx-autobuild - I'm not sure why it fighting it - but we should not have this by default - agreed.