sandboxbox 2.0.7 → 2.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CLAUDE.md CHANGED
@@ -132,7 +132,74 @@ exec claude # Changes save directly to local repo
132
132
  ### Path resolution issues
133
133
  **Solution**: Use explicit REPO_PATH environment variable
134
134
 
135
+ ## Command Isolation Principles
136
+
137
+ ### Critical Architecture Distinction
138
+ - **`run` command**: Creates isolated temporary environment - changes DO NOT affect host
139
+ - **`claude` command**: Mounts local repository directly - changes DO affect host
140
+ - **`shell` command**: Creates isolated temporary environment - changes DO NOT affect host
141
+
142
+ ### Isolation Implementation (run/shell commands)
143
+ ```javascript
144
+ // Creates temporary directory with copied project
145
+ const tempDir = mkdtempSync(join(tmpdir(), 'sandboxbox-'));
146
+ const tempProjectDir = join(tempDir, projectName);
147
+
148
+ // Cross-platform file copying with hidden files (.git, etc.)
149
+ if (process.platform === 'win32') {
150
+ execSync(`powershell -Command "Copy-Item -Path '${projectDir}\\*' -Destination '${tempProjectDir}' -Recurse -Force"`, {
151
+ stdio: 'pipe',
152
+ shell: true
153
+ });
154
+ // Copy hidden files separately
155
+ execSync(`powershell -Command "Get-ChildItem -Path '${projectDir}' -Force -Name | Where-Object { $_ -like '.*' } | ForEach-Object { Copy-Item -Path (Join-Path '${projectDir}' $_) -Destination '${tempProjectDir}' -Recurse -Force }"`, {
156
+ stdio: 'pipe',
157
+ shell: true
158
+ });
159
+ } else {
160
+ execSync(`cp -r "${projectDir}"/.* "${tempProjectDir}/" 2>/dev/null || true`, {
161
+ stdio: 'pipe',
162
+ shell: true
163
+ });
164
+ execSync(`cp -r "${projectDir}"/* "${tempProjectDir}/"`, {
165
+ stdio: 'pipe',
166
+ shell: true
167
+ });
168
+ }
169
+
170
+ // Automatic cleanup on exit
171
+ const cleanup = () => {
172
+ try {
173
+ rmSync(tempDir, { recursive: true, force: true });
174
+ } catch (cleanupError) {
175
+ // Ignore cleanup errors
176
+ }
177
+ };
178
+
179
+ process.on('exit', cleanup);
180
+ process.on('SIGINT', () => { cleanup(); process.exit(130); });
181
+ process.on('SIGTERM', () => { cleanup(); process.exit(143); });
182
+ ```
183
+
184
+ ### Container Naming and Cleanup
185
+ - Use random short names: `sandboxbox-run-${Math.random().toString(36).substr(2, 9)}`
186
+ - Force cleanup: `podman rm -f container-name`
187
+ - Automatic cleanup handlers for all exit scenarios
188
+ - Cross-platform signal handling (SIGINT, SIGTERM)
189
+
190
+ ### Cross-Platform Path Handling
191
+ ```javascript
192
+ // Normalize Windows paths for podman cp command
193
+ const normalizedProjectDir = projectDir.replace(/\\/g, '/');
194
+ ```
195
+
135
196
  ## Version Management
136
197
  - Publish new version when fixing critical Windows issues
137
198
  - Clear npm cache: `npm cache clean --force`
138
- - Use specific version: `npx sandboxbox@latest`
199
+ - Use specific version: `npx sandboxbox@latest`
200
+
201
+ ## File Cleanup Requirements
202
+ - All temporary containers auto-cleanup on exit
203
+ - All temporary directories auto-cleanup on exit
204
+ - Error handling for cleanup failures (ignore errors)
205
+ - Signal handlers ensure cleanup on interrupts
@@ -0,0 +1,18 @@
1
+ FROM node:20
2
+
3
+ # Install basic development tools
4
+ RUN apt-get update && apt-get install -y --no-install-recommends \
5
+ git \
6
+ bash \
7
+ curl \
8
+ nano \
9
+ && apt-get clean && rm -rf /var/lib/apt/lists/*
10
+
11
+ # Create workspace directory
12
+ WORKDIR /workspace
13
+
14
+ # Set up non-root user
15
+ USER node
16
+
17
+ # Install Claude Code
18
+ RUN npm install -g @anthropic-ai/claude-code@latest
package/cli.js CHANGED
@@ -7,10 +7,11 @@
7
7
  * Works on Windows, macOS, and Linux
8
8
  */
