sandboxbox 1.2.2 â 2.0.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.
- package/README.md +180 -99
- package/cli.js +125 -162
- package/package.json +11 -12
- package/BUBBLEWRAP-REALITY.md +0 -210
- package/Dockerfile.test +0 -16
- package/USAGE.md +0 -111
- package/bin/bwrap +0 -0
- package/build-final.log +0 -2217
- package/build-output.log +0 -289
- package/complete-build.log +0 -231
- package/container.js +0 -847
- package/debug-cli.js +0 -15
- package/final-build.log +0 -268
- package/final-complete-build.log +0 -240
- package/full-build.log +0 -234
- package/init-firewall.sh +0 -36
- package/lib/bubblewrap.js +0 -203
- package/npm-build-test.log +0 -410
- package/playwright.sh +0 -183
- package/run.sh +0 -12
- package/sandboxbox-sandbox/build.sh +0 -83
- package/scripts/build.js +0 -303
- package/scripts/download-bubblewrap.js +0 -186
- package/test-cli.js +0 -72
- package/test-project/Dockerfile.sandboxbox +0 -20
@@ -1,83 +0,0 @@
|
|
1
|
-
#!/bin/bash
|
2
|
-
set -e
|
3
|
-
|
4
|
-
# Build script generated from Dockerfile
|
5
|
-
# Base image: node:20
|
6
|
-
# Total commands: 10
|
7
|
-
|
8
|
-
echo "đī¸ Starting build process..."
|
9
|
-
echo ""
|
10
|
-
|
11
|
-
|
12
|
-
# Command 1/10
|
13
|
-
echo "âī¸ [1/10] Executing: apt-get update && apt-get install -y --no-install-recommends..."
|
14
|
-
|
15
|
-
apt-get update && apt-get install -y --no-install-recommends less git procps sudo fzf zsh man-db unzip gnupg2 gh iptables ipset iproute2 dnsutils aggregate jq nano vim && apt-get clean && rm -rf /var/lib/apt/lists/*
|
16
|
-
echo " â
Command 1 completed"
|
17
|
-
echo ""
|
18
|
-
|
19
|
-
# Command 2/10
|
20
|
-
echo "âī¸ [2/10] Executing: mkdir -p /usr/local/share/npm-global && chown -R node:node ..."
|
21
|
-
|
22
|
-
mkdir -p /usr/local/share/npm-global && chown -R node:node /usr/local/share
|
23
|
-
echo " â
Command 2 completed"
|
24
|
-
echo ""
|
25
|
-
|
26
|
-
# Command 3/10
|
27
|
-
echo "âī¸ [3/10] Executing: SNIPPET="export PROMPT_COMMAND='history -a' && export HISTFI..."
|
28
|
-
|
29
|
-
SNIPPET="export PROMPT_COMMAND='history -a' && export HISTFILE=/commandhistory/.bash_history" && mkdir -p /commandhistory && touch /commandhistory/.bash_history && chown -R $USERNAME /commandhistory
|
30
|
-
echo " â
Command 3 completed"
|
31
|
-
echo ""
|
32
|
-
|
33
|
-
# Command 4/10
|
34
|
-
echo "âī¸ [4/10] Executing: mkdir -p /workspace /home/node/.claude && chown -R node:nod..."
|
35
|
-
|
36
|
-
mkdir -p /workspace /home/node/.claude && chown -R node:node /workspace /home/node/.claude
|
37
|
-
echo " â
Command 4 completed"
|
38
|
-
echo ""
|
39
|
-
|
40
|
-
# Command 5/10
|
41
|
-
echo "âī¸ [5/10] Executing: ARCH=$(dpkg --print-architecture) && wget "https://github.c..."
|
42
|
-
|
43
|
-
ARCH=$(dpkg --print-architecture) && wget "https://github.com/dandavison/delta/releases/download/${GIT_DELTA_VERSION}/git-delta_${GIT_DELTA_VERSION}_${ARCH}.deb" && sudo dpkg -i "git-delta_${GIT_DELTA_VERSION}_${ARCH}.deb" && rm "git-delta_${GIT_DELTA_VERSION}_${ARCH}.deb"
|
44
|
-
echo " â
Command 5 completed"
|
45
|
-
echo ""
|
46
|
-
|
47
|
-
# Command 6/10
|
48
|
-
echo "âī¸ [6/10] Executing: sh -c "$(wget -O- https://github.com/deluan/zsh-in-docker/re..."
|
49
|
-
# Running as user: node
|
50
|
-
sh -c "$(wget -O- https://github.com/deluan/zsh-in-docker/releases/download/v${ZSH_IN_DOCKER_VERSION}/zsh-in-docker.sh)" -- -p git -p fzf -a "source /usr/share/doc/fzf/examples/key-bindings.zsh" -a "source /usr/share/doc/fzf/examples/completion.zsh" -a "export PROMPT_COMMAND='history -a' && export HISTFILE=/commandhistory/.bash_history" -x
|
51
|
-
echo " â
Command 6 completed"
|
52
|
-
echo ""
|
53
|
-
|
54
|
-
# Command 7/10
|
55
|
-
echo "âī¸ [7/10] Executing: npm install -g @anthropic-ai/claude-code@${CLAUDE_CODE_VERSI..."
|
56
|
-
# Running as user: node
|
57
|
-
npm install -g @anthropic-ai/claude-code@${CLAUDE_CODE_VERSION}
|
58
|
-
echo " â
Command 7 completed"
|
59
|
-
echo ""
|
60
|
-
|
61
|
-
# Command 8/10
|
62
|
-
echo "âī¸ [8/10] Executing: npx --yes playwright install-deps..."
|
63
|
-
# Running as user: node
|
64
|
-
npx --yes playwright install-deps
|
65
|
-
echo " â
Command 8 completed"
|
66
|
-
echo ""
|
67
|
-
|
68
|
-
# Command 9/10
|
69
|
-
echo "âī¸ [9/10] Executing: npm i -g @playwright/mcp..."
|
70
|
-
# Running as user: node
|
71
|
-
npm i -g @playwright/mcp
|
72
|
-
echo " â
Command 9 completed"
|
73
|
-
echo ""
|
74
|
-
|
75
|
-
# Command 10/10
|
76
|
-
echo "âī¸ [10/10] Executing: chmod +x /usr/local/bin/init-firewall.sh && echo "node ALL=..."
|
77
|
-
|
78
|
-
chmod +x /usr/local/bin/init-firewall.sh && echo "node ALL=(root) NOPASSWD: /usr/local/bin/init-firewall.sh" > /etc/sudoers.d/node-firewall && chmod 0440 /etc/sudoers.d/node-firewall
|
79
|
-
echo " â
Command 10 completed"
|
80
|
-
echo ""
|
81
|
-
|
82
|
-
|
83
|
-
echo "â
Build complete!"
|
package/scripts/build.js
DELETED
@@ -1,303 +0,0 @@
|
|
1
|
-
#!/usr/bin/env node
|
2
|
-
|
3
|
-
/**
|
4
|
-
* SQLite-style build script for SandboxBox
|
5
|
-
* Downloads bubblewrap binary during npm install, with fallback to building from source
|
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
|
-
// SQLite-style approach: try binary downloads first, then build from source
|
50
|
-
if (await downloadPreBuiltBinary(binaryPath)) {
|
51
|
-
return; // Binary download succeeded
|
52
|
-
}
|
53
|
-
|
54
|
-
if (await buildFromSource(binaryPath)) {
|
55
|
-
return; // Build from source succeeded
|
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);
|
72
|
-
}
|
73
|
-
|
74
|
-
async function downloadPreBuiltBinary(binaryPath) {
|
75
|
-
console.log('đĨ Trying pre-built bubblewrap binary...');
|
76
|
-
|
77
|
-
const arch = process.arch === 'x64' ? 'x86_64' : process.arch;
|
78
|
-
const possibleUrls = [
|
79
|
-
// Alpine packages (HTTPS) - use the actual available version
|
80
|
-
`https://dl-cdn.alpinelinux.org/alpine/v3.20/main/${arch}/bubblewrap-0.10.0-r0.apk`,
|
81
|
-
// Try GitHub releases with different architectures
|
82
|
-
`https://github.com/containers/bubblewrap/releases/download/v${BWRAP_VERSION}/bubblewrap-${BWRAP_VERSION}-${arch}.tar.xz`,
|
83
|
-
`https://github.com/containers/bubblewrap/releases/download/v${BWRAP_VERSION}/bubblewrap-${BWRAP_VERSION}.tar.gz`,
|
84
|
-
];
|
85
|
-
|
86
|
-
for (const url of possibleUrls) {
|
87
|
-
try {
|
88
|
-
console.log(`đĻ Trying: ${url.split('/').pop()}`);
|
89
|
-
|
90
|
-
const response = await new Promise((resolve, reject) => {
|
91
|
-
https.get(url, (res) => {
|
92
|
-
if (res.statusCode === 200) {
|
93
|
-
resolve(res);
|
94
|
-
} else {
|
95
|
-
reject(new Error(`HTTP ${res.statusCode}`));
|
96
|
-
}
|
97
|
-
}).on('error', reject);
|
98
|
-
});
|
99
|
-
|
100
|
-
if (url.endsWith('.apk')) {
|
101
|
-
// Handle Alpine package
|
102
|
-
console.log('đĻ Alpine package found, extracting...');
|
103
|
-
return await extractAlpinePackage(url, binaryPath);
|
104
|
-
} else {
|
105
|
-
// Handle tarball
|
106
|
-
return await extractTarball(url, binaryPath);
|
107
|
-
}
|
108
|
-
} catch (error) {
|
109
|
-
console.log(`â Failed: ${error.message}`);
|
110
|
-
continue;
|
111
|
-
}
|
112
|
-
}
|
113
|
-
|
114
|
-
console.log('â No pre-built binaries available');
|
115
|
-
return false;
|
116
|
-
}
|
117
|
-
|
118
|
-
async function extractAlpinePackage(url, binaryPath) {
|
119
|
-
const tmpDir = fs.mkdtempSync(path.join(process.env.TMPDIR || '/tmp', 'apk-extract-'));
|
120
|
-
|
121
|
-
try {
|
122
|
-
const apkPath = path.join(tmpDir, 'bubblewrap.apk');
|
123
|
-
|
124
|
-
// Download APK
|
125
|
-
await new Promise((resolve, reject) => {
|
126
|
-
const file = fs.createWriteStream(apkPath);
|
127
|
-
https.get(url, (response) => {
|
128
|
-
response.pipe(file);
|
129
|
-
file.on('finish', resolve);
|
130
|
-
}).on('error', reject);
|
131
|
-
});
|
132
|
-
|
133
|
-
// Extract APK (tar.gz format)
|
134
|
-
execSync(`tar -xzf "${apkPath}" -C "${tmpDir}"`, { stdio: 'inherit' });
|
135
|
-
|
136
|
-
// Find the binary
|
137
|
-
const possiblePaths = [
|
138
|
-
path.join(tmpDir, 'usr', 'bin', 'bwrap'),
|
139
|
-
path.join(tmpDir, 'bin', 'bwrap'),
|
140
|
-
];
|
141
|
-
|
142
|
-
for (const possiblePath of possiblePaths) {
|
143
|
-
if (fs.existsSync(possiblePath)) {
|
144
|
-
fs.copyFileSync(possiblePath, binaryPath);
|
145
|
-
fs.chmodSync(binaryPath, 0o755);
|
146
|
-
console.log('â
Extracted pre-built binary from Alpine package');
|
147
|
-
return true;
|
148
|
-
}
|
149
|
-
}
|
150
|
-
|
151
|
-
throw new Error('Binary not found in package');
|
152
|
-
} finally {
|
153
|
-
fs.rmSync(tmpDir, { recursive: true, force: true });
|
154
|
-
}
|
155
|
-
}
|
156
|
-
|
157
|
-
async function extractTarball(url, binaryPath) {
|
158
|
-
const tmpDir = fs.mkdtempSync(path.join(process.env.TMPDIR || '/tmp', 'tar-extract-'));
|
159
|
-
|
160
|
-
try {
|
161
|
-
const tarballPath = path.join(tmpDir, 'bubblewrap.tar');
|
162
|
-
|
163
|
-
// Download tarball
|
164
|
-
await new Promise((resolve, reject) => {
|
165
|
-
const file = fs.createWriteStream(tarballPath);
|
166
|
-
https.get(url, (response) => {
|
167
|
-
response.pipe(file);
|
168
|
-
file.on('finish', resolve);
|
169
|
-
}).on('error', reject);
|
170
|
-
});
|
171
|
-
|
172
|
-
// Extract with available tools
|
173
|
-
if (tarballPath.endsWith('.xz')) {
|
174
|
-
try {
|
175
|
-
execSync(`tar -xf "${tarballPath}" -C "${tmpDir}"`, { stdio: 'inherit' });
|
176
|
-
} catch (e) {
|
177
|
-
throw new Error('xz extraction failed - need xz-utils');
|
178
|
-
}
|
179
|
-
} else {
|
180
|
-
execSync(`tar -xzf "${tarballPath}" -C "${tmpDir}"`, { stdio: 'inherit' });
|
181
|
-
}
|
182
|
-
|
183
|
-
// Find the binary
|
184
|
-
const possiblePaths = [
|
185
|
-
path.join(tmpDir, `bubblewrap-${BWRAP_VERSION}`, 'bwrap'),
|
186
|
-
path.join(tmpDir, 'bwrap'),
|
187
|
-
path.join(tmpDir, 'bin', 'bwrap'),
|
188
|
-
];
|
189
|
-
|
190
|
-
for (const possiblePath of possiblePaths) {
|
191
|
-
if (fs.existsSync(possiblePath)) {
|
192
|
-
fs.copyFileSync(possiblePath, binaryPath);
|
193
|
-
fs.chmodSync(binaryPath, 0o755);
|
194
|
-
console.log('â
Extracted pre-built binary');
|
195
|
-
return true;
|
196
|
-
}
|
197
|
-
}
|
198
|
-
|
199
|
-
throw new Error('Binary not found in tarball');
|
200
|
-
} finally {
|
201
|
-
fs.rmSync(tmpDir, { recursive: true, force: true });
|
202
|
-
}
|
203
|
-
}
|
204
|
-
|
205
|
-
async function buildFromSource(binaryPath) {
|
206
|
-
console.log('đ¨ Building bubblewrap from source (SQLite-style)...');
|
207
|
-
|
208
|
-
const tmpDir = fs.mkdtempSync(path.join(process.env.TMPDIR || '/tmp', 'bwrap-build-'));
|
209
|
-
|
210
|
-
try {
|
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;
|
219
|
-
}
|
220
|
-
} catch (e) {
|
221
|
-
// System bwrap not found, continue with build
|
222
|
-
}
|
223
|
-
|
224
|
-
// Clone git repository for build files
|
225
|
-
console.log('đĨ Downloading bubblewrap source from git...');
|
226
|
-
const sourceDir = path.join(tmpDir, 'bubblewrap');
|
227
|
-
|
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' });
|
232
|
-
|
233
|
-
// Check for required build tools
|
234
|
-
const missingTools = [];
|
235
|
-
try {
|
236
|
-
execSync('which gcc', { stdio: 'ignore' });
|
237
|
-
} catch (e) {
|
238
|
-
missingTools.push('gcc');
|
239
|
-
}
|
240
|
-
|
241
|
-
try {
|
242
|
-
execSync('which git', { stdio: 'ignore' });
|
243
|
-
} catch (e) {
|
244
|
-
missingTools.push('git');
|
245
|
-
}
|
246
|
-
|
247
|
-
if (missingTools.length > 0) {
|
248
|
-
console.error(`â Missing build tools: ${missingTools.join(', ')}`);
|
249
|
-
console.error('');
|
250
|
-
console.error('đĄ Install build tools:');
|
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');
|
253
|
-
console.error('');
|
254
|
-
console.error('đĢ SandboxBox requires these build tools to compile bubblewrap.');
|
255
|
-
return false;
|
256
|
-
}
|
257
|
-
|
258
|
-
// Simple compilation without autotools
|
259
|
-
console.log('đī¸ Compiling bubblewrap directly...');
|
260
|
-
try {
|
261
|
-
execSync(`
|
262
|
-
cd "${sourceDir}" &&
|
263
|
-
timeout 120 gcc -std=c99 -O2 -DHAVE_CONFIG_H=1 -o bwrap bubblewrap.c || \
|
264
|
-
gcc -std=c99 -O2 -o bwrap bubblewrap.c
|
265
|
-
`, { stdio: 'inherit' });
|
266
|
-
} catch (e) {
|
267
|
-
console.error('â Direct compilation failed');
|
268
|
-
return false;
|
269
|
-
}
|
270
|
-
|
271
|
-
// Copy binary to final location
|
272
|
-
const builtBinary = path.join(sourceDir, 'bwrap');
|
273
|
-
if (fs.existsSync(builtBinary)) {
|
274
|
-
fs.copyFileSync(builtBinary, binaryPath);
|
275
|
-
fs.chmodSync(binaryPath, 0o755);
|
276
|
-
console.log('â
Bubblewrap built successfully!');
|
277
|
-
|
278
|
-
// Test the binary
|
279
|
-
const version = execSync(`"${binaryPath}" --version`, { encoding: 'utf8' });
|
280
|
-
console.log(`đ¯ Built: ${version.trim()}`);
|
281
|
-
return true;
|
282
|
-
} else {
|
283
|
-
console.log('â Built binary not found');
|
284
|
-
return false;
|
285
|
-
}
|
286
|
-
|
287
|
-
} catch (error) {
|
288
|
-
console.log(`â Build from source failed: ${error.message}`);
|
289
|
-
return false;
|
290
|
-
} finally {
|
291
|
-
// Cleanup
|
292
|
-
fs.rmSync(tmpDir, { recursive: true, force: true });
|
293
|
-
}
|
294
|
-
}
|
295
|
-
|
296
|
-
// Run the build
|
297
|
-
downloadAndBuild().catch(error => {
|
298
|
-
console.error('â Bubblewrap build failed:', error.message);
|
299
|
-
console.error('');
|
300
|
-
console.error('đĢ SandboxBox cannot function without bubblewrap.');
|
301
|
-
console.error(' Please install build tools and try again.');
|
302
|
-
process.exit(1);
|
303
|
-
});
|
@@ -1,186 +0,0 @@
|
|
1
|
-
#!/usr/bin/env node
|
2
|
-
|
3
|
-
/**
|
4
|
-
* Download bubblewrap binary during npm install
|
5
|
-
* Makes SandboxBox completely self-contained
|
6
|
-
*/
|
7
|
-
|
8
|
-
import https from 'https';
|
9
|
-
import fs from 'fs';
|
10
|
-
import path from 'path';
|
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.8.0';
|
20
|
-
|
21
|
-
console.log('đĻ Setting up SandboxBox with bubblewrap...');
|
22
|
-
|
23
|
-
async function downloadBubblewrap() {
|
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 download on non-Linux platforms
|
32
|
-
if (process.platform !== 'linux') {
|
33
|
-
console.log('âšī¸ Skipping bubblewrap download on non-Linux platform');
|
34
|
-
console.log(' SandboxBox works on Linux only');
|
35
|
-
return;
|
36
|
-
}
|
37
|
-
|
38
|
-
// Try to use system bubblewrap first (fastest option)
|
39
|
-
try {
|
40
|
-
const systemBwrap = execSync('which bwrap', { encoding: 'utf8' }).trim();
|
41
|
-
if (systemBwrap && fs.existsSync(systemBwrap)) {
|
42
|
-
fs.copyFileSync(systemBwrap, binaryPath);
|
43
|
-
fs.chmodSync(binaryPath, 0o755);
|
44
|
-
console.log('â
Using system bubblewrap:', systemBwrap);
|
45
|
-
return;
|
46
|
-
}
|
47
|
-
} catch (e) {
|
48
|
-
// System bwrap not found, continue with download
|
49
|
-
}
|
50
|
-
|
51
|
-
// Try to download pre-built binary
|
52
|
-
const arch = process.arch === 'x64' ? 'x86_64' : process.arch;
|
53
|
-
const binaryUrl = `https://github.com/containers/bubblewrap/releases/download/v${BWRAP_VERSION}/bubblewrap-${BWRAP_VERSION}.${arch}.tar.xz`;
|
54
|
-
|
55
|
-
try {
|
56
|
-
console.log('đĨ Downloading bubblewrap binary...');
|
57
|
-
|
58
|
-
// Download with fallback
|
59
|
-
await new Promise((resolve, reject) => {
|
60
|
-
const file = fs.createWriteStream(path.join(BINARY_DIR, `bubblewrap-${BWRAP_VERSION}.tar.xz`));
|
61
|
-
|
62
|
-
https.get(binaryUrl, (response) => {
|
63
|
-
if (response.statusCode !== 200) {
|
64
|
-
reject(new Error(`HTTP ${response.statusCode}: ${response.statusMessage}`));
|
65
|
-
return;
|
66
|
-
}
|
67
|
-
|
68
|
-
response.pipe(file);
|
69
|
-
|
70
|
-
file.on('finish', () => {
|
71
|
-
file.close();
|
72
|
-
console.log('đĻ Extracting bubblewrap...');
|
73
|
-
|
74
|
-
// Extract binary
|
75
|
-
try {
|
76
|
-
execSync(`tar -xf "${path.join(BINARY_DIR, `bubblewrap-${BWRAP_VERSION}.tar.xz`)}" -C "${BINARY_DIR}" --strip-components=1`, { stdio: 'inherit' });
|
77
|
-
|
78
|
-
// Move binary to expected location
|
79
|
-
const extractedBinary = path.join(BINARY_DIR, 'bin', 'bwrap');
|
80
|
-
if (fs.existsSync(extractedBinary)) {
|
81
|
-
fs.renameSync(extractedBinary, binaryPath);
|
82
|
-
} else {
|
83
|
-
// Try alternative extraction pattern
|
84
|
-
const altBinary = path.join(BINARY_DIR, 'bubblewrap-0.8.0', 'bwrap');
|
85
|
-
if (fs.existsSync(altBinary)) {
|
86
|
-
fs.renameSync(altBinary, binaryPath);
|
87
|
-
}
|
88
|
-
}
|
89
|
-
|
90
|
-
// Set executable permissions
|
91
|
-
fs.chmodSync(binaryPath, 0o755);
|
92
|
-
|
93
|
-
// Cleanup
|
94
|
-
fs.rmSync(path.join(BINARY_DIR, `bubblewrap-${BWRAP_VERSION}.tar.xz`), { force: true });
|
95
|
-
fs.rmSync(path.join(BINARY_DIR, 'bubblewrap-0.8.0'), { recursive: true, force: true });
|
96
|
-
|
97
|
-
console.log('â
Bubblewrap downloaded successfully');
|
98
|
-
resolve();
|
99
|
-
} catch (extractError) {
|
100
|
-
reject(new Error(`Failed to extract: ${extractError.message}`));
|
101
|
-
}
|
102
|
-
});
|
103
|
-
}).on('error', reject);
|
104
|
-
});
|
105
|
-
|
106
|
-
} catch (downloadError) {
|
107
|
-
console.log('â ī¸ Download failed, trying to compile from source...');
|
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
|
-
}
|
122
|
-
}
|
123
|
-
}
|
124
|
-
|
125
|
-
async function compileBubblewrap(binaryPath) {
|
126
|
-
try {
|
127
|
-
console.log('đ¨ Compiling bubblewrap from source...');
|
128
|
-
|
129
|
-
const tmpDir = fs.mkdtempSync(path.join(process.env.TMPDIR || '/tmp', 'bwrap-build-'));
|
130
|
-
|
131
|
-
try {
|
132
|
-
// Download source
|
133
|
-
execSync(`
|
134
|
-
cd "${tmpDir}" &&
|
135
|
-
wget -q https://github.com/containers/bubblewrap/releases/download/v${BWRAP_VERSION}/bubblewrap-${BWRAP_VERSION}.tar.xz &&
|
136
|
-
tar -xf bubblewrap-${BWRAP_VERSION}.tar.xz
|
137
|
-
`, { stdio: 'inherit' });
|
138
|
-
|
139
|
-
// Build dependencies check
|
140
|
-
try {
|
141
|
-
execSync('which gcc', { stdio: 'ignore' });
|
142
|
-
} catch (e) {
|
143
|
-
console.log('â GCC not found. Please install build-essential:');
|
144
|
-
console.log(' Ubuntu/Debian: sudo apt-get install build-essential');
|
145
|
-
console.log(' CentOS/RHEL: sudo yum groupinstall "Development Tools"');
|
146
|
-
console.log(' Or install bubblewrap system-wide: sudo apt-get install bubblewrap');
|
147
|
-
process.exit(1);
|
148
|
-
}
|
149
|
-
|
150
|
-
// Compile
|
151
|
-
execSync(`
|
152
|
-
cd "${tmpDir}/bubblewrap-${BWRAP_VERSION}" &&
|
153
|
-
./configure --prefix="${tmpDir}/install" &&
|
154
|
-
make -j$(nproc 2>/dev/null || echo 4) &&
|
155
|
-
make install
|
156
|
-
`, { stdio: 'inherit' });
|
157
|
-
|
158
|
-
// Copy binary
|
159
|
-
fs.copyFileSync(path.join(tmpDir, 'install', 'bin', 'bwrap'), binaryPath);
|
160
|
-
fs.chmodSync(binaryPath, 0o755);
|
161
|
-
|
162
|
-
console.log('â
Bubblewrap compiled successfully');
|
163
|
-
|
164
|
-
} finally {
|
165
|
-
// Cleanup
|
166
|
-
fs.rmSync(tmpDir, { recursive: true, force: true });
|
167
|
-
}
|
168
|
-
|
169
|
-
} catch (compileError) {
|
170
|
-
console.log('â Failed to compile bubblewrap');
|
171
|
-
console.log('đĄ Please install bubblewrap system-wide:');
|
172
|
-
console.log(' sudo apt-get install bubblewrap # Ubuntu/Debian');
|
173
|
-
console.log(' sudo apk add bubblewrap # Alpine');
|
174
|
-
console.log(' sudo yum install bubblewrap # CentOS/RHEL');
|
175
|
-
console.log('');
|
176
|
-
console.log('Then try installing SandboxBox again.');
|
177
|
-
throw compileError; // Re-throw to let the caller handle it
|
178
|
-
}
|
179
|
-
}
|
180
|
-
|
181
|
-
// Run the download
|
182
|
-
downloadBubblewrap().catch(error => {
|
183
|
-
console.error('â Setup failed:', error.message);
|
184
|
-
// Don't exit with error code 1, just warn and continue
|
185
|
-
console.log('âšī¸ SandboxBox will use system bubblewrap if available');
|
186
|
-
});
|
package/test-cli.js
DELETED
@@ -1,72 +0,0 @@
|
|
1
|
-
#!/usr/bin/env node
|
2
|
-
|
3
|
-
console.log('đ SandboxBox test starting...');
|
4
|
-
console.log('Platform:', process.platform);
|
5
|
-
console.log('Node.js:', process.version);
|
6
|
-
|
7
|
-
const args = process.argv.slice(2);
|
8
|
-
|
9
|
-
// Handle --help and no arguments
|
10
|
-
if (args.length === 0 || args.includes('--help') || args.includes('-h')) {
|
11
|
-
showHelp();
|
12
|
-
process.exit(0);
|
13
|
-
}
|
14
|
-
|
15
|
-
// Handle version
|
16
|
-
if (args.includes('--version') || args[0] === 'version') {
|
17
|
-
console.log('SandboxBox v1.0.4');
|
18
|
-
console.log('Zero-privilege containers with Playwright support');
|
19
|
-
process.exit(0);
|
20
|
-
}
|
21
|
-
|
22
|
-
if (process.platform !== 'linux') {
|
23
|
-
console.log('â SandboxBox only works on Linux systems');
|
24
|
-
console.log('đ§ Required: Linux with bubblewrap (bwrap)');
|
25
|
-
console.log('');
|
26
|
-
console.log('đĄ Alternatives for Windows users:');
|
27
|
-
console.log(' âĸ Use WSL2 (Windows Subsystem for Linux 2)');
|
28
|
-
console.log(' âĸ Use Docker Desktop with Linux containers');
|
29
|
-
console.log(' âĸ Use GitHub Actions (ubuntu-latest runners)');
|
30
|
-
console.log(' âĸ Use a cloud Linux instance (AWS, GCP, Azure)');
|
31
|
-
console.log('');
|
32
|
-
console.log('â
On Linux/WSL2, simply run: npx sandboxbox --help');
|
33
|
-
process.exit(1);
|
34
|
-
}
|
35
|
-
|
36
|
-
console.log('â
Platform check passed - you are on Linux!');
|
37
|
-
console.log('đĻ SandboxBox - Zero-Privilege Container Runner');
|
38
|
-
console.log('âââââââââââââââââââââââââââââââââââââââââââââââââââââ');
|
39
|
-
console.log('');
|
40
|
-
console.log('â ī¸ This is a simplified test version.');
|
41
|
-
console.log('đ§ Full SandboxBox features are available on Linux systems.');
|
42
|
-
console.log('');
|
43
|
-
console.log('đ 8ms startup âĸ True isolation âĸ Playwright ready');
|
44
|
-
|
45
|
-
function showHelp() {
|
46
|
-
console.log('đĻ SandboxBox - Zero-Privilege Container Runner');
|
47
|
-
console.log('âââââââââââââââââââââââââââââââââââââââââââââââââââââ');
|
48
|
-
console.log('');
|
49
|
-
console.log('Usage: npx sandboxbox <command> [options]');
|
50
|
-
console.log('');
|
51
|
-
console.log('Commands:');
|
52
|
-
console.log(' setup Set up Alpine Linux environment (one-time)');
|
53
|
-
console.log(' build <dockerfile> Build container from Dockerfile');
|
54
|
-
console.log(' run <project-dir> Run Playwright tests in isolation');
|
55
|
-
console.log(' shell <project-dir> Start interactive shell in container');
|
56
|
-
console.log(' quick-test <project-dir> Quick test with sample Dockerfile');
|
57
|
-
console.log(' version Show version information');
|
58
|
-
console.log('');
|
59
|
-
console.log('Examples:');
|
60
|
-
console.log(' npx sandboxbox setup');
|
61
|
-
console.log(' npx sandboxbox build ./Dockerfile');
|
62
|
-
console.log(' npx sandboxbox run ./my-project');
|
63
|
-
console.log(' npx sandboxbox shell ./my-project');
|
64
|
-
console.log(' npx sandboxbox quick-test ./my-app');
|
65
|
-
console.log('');
|
66
|
-
console.log('Requirements:');
|
67
|
-
console.log(' - Linux system (WSL2 on Windows works great!)');
|
68
|
-
console.log(' - bubblewrap (bwrap): sudo apt-get install bubblewrap');
|
69
|
-
console.log(' - No root privileges needed after installation!');
|
70
|
-
console.log('');
|
71
|
-
console.log('đ 8ms startup âĸ True isolation âĸ Playwright ready');
|
72
|
-
}
|
@@ -1,20 +0,0 @@
|
|
1
|
-
# Sample Dockerfile for SandboxBox
|
2
|
-
FROM alpine
|
3
|
-
|
4
|
-
# Install Node.js and test dependencies
|
5
|
-
RUN apk add --no-cache nodejs npm
|
6
|
-
|
7
|
-
# Set working directory
|
8
|
-
WORKDIR /app
|
9
|
-
|
10
|
-
# Copy package files (if they exist)
|
11
|
-
COPY package*.json ./
|
12
|
-
|
13
|
-
# Install dependencies (if package.json exists)
|
14
|
-
RUN if [ -f package.json ]; then npm install; fi
|
15
|
-
|
16
|
-
# Copy application code
|
17
|
-
COPY . .
|
18
|
-
|
19
|
-
# Default command - run tests or start app
|
20
|
-
CMD ["npm", "test"]
|