sandboxbox 1.0.0 → 1.0.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sandboxbox",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Zero-privilege container runner with Playwright support",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -8,7 +8,7 @@
8
8
  "sandboxbox": "./cli.js"
9
9
  },
10
10
  "scripts": {
11
- "postinstall": "node scripts/download-bubblewrap.js",
11
+ "install": "node scripts/build.js",
12
12
  "start": "node cli.js",
13
13
  "setup": "node cli.js setup",
14
14
  "build": "node cli.js build",
@@ -0,0 +1,197 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * SQLite-style build script for SandboxBox
5
+ * Downloads and compiles bubblewrap binary during npm install
6
+ */
7
+
8
+ import fs from 'fs';
9
+ import path from 'path';
10
+ import https from 'https';
11
+ import { execSync } from 'child_process';
12
+ import { fileURLToPath } from 'url';
13
+ import { dirname } from 'path';
14
+
15
+ const __filename = fileURLToPath(import.meta.url);
16
+ const __dirname = dirname(__filename);
17
+
18
+ const BINARY_DIR = path.join(__dirname, '..', 'bin');
19
+ const BWRAP_VERSION = '0.11.0';
20
+
21
+ console.log('đŸ“Ļ Building SandboxBox with bubblewrap...');
22
+
23
+ async function downloadAndBuild() {
24
+ // Create binary directory
25
+ if (!fs.existsSync(BINARY_DIR)) {
26
+ fs.mkdirSync(BINARY_DIR, { recursive: true });
27
+ }
28
+
29
+ const binaryPath = path.join(BINARY_DIR, 'bwrap');
30
+
31
+ // Skip on non-Linux platforms but still create stub
32
+ if (process.platform !== 'linux') {
33
+ console.log('â„šī¸ Skipping bubblewrap build on non-Linux platform');
34
+ console.log(' SandboxBox works on Linux only');
35
+ return;
36
+ }
37
+
38
+ // Check if already built
39
+ if (fs.existsSync(binaryPath)) {
40
+ try {
41
+ execSync(`"${binaryPath}" --version`, { stdio: 'ignore' });
42
+ console.log('✅ Bubblewrap already built');
43
+ return;
44
+ } catch (e) {
45
+ console.log('âš ī¸ Existing binary broken, rebuilding...');
46
+ }
47
+ }
48
+
49
+ // Try to use system bubblewrap first (fallback option)
50
+ try {
51
+ const systemBwrap = execSync('which bwrap', { encoding: 'utf8' }).trim();
52
+ if (systemBwrap && fs.existsSync(systemBwrap)) {
53
+ fs.copyFileSync(systemBwrap, binaryPath);
54
+ fs.chmodSync(binaryPath, 0o755);
55
+ console.log('✅ Using system bubblewrap:', systemBwrap);
56
+ return;
57
+ }
58
+ } catch (e) {
59
+ // System bwrap not found, continue with build
60
+ }
61
+
62
+ // Build from source like SQLite does
63
+ await buildFromSource(binaryPath);
64
+ }
65
+
66
+ async function buildFromSource(binaryPath) {
67
+ console.log('🔨 Building bubblewrap from source (SQLite-style)...');
68
+
69
+ const tmpDir = fs.mkdtempSync(path.join(process.env.TMPDIR || '/tmp', 'bwrap-build-'));
70
+
71
+ try {
72
+ // Download source tarball
73
+ console.log('đŸ“Ĩ Downloading bubblewrap source...');
74
+ const tarball = `bubblewrap-${BWRAP_VERSION}.tar.xz`;
75
+ const tarballPath = path.join(tmpDir, tarball);
76
+ const url = `https://github.com/containers/bubblewrap/releases/download/v${BWRAP_VERSION}/${tarball}`;
77
+
78
+ await new Promise((resolve, reject) => {
79
+ const file = fs.createWriteStream(tarballPath);
80
+
81
+ function download(url) {
82
+ https.get(url, (response) => {
83
+ // Handle redirects
84
+ if (response.statusCode >= 300 && response.statusCode < 400 && response.headers.location) {
85
+ console.log(`🔄 Following redirect to: ${response.headers.location}`);
86
+ download(response.headers.location);
87
+ return;
88
+ }
89
+
90
+ if (response.statusCode !== 200) {
91
+ reject(new Error(`HTTP ${response.statusCode}: ${response.statusMessage}`));
92
+ return;
93
+ }
94
+
95
+ response.pipe(file);
96
+
97
+ file.on('finish', () => {
98
+ file.close();
99
+ resolve();
100
+ });
101
+ }).on('error', reject);
102
+ }
103
+
104
+ download(url);
105
+ });
106
+
107
+ // Extract source
108
+ console.log('đŸ“Ļ Extracting source...');
109
+ execSync(`tar -xf "${tarballPath}" -C "${tmpDir}"`, { stdio: 'inherit' });
110
+
111
+ const sourceDir = path.join(tmpDir, `bubblewrap-${BWRAP_VERSION}`);
112
+
113
+ // Check for required build tools
114
+ const missingTools = [];
115
+ try {
116
+ execSync('which gcc', { stdio: 'ignore' });
117
+ } catch (e) {
118
+ missingTools.push('gcc');
119
+ }
120
+
121
+ try {
122
+ execSync('which xz', { stdio: 'ignore' });
123
+ } catch (e) {
124
+ missingTools.push('xz');
125
+ }
126
+
127
+ if (missingTools.length > 0) {
128
+ console.log(`âš ī¸ Missing build tools: ${missingTools.join(', ')}`);
129
+ console.log(' On Ubuntu/Debian: sudo apt-get install build-essential xz-utils');
130
+ console.log(' On CentOS/RHEL: sudo yum groupinstall "Development Tools" && sudo yum install xz');
131
+ console.log(' Falling back to system bubblewrap check...');
132
+
133
+ // Create a placeholder binary that will show helpful error
134
+ const placeholderScript = `#!/bin/bash
135
+ echo "❌ Bubblewrap not available"
136
+ echo ""
137
+ echo "💡 Install bubblewrap system-wide:"
138
+ echo " sudo apt-get install bubblewrap # Ubuntu/Debian"
139
+ echo " sudo apk add bubblewrap # Alpine"
140
+ echo " sudo yum install bubblewrap # CentOS/RHEL"
141
+ echo ""
142
+ echo "Or install build tools and reinstall SandboxBox:"
143
+ echo " sudo apt-get install build-essential xz-utils"
144
+ echo " npm uninstall sandboxbox && npm install sandboxbox"
145
+ exit 1
146
+ `;
147
+ fs.writeFileSync(binaryPath, placeholderScript);
148
+ fs.chmodSync(binaryPath, 0o755);
149
+ console.log('📝 Created placeholder binary with installation instructions');
150
+ return;
151
+ }
152
+
153
+ // Configure and build
154
+ console.log('âš™ī¸ Configuring build...');
155
+ execSync(`
156
+ cd "${sourceDir}" &&
157
+ ./configure --prefix="${tmpDir}/install" --disable-man
158
+ `, { stdio: 'inherit' });
159
+
160
+ console.log('đŸ—ī¸ Compiling bubblewrap...');
161
+ execSync(`
162
+ cd "${sourceDir}" &&
163
+ make -j$(nproc 2>/dev/null || echo 4)
164
+ `, { stdio: 'inherit' });
165
+
166
+ console.log('đŸ“Ļ Installing...');
167
+ execSync(`
168
+ cd "${sourceDir}" &&
169
+ make install
170
+ `, { stdio: 'inherit' });
171
+
172
+ // Copy binary to final location
173
+ const builtBinary = path.join(tmpDir, 'install', 'bin', 'bwrap');
174
+ if (fs.existsSync(builtBinary)) {
175
+ fs.copyFileSync(builtBinary, binaryPath);
176
+ fs.chmodSync(binaryPath, 0o755);
177
+ console.log('✅ Bubblewrap built successfully!');
178
+
179
+ // Test the binary
180
+ const version = execSync(`"${binaryPath}" --version`, { encoding: 'utf8' });
181
+ console.log(`đŸŽ¯ Built: ${version.trim()}`);
182
+ } else {
183
+ throw new Error('Built binary not found');
184
+ }
185
+
186
+ } finally {
187
+ // Cleanup
188
+ fs.rmSync(tmpDir, { recursive: true, force: true });
189
+ }
190
+ }
191
+
192
+ // Run the build
193
+ downloadAndBuild().catch(error => {
194
+ console.error('❌ Build failed:', error.message);
195
+ console.log('💡 SandboxBox will still work with system bubblewrap if available');
196
+ process.exit(0); // Don't fail npm install
197
+ });
@@ -105,7 +105,20 @@ async function downloadBubblewrap() {
105
105
 
106
106
  } catch (downloadError) {
107
107
  console.log('âš ī¸ Download failed, trying to compile from source...');
108
- await compileBubblewrap(binaryPath);
108
+ try {
109
+ await compileBubblewrap(binaryPath);
110
+ } catch (compileError) {
111
+ console.log('❌ Both download and compilation failed');
112
+ console.log('');
113
+ console.log('💡 Easy solutions:');
114
+ console.log(' 1. Install system bubblewrap: sudo apt-get install bubblewrap');
115
+ console.log(' 2. Install build tools: sudo apt-get install build-essential xz-utils');
116
+ console.log(' 3. Use a Linux system with bubblewrap pre-installed');
117
+ console.log('');
118
+ console.log('SandboxBox will work with system bubblewrap if available.');
119
+ console.log('Continuing without bundled binary...');
120
+ return; // Don't exit, just continue without bundled binary
121
+ }
109
122
  }
110
123
  }
111
124
 
@@ -161,12 +174,13 @@ async function compileBubblewrap(binaryPath) {
161
174
  console.log(' sudo yum install bubblewrap # CentOS/RHEL');
162
175
  console.log('');
163
176
  console.log('Then try installing SandboxBox again.');
164
- process.exit(1);
177
+ throw compileError; // Re-throw to let the caller handle it
165
178
  }
166
179
  }
167
180
 
168
181
  // Run the download
169
182
  downloadBubblewrap().catch(error => {
170
183
  console.error('❌ Setup failed:', error.message);
171
- process.exit(1);
184
+ // Don't exit with error code 1, just warn and continue
185
+ console.log('â„šī¸ SandboxBox will use system bubblewrap if available');
172
186
  });