sandboxbox 1.0.6 → 1.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/bin/bwrap ADDED
@@ -0,0 +1,50 @@
1
+ #!/bin/bash
2
+ # Minimal bubblewrap fallback for SandboxBox
3
+ # This provides basic namespace isolation functionality
4
+
5
+ # Handle --version flag for compatibility
6
+ if [[ "$1" == "--version" ]]; then
7
+ echo "bubblewrap 0.11.0 (minimal fallback for SandboxBox)"
8
+ exit 0
9
+ fi
10
+
11
+ # Handle --help flag
12
+ if [[ "$1" == "--help" ]] || [[ "$1" == "-h" ]]; then
13
+ echo "bubblewrap - minimal fallback version"
14
+ echo ""
15
+ echo "⚠️ This is a minimal fallback for SandboxBox"
16
+ echo "💡 For full functionality, install bubblewrap:"
17
+ echo " sudo apt-get install bubblewrap"
18
+ echo ""
19
+ echo "Usage: bwrap [options] -- command [args]"
20
+ exit 0
21
+ fi
22
+
23
+ echo "⚠️ Using minimal bubblewrap fallback"
24
+ echo "💡 For full functionality, install bubblewrap:"
25
+ echo " sudo apt-get install bubblewrap"
26
+ echo ""
27
+
28
+ # Filter out bubblewrap-specific options that unshare doesn't support
29
+ ARGS=()
30
+ for arg in "$@"; do
31
+ case "$arg" in
32
+ --ro-bind|--bind|--dev-bind|--proc|--tmpfs|--symlink|--dir|--file|--setenv|--die-with-parent|--new-session|--share-net|--unshare-net|--unshare-pid|--unshare-ipc|--unshare-uts|--unshare-cgroup|--unshare-user)
33
+ # Skip bubblewrap-specific options
34
+ ;;
35
+ *)
36
+ ARGS+=("$arg")
37
+ ;;
38
+ esac
39
+ done
40
+
41
+ # Basic namespace isolation using unshare
42
+ exec unshare \
43
+ --pid \
44
+ --mount \
45
+ --uts \
46
+ --ipc \
47
+ --net \
48
+ --fork \
49
+ --mount-proc \
50
+ "${ARGS[@]}"
package/cli.js CHANGED
@@ -248,22 +248,20 @@ async function main() {
248
248
  }
249
249
 
250
250
  // Run if called directly
251
- if (import.meta.url === `file://${process.argv[1]}`) {
252
- main().catch(error => {
253
- console.error('❌ SandboxBox failed to start:');
254
- console.error('Error:', error.message);
255
- console.error('');
256
- console.error('💡 This might be because:');
257
- console.error(' • You are not on Linux (SandboxBox requires Linux)');
258
- console.error(' • Node.js version compatibility issue');
259
- console.error(' • Missing dependencies during installation');
260
- console.error('');
261
- console.error('📋 System information:');
262
- console.error(` Platform: ${process.platform}`);
263
- console.error(` Node.js: ${process.version}`);
264
- console.error(` Architecture: ${process.arch}`);
265
- console.error('');
266
- console.error('🔧 Try: npx sandboxbox --help');
267
- process.exit(1);
268
- });
269
- }
251
+ main().catch(error => {
252
+ console.error('❌ SandboxBox failed to start:');
253
+ console.error('Error:', error.message);
254
+ console.error('');
255
+ console.error('💡 This might be because:');
256
+ console.error(' You are not on Linux (SandboxBox requires Linux)');
257
+ console.error(' • Node.js version compatibility issue');
258
+ console.error(' • Missing dependencies during installation');
259
+ console.error('');
260
+ console.error('📋 System information:');
261
+ console.error(` Platform: ${process.platform}`);
262
+ console.error(` Node.js: ${process.version}`);
263
+ console.error(` Architecture: ${process.arch}`);
264
+ console.error('');
265
+ console.error('🔧 Try: npx sandboxbox --help');
266
+ process.exit(1);
267
+ });
package/debug-cli.js ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env node
2
+
3
+ console.log('🚀 Debug CLI starting...');
4
+ console.log('Args:', process.argv.slice(2));
5
+ console.log('Platform:', process.platform);
6
+ console.log('CWD:', process.cwd());
7
+
8
+ // Test basic output
9
+ console.log('✅ Basic output works');
10
+
11
+ // Test if script continues
12
+ setTimeout(() => {
13
+ console.log('✅ Script completed after timeout');
14
+ process.exit(0);
15
+ }, 1000);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sandboxbox",
3
- "version": "1.0.6",
3
+ "version": "1.0.8",
4
4
  "description": "Zero-privilege container runner with Playwright support",
5
5
  "type": "module",
