isol8 0.1.0-alpha.2 → 0.3.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 +39 -2
- package/dist/cli.js +255 -33
- package/dist/cli.js.map +8 -6
- package/dist/index.js +157 -12
- package/dist/index.js.map +7 -6
- package/dist/src/cli.d.ts.map +1 -0
- package/dist/src/client/remote.d.ts.map +1 -0
- package/dist/src/config.d.ts.map +1 -0
- package/dist/src/engine/concurrency.d.ts.map +1 -0
- package/dist/{engine → src/engine}/docker.d.ts +26 -0
- package/dist/src/engine/docker.d.ts.map +1 -0
- package/dist/src/engine/image-builder.d.ts.map +1 -0
- package/dist/src/engine/pool.d.ts.map +1 -0
- package/dist/src/engine/utils.d.ts.map +1 -0
- package/dist/{index.d.ts → src/index.d.ts} +1 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/runtime/adapter.d.ts.map +1 -0
- package/dist/src/runtime/adapters/bash.d.ts.map +1 -0
- package/dist/src/runtime/adapters/bun.d.ts.map +1 -0
- package/dist/src/runtime/adapters/deno.d.ts.map +1 -0
- package/dist/src/runtime/adapters/node.d.ts.map +1 -0
- package/dist/src/runtime/adapters/python.d.ts.map +1 -0
- package/dist/src/runtime/index.d.ts.map +1 -0
- package/dist/src/server/auth.d.ts.map +1 -0
- package/dist/src/server/index.d.ts.map +1 -0
- package/dist/{types.d.ts → src/types.d.ts} +4 -4
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/version.d.ts +15 -0
- package/dist/src/version.d.ts.map +1 -0
- package/package.json +11 -5
- package/schema/isol8.config.schema.json +10 -0
- package/dist/cli.d.ts.map +0 -1
- package/dist/client/remote.d.ts.map +0 -1
- package/dist/config.d.ts.map +0 -1
- package/dist/engine/concurrency.d.ts.map +0 -1
- package/dist/engine/docker.d.ts.map +0 -1
- package/dist/engine/image-builder.d.ts.map +0 -1
- package/dist/engine/pool.d.ts.map +0 -1
- package/dist/engine/utils.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/runtime/adapter.d.ts.map +0 -1
- package/dist/runtime/adapters/bash.d.ts.map +0 -1
- package/dist/runtime/adapters/bun.d.ts.map +0 -1
- package/dist/runtime/adapters/deno.d.ts.map +0 -1
- package/dist/runtime/adapters/node.d.ts.map +0 -1
- package/dist/runtime/adapters/python.d.ts.map +0 -1
- package/dist/runtime/index.d.ts.map +0 -1
- package/dist/server/auth.d.ts.map +0 -1
- package/dist/server/index.d.ts.map +0 -1
- package/dist/types.d.ts.map +0 -1
- /package/dist/{cli.d.ts → src/cli.d.ts} +0 -0
- /package/dist/{client → src/client}/remote.d.ts +0 -0
- /package/dist/{config.d.ts → src/config.d.ts} +0 -0
- /package/dist/{engine → src/engine}/concurrency.d.ts +0 -0
- /package/dist/{engine → src/engine}/image-builder.d.ts +0 -0
- /package/dist/{engine → src/engine}/pool.d.ts +0 -0
- /package/dist/{engine → src/engine}/utils.d.ts +0 -0
- /package/dist/{runtime → src/runtime}/adapter.d.ts +0 -0
- /package/dist/{runtime → src/runtime}/adapters/bash.d.ts +0 -0
- /package/dist/{runtime → src/runtime}/adapters/bun.d.ts +0 -0
- /package/dist/{runtime → src/runtime}/adapters/deno.d.ts +0 -0
- /package/dist/{runtime → src/runtime}/adapters/node.d.ts +0 -0
- /package/dist/{runtime → src/runtime}/adapters/python.d.ts +0 -0
- /package/dist/{runtime → src/runtime}/index.d.ts +0 -0
- /package/dist/{server → src/server}/auth.d.ts +0 -0
- /package/dist/{server → src/server}/index.d.ts +0 -0
package/README.md
CHANGED
|
@@ -44,6 +44,14 @@ npm install isol8
|
|
|
44
44
|
- [Docker](https://docs.docker.com/get-docker/) running locally
|
|
45
45
|
- [Bun](https://bun.sh) (recommended) or Node.js 20+
|
|
46
46
|
|
|
47
|
+
### Agent Skill
|
|
48
|
+
|
|
49
|
+
AI agents can install isol8 as a skill for automatic discovery and usage:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
npx skills add Illusion47586/isol8/skill/isol8
|
|
53
|
+
```
|
|
54
|
+
|
|
47
55
|
## CLI
|
|
48
56
|
|
|
49
57
|
### `isol8 setup`
|
|
@@ -93,6 +101,7 @@ isol8 run script.py --host http://server:3000 --key my-api-key
|
|
|
93
101
|
| `--allow <regex>` | Whitelist regex (repeatable, for `filtered`) | — |
|
|
94
102
|
| `--deny <regex>` | Blacklist regex (repeatable, for `filtered`) | — |
|
|
95
103
|
| `--out <file>` | Write stdout to file | — |
|
|
104
|
+
| `--stream` | Stream output in real-time | `false` |
|
|
96
105
|
| `--persistent` | Keep container alive between runs | `false` |
|
|
97
106
|
| `--timeout <ms>` | Execution timeout in milliseconds | `30000` |
|
|
98
107
|
| `--memory <limit>` | Memory limit (e.g. `512m`, `1g`) | `512m` |
|
|
@@ -102,12 +111,25 @@ isol8 run script.py --host http://server:3000 --key my-api-key
|
|
|
102
111
|
| `--writable` | Disable read-only root filesystem | `false` |
|
|
103
112
|
| `--max-output <bytes>` | Maximum output size in bytes | `1048576` |
|
|
104
113
|
| `--secret <KEY=VALUE>` | Secret env var (repeatable, values masked) | — |
|
|
105
|
-
| `--sandbox-size <size>` | Sandbox tmpfs size (e.g. `
|
|
114
|
+
| `--sandbox-size <size>` | Sandbox tmpfs size (e.g. `512m`, `1g`) | `512m` |
|
|
115
|
+
| `--tmp-size <size>` | Tmp tmpfs size (e.g. `256m`, `512m`) | `256m` |
|
|
106
116
|
| `--stdin <data>` | Data to pipe to stdin | — |
|
|
107
117
|
| `--install <pkg>` | Install package for runtime (repeatable) | — |
|
|
108
118
|
| `--host <url>` | Remote server URL | — |
|
|
109
119
|
| `--key <key>` | API key for remote server | `$ISOL8_API_KEY` |
|
|
110
120
|
|
|
121
|
+
### `isol8 cleanup`
|
|
122
|
+
|
|
123
|
+
Remove orphaned isol8 containers.
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
# Interactive (prompts for confirmation)
|
|
127
|
+
isol8 cleanup
|
|
128
|
+
|
|
129
|
+
# Force (skip confirmation)
|
|
130
|
+
isol8 cleanup --force
|
|
131
|
+
```
|
|
132
|
+
|
|
111
133
|
### `isol8 serve`
|
|
112
134
|
|
|
113
135
|
Start the isol8 remote HTTP server. **Requires Bun runtime.**
|
|
@@ -331,13 +353,28 @@ bun run bench:detailed # Phase breakdown
|
|
|
331
353
|
|
|
332
354
|
| Layer | Protection |
|
|
333
355
|
|-------|-----------|
|
|
334
|
-
| **Filesystem** | Read-only root, writable `/sandbox` (tmpfs,
|
|
356
|
+
| **Filesystem** | Read-only root, writable `/sandbox` (tmpfs, 512MB, exec allowed), writable `/tmp` (tmpfs, 256MB, noexec) |
|
|
335
357
|
| **Processes** | PID limit (default 64), `no-new-privileges` |
|
|
336
358
|
| **Resources** | CPU (1 core), memory (512MB), execution timeout (30s) |
|
|
337
359
|
| **Network** | Disabled by default; optional proxy-based filtering |
|
|
338
360
|
| **Output** | Truncated at 1MB; secrets masked from stdout/stderr |
|
|
339
361
|
| **Isolation** | Each execution in its own container (ephemeral) or exec (persistent) |
|
|
340
362
|
|
|
363
|
+
### Container Filesystem
|
|
364
|
+
|
|
365
|
+
Containers use two tmpfs mounts:
|
|
366
|
+
|
|
367
|
+
1. **`/sandbox`** (default: 512MB, configurable via `--sandbox-size` or config)
|
|
368
|
+
- Working directory for code execution
|
|
369
|
+
- Package installations stored here (`.local`, `.npm-global`, etc.)
|
|
370
|
+
- Allows execution (`exec` flag) for shared libraries like numpy's `.so` files
|
|
371
|
+
- User files and outputs
|
|
372
|
+
|
|
373
|
+
2. **`/tmp`** (default: 256MB, configurable via `--tmp-size` or config)
|
|
374
|
+
- Temporary files and caches
|
|
375
|
+
- No execution allowed (`noexec` flag) for security
|
|
376
|
+
- Used during package installation
|
|
377
|
+
|
|
341
378
|
## REST API
|
|
342
379
|
|
|
343
380
|
When running `isol8 serve`, these endpoints are available:
|
package/dist/cli.js
CHANGED
|
@@ -24360,6 +24360,115 @@ var require_browser = __commonJS((exports, module) => {
|
|
|
24360
24360
|
};
|
|
24361
24361
|
});
|
|
24362
24362
|
|
|
24363
|
+
// node_modules/has-flag/index.js
|
|
24364
|
+
var require_has_flag = __commonJS((exports, module) => {
|
|
24365
|
+
module.exports = (flag, argv = process.argv) => {
|
|
24366
|
+
const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
|
|
24367
|
+
const position = argv.indexOf(prefix + flag);
|
|
24368
|
+
const terminatorPosition = argv.indexOf("--");
|
|
24369
|
+
return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
|
|
24370
|
+
};
|
|
24371
|
+
});
|
|
24372
|
+
|
|
24373
|
+
// node_modules/supports-color/index.js
|
|
24374
|
+
var require_supports_color = __commonJS((exports, module) => {
|
|
24375
|
+
var os = __require("os");
|
|
24376
|
+
var tty = __require("tty");
|
|
24377
|
+
var hasFlag = require_has_flag();
|
|
24378
|
+
var { env } = process;
|
|
24379
|
+
var forceColor;
|
|
24380
|
+
if (hasFlag("no-color") || hasFlag("no-colors") || hasFlag("color=false") || hasFlag("color=never")) {
|
|
24381
|
+
forceColor = 0;
|
|
24382
|
+
} else if (hasFlag("color") || hasFlag("colors") || hasFlag("color=true") || hasFlag("color=always")) {
|
|
24383
|
+
forceColor = 1;
|
|
24384
|
+
}
|
|
24385
|
+
if ("FORCE_COLOR" in env) {
|
|
24386
|
+
if (env.FORCE_COLOR === "true") {
|
|
24387
|
+
forceColor = 1;
|
|
24388
|
+
} else if (env.FORCE_COLOR === "false") {
|
|
24389
|
+
forceColor = 0;
|
|
24390
|
+
} else {
|
|
24391
|
+
forceColor = env.FORCE_COLOR.length === 0 ? 1 : Math.min(parseInt(env.FORCE_COLOR, 10), 3);
|
|
24392
|
+
}
|
|
24393
|
+
}
|
|
24394
|
+
function translateLevel(level) {
|
|
24395
|
+
if (level === 0) {
|
|
24396
|
+
return false;
|
|
24397
|
+
}
|
|
24398
|
+
return {
|
|
24399
|
+
level,
|
|
24400
|
+
hasBasic: true,
|
|
24401
|
+
has256: level >= 2,
|
|
24402
|
+
has16m: level >= 3
|
|
24403
|
+
};
|
|
24404
|
+
}
|
|
24405
|
+
function supportsColor(haveStream, streamIsTTY) {
|
|
24406
|
+
if (forceColor === 0) {
|
|
24407
|
+
return 0;
|
|
24408
|
+
}
|
|
24409
|
+
if (hasFlag("color=16m") || hasFlag("color=full") || hasFlag("color=truecolor")) {
|
|
24410
|
+
return 3;
|
|
24411
|
+
}
|
|
24412
|
+
if (hasFlag("color=256")) {
|
|
24413
|
+
return 2;
|
|
24414
|
+
}
|
|
24415
|
+
if (haveStream && !streamIsTTY && forceColor === undefined) {
|
|
24416
|
+
return 0;
|
|
24417
|
+
}
|
|
24418
|
+
const min = forceColor || 0;
|
|
24419
|
+
if (env.TERM === "dumb") {
|
|
24420
|
+
return min;
|
|
24421
|
+
}
|
|
24422
|
+
if (process.platform === "win32") {
|
|
24423
|
+
const osRelease = os.release().split(".");
|
|
24424
|
+
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
|
|
24425
|
+
return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
24426
|
+
}
|
|
24427
|
+
return 1;
|
|
24428
|
+
}
|
|
24429
|
+
if ("CI" in env) {
|
|
24430
|
+
if (["TRAVIS", "CIRCLECI", "APPVEYOR", "GITLAB_CI", "GITHUB_ACTIONS", "BUILDKITE"].some((sign) => (sign in env)) || env.CI_NAME === "codeship") {
|
|
24431
|
+
return 1;
|
|
24432
|
+
}
|
|
24433
|
+
return min;
|
|
24434
|
+
}
|
|
24435
|
+
if ("TEAMCITY_VERSION" in env) {
|
|
24436
|
+
return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0;
|
|
24437
|
+
}
|
|
24438
|
+
if (env.COLORTERM === "truecolor") {
|
|
24439
|
+
return 3;
|
|
24440
|
+
}
|
|
24441
|
+
if ("TERM_PROGRAM" in env) {
|
|
24442
|
+
const version = parseInt((env.TERM_PROGRAM_VERSION || "").split(".")[0], 10);
|
|
24443
|
+
switch (env.TERM_PROGRAM) {
|
|
24444
|
+
case "iTerm.app":
|
|
24445
|
+
return version >= 3 ? 3 : 2;
|
|
24446
|
+
case "Apple_Terminal":
|
|
24447
|
+
return 2;
|
|
24448
|
+
}
|
|
24449
|
+
}
|
|
24450
|
+
if (/-256(color)?$/i.test(env.TERM)) {
|
|
24451
|
+
return 2;
|
|
24452
|
+
}
|
|
24453
|
+
if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) {
|
|
24454
|
+
return 1;
|
|
24455
|
+
}
|
|
24456
|
+
if ("COLORTERM" in env) {
|
|
24457
|
+
return 1;
|
|
24458
|
+
}
|
|
24459
|
+
return min;
|
|
24460
|
+
}
|
|
24461
|
+
function getSupportLevel(stream) {
|
|
24462
|
+
const level = supportsColor(stream, stream && stream.isTTY);
|
|
24463
|
+
return translateLevel(level);
|
|
24464
|
+
}
|
|
24465
|
+
module.exports = {
|
|
24466
|
+
supportsColor: getSupportLevel,
|
|
24467
|
+
stdout: translateLevel(supportsColor(true, tty.isatty(1))),
|
|
24468
|
+
stderr: translateLevel(supportsColor(true, tty.isatty(2)))
|
|
24469
|
+
};
|
|
24470
|
+
});
|
|
24471
|
+
|
|
24363
24472
|
// node_modules/debug/src/node.js
|
|
24364
24473
|
var require_node2 = __commonJS((exports, module) => {
|
|
24365
24474
|
var tty = __require("tty");
|
|
@@ -24373,7 +24482,7 @@ var require_node2 = __commonJS((exports, module) => {
|
|
|
24373
24482
|
exports.destroy = util.deprecate(() => {}, "Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.");
|
|
24374
24483
|
exports.colors = [6, 2, 3, 4, 5, 1];
|
|
24375
24484
|
try {
|
|
24376
|
-
const supportsColor = (
|
|
24485
|
+
const supportsColor = require_supports_color();
|
|
24377
24486
|
if (supportsColor && (supportsColor.stderr || supportsColor).level >= 2) {
|
|
24378
24487
|
exports.colors = [
|
|
24379
24488
|
20,
|
|
@@ -54701,8 +54810,8 @@ var init_config = __esm(() => {
|
|
|
54701
54810
|
memoryLimit: "512m",
|
|
54702
54811
|
cpuLimit: 1,
|
|
54703
54812
|
network: "none",
|
|
54704
|
-
sandboxSize: "
|
|
54705
|
-
tmpSize: "
|
|
54813
|
+
sandboxSize: "512m",
|
|
54814
|
+
tmpSize: "256m"
|
|
54706
54815
|
},
|
|
54707
54816
|
network: {
|
|
54708
54817
|
whitelist: [],
|
|
@@ -55184,11 +55293,11 @@ function wrapWithTimeout(cmd, timeoutSec) {
|
|
|
55184
55293
|
function getInstallCommand(runtime, packages) {
|
|
55185
55294
|
switch (runtime) {
|
|
55186
55295
|
case "python":
|
|
55187
|
-
return ["pip", "install", "--no-cache-dir", "--break-system-packages", ...packages];
|
|
55296
|
+
return ["pip", "install", "--user", "--no-cache-dir", "--break-system-packages", ...packages];
|
|
55188
55297
|
case "node":
|
|
55189
|
-
return ["npm", "install", "-g", ...packages];
|
|
55298
|
+
return ["npm", "install", "-g", "--prefix=/sandbox/.npm-global", ...packages];
|
|
55190
55299
|
case "bun":
|
|
55191
|
-
return ["bun", "install", "-g", ...packages];
|
|
55300
|
+
return ["bun", "install", "-g", "--global-dir=/sandbox/.bun-global", ...packages];
|
|
55192
55301
|
case "deno":
|
|
55193
55302
|
return ["sh", "-c", packages.map((p) => `deno cache ${p}`).join(" && ")];
|
|
55194
55303
|
case "bash":
|
|
@@ -55200,10 +55309,23 @@ function getInstallCommand(runtime, packages) {
|
|
|
55200
55309
|
async function installPackages(container, runtime, packages) {
|
|
55201
55310
|
const cmd = getInstallCommand(runtime, packages);
|
|
55202
55311
|
console.error(`[DEBUG] Installing packages: ${JSON.stringify(cmd)}`);
|
|
55312
|
+
const env2 = [
|
|
55313
|
+
"PATH=/sandbox/.local/bin:/sandbox/.npm-global/bin:/sandbox/.bun-global/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin"
|
|
55314
|
+
];
|
|
55315
|
+
if (runtime === "python") {
|
|
55316
|
+
env2.push("PYTHONUSERBASE=/sandbox/.local");
|
|
55317
|
+
} else if (runtime === "node") {
|
|
55318
|
+
env2.push("NPM_CONFIG_PREFIX=/sandbox/.npm-global");
|
|
55319
|
+
env2.push("NPM_CONFIG_CACHE=/sandbox/.npm-cache");
|
|
55320
|
+
env2.push("npm_config_cache=/sandbox/.npm-cache");
|
|
55321
|
+
} else if (runtime === "deno") {
|
|
55322
|
+
env2.push("DENO_DIR=/sandbox/.deno");
|
|
55323
|
+
}
|
|
55203
55324
|
const exec = await container.exec({
|
|
55204
55325
|
Cmd: cmd,
|
|
55205
55326
|
AttachStdout: true,
|
|
55206
|
-
AttachStderr: true
|
|
55327
|
+
AttachStderr: true,
|
|
55328
|
+
Env: env2
|
|
55207
55329
|
});
|
|
55208
55330
|
const stream = await exec.start({ Detach: false, Tty: false });
|
|
55209
55331
|
return new Promise((resolve2, reject) => {
|
|
@@ -55263,8 +55385,8 @@ class DockerIsol8 {
|
|
|
55263
55385
|
this.defaultTimeoutMs = options.timeoutMs ?? 30000;
|
|
55264
55386
|
this.overrideImage = options.image;
|
|
55265
55387
|
this.semaphore = new Semaphore(maxConcurrent);
|
|
55266
|
-
this.sandboxSize = options.sandboxSize ?? "
|
|
55267
|
-
this.tmpSize = options.tmpSize ?? "
|
|
55388
|
+
this.sandboxSize = options.sandboxSize ?? "512m";
|
|
55389
|
+
this.tmpSize = options.tmpSize ?? "256m";
|
|
55268
55390
|
}
|
|
55269
55391
|
async start() {}
|
|
55270
55392
|
async stop() {
|
|
@@ -55577,8 +55699,8 @@ class DockerIsol8 {
|
|
|
55577
55699
|
PidsLimit: this.pidsLimit,
|
|
55578
55700
|
ReadonlyRootfs: this.readonlyRootFs,
|
|
55579
55701
|
Tmpfs: {
|
|
55580
|
-
"/tmp": `rw,noexec,nosuid,size=${this.tmpSize}`,
|
|
55581
|
-
[SANDBOX_WORKDIR]: `rw,size=${this.sandboxSize}`
|
|
55702
|
+
"/tmp": `rw,noexec,nosuid,nodev,size=${this.tmpSize}`,
|
|
55703
|
+
[SANDBOX_WORKDIR]: `rw,exec,nosuid,nodev,size=${this.sandboxSize}`
|
|
55582
55704
|
},
|
|
55583
55705
|
SecurityOpt: ["no-new-privileges"]
|
|
55584
55706
|
};
|
|
@@ -55592,7 +55714,11 @@ class DockerIsol8 {
|
|
|
55592
55714
|
buildEnv(extra) {
|
|
55593
55715
|
const env2 = [
|
|
55594
55716
|
"PYTHONUNBUFFERED=1",
|
|
55595
|
-
"
|
|
55717
|
+
"PYTHONUSERBASE=/sandbox/.local",
|
|
55718
|
+
"NPM_CONFIG_PREFIX=/sandbox/.npm-global",
|
|
55719
|
+
"DENO_DIR=/sandbox/.deno",
|
|
55720
|
+
"PATH=/sandbox/.local/bin:/sandbox/.npm-global/bin:/sandbox/.bun-global/bin:/usr/local/bin:/usr/bin:/bin",
|
|
55721
|
+
"NODE_PATH=/usr/local/lib/node_modules:/sandbox/.npm-global/lib/node_modules:/sandbox/node_modules"
|
|
55596
55722
|
];
|
|
55597
55723
|
for (const [key, value] of Object.entries(this.secrets)) {
|
|
55598
55724
|
env2.push(`${key}=${value}`);
|
|
@@ -55731,6 +55857,26 @@ class DockerIsol8 {
|
|
|
55731
55857
|
}
|
|
55732
55858
|
return result.trimEnd();
|
|
55733
55859
|
}
|
|
55860
|
+
static async cleanup(docker) {
|
|
55861
|
+
const dockerInstance = docker ?? new import_dockerode.default;
|
|
55862
|
+
const containers = await dockerInstance.listContainers({ all: true });
|
|
55863
|
+
const isol8Containers = containers.filter((c) => c.Image.startsWith("isol8:") || c.Image.startsWith("isol8-custom:"));
|
|
55864
|
+
let removed = 0;
|
|
55865
|
+
let failed = 0;
|
|
55866
|
+
const errors = [];
|
|
55867
|
+
for (const containerInfo of isol8Containers) {
|
|
55868
|
+
try {
|
|
55869
|
+
const container = dockerInstance.getContainer(containerInfo.Id);
|
|
55870
|
+
await container.remove({ force: true });
|
|
55871
|
+
removed++;
|
|
55872
|
+
} catch (err) {
|
|
55873
|
+
failed++;
|
|
55874
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
55875
|
+
errors.push(`${containerInfo.Id.slice(0, 12)}: ${errorMsg}`);
|
|
55876
|
+
}
|
|
55877
|
+
}
|
|
55878
|
+
return { removed, failed, errors };
|
|
55879
|
+
}
|
|
55734
55880
|
}
|
|
55735
55881
|
var import_dockerode, SANDBOX_WORKDIR = "/sandbox", MAX_OUTPUT_BYTES, PROXY_PORT = 8118, PROXY_STARTUP_TIMEOUT_MS = 5000, PROXY_POLL_INTERVAL_MS = 100;
|
|
55736
55882
|
var init_docker = __esm(() => {
|
|
@@ -58079,7 +58225,7 @@ function mimicFunction(to, from, { ignoreNonConfigurable = false } = {}) {
|
|
|
58079
58225
|
return to;
|
|
58080
58226
|
}
|
|
58081
58227
|
|
|
58082
|
-
// node_modules/onetime/index.js
|
|
58228
|
+
// node_modules/restore-cursor/node_modules/onetime/index.js
|
|
58083
58229
|
var calledFunctions = new WeakMap;
|
|
58084
58230
|
var onetime = (function_, options = {}) => {
|
|
58085
58231
|
if (typeof function_ !== "function") {
|
|
@@ -61077,7 +61223,7 @@ program2.command("setup").description("Check Docker and build isol8 images").opt
|
|
|
61077
61223
|
console.log(`
|
|
61078
61224
|
[DONE] Setup complete!`);
|
|
61079
61225
|
});
|
|
61080
|
-
program2.command("run").description("Execute code in isol8").argument("[file]", "Script file to execute").option("-e, --eval <code>", "Execute inline code string").option("-r, --runtime <name>", "Force runtime (python, node, bun, deno, bash)").option("--net <mode>", "Network mode: none, host, filtered", "none").option("--allow <regex>", "Whitelist regex for filtered mode (repeatable)", collect, []).option("--deny <regex>", "Blacklist regex for filtered mode (repeatable)", collect, []).option("--out <file>", "Write output to file").option("--persistent", "Use persistent container").option("--timeout <ms>", "Execution timeout in milliseconds").option("--memory <limit>", "Memory limit (e.g. 512m, 1g)").option("--cpu <limit>", "CPU limit as fraction (e.g. 0.5, 2.0)").option("--image <name>", "Override Docker image").option("--pids-limit <n>", "Maximum number of processes").option("--writable", "Disable read-only root filesystem").option("--max-output <bytes>", "Maximum output size in bytes").option("--secret <KEY=VALUE>", "Secret env var (repeatable, values masked)", collect, []).option("--sandbox-size <size>", "Sandbox tmpfs size (e.g. 128m)").option("--stdin <data>", "Data to pipe to stdin").option("--install <package>", "Install package for runtime (repeatable)", collect, []).option("--host <url>", "Execute on remote server").option("--key <key>", "API key for remote server").action(async (file, opts) => {
|
|
61226
|
+
program2.command("run").description("Execute code in isol8").argument("[file]", "Script file to execute").option("-e, --eval <code>", "Execute inline code string").option("-r, --runtime <name>", "Force runtime (python, node, bun, deno, bash)").option("--net <mode>", "Network mode: none, host, filtered", "none").option("--allow <regex>", "Whitelist regex for filtered mode (repeatable)", collect, []).option("--deny <regex>", "Blacklist regex for filtered mode (repeatable)", collect, []).option("--out <file>", "Write output to file").option("--persistent", "Use persistent container").option("--timeout <ms>", "Execution timeout in milliseconds").option("--memory <limit>", "Memory limit (e.g. 512m, 1g)").option("--cpu <limit>", "CPU limit as fraction (e.g. 0.5, 2.0)").option("--image <name>", "Override Docker image").option("--pids-limit <n>", "Maximum number of processes").option("--writable", "Disable read-only root filesystem").option("--max-output <bytes>", "Maximum output size in bytes").option("--secret <KEY=VALUE>", "Secret env var (repeatable, values masked)", collect, []).option("--sandbox-size <size>", "Sandbox tmpfs size (e.g. 128m)").option("--tmp-size <size>", "Tmp tmpfs size (e.g. 256m, 512m)").option("--stdin <data>", "Data to pipe to stdin").option("--install <package>", "Install package for runtime (repeatable)", collect, []).option("--host <url>", "Execute on remote server").option("--key <key>", "API key for remote server").option("--stream", "Stream output in real-time").action(async (file, opts) => {
|
|
61081
61227
|
const { code, runtime, engineOptions, engine, stdinData } = await resolveRunInput(file, opts);
|
|
61082
61228
|
const spinner = ora("Starting execution...").start();
|
|
61083
61229
|
try {
|
|
@@ -61090,23 +61236,42 @@ program2.command("run").description("Execute code in isol8").argument("[file]",
|
|
|
61090
61236
|
...stdinData ? { stdin: stdinData } : {},
|
|
61091
61237
|
...opts.install.length > 0 ? { installPackages: opts.install } : {}
|
|
61092
61238
|
};
|
|
61093
|
-
|
|
61094
|
-
|
|
61095
|
-
|
|
61096
|
-
|
|
61097
|
-
|
|
61098
|
-
|
|
61099
|
-
|
|
61100
|
-
|
|
61101
|
-
|
|
61102
|
-
|
|
61103
|
-
|
|
61104
|
-
|
|
61105
|
-
|
|
61106
|
-
|
|
61107
|
-
|
|
61108
|
-
|
|
61109
|
-
|
|
61239
|
+
if (opts.stream) {
|
|
61240
|
+
spinner.stop();
|
|
61241
|
+
const stream = engine.executeStream(req);
|
|
61242
|
+
for await (const event of stream) {
|
|
61243
|
+
if (event.type === "stdout") {
|
|
61244
|
+
process.stdout.write(event.data);
|
|
61245
|
+
} else if (event.type === "stderr") {
|
|
61246
|
+
process.stderr.write(event.data);
|
|
61247
|
+
} else if (event.type === "exit") {
|
|
61248
|
+
if (event.data !== "0") {
|
|
61249
|
+
process.exit(Number.parseInt(event.data, 10));
|
|
61250
|
+
}
|
|
61251
|
+
} else if (event.type === "error") {
|
|
61252
|
+
console.error(`[ERR] ${event.data}`);
|
|
61253
|
+
process.exit(1);
|
|
61254
|
+
}
|
|
61255
|
+
}
|
|
61256
|
+
} else {
|
|
61257
|
+
const result = await engine.execute(req);
|
|
61258
|
+
spinner.stop();
|
|
61259
|
+
if (result.stdout) {
|
|
61260
|
+
console.log(result.stdout);
|
|
61261
|
+
}
|
|
61262
|
+
if (result.stderr) {
|
|
61263
|
+
console.error(result.stderr);
|
|
61264
|
+
}
|
|
61265
|
+
if (result.truncated) {
|
|
61266
|
+
console.error("[WARN] Output was truncated");
|
|
61267
|
+
}
|
|
61268
|
+
if (opts.out && result.stdout) {
|
|
61269
|
+
writeFileSync(opts.out, result.stdout, "utf-8");
|
|
61270
|
+
console.error(`[INFO] Output written to ${opts.out}`);
|
|
61271
|
+
}
|
|
61272
|
+
if (result.exitCode !== 0) {
|
|
61273
|
+
process.exit(result.exitCode);
|
|
61274
|
+
}
|
|
61110
61275
|
}
|
|
61111
61276
|
} catch (err) {
|
|
61112
61277
|
spinner.stop();
|
|
@@ -61166,6 +61331,8 @@ Isol8 Configuration
|
|
|
61166
61331
|
console.log(` Memory limit: ${config.defaults.memoryLimit}`);
|
|
61167
61332
|
console.log(` CPU limit: ${config.defaults.cpuLimit}`);
|
|
61168
61333
|
console.log(` Network: ${config.defaults.network}`);
|
|
61334
|
+
console.log(` Sandbox size: ${config.defaults.sandboxSize}`);
|
|
61335
|
+
console.log(` Tmp size: ${config.defaults.tmpSize}`);
|
|
61169
61336
|
console.log("");
|
|
61170
61337
|
console.log(" ── Network Filter ──");
|
|
61171
61338
|
if (config.network.whitelist.length > 0) {
|
|
@@ -61204,6 +61371,60 @@ Isol8 Configuration
|
|
|
61204
61371
|
}
|
|
61205
61372
|
console.log("");
|
|
61206
61373
|
});
|
|
61374
|
+
program2.command("cleanup").description("Remove orphaned isol8 containers").option("--force", "Skip confirmation prompt").action(async (opts) => {
|
|
61375
|
+
const docker = new import_dockerode2.default;
|
|
61376
|
+
const spinner = ora("Checking Docker...").start();
|
|
61377
|
+
try {
|
|
61378
|
+
await docker.ping();
|
|
61379
|
+
spinner.succeed("Docker is running");
|
|
61380
|
+
} catch {
|
|
61381
|
+
spinner.fail("Docker is not running or not installed.");
|
|
61382
|
+
process.exit(1);
|
|
61383
|
+
}
|
|
61384
|
+
spinner.start("Finding isol8 containers...");
|
|
61385
|
+
const containers = await docker.listContainers({ all: true });
|
|
61386
|
+
const isol8Containers = containers.filter((c) => c.Image.startsWith("isol8:") || c.Image.startsWith("isol8-custom:"));
|
|
61387
|
+
if (isol8Containers.length === 0) {
|
|
61388
|
+
spinner.info("No isol8 containers found");
|
|
61389
|
+
return;
|
|
61390
|
+
}
|
|
61391
|
+
spinner.succeed(`Found ${isol8Containers.length} isol8 container(s)`);
|
|
61392
|
+
console.log("");
|
|
61393
|
+
for (const c of isol8Containers) {
|
|
61394
|
+
const status = c.State === "running" ? "\uD83D\uDFE2 running" : "⚪ stopped";
|
|
61395
|
+
const created = new Date(c.Created * 1000).toLocaleString();
|
|
61396
|
+
console.log(` ${status} ${c.Id.slice(0, 12)} | ${c.Image} | created ${created}`);
|
|
61397
|
+
}
|
|
61398
|
+
console.log("");
|
|
61399
|
+
if (!opts.force) {
|
|
61400
|
+
const readline = await import("node:readline");
|
|
61401
|
+
const rl = readline.createInterface({
|
|
61402
|
+
input: process.stdin,
|
|
61403
|
+
output: process.stdout
|
|
61404
|
+
});
|
|
61405
|
+
const answer = await new Promise((resolve3) => {
|
|
61406
|
+
rl.question("Remove all these containers? [y/N] ", resolve3);
|
|
61407
|
+
});
|
|
61408
|
+
rl.close();
|
|
61409
|
+
if (answer.toLowerCase() !== "y" && answer.toLowerCase() !== "yes") {
|
|
61410
|
+
console.log("Cleanup cancelled");
|
|
61411
|
+
return;
|
|
61412
|
+
}
|
|
61413
|
+
}
|
|
61414
|
+
spinner.start("Removing containers...");
|
|
61415
|
+
const result = await DockerIsol8.cleanup(docker);
|
|
61416
|
+
if (result.errors.length > 0) {
|
|
61417
|
+
console.log("");
|
|
61418
|
+
for (const err of result.errors) {
|
|
61419
|
+
console.error(` Failed to remove ${err}`);
|
|
61420
|
+
}
|
|
61421
|
+
}
|
|
61422
|
+
if (result.failed === 0) {
|
|
61423
|
+
spinner.succeed(`Removed ${result.removed} container(s)`);
|
|
61424
|
+
} else {
|
|
61425
|
+
spinner.warn(`Removed ${result.removed} container(s), ${result.failed} failed`);
|
|
61426
|
+
}
|
|
61427
|
+
});
|
|
61207
61428
|
async function resolveRunInput(file, opts) {
|
|
61208
61429
|
const config = loadConfig();
|
|
61209
61430
|
let code;
|
|
@@ -61250,7 +61471,8 @@ async function resolveRunInput(file, opts) {
|
|
|
61250
61471
|
...opts.pidsLimit ? { pidsLimit: Number.parseInt(opts.pidsLimit, 10) } : {},
|
|
61251
61472
|
...opts.writable ? { readonlyRootFs: false } : {},
|
|
61252
61473
|
...opts.maxOutput ? { maxOutputSize: Number.parseInt(opts.maxOutput, 10) } : {},
|
|
61253
|
-
...opts.sandboxSize ? { sandboxSize: opts.sandboxSize } : {}
|
|
61474
|
+
...opts.sandboxSize ? { sandboxSize: opts.sandboxSize } : {},
|
|
61475
|
+
...opts.tmpSize ? { tmpSize: opts.tmpSize } : {}
|
|
61254
61476
|
};
|
|
61255
61477
|
const secrets = {};
|
|
61256
61478
|
for (const s of opts.secret ?? []) {
|
|
@@ -61285,4 +61507,4 @@ if (!process.argv.slice(2).length) {
|
|
|
61285
61507
|
}
|
|
61286
61508
|
program2.parse();
|
|
61287
61509
|
|
|
61288
|
-
//# debugId=
|
|
61510
|
+
//# debugId=1EC5CA4C4BAF17C964756E2164756E21
|