sandboxbox 1.1.0 → 1.2.0

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/scripts/build.js +55 -165
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sandboxbox",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Zero-privilege container runner with Playwright support",
5
5
  "type": "module",
6
6
  "main": "index.js",
package/scripts/build.js CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  /**
4
4
  * SQLite-style build script for SandboxBox
5
- * Downloads and compiles bubblewrap binary during npm install
5
+ * Downloads bubblewrap binary during npm install, with fallback to building from source
6
6
  */
7
7
 
8
8
  import fs from 'fs';
@@ -46,21 +46,29 @@ async function downloadAndBuild() {
46
46
  }
47
47
  }
48
48
 
49
- // Build from source like SQLite does - the ONLY method
49
+ // SQLite-style approach: try binary downloads first, then build from source
50
+ if (await downloadPreBuiltBinary(binaryPath)) {
51
+ return; // Binary download succeeded
52
+ }
53
+
50
54
  if (await buildFromSource(binaryPath)) {
51
- return; // Build succeeded
52
- } else {
53
- // Build failed - exit with error to make the problem visible
54
- console.error('❌ Bubblewrap build failed!');
55
- console.error('');
56
- console.error('💡 Install build tools:');
57
- console.error(' Ubuntu/Debian: sudo apt-get install build-essential autoconf automake libtool xz-utils');
58
- console.error(' CentOS/RHEL: sudo yum groupinstall "Development Tools" && sudo yum install xz');
59
- console.error('');
60
- console.error('🚫 SandboxBox cannot function without bubblewrap.');
61
- console.error(' Please install build tools and try again.');
62
- process.exit(1);
55
+ return; // Build from source succeeded
63
56
  }
57
+
58
+ // Everything failed - show clear error
59
+ console.error('❌ All bubblewrap installation methods failed!');
60
+ console.error('');
61
+ console.error('💡 Option 1 - Install system bubblewrap (recommended):');
62
+ console.error(' sudo apt-get install bubblewrap # Ubuntu/Debian');
63
+ console.error(' sudo apk add bubblewrap # Alpine');
64
+ console.error(' sudo yum install bubblewrap # CentOS/RHEL');
65
+ console.error('');
66
+ console.error('💡 Option 2 - Install build tools for compilation:');
67
+ console.error(' sudo apt-get install build-essential git autoconf automake libtool xz-utils');
68
+ console.error(' sudo yum groupinstall "Development Tools" && sudo yum install git xz');
69
+ console.error('');
70
+ console.error('🚫 SandboxBox cannot function without bubblewrap.');
71
+ process.exit(1);
64
72
  }
65
73
 
