Skip to content

Introduce Devcontainers-based Claude Code sandbox#2194

Open
Stephan202 wants to merge 2 commits intomasterfrom
sschroevers/introduce-devcontainer-sandbox
Open

Introduce Devcontainers-based Claude Code sandbox#2194
Stephan202 wants to merge 2 commits intomasterfrom
sschroevers/introduce-devcontainer-sandbox

Conversation

@Stephan202
Copy link
Copy Markdown
Member

@Stephan202 Stephan202 commented Apr 7, 2026

Suggested commit message:

Introduce Devcontainers-based Claude Code sandbox (#2194)

The new `claude-sandbox.sh` script executes Claude Code with
`--dangerously-skip-permissions` in a Devcontainers-managed Docker container,
with limited access to the host filesystem. The container's working directory
is either an explicitly specified directory, or a Git worktree (which will be
created if it does not yet exist).

Maven SNAPSHOTs installed by the container have a custom prefix, so that these
artifacts are ignored by other containers and processes on the host system.
This enables concurrent work on multiple branches.

This setup is not fully secure: the host system access provides plenty of
opportunity to wreak havoc, and network access is not restricted. The primary
aim here is to reduce friction and facilitate concurrent development.

@Stephan202 Stephan202 added this to the 0.29.0 milestone Apr 7, 2026
@Stephan202 Stephan202 added the chore A task not related to code (build, formatting, process, ...) label Apr 7, 2026
Comment thread .devcontainer/Dockerfile Dismissed
Comment thread .devcontainer/Dockerfile Dismissed
@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 7, 2026

Suggested commit message:

See above.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 7, 2026

📝 Walkthrough

Walkthrough

Added a development container setup comprising a Dockerfile with Node, build tools, and SDKMAN!, a corresponding devcontainer.json configuration file, and a claude-sandbox.sh script that manages git worktrees and launches Claude Code sessions isolated per workspace within the container.

Changes

Cohort / File(s) Summary
Dev Container Configuration
.devcontainer/Dockerfile, .devcontainer/devcontainer.json
Dockerfile defines a Node-based container with Debian utilities, non-root user setup, and SDKMAN!/JDK tooling. devcontainer.json specifies build args, volume mounts for credentials and configuration, environment variables, and workspace binding.
Launch Script
claude-sandbox.sh
Bash script that validates prerequisites, resolves or creates git worktrees for workspace isolation, coordinates concurrent sessions via flock, manages devcontainer lifecycle with cleanup on exit, and launches Claude Code inside the container.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Introduce Devcontainers-based Claude Code sandbox' directly and clearly summarizes the main change: adding a new Devcontainers-based sandbox setup for running Claude Code, which matches the primary additions (claude-sandbox.sh, .devcontainer/Dockerfile, and .devcontainer/devcontainer.json).
Description check ✅ Passed The description provides a detailed commit message explaining the new claude-sandbox.sh script, its functionality, Maven SNAPSHOT prefixing for concurrent work, and security tradeoffs, which directly relates to and documents the changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch sschroevers/introduce-devcontainer-sandbox

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.devcontainer/Dockerfile:
- Around line 50-58: Avoid piping remote installers directly to bash: for the
Claude Code install (the RUN curl ... | bash line) and the SDKMAN! install (the
RUN curl ... | bash line), change to a two-step approach that downloads a
pinned/versioned installer to a local file, verify its checksum or signature
against a known good value, and only then execute the saved installer with bash;
update the Dockerfile to reference explicit installer versions/URLs and include
checksum verification commands before running the installer, and preserve the
existing ARG TARGET_JDK and .sdkmanrc usage while replacing the direct curl |
bash invocations.
- Around line 55-61: The current RUN step appends "java=${TARGET_JDK}" to
.sdkmanrc which creates duplicate java= entries; modify the RUN command that
currently echoes into .sdkmanrc so it replaces the existing java= line instead
(e.g., use a sed/awk replacement or remove any existing ^java= line then write
the new one) before running "sdk env install", targeting the .sdkmanrc file and
using the TARGET_JDK variable to ensure the java entry is updated rather than
appended.

In `@claude-sandbox.sh`:
- Around line 74-80: The shared lock (LOCK_FILE / LOCK_FD with flock -s) only
tracks active sessions and does not prevent two processes racing through
devcontainer up; fix by adding a separate exclusive startup lock around the
devcontainer up call: create a new lock file (e.g.,
STARTUP_LOCK="/tmp/claude-sandbox-${WORKSPACE_ID}.startup.lock"), open a new FD
(e.g., STARTUP_FD), acquire flock -x on that FD before running devcontainer up,
run devcontainer up, then release/close STARTUP_FD so other processes can
proceed; keep the original shared LOCK_FILE/LOCK_FD and flock -s for lifetime
tracking/teardown as before (apply same change to the other startup block
referenced near the second flock usage).
- Around line 24-27: Add upfront checks similar to the existing devcontainer
check to verify required host commands: git, docker, and flock; for SHA-256
support check for sha256sum and if missing check for shasum and fail with an
actionable message listing install steps. Implement a portable SHA-256 helper
function (e.g., compute_sha256) used elsewhere that calls sha256sum when
available or falls back to shasum -a 256, and update any call sites to use this
helper; keep error messages clear and reference the missing command so users
know how to install it.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: afe13e48-0836-4260-bc65-564b4e110517

📥 Commits

Reviewing files that changed from the base of the PR and between 1afa509 and 94a0df6.

📒 Files selected for processing (3)
  • .devcontainer/Dockerfile
  • .devcontainer/devcontainer.json
  • claude-sandbox.sh

Comment thread .devcontainer/devcontainer.json Outdated
Comment thread .devcontainer/Dockerfile
Comment thread .devcontainer/Dockerfile
Comment thread claude-sandbox.sh Outdated
Comment thread claude-sandbox.sh Outdated
@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 7, 2026

Looks good. No mutations were possible for these changes.
Mutation testing report by Pitest. Review any surviving mutants by inspecting the line comments under Files changed.

"remoteEnv": {
"GITHUB_ACTOR": "${localEnv:GITHUB_ACTOR}",
"GITHUB_TOKEN": "${localEnv:GITHUB_TOKEN}",
"MAVEN_OPTS": "-Daether.enhancedLocalRepository.split=true -Daether.enhancedLocalRepository.splitRemoteRepository=true -Daether.enhancedLocalRepository.localPrefix=${localEnv:WORKSPACE_ID}"
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This setup works with mvn, but not with mvnd. I didn't investigate that further right now. This could in theory cause some issues i.c.w. apply-error-prone-suggestions.sh, which is the only script that uses mvnd if available.

@Stephan202 Stephan202 force-pushed the sschroevers/introduce-devcontainer-sandbox branch from 7156d0d to 2a639f1 Compare April 7, 2026 16:37
Copy link
Copy Markdown
Member Author

@Stephan202 Stephan202 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I rebased and squashed the commits, because I want to cherry-pick this on another branch I'm working on.

Comment thread .devcontainer/Dockerfile
Comment on lines +10 to +11
# XXX: Drop `pandoc` installation if `./generate-review-checklist.sh` is
# migrated to Java.
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment makes sense only in the context of #2187; ideally we merge that PR first.

@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 7, 2026

Looks good. No mutations were possible for these changes.
Mutation testing report by Pitest. Review any surviving mutants by inspecting the line comments under Files changed.

Copy link
Copy Markdown
Member

@rickie rickie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding what I encountered and mentioned offline. Didn't dive into it further yet.

Comment thread .devcontainer/Dockerfile
zip \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure where, but it doesn't fully work for me to run this locally.

[+] Building 0.0s (6/6) FINISHED docker:default
=> [internal] load build definition from updateUID.Dockerfile-0.85.0 0.0s
=> => transferring dockerfile: 1.52kB 0.0s
=> WARN: InvalidDefaultArgInFrom: Default value for ARG $BASE_IMAGE results in empty or invalid base image name (line 4) 0.0s
=> [internal] load metadata for docker.io/library/vsc-branchname-36c33d6251eaf99073cf5c101dd4b4ad73668df3de509ffb2ca536ec1b113c1d:latest 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [1/2] FROM docker.io/library/vsc-branchname-36c33d6251eaf99073cf5c101dd4b4ad73668df3de509ffb2ca536ec1b113c1d:latest 0.0s
=> CACHED [2/2] RUN eval $(sed -n "s/rick:[^:]:([^:]):([^:]):[^:]:([^:])./OLD_UID=\1;OLD_GID=\2;HOME_FOLDER=\3/p" /etc/passwd); eval $(sed -n "s/([^:]):[^:]:10 0.0s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:34977a3a11e44759cecc0d9e0252bdfd375e90b7812f5598eda1b080b1226f70 0.0s
=> => naming to docker.io/library/vsc-branchname-36c33d6251eaf99073cf5c101dd4b4ad73668df3de509ffb2ca536ec1b113c1d-uid 0.0s
1 warning found (use docker --debug to expand):
InvalidDefaultArgInFrom: Default value for ARG $BASE_IMAGE results in empty or invalid base image name (line 4)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There were some things that didn't exist yet and adding this would fix all that:

   93 +# Ensure all bind-mount source paths exist. Docker bind mounts fail if the                                                                                                   
       94 +# source does not exist on the host.                                                                                                                                         
       95 +mkdir -p "${HOME}/.claude" \                                                                                                                                                 
       96 +         "${HOME}/.config/ccstatusline" \                                                                                                                                    
       97 +         "${HOME}/.config/gh" \                                                                                                                                           
       98 +         "${HOME}/.m2/repository" \                                                                                                                                   
       99 +         "${HOME}/.ssh"                                                                                                                                               
      100 +touch "${HOME}/.claude.json" \                                                                                                                                        
      101 +      "${HOME}/.gitconfig" \                                                                                                                                          
      102 +      "${HOME}/.ssh/known_hosts"                                                                                                                                      
    103 +               

@Stephan202 Stephan202 force-pushed the sschroevers/introduce-devcontainer-sandbox branch from 2a639f1 to d56c536 Compare April 9, 2026 19:33
@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 9, 2026

Looks good. No mutations were possible for these changes.
Mutation testing report by Pitest. Review any surviving mutants by inspecting the line comments under Files changed.

@Stephan202 Stephan202 force-pushed the sschroevers/introduce-devcontainer-sandbox branch from d56c536 to 77e5fec Compare April 10, 2026 10:46
The new `claude-sandbox.sh` script executes Claude Code with
`--dangerously-skip-permissions` in a Devcontainers-managed Docker container,
with limited access to the host filesystem. The container's working directory
is either an explicitly specified directory, or a Git worktree (which will be
created if it does not yet exist).

Maven SNAPSHOTs installed by the container have a custom prefix, so that these
artifacts are ignored by other containers and processes on the host system.
This enables concurrent work on multiple branches.

This setup is not fully secure: the host system access provides plenty of
opportunity to wreak havoc, and network access is not restricted. The primary
aim here is to reduce friction and facilitate concurrent development.
@Stephan202 Stephan202 force-pushed the sschroevers/introduce-devcontainer-sandbox branch from 77e5fec to c6c46bd Compare April 10, 2026 17:29
@github-actions
Copy link
Copy Markdown

Looks good. No mutations were possible for these changes.
Mutation testing report by Pitest. Review any surviving mutants by inspecting the line comments under Files changed.

@sonarqubecloud
Copy link
Copy Markdown

@Stephan202 Stephan202 removed this from the 0.29.0 milestone Apr 13, 2026
@Stephan202 Stephan202 added this to the 0.30.0 milestone Apr 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

chore A task not related to code (build, formatting, process, ...)

Development

Successfully merging this pull request may close these issues.

3 participants