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 +2 -2
- package/scripts/build.js +197 -0
- package/scripts/download-bubblewrap.js +17 -3
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "sandboxbox",
|
3
|
-
"version": "1.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
|
-
"
|
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",
|
package/scripts/build.js
ADDED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
184
|
+
// Don't exit with error code 1, just warn and continue
|
185
|
+
console.log('âšī¸ SandboxBox will use system bubblewrap if available');
|
172
186
|
});
|