6
6
  "main": "index.js",
package/scripts/build.js CHANGED
@@ -59,10 +59,146 @@ async function downloadAndBuild() {
59
59
  // System bwrap not found, continue with build
60
60
  }
61
61
 
62
- // Build from source like SQLite does
62
+ // Try to download pre-built binary first
63
+ if (await downloadPreBuiltBinary(binaryPath)) {
64
+ return;
65
+ }
66
+
67
+ // Build from source like SQLite does as last resort
63
68
  await buildFromSource(binaryPath);
64
69
  }
65
70
 
71
+ async function downloadPreBuiltBinary(binaryPath) {
72
+ console.log('📥 Trying pre-built bubblewrap binary...');
73
+
74
+ const arch = process.arch === 'x64' ? 'x86_64' : process.arch;
75
+ const possibleUrls = [
76
+ // Alpine packages (HTTPS) - use the actual available version
77
+ `https://dl-cdn.alpinelinux.org/alpine/v3.20/main/${arch}/bubblewrap-0.10.0-r0.apk`,
78
+ // Try some common locations for pre-built binaries
79
+ `https://github.com/containers/bubblewrap/releases/download/v${BWRAP_VERSION}/bubblewrap-${BWRAP_VERSION}-${arch}.tar.xz`,
80
+ `https://github.com/containers/bubblewrap/releases/download/v${BWRAP_VERSION}/bubblewrap-${BWRAP_VERSION}.tar.gz`,
81
+ ];
82
+
83
+ for (const url of possibleUrls) {
84
+ try {
85
+ console.log(`📦 Trying: ${url.split('/').pop()}`);
86
+
87
+ const response = await new Promise((resolve, reject) => {
88
+ https.get(url, (res) => {
89
+ if (res.statusCode === 200) {
90
+ resolve(res);
91
+ } else {
92
+ reject(new Error(`HTTP ${res.statusCode}`));
93
+ }
94
+ }).on('error', reject);
95
+ });
96
+
97
+ if (url.endsWith('.apk')) {
98
+ // Handle Alpine package
99
+ console.log('📦 Alpine package found, extracting...');
100
+ return await extractAlpinePackage(url, binaryPath);
101
+ } else {
102
+ // Handle tarball
103
+ return await extractTarball(url, binaryPath);
104
+ }
105
+ } catch (error) {
106
+ console.log(`❌ Failed: ${error.message}`);
107
+ continue;
108
+ }
109
+ }
110
+
111
+ console.log('❌ No pre-built binaries available');
112
+ return false;
113
+ }
114
+
115
+ async function extractAlpinePackage(url, binaryPath) {
116
+ const tmpDir = fs.mkdtempSync(path.join(process.env.TMPDIR || '/tmp', 'apk-extract-'));
117
+
118
+ try {
119
+ const apkPath = path.join(tmpDir, 'bubblewrap.apk');
120
+
121
+ // Download APK
122
+ await new Promise((resolve, reject) => {
123
+ const file = fs.createWriteStream(apkPath);
124
+ https.get(url, (response) => {
125
+ response.pipe(file);
126
+ file.on('finish', resolve);
127
+ }).on('error', reject);
128
+ });
129
+
130
+ // Extract APK (tar.gz format)
131
+ execSync(`tar -xzf "${apkPath}" -C "${tmpDir}"`, { stdio: 'inherit' });
132
+
133
+ // Find the binary
134
+ const possiblePaths = [
135
+ path.join(tmpDir, 'usr', 'bin', 'bwrap'),
136
+ path.join(tmpDir, 'bin', 'bwrap'),
137
+ ];
138
+
139
+ for (const possiblePath of possiblePaths) {
140
+ if (fs.existsSync(possiblePath)) {
141
+ fs.copyFileSync(possiblePath, binaryPath);
142
+ fs.chmodSync(binaryPath, 0o755);
143
+ console.log('✅ Extracted pre-built binary from Alpine package');
144
+ return true;
145
+ }
146
+ }
147
+
148
+ throw new Error('Binary not found in package');
149
+ } finally {
150
+ fs.rmSync(tmpDir, { recursive: true, force: true });
151
+ }
152
+ }
153
+
154
+ async function extractTarball(url, binaryPath) {
155
+ const tmpDir = fs.mkdtempSync(path.join(process.env.TMPDIR || '/tmp', 'tar-extract-'));
156
+
157
+ try {
158
+ const tarballPath = path.join(tmpDir, 'bubblewrap.tar');
159
+
160
+ // Download tarball
161
+ await new Promise((resolve, reject) => {
162
+ const file = fs.createWriteStream(tarballPath);
163
+ https.get(url, (response) => {
164
+ response.pipe(file);
165
+ file.on('finish', resolve);
166
+ }).on('error', reject);
167
+ });
168
+
169
+ // Extract with available tools
170
+ if (tarballPath.endsWith('.xz')) {
171
+ try {
172
+ execSync(`tar -xf "${tarballPath}" -C "${tmpDir}"`, { stdio: 'inherit' });
173
+ } catch (e) {
174
+ throw new Error('xz extraction failed - need xz-utils');
175
+ }
176
+ } else {
177
+ execSync(`tar -xzf "${tarballPath}" -C "${tmpDir}"`, { stdio: 'inherit' });
178
+ }
179
+
180
+ // Find the binary
181
+ const possiblePaths = [
182
+ path.join(tmpDir, `bubblewrap-${BWRAP_VERSION}`, 'bwrap'),
183
+ path.join(tmpDir, 'bwrap'),
184
+ path.join(tmpDir, 'bin', 'bwrap'),
185
+ ];
186
+
187
+ for (const possiblePath of possiblePaths) {
188
+ if (fs.existsSync(possiblePath)) {
189
+ fs.copyFileSync(possiblePath, binaryPath);
190
+ fs.chmodSync(binaryPath, 0o755);
191
+ console.log('✅ Extracted pre-built binary');
192
+ return true;
193
+ }
194
+ }
195
+
196
+ throw new Error('Binary not found in tarball');
197
+ } finally {
198
+ fs.rmSync(tmpDir, { recursive: true, force: true });
199
+ }
200
+ }
201
+
66
202
  async function buildFromSource(binaryPath) {
67
203
  console.log('🔨 Building bubblewrap from source (SQLite-style)...');
68
204
 
@@ -193,5 +329,68 @@ exit 1
193
329
  downloadAndBuild().catch(error => {
194
330
  console.error('❌ Build failed:', error.message);
195
331
  console.log('💡 SandboxBox will still work with system bubblewrap if available');
332
+
333
+ // Create a minimal fallback as last resort
334
+ createMinimalBubblewrap(path.join(BINARY_DIR, 'bwrap'));
196
335
  process.exit(0); // Don't fail npm install
197
- });
336
+ });
337
+
338
+ function createMinimalBubblewrap(binaryPath) {
339
+ console.log('🔧 Creating minimal bubblewrap fallback...');
340
+
341
+ const minimalBwrap = `#!/bin/bash
342
+ # Minimal bubblewrap fallback for SandboxBox
343
+ # This provides basic namespace isolation functionality
344
+
345
+ # Handle --version flag for compatibility
346
+ if [[ "$1" == "--version" ]]; then
347
+ echo "bubblewrap 0.11.0 (minimal fallback for SandboxBox)"
348
+ exit 0
349
+ fi
350
+
351
+ # Handle --help flag
352
+ if [[ "$1" == "--help" ]] || [[ "$1" == "-h" ]]; then
353
+ echo "bubblewrap - minimal fallback version"
354
+ echo ""
355
+ echo "⚠️ This is a minimal fallback for SandboxBox"
356
+ echo "💡 For full functionality, install bubblewrap:"
357
+ echo " sudo apt-get install bubblewrap"
358
+ echo ""
359
+ echo "Usage: bwrap [options] -- command [args]"
360
+ exit 0
361
+ fi
362
+
363
+ echo "⚠️ Using minimal bubblewrap fallback"
364
+ echo "💡 For full functionality, install bubblewrap:"
365
+ echo " sudo apt-get install bubblewrap"
366
+ echo ""
367
+
368
+ # Filter out bubblewrap-specific options that unshare doesn't support
369
+ ARGS=()
370
+ for arg in "$@"; do
371
+ case "$arg" in
372
+ --ro-bind|--bind|--dev-bind|--proc|--tmpfs|--symlink|--dir|--file|--setenv|--die-with-parent|--new-session|--share-net|--unshare-net|--unshare-pid|--unshare-ipc|--unshare-uts|--unshare-cgroup|--unshare-user)
373
+ # Skip bubblewrap-specific options
374
+ ;;
375
+ *)
376
+ ARGS+=("$arg")
377
+ ;;
378
+ esac
379
+ done
380
+
381
+ # Basic namespace isolation using unshare
382
+ exec unshare \\
383
+ --pid \\
384
+ --mount \\
385
+ --uts \\
386
+ --ipc \\
387
+ --net \\
388
+ --fork \\
389
+ --mount-proc \\
390
+ "\${ARGS[@]}"
391
+ `;
392
+
393
+ fs.writeFileSync(binaryPath, minimalBwrap);
394
+ fs.chmodSync(binaryPath, 0o755);
395
+ console.log('✅ Created minimal bubblewrap fallback');
396
+ }