9
9
 
10
- import { readFileSync, existsSync, writeFileSync } from 'fs';
10
+ import { readFileSync, existsSync, writeFileSync, mkdtempSync, rmSync } from 'fs';
11
11
  import { execSync } from 'child_process';
12
- import { resolve, dirname } from 'path';
12
+ import { resolve, dirname, join } from 'path';
13
13
  import { fileURLToPath } from 'url';
14
+ import { tmpdir } from 'os';
14
15
 
15
16
  import { color } from './utils/colors.js';
16
17
  import { checkPodman, getPodmanPath } from './utils/podman.js';
@@ -161,19 +162,74 @@ async function main() {
161
162
  process.exit(1);
162
163
  }
163
164
 
164
- console.log(color('blue', 'šŸš€ Running project in container...'));
165
+ console.log(color('blue', 'šŸš€ Running project in isolated container...'));
165
166
  console.log(color('yellow', `Project: ${projectDir}`));
166
167
  console.log(color('yellow', `Command: ${cmd}\n`));
168
+ console.log(color('cyan', 'šŸ“¦ Note: Changes will NOT affect host files (isolated environment)'));
167
169
 
168
170
  const runPodman = checkPodman();
169
171
  if (!runPodman) process.exit(1);
170
172
 
171
173
  try {
172
- execSync(`"${runPodman}" run --rm -it -v "${projectDir}:/workspace" -w /workspace sandboxbox:latest ${cmd}`, {
174
+ // Create a temporary directory for isolation
175
+ const tempDir = mkdtempSync(join(tmpdir(), 'sandboxbox-'));
176
+ const projectName = projectDir.split(/[\\\/]/).pop() || 'project';
177
+ const tempProjectDir = join(tempDir, projectName);
178
+
179
+ // Copy project to temporary directory (creates isolation)
180
+ // First create the directory
181
+ execSync(`mkdir -p "${tempProjectDir}"`, {
182
+ stdio: 'pipe',
183
+ shell: true
184
+ });
185
+
186
+ if (process.platform === 'win32') {
187
+ // Windows approach - include hidden files like .git
188
+ execSync(`powershell -Command "Copy-Item -Path '${projectDir}\\*' -Destination '${tempProjectDir}' -Recurse -Force -Exclude 'node_modules'"`, {
189
+ stdio: 'pipe',
190
+ shell: true
191
+ });
192
+ // Also copy hidden files separately
193
+ execSync(`powershell -Command "Get-ChildItem -Path '${projectDir}' -Force -Name | Where-Object { $_ -like '.*' } | ForEach-Object { Copy-Item -Path (Join-Path '${projectDir}' $_) -Destination '${tempProjectDir}' -Recurse -Force }"`, {
194
+ stdio: 'pipe',
195
+ shell: true
196
+ });
197
+ } else {
198
+ // Unix approach - include hidden files
199
+ execSync(`cp -r "${projectDir}"/.* "${tempProjectDir}/" 2>/dev/null || true`, {
200
+ stdio: 'pipe',
201
+ shell: true
202
+ });
203
+ execSync(`cp -r "${projectDir}"/* "${tempProjectDir}/"`, {
204
+ stdio: 'pipe',
205
+ shell: true
206
+ });
207
+ }
208
+
209
+ // Ensure cleanup on exit
210
+ const cleanup = () => {
211
+ try {
212
+ rmSync(tempDir, { recursive: true, force: true });
213
+ } catch (cleanupError) {
214
+ // Ignore cleanup errors
215
+ }
216
+ };
217
+
218
+ // Set up cleanup handlers
219
+ process.on('exit', cleanup);
220
+ process.on('SIGINT', () => { cleanup(); process.exit(130); });
221
+ process.on('SIGTERM', () => { cleanup(); process.exit(143); });
222
+
223
+ // Run the command in isolated container with temporary directory
224
+ execSync(`"${runPodman}" run --rm -it -v "${tempProjectDir}:/workspace:rw" -w /workspace sandboxbox:latest ${cmd}`, {
173
225
  stdio: 'inherit',
174
226
  shell: process.platform === 'win32'
175
227
  });
176
- console.log(color('green', '\nāœ… Container execution completed!'));
228
+
229
+ // Clean up the temporary directory
230
+ cleanup();
231
+
232
+ console.log(color('green', '\nāœ… Container execution completed! (Isolated - no host changes)'));
177
233
  } catch (error) {
178
234
  console.log(color('red', `\nāŒ Run failed: ${error.message}`));
179
235
  process.exit(1);
@@ -194,17 +250,55 @@ async function main() {
194
250
  process.exit(1);
195
251
  }
196
252
 
197
- console.log(color('blue', '🐚 Starting interactive shell...'));
253
+ console.log(color('blue', '🐚 Starting interactive shell in isolated container...'));
198
254
  console.log(color('yellow', `Project: ${shellProjectDir}\n`));
255
+ console.log(color('cyan', 'šŸ“¦ Note: Changes will NOT affect host files (isolated environment)'));
199
256
 
200
257
  const shellPodman = checkPodman();
201
258
  if (!shellPodman) process.exit(1);
202
259
 
203
260
  try {
204
- execSync(`"${shellPodman}" run --rm -it -v "${shellProjectDir}:/workspace" -w /workspace sandboxbox:latest /bin/bash`, {
261
+ // Create a temporary container with copied project (isolated environment)
262
+ const tempShellContainerName = `sandboxbox-shell-${Math.random().toString(36).substr(2, 9)}`;
263
+
264
+ // Ensure cleanup on exit
265
+ const cleanup = () => {
266
+ try {
267
+ execSync(`"${shellPodman}" rm -f "${tempShellContainerName}"`, {
268
+ stdio: 'pipe',
269
+ shell: process.platform === 'win32'
270
+ });
271
+ } catch (cleanupError) {
272
+ // Ignore cleanup errors
273
+ }
274
+ };
275
+
276
+ // Set up cleanup handlers
277
+ process.on('exit', cleanup);
278
+ process.on('SIGINT', () => { cleanup(); process.exit(130); });
279
+ process.on('SIGTERM', () => { cleanup(); process.exit(143); });
280
+
281
+ // Copy project into container (isolated)
282
+ execSync(`"${shellPodman}" create --name "${tempShellContainerName}" -w /workspace -it sandboxbox:latest /bin/bash`, {
283
+ stdio: 'pipe',
284
+ shell: process.platform === 'win32'
285
+ });
286
+
287
+ // Copy project files into isolated container - use proper path handling
288
+ const normalizedShellProjectDir = shellProjectDir.replace(/\\/g, '/');
289
+ execSync(`"${shellPodman}" cp "${normalizedShellProjectDir}" "${tempShellContainerName}:/workspace"`, {
290
+ stdio: 'pipe',
291
+ shell: process.platform === 'win32'
292
+ });
293
+
294
+ // Start interactive shell in the isolated container
295
+ execSync(`"${shellPodman}" start -i "${tempShellContainerName}"`, {
205
296
  stdio: 'inherit',
206
297
  shell: process.platform === 'win32'
207
298
  });
299
+
300
+ // Clean up the temporary container
301
+ cleanup();
208
302
  } catch (error) {
209
303
  console.log(color('red', `\nāŒ Shell failed: ${error.message}`));
210
304
  process.exit(1);
package/file.txt ADDED
@@ -0,0 +1 @@
1
+ 'modified in container'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sandboxbox",
3
- "version": "2.0.7",
3
+ "version": "2.0.8",
4
4
  "description": "Portable container runner with Podman - Claude Code & Playwright support. Works on Windows, macOS, and Linux.",
5
5
  "type": "module",
6
6
  "main": "cli.js",