66
74
  async function downloadPreBuiltBinary(binaryPath) {
@@ -70,7 +78,7 @@ async function downloadPreBuiltBinary(binaryPath) {
70
78
  const possibleUrls = [
71
79
  // Alpine packages (HTTPS) - use the actual available version
72
80
  `https://dl-cdn.alpinelinux.org/alpine/v3.20/main/${arch}/bubblewrap-0.10.0-r0.apk`,
73
- // Try some common locations for pre-built binaries
81
+ // Try GitHub releases with different architectures
74
82
  `https://github.com/containers/bubblewrap/releases/download/v${BWRAP_VERSION}/bubblewrap-${BWRAP_VERSION}-${arch}.tar.xz`,
75
83
  `https://github.com/containers/bubblewrap/releases/download/v${BWRAP_VERSION}/bubblewrap-${BWRAP_VERSION}.tar.gz`,
76
84
  ];
@@ -200,46 +208,27 @@ async function buildFromSource(binaryPath) {
200
208
  const tmpDir = fs.mkdtempSync(path.join(process.env.TMPDIR || '/tmp', 'bwrap-build-'));
201
209
 
202
210
  try {
203
- // Download source tarball
204
- console.log('📥 Downloading bubblewrap source...');
205
- const tarball = `bubblewrap-${BWRAP_VERSION}.tar.xz`;
206
- const tarballPath = path.join(tmpDir, tarball);
207
- const url = `https://github.com/containers/bubblewrap/releases/download/v${BWRAP_VERSION}/${tarball}`;
208
-
209
- await new Promise((resolve, reject) => {
210
- const file = fs.createWriteStream(tarballPath);
211
-
212
- function download(url) {
213
- https.get(url, (response) => {
214
- // Handle redirects
215
- if (response.statusCode >= 300 && response.statusCode < 400 && response.headers.location) {
216
- console.log(`🔄 Following redirect to: ${response.headers.location}`);
217
- download(response.headers.location);
218
- return;
219
- }
220
-
221
- if (response.statusCode !== 200) {
222
- reject(new Error(`HTTP ${response.statusCode}: ${response.statusMessage}`));
223
- return;
224
- }
225
-
226
- response.pipe(file);
227
-
228
- file.on('finish', () => {
229
- file.close();
230
- resolve();
231
- });
232
- }).on('error', reject);
211
+ // Try to use system bubblewrap as fallback if available
212
+ try {
213
+ const systemBwrap = execSync('which bwrap', { encoding: 'utf8' }).trim();
214
+ if (systemBwrap && fs.existsSync(systemBwrap)) {
215
+ fs.copyFileSync(systemBwrap, binaryPath);
216
+ fs.chmodSync(binaryPath, 0o755);
217
+ console.log('✅ Using system bubblewrap:', systemBwrap);
218
+ return true;
233
219
  }
220
+ } catch (e) {
221
+ // System bwrap not found, continue with build
222
+ }
234
223
 
235
- download(url);
236
- });
237
-
238
- // Extract source
239
- console.log('📦 Extracting source...');
240
- execSync(`tar -xf "${tarballPath}" -C "${tmpDir}"`, { stdio: 'inherit' });
224
+ // Clone git repository for build files
225
+ console.log('📥 Downloading bubblewrap source from git...');
226
+ const sourceDir = path.join(tmpDir, 'bubblewrap');
241
227
 
242
- const sourceDir = path.join(tmpDir, `bubblewrap-${BWRAP_VERSION}`);
228
+ execSync(`
229
+ cd "${tmpDir}" &&
230
+ timeout 120 git clone --depth 1 --branch v${BWRAP_VERSION} https://github.com/containers/bubblewrap.git
231
+ `, { stdio: 'inherit' });
243
232
 
244
233
  // Check for required build tools
245
234
  const missingTools = [];
@@ -250,76 +239,37 @@ async function buildFromSource(binaryPath) {
250
239
  }
251
240
 
252
241
  try {
253
- execSync('which xz', { stdio: 'ignore' });
242
+ execSync('which git', { stdio: 'ignore' });
254
243
  } catch (e) {
255
- missingTools.push('xz');
256
- }
257
-
258
- try {
259
- execSync('which autoconf', { stdio: 'ignore' });
260
- } catch (e) {
261
- missingTools.push('autoconf');
262
- }
263
-
264
- try {
265
- execSync('which automake', { stdio: 'ignore' });
266
- } catch (e) {
267
- missingTools.push('automake');
268
- }
269
-
270
- try {
271
- execSync('which libtool', { stdio: 'ignore' });
272
- } catch (e) {
273
- missingTools.push('libtool');
244
+ missingTools.push('git');
274
245
  }
275
246
 
276
247
  if (missingTools.length > 0) {
277
248
  console.error(`❌ Missing build tools: ${missingTools.join(', ')}`);
278
249
  console.error('');
279
250
  console.error('💡 Install build tools:');
280
- console.error(' Ubuntu/Debian: sudo apt-get install build-essential autoconf automake libtool xz-utils');
281
- console.error(' CentOS/RHEL: sudo yum groupinstall "Development Tools" && sudo yum install xz');
251
+ console.error(' Ubuntu/Debian: sudo apt-get install build-essential git');
252
+ console.error(' CentOS/RHEL: sudo yum groupinstall "Development Tools" && sudo yum install git');
282
253
  console.error('');
283
254
  console.error('🚫 SandboxBox requires these build tools to compile bubblewrap.');
284
- return false; // Indicate build failed
285
- }
286
-
287
- // Configure and build
288
- console.log('⚙️ Configuring build...');
289
- try {
290
- execSync(`
291
- cd "${sourceDir}" &&
292
- timeout 60 ./configure --prefix="${tmpDir}/install" --disable-man
293
- `, { stdio: 'inherit' });
294
- } catch (e) {
295
- console.error('❌ Configure step failed or timed out');
296
255
  return false;
297
256
  }
298
257
 
299
- console.log('🏗️ Compiling bubblewrap...');
258
+ // Simple compilation without autotools
259
+ console.log('🏗️ Compiling bubblewrap directly...');
300
260
  try {
301
261
  execSync(`
302
262
  cd "${sourceDir}" &&
303
- timeout 300 make -j$(nproc 2>/dev/null || echo 4)
263
+ timeout 120 gcc -std=c99 -O2 -DHAVE_CONFIG_H=1 -o bwrap bubblewrap.c || \
264
+ gcc -std=c99 -O2 -o bwrap bubblewrap.c
304
265
  `, { stdio: 'inherit' });
305
266
  } catch (e) {
306
- console.error('❌ Compile step failed or timed out');
307
- return false;
308
- }
309
-
310
- console.log('📦 Installing...');
311
- try {
312
- execSync(`
313
- cd "${sourceDir}" &&
314
- timeout 60 make install
315
- `, { stdio: 'inherit' });
316
- } catch (e) {
317
- console.error('❌ Install step failed or timed out');
267
+ console.error('❌ Direct compilation failed');
318
268
  return false;
319
269
  }
320
270
 
321
271
  // Copy binary to final location
322
- const builtBinary = path.join(tmpDir, 'install', 'bin', 'bwrap');
272
+ const builtBinary = path.join(sourceDir, 'bwrap');
323
273
  if (fs.existsSync(builtBinary)) {
324
274
  fs.copyFileSync(builtBinary, binaryPath);
325
275
  fs.chmodSync(binaryPath, 0o755);
@@ -328,15 +278,15 @@ async function buildFromSource(binaryPath) {
328
278
  // Test the binary
329
279
  const version = execSync(`"${binaryPath}" --version`, { encoding: 'utf8' });
330
280
  console.log(`🎯 Built: ${version.trim()}`);
331
- return true; // Build succeeded
281
+ return true;
332
282
  } else {
333
283
  console.log('❌ Built binary not found');
334
- return false; // Build failed
284
+ return false;
335
285
  }
336
286
 
337
287
  } catch (error) {
338
288
  console.log(`❌ Build from source failed: ${error.message}`);
339
- return false; // Build failed
289
+ return false;
340
290
  } finally {
341
291
  // Cleanup
342
292
  fs.rmSync(tmpDir, { recursive: true, force: true });
@@ -350,64 +300,4 @@ downloadAndBuild().catch(error => {
350
300
  console.error('🚫 SandboxBox cannot function without bubblewrap.');
351
301
  console.error(' Please install build tools and try again.');
352
302
  process.exit(1);
353
- });
354
-
355
- function createMinimalBubblewrap(binaryPath) {
356
- console.log('🔧 Creating minimal bubblewrap fallback...');
357
-
358
- const minimalBwrap = `#!/bin/bash
359
- # Minimal bubblewrap fallback for SandboxBox
360
- # This provides basic namespace isolation functionality
361
-
362
- # Handle --version flag for compatibility
363
- if [[ "$1" == "--version" ]]; then
364
- echo "bubblewrap 0.11.0 (minimal fallback for SandboxBox)"
365
- exit 0
366
- fi
367
-
368
- # Handle --help flag
369
- if [[ "$1" == "--help" ]] || [[ "$1" == "-h" ]]; then
370
- echo "bubblewrap - minimal fallback version"
371
- echo ""
372
- echo "⚠️ This is a minimal fallback for SandboxBox"
373
- echo "💡 For full functionality, install bubblewrap:"
374
- echo " sudo apt-get install bubblewrap"
375
- echo ""
376
- echo "Usage: bwrap [options] -- command [args]"
377
- exit 0
378
- fi
379
-
380
- echo "⚠️ Using minimal bubblewrap fallback"
381
- echo "💡 For full functionality, install bubblewrap:"
382
- echo " sudo apt-get install bubblewrap"
383
- echo ""
384
-
385
- # Filter out bubblewrap-specific options that unshare doesn't support
386
- ARGS=()
387
- for arg in "$@"; do
388
- case "$arg" in
389
- --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)
390
- # Skip bubblewrap-specific options
391
- ;;
392
- *)
393
- ARGS+=("$arg")
394
- ;;
395
- esac
396
- done
397
-
398
- # Basic namespace isolation using unshare
399
- exec unshare \\
400
- --pid \\
401
- --mount \\
402
- --uts \\
403
- --ipc \\
404
- --net \\
405
- --fork \\
406
- --mount-proc \\
407
- "\${ARGS[@]}"
408
- `;
409
-
410
- fs.writeFileSync(binaryPath, minimalBwrap);
411
- fs.chmodSync(binaryPath, 0o755);
412
- console.log('✅ Created minimal bubblewrap fallback');
413
- }
303
+ });