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 +50 -0
- package/cli.js +17 -19
- package/debug-cli.js +15 -0
- package/package.json +1 -1
- package/scripts/build.js +201 -2
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
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
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
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
|
-
//
|
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
|
+
}
|