chore: import upstream snapshot with attribution
Component Security Validation / Security Audit (push) Has been cancelled
Deploy to Cloudflare Pages / deploy (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 12:38:58 +08:00
commit bb5c75ce05
8824 changed files with 1946442 additions and 0 deletions
@@ -0,0 +1,38 @@
# syntax=docker/dockerfile:1
FROM node:22-alpine
# Install runtime dependencies
RUN apk --no-cache add \
git \
bash \
python3 \
py3-pip \
curl \
&& npm install -g @anthropic-ai/claude-agent-sdk
# Create non-root user for security
RUN adduser -u 10001 -D -s /bin/bash sandboxuser
# Set working directory
WORKDIR /app
# Create output directory
RUN mkdir -p /output && chown sandboxuser:sandboxuser /output
# Copy execution script
COPY execute.js /app/execute.js
COPY package.json /app/package.json
# Install dependencies
RUN npm install --production && \
chown -R sandboxuser:sandboxuser /app
# Switch to non-root user
USER sandboxuser
# Set environment
ENV HOME=/home/sandboxuser
ENV NODE_ENV=production
# Default command (overridden by launcher)
CMD ["node", "/app/execute.js"]
@@ -0,0 +1,453 @@
# Docker Claude Code Sandbox
Execute Claude Code in isolated Docker containers with AI-powered code generation using the Claude Agent SDK.
## Quick Start
### 1. Install Docker
Ensure Docker is installed and running on your system:
```bash
# Check Docker installation
docker --version
# Verify Docker daemon is running
docker ps
```
If Docker is not installed, visit: https://docs.docker.com/get-docker/
### 2. Configure API Key
Set your Anthropic API key:
```bash
# Set as environment variable
export ANTHROPIC_API_KEY=sk-ant-your-api-key-here
# Or pass directly when using the CLI
npx claude-code-templates@latest --sandbox docker \
--agent development/frontend-developer \
--prompt "Create a React component" \
--anthropic-api-key sk-ant-your-key
```
### 3. Run Your First Sandbox
```bash
# Basic execution
npx claude-code-templates@latest --sandbox docker \
--prompt "Write a function to calculate factorial"
# With specific agent
npx claude-code-templates@latest --sandbox docker \
--agent development/python-developer \
--prompt "Create a data validation script"
# With multiple components
npx claude-code-templates@latest --sandbox docker \
--agent development/fullstack-developer \
--command development/setup-testing \
--prompt "Set up a complete testing environment"
```
## Architecture
This sandbox combines two powerful technologies:
1. **Claude Agent SDK** - Provides programmatic access to Claude Code
2. **Docker** - Provides isolated container execution
```
User Prompt → Docker Launcher → Container Build → Execute Script → Claude Agent SDK → Output Files
```
### Components
```
docker/
├── docker-launcher.js # Node.js launcher that orchestrates Docker
├── Dockerfile # Container definition with Claude Agent SDK
├── execute.js # Script that runs inside container
├── package.json # Dependencies (Claude Agent SDK)
└── README.md # This file
```
## How It Works
### 1. Launcher Phase (docker-launcher.js)
- Checks Docker installation and daemon status
- Builds container image if it doesn't exist
- Prepares environment variables and volume mounts
- Launches container with user prompt
### 2. Container Phase (execute.js)
- Installs requested components (agents, commands, MCPs, etc.)
- Executes Claude Agent SDK with the user's prompt
- Auto-allows all tool uses (no permission prompts)
- Captures output and generated files
- Copies results to mounted output directory
### 3. Output Phase
- Generated files are saved to `output/` directory
- Files preserve directory structure
- Accessible on host machine for inspection
## Usage Examples
### Simple Code Generation
```bash
npx claude-code-templates@latest --sandbox docker \
--prompt "Create a REST API server with Express.js"
```
### With Specific Agent
```bash
npx claude-code-templates@latest --sandbox docker \
--agent security/security-auditor \
--prompt "Audit this codebase for security vulnerabilities"
```
### Multiple Components
```bash
npx claude-code-templates@latest --sandbox docker \
--agent development/frontend-developer \
--command testing/setup-testing \
--setting performance/performance-optimization \
--prompt "Create a React app with testing setup"
```
### Development Workflow
```bash
# 1. Generate initial code
npx claude-code-templates@latest --sandbox docker \
--agent development/fullstack-developer \
--prompt "Create a blog API with authentication"
# 2. Check output
ls -la output/
# 3. Iterate on generated code
npx claude-code-templates@latest --sandbox docker \
--prompt "Add pagination to the blog API"
```
## Configuration
### Environment Variables
**Required:**
- `ANTHROPIC_API_KEY` - Your Anthropic API key
**Optional:**
- `DOCKER_BUILDKIT=1` - Enable BuildKit for faster builds
### Docker Image Details
The Docker image (`claude-sandbox`) includes:
- **Base**: Node.js 22 Alpine Linux (minimal, secure)
- **Runtime**: Git, Bash, Python3, Pip, Curl
- **Claude SDK**: `@anthropic-ai/claude-agent-sdk` installed globally
- **Security**: Runs as non-root user (UID 10001)
- **Working Directory**: `/app`
- **Output Directory**: `/output` (mounted as volume)
### Build Configuration
Edit `Dockerfile` to customize:
```dockerfile
# Add additional system dependencies
RUN apk --no-cache add postgresql-client redis
# Install additional global npm packages
RUN npm install -g typescript tsx
# Set custom environment variables
ENV CUSTOM_VAR=value
```
## Command Reference
### Build Image Manually
```bash
cd .claude/sandbox/docker
docker build -t claude-sandbox .
```
### Run Container Directly
```bash
docker run --rm \
-e ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY \
-v $(pwd)/output:/output \
claude-sandbox \
node /app/execute.js "Your prompt here" ""
```
### Clean Up
```bash
# Remove built image
docker rmi claude-sandbox
# Remove all stopped containers
docker container prune
# Remove dangling images
docker image prune
```
## Troubleshooting
### Docker Not Found
**Error:** `Docker is not installed`
**Solution:**
```bash
# Install Docker from official site
# macOS: https://docs.docker.com/desktop/install/mac-install/
# Linux: https://docs.docker.com/engine/install/
# Windows: https://docs.docker.com/desktop/install/windows-install/
```
### Docker Daemon Not Running
**Error:** `Docker daemon is not running`
**Solution:**
```bash
# macOS/Windows: Start Docker Desktop application
# Linux: sudo systemctl start docker
```
### API Key Not Set
**Error:** `ANTHROPIC_API_KEY environment variable is required`
**Solution:**
```bash
export ANTHROPIC_API_KEY=sk-ant-your-key-here
```
### Build Failures
**Error:** Failed to build Docker image
**Solution:**
```bash
# Check Docker logs
docker logs <container-id>
# Rebuild from scratch
docker build --no-cache -t claude-sandbox .
# Check disk space
docker system df
```
### Permission Issues
**Error:** Permission denied when accessing output files
**Solution:**
```bash
# Check output directory permissions
ls -la output/
# Fix permissions (if needed)
sudo chown -R $USER:$USER output/
```
### Container Execution Failures
**Error:** Container failed with code 1
**Solution:**
```bash
# Run container interactively for debugging
docker run -it --rm \
-e ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY \
claude-sandbox \
/bin/bash
# Check container logs
docker logs <container-id>
```
## Performance Tips
1. **Image Caching**: First build takes longer, subsequent builds are fast
2. **Volume Mounts**: Use volumes instead of COPY for faster iteration
3. **Layer Optimization**: Group RUN commands to reduce image layers
4. **BuildKit**: Enable for parallel builds (`DOCKER_BUILDKIT=1`)
5. **Prune Regularly**: Clean up unused images and containers
## Security
- **Isolation**: Containers are isolated from host system
- **Non-root User**: Execution runs as `sandboxuser` (UID 10001)
- **No Network**: Container has no internet access (except during build)
- **Read-only**: Host filesystem is mounted read-only
- **Resource Limits**: Docker enforces CPU and memory limits
- **Secret Management**: API keys are passed as environment variables (not stored in image)
## Cost Estimation
**Docker:**
- Free and open-source
- No cloud costs (runs locally)
- Resource usage: ~500MB disk space, ~512MB RAM during execution
**Anthropic API:**
- Claude Sonnet 4.5: ~$3 per million input tokens
- Average request: ~200 tokens = $0.0006 per request
**Example costs for 100 executions:**
- Docker: $0 (local execution)
- Anthropic: ~$0.06 (avg 200 tokens/request)
- **Total: ~$0.06**
## Comparison with Other Providers
| Feature | Docker | E2B | Cloudflare |
|---------|--------|-----|------------|
| Execution Location | 🏠 Local | ☁️ Cloud | 🌍 Edge |
| Setup Complexity | Medium | Easy | Easy |
| Internet Required | Setup only | Yes | Yes |
| Cost | Free | Paid | Paid |
| Privacy | Full control | Third-party | Third-party |
| Offline Support | Yes | No | No |
| Best For | Local dev, privacy, offline | Full stack projects | Serverless, global APIs |
## Development
### Project Structure
```
docker/
├── docker-launcher.js # Orchestrates container lifecycle
│ ├── checkDockerInstalled()
│ ├── checkDockerRunning()
│ ├── buildDockerImage()
│ └── runDockerContainer()
├── Dockerfile # Container definition
│ ├── Base image (Node 22 Alpine)
│ ├── System dependencies
│ ├── Claude Agent SDK
│ └── Security (non-root user)
├── execute.js # Execution script (runs in container)
│ ├── installComponents()
│ ├── executeQuery()
│ └── copyGeneratedFiles()
├── package.json # NPM dependencies
└── README.md # Documentation
```
### Scripts
```bash
# Build image
npm run build
# Clean image
npm run clean
```
### Extending the Image
Add custom tools to the Dockerfile:
```dockerfile
# Install Python packages
RUN pip install --no-cache-dir pandas numpy matplotlib
# Install Node.js packages globally
RUN npm install -g typescript eslint prettier
# Add custom scripts
COPY scripts/ /app/scripts/
```
## Advanced Usage
### Custom Dockerfile
Create a custom Dockerfile for specialized environments:
```dockerfile
FROM node:22-alpine
# Install database clients
RUN apk add --no-cache postgresql-client mysql-client
# Install development tools
RUN apk add --no-cache vim nano tmux
# Install Claude Agent SDK
RUN npm install -g @anthropic-ai/claude-agent-sdk
# ... rest of configuration
```
### Multi-stage Builds
Optimize image size with multi-stage builds:
```dockerfile
# Build stage
FROM node:22-alpine AS builder
WORKDIR /build
COPY package*.json ./
RUN npm ci --only=production
# Runtime stage
FROM node:22-alpine
COPY --from=builder /build/node_modules ./node_modules
# ... rest of configuration
```
### Persistent Storage
Mount additional volumes for persistent data:
```bash
docker run --rm \
-e ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY \
-v $(pwd)/output:/output \
-v $(pwd)/cache:/cache \
claude-sandbox
```
## Resources
- [Docker Documentation](https://docs.docker.com/)
- [Claude Agent SDK](https://github.com/anthropics/claude-agent-sdk)
- [Anthropic API Documentation](https://docs.anthropic.com/)
- [Docker Best Practices](https://docs.docker.com/develop/dev-best-practices/)
- [Container Security](https://docs.docker.com/engine/security/)
## License
MIT License - See LICENSE file for details
## Support
For issues and questions:
1. Check Docker installation: `docker --version && docker ps`
2. Verify API key: `echo $ANTHROPIC_API_KEY`
3. Check container logs: `docker logs <container-id>`
4. Review output directory: `ls -la output/`
5. Open an issue on GitHub
---
Built with ❤️ using Docker, Node.js, and Claude Agent SDK
+184
View File
@@ -0,0 +1,184 @@
#!/usr/bin/env node
/**
* Docker Sandbox Launcher
* Orchestrates Docker container execution for Claude Code
*/
import { spawn, execSync } from 'child_process';
import fs from 'fs/promises';
import path from 'path';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// Parse command line arguments
const args = process.argv.slice(2);
const prompt = args[0] || 'Hello, Claude!';
const componentsToInstall = args[1] || '';
const anthropicApiKey = process.env.ANTHROPIC_API_KEY;
// Validate API key
if (!anthropicApiKey) {
console.error('❌ Error: ANTHROPIC_API_KEY environment variable is required');
process.exit(1);
}
console.log('🐳 Docker Sandbox Launcher');
console.log('═══════════════════════════════════════\n');
/**
* Check if Docker is installed
*/
function checkDockerInstalled() {
try {
execSync('docker --version', { stdio: 'pipe' });
return true;
} catch (error) {
console.error('❌ Error: Docker is not installed');
console.error(' Please install Docker: https://docs.docker.com/get-docker/\n');
return false;
}
}
/**
* Check if Docker daemon is running
*/
function checkDockerRunning() {
try {
execSync('docker ps', { stdio: 'pipe' });
return true;
} catch (error) {
console.error('❌ Error: Docker daemon is not running');
console.error(' Please start Docker and try again\n');
return false;
}
}
/**
* Build Docker image if it doesn't exist
*/
async function buildDockerImage() {
console.log('🔨 Checking Docker image...');
// Check if image exists
try {
execSync('docker image inspect claude-sandbox', { stdio: 'pipe' });
console.log(' ✅ Image already exists\n');
return true;
} catch (error) {
// Image doesn't exist, build it
console.log(' 📦 Building Docker image (this may take a few minutes)...\n');
return new Promise((resolve) => {
const build = spawn('docker', [
'build',
'-t', 'claude-sandbox',
'.'
], {
cwd: __dirname,
stdio: 'inherit'
});
build.on('close', (code) => {
if (code === 0) {
console.log('\n✅ Docker image built successfully\n');
resolve(true);
} else {
console.error('\n❌ Failed to build Docker image');
resolve(false);
}
});
build.on('error', (error) => {
console.error('❌ Build error:', error.message);
resolve(false);
});
});
}
}
/**
* Run Docker container
*/
async function runDockerContainer() {
console.log('🚀 Starting Docker container...\n');
// Create output directory
const outputDir = path.join(process.cwd(), 'output');
await fs.mkdir(outputDir, { recursive: true });
return new Promise((resolve) => {
const dockerArgs = [
'run',
'--rm',
'-e', `ANTHROPIC_API_KEY=${anthropicApiKey}`,
'-v', `${outputDir}:/output`,
'claude-sandbox',
'node', '/app/execute.js',
prompt,
componentsToInstall
];
const container = spawn('docker', dockerArgs, {
stdio: 'inherit'
});
container.on('close', (code) => {
if (code === 0) {
console.log('\n✅ Docker container completed successfully');
// Show output directory
console.log(`\n📂 Output files saved to: ${outputDir}`);
resolve(true);
} else {
console.error('\n❌ Docker container failed with code:', code);
resolve(false);
}
});
container.on('error', (error) => {
console.error('❌ Container error:', error.message);
resolve(false);
});
});
}
/**
* Main execution flow
*/
async function main() {
try {
// Step 1: Check Docker installation
if (!checkDockerInstalled()) {
process.exit(1);
}
// Step 2: Check Docker daemon
if (!checkDockerRunning()) {
process.exit(1);
}
// Step 3: Build Docker image
const buildSuccess = await buildDockerImage();
if (!buildSuccess) {
process.exit(1);
}
// Step 4: Run container
const runSuccess = await runDockerContainer();
if (!runSuccess) {
process.exit(1);
}
console.log('\n🎉 Docker sandbox execution completed!');
process.exit(0);
} catch (error) {
console.error('❌ Fatal error:', error.message);
process.exit(1);
}
}
// Run main function
main();
@@ -0,0 +1,251 @@
#!/usr/bin/env node
/**
* Docker Sandbox Executor
* Runs inside Docker container using Claude Agent SDK
*/
import { query } from '@anthropic-ai/claude-agent-sdk';
import fs from 'fs/promises';
import path from 'path';
import { spawn } from 'child_process';
// Parse command line arguments
const args = process.argv.slice(2);
const prompt = args[0] || 'Hello, Claude!';
const componentsToInstall = args[1] || '';
const anthropicApiKey = process.env.ANTHROPIC_API_KEY;
// Validate API key
if (!anthropicApiKey) {
console.error('❌ Error: ANTHROPIC_API_KEY environment variable is required');
process.exit(1);
}
console.log('🐳 Docker Sandbox Executor');
console.log('═══════════════════════════════════════\n');
/**
* Install Claude Code components if specified
*/
async function installComponents() {
if (!componentsToInstall || componentsToInstall.trim() === '') {
return true;
}
console.log('📦 Installing components...');
console.log(` Components: ${componentsToInstall}\n`);
return new Promise((resolve) => {
const installCmd = `npx claude-code-templates@latest ${componentsToInstall} --yes`;
const child = spawn('sh', ['-c', installCmd], {
stdio: 'inherit',
env: process.env
});
child.on('close', (code) => {
if (code === 0) {
console.log('\n✅ Components installed successfully\n');
resolve(true);
} else {
console.log('\n⚠️ Component installation had warnings (continuing...)\n');
resolve(true); // Continue even if installation has warnings
}
});
child.on('error', (error) => {
console.error(`❌ Installation error: ${error.message}`);
resolve(false);
});
});
}
/**
* Execute Claude Code query using Agent SDK
*/
async function executeQuery() {
try {
console.log('🤖 Executing Claude Code...');
console.log(` Prompt: "${prompt.substring(0, 80)}${prompt.length > 80 ? '...' : ''}"\n`);
console.log('─'.repeat(60));
console.log('📝 CLAUDE OUTPUT:');
console.log('─'.repeat(60) + '\n');
// Enhance prompt with working directory context
const enhancedPrompt = `${prompt}\n\nNote: Your current working directory is /app. When creating files, save them in the current directory (/app) so they can be captured in the output.`;
// query() returns an async generator - we need to iterate it
const generator = query({
prompt: enhancedPrompt,
options: {
apiKey: anthropicApiKey,
model: 'claude-sonnet-4-5',
permissionMode: 'bypassPermissions', // Auto-allow all tool uses
}
});
let assistantResponses = [];
let messageCount = 0;
// Iterate through the async generator
for await (const message of generator) {
messageCount++;
if (message.type === 'assistant') {
// Extract text from assistant message content
if (message.message && message.message.content) {
const content = Array.isArray(message.message.content)
? message.message.content
: [message.message.content];
content.forEach(block => {
if (block.type === 'text') {
console.log(block.text);
assistantResponses.push(block.text);
}
});
}
} else if (message.type === 'result') {
// Show final result metadata
console.log('\n' + '─'.repeat(60));
console.log(`✅ Execution completed (${message.num_turns} turn${message.num_turns > 1 ? 's' : ''})`);
console.log(` Duration: ${message.duration_ms}ms`);
console.log(` Cost: $${message.total_cost_usd.toFixed(5)}`);
console.log('─'.repeat(60) + '\n');
}
}
// Show response summary
const responseText = assistantResponses.join('\n');
if (responseText) {
console.log('📄 Response Summary:');
console.log(` ${messageCount} message(s) received`);
console.log(` ${assistantResponses.length} assistant response(s)`);
console.log(` ${responseText.length} characters generated`);
console.log('');
}
return true;
} catch (error) {
console.error('\n❌ Execution error:', error.message);
if (error.stack) {
console.error('\nStack trace:');
console.error(error.stack);
}
return false;
}
}
/**
* Find and copy generated files to output directory
*/
async function copyGeneratedFiles() {
try {
console.log('📁 Searching for generated files...\n');
// Common file extensions to look for
const extensions = [
'js', 'jsx', 'ts', 'tsx',
'py', 'html', 'css', 'scss',
'json', 'md', 'yaml', 'yml',
'txt', 'sh', 'bash'
];
// Search for files in multiple directories
const { execSync } = await import('child_process');
const findPattern = extensions.map(ext => `-name "*.${ext}"`).join(' -o ');
// Search in /app and /tmp for generated files
const searchPaths = ['/app', '/tmp'];
let allFiles = [];
for (const searchPath of searchPaths) {
const findCmd = `find ${searchPath} -type f \\( ${findPattern} \\) ! -path "*/node_modules/*" ! -path "*/.npm/*" ! -path "/app/execute.js" ! -path "/app/package*.json" -newer /app/execute.js 2>/dev/null | head -50`;
try {
const output = execSync(findCmd, { encoding: 'utf8' });
const files = output.trim().split('\n').filter(f => f.trim());
allFiles = allFiles.concat(files);
} catch (error) {
// Continue to next search path
}
}
if (allFiles.length === 0) {
console.log('️ No generated files found\n');
return;
}
console.log(`📦 Found ${allFiles.length} file(s):\n`);
// Copy files to output directory preserving structure
let copiedCount = 0;
for (const file of allFiles) {
try {
// Determine relative path based on source directory
let relativePath;
if (file.startsWith('/app/')) {
relativePath = file.replace('/app/', '');
} else if (file.startsWith('/tmp/')) {
relativePath = file.replace('/tmp/', '');
} else {
relativePath = path.basename(file);
}
const outputPath = path.join('/output', relativePath);
// Create directory structure
await fs.mkdir(path.dirname(outputPath), { recursive: true });
// Copy file
await fs.copyFile(file, outputPath);
console.log(`${relativePath}`);
copiedCount++;
} catch (error) {
console.log(` ⚠️ Failed to copy: ${file}`);
}
}
if (copiedCount > 0) {
console.log(`\n✅ Copied ${copiedCount} file(s) to output directory\n`);
}
} catch (error) {
console.error('❌ Error copying files:', error.message);
}
}
/**
* Main execution flow
*/
async function main() {
try {
// Step 1: Install components
const installSuccess = await installComponents();
if (!installSuccess) {
console.error('❌ Component installation failed');
process.exit(1);
}
// Step 2: Execute Claude query
const executeSuccess = await executeQuery();
if (!executeSuccess) {
console.error('❌ Query execution failed');
process.exit(1);
}
// Step 3: Copy generated files
await copyGeneratedFiles();
console.log('🎉 Docker sandbox execution completed successfully!');
process.exit(0);
} catch (error) {
console.error('❌ Fatal error:', error.message);
process.exit(1);
}
}
// Run main function
main();
@@ -0,0 +1,26 @@
{
"name": "claude-code-docker-sandbox",
"version": "1.0.0",
"description": "Docker sandbox for Claude Code execution with Claude Agent SDK",
"main": "docker-launcher.js",
"type": "module",
"scripts": {
"build": "docker build -t claude-sandbox .",
"clean": "docker rmi claude-sandbox || true"
},
"dependencies": {
"@anthropic-ai/claude-agent-sdk": "^0.1.30"
},
"engines": {
"node": ">=18.0.0"
},
"keywords": [
"claude",
"docker",
"sandbox",
"ai",
"agent"
],
"author": "Claude Code Templates",
"license": "MIT"
}