isol8 0.4.1 → 0.4.3
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 +3 -2
- package/dist/cli.js +32 -15
- package/dist/cli.js.map +7 -7
- package/dist/index.js +14 -8
- package/dist/index.js.map +6 -6
- package/dist/src/engine/docker.d.ts.map +1 -1
- package/dist/src/runtime/adapter.d.ts +4 -1
- package/dist/src/runtime/adapter.d.ts.map +1 -1
- package/dist/src/types.d.ts +5 -0
- package/dist/src/types.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,8 +11,9 @@ Secure code execution engine for AI agents. Run untrusted Python, Node.js, Bun,
|
|
|
11
11
|
- **Security first** — read-only rootfs, `no-new-privileges`, PID/memory/CPU limits
|
|
12
12
|
- **Network control** — `none` (default), `host`, or `filtered` (HTTP/HTTPS proxy with regex whitelist/blacklist)
|
|
13
13
|
- **File I/O** — upload files into and download files from sandboxes
|
|
14
|
-
-
|
|
15
|
-
-
|
|
14
|
+
- **Runtime packages** — install pip/npm/bun packages on-the-fly (`--install`)
|
|
15
|
+
- **Modern Node.js** — defaults to ESM (`.mjs`), supports CommonJS (`.cjs`)
|
|
16
|
+
- **Secret masking** — environment variables are scrubbed from output
|
|
16
17
|
- **Output truncation** — prevents runaway stdout (default 1MB cap)
|
|
17
18
|
- **Remote mode** — run an HTTP server and execute from anywhere
|
|
18
19
|
- **Embeddable** — use as a TypeScript library in your own project
|
package/dist/cli.js
CHANGED
|
@@ -54831,9 +54831,12 @@ var init_adapter = __esm(() => {
|
|
|
54831
54831
|
adapters = new Map;
|
|
54832
54832
|
extensionMap = new Map;
|
|
54833
54833
|
RuntimeRegistry = {
|
|
54834
|
-
register(adapter) {
|
|
54834
|
+
register(adapter, aliases = []) {
|
|
54835
54835
|
adapters.set(adapter.name, adapter);
|
|
54836
54836
|
extensionMap.set(adapter.getFileExtension(), adapter);
|
|
54837
|
+
for (const ext of aliases) {
|
|
54838
|
+
extensionMap.set(ext, adapter);
|
|
54839
|
+
}
|
|
54837
54840
|
},
|
|
54838
54841
|
get(name) {
|
|
54839
54842
|
const adapter = adapters.get(name);
|
|
@@ -54931,7 +54934,7 @@ var init_node = __esm(() => {
|
|
|
54931
54934
|
return ["node", "-e", code];
|
|
54932
54935
|
},
|
|
54933
54936
|
getFileExtension() {
|
|
54934
|
-
return ".
|
|
54937
|
+
return ".mjs";
|
|
54935
54938
|
}
|
|
54936
54939
|
};
|
|
54937
54940
|
});
|
|
@@ -54969,7 +54972,7 @@ var init_runtime = __esm(() => {
|
|
|
54969
54972
|
init_node();
|
|
54970
54973
|
init_python();
|
|
54971
54974
|
RuntimeRegistry.register(PythonAdapter);
|
|
54972
|
-
RuntimeRegistry.register(NodeAdapter);
|
|
54975
|
+
RuntimeRegistry.register(NodeAdapter, [".js", ".cjs"]);
|
|
54973
54976
|
RuntimeRegistry.register(BunAdapter);
|
|
54974
54977
|
RuntimeRegistry.register(bashAdapter);
|
|
54975
54978
|
RuntimeRegistry.register(DenoAdapter);
|
|
@@ -55464,7 +55467,8 @@ class DockerIsol8 {
|
|
|
55464
55467
|
if (this.network === "filtered") {
|
|
55465
55468
|
await startProxy(container, this.networkFilter);
|
|
55466
55469
|
}
|
|
55467
|
-
const
|
|
55470
|
+
const ext = req.fileExtension ?? adapter.getFileExtension();
|
|
55471
|
+
const filePath = `${SANDBOX_WORKDIR}/main${ext}`;
|
|
55468
55472
|
await writeFileViaExec(container, filePath, req.code);
|
|
55469
55473
|
if (req.installPackages?.length) {
|
|
55470
55474
|
await installPackages(container, req.runtime, req.installPackages);
|
|
@@ -55538,7 +55542,8 @@ class DockerIsol8 {
|
|
|
55538
55542
|
if (this.network === "filtered") {
|
|
55539
55543
|
await startProxy(container, this.networkFilter);
|
|
55540
55544
|
}
|
|
55541
|
-
const
|
|
55545
|
+
const ext = req.fileExtension ?? adapter.getFileExtension();
|
|
55546
|
+
const filePath = `${SANDBOX_WORKDIR}/main${ext}`;
|
|
55542
55547
|
await writeFileViaExec(container, filePath, req.code);
|
|
55543
55548
|
if (req.installPackages?.length) {
|
|
55544
55549
|
await installPackages(container, req.runtime, req.installPackages);
|
|
@@ -55595,7 +55600,8 @@ class DockerIsol8 {
|
|
|
55595
55600
|
} else if (this.persistentRuntime?.name !== adapter.name) {
|
|
55596
55601
|
throw new Error(`Cannot switch runtime from "${this.persistentRuntime?.name}" to "${adapter.name}". Each persistent container supports a single runtime. Create a new Isol8 instance for a different runtime.`);
|
|
55597
55602
|
}
|
|
55598
|
-
const
|
|
55603
|
+
const ext = req.fileExtension ?? adapter.getFileExtension();
|
|
55604
|
+
const filePath = `${SANDBOX_WORKDIR}/exec_${Date.now()}${ext}`;
|
|
55599
55605
|
if (this.readonlyRootFs) {
|
|
55600
55606
|
await writeFileViaExec(this.container, filePath, req.code);
|
|
55601
55607
|
} else {
|
|
@@ -61226,7 +61232,7 @@ program2.command("setup").description("Check Docker and build isol8 images").opt
|
|
|
61226
61232
|
[DONE] Setup complete!`);
|
|
61227
61233
|
});
|
|
61228
61234
|
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("--no-stream", "Disable real-time output streaming").action(async (file, opts) => {
|
|
61229
|
-
const { code, runtime, engineOptions, engine, stdinData } = await resolveRunInput(file, opts);
|
|
61235
|
+
const { code, runtime, engineOptions, engine, stdinData, fileExtension } = await resolveRunInput(file, opts);
|
|
61230
61236
|
const cleanup = async () => {
|
|
61231
61237
|
await engine.stop();
|
|
61232
61238
|
process.exit(0);
|
|
@@ -61234,6 +61240,7 @@ program2.command("run").description("Execute code in isol8").argument("[file]",
|
|
|
61234
61240
|
process.on("SIGINT", cleanup);
|
|
61235
61241
|
process.on("SIGTERM", cleanup);
|
|
61236
61242
|
const spinner = ora("Starting execution...").start();
|
|
61243
|
+
let exitCode = 0;
|
|
61237
61244
|
try {
|
|
61238
61245
|
await engine.start();
|
|
61239
61246
|
spinner.text = "Running code...";
|
|
@@ -61242,7 +61249,8 @@ program2.command("run").description("Execute code in isol8").argument("[file]",
|
|
|
61242
61249
|
runtime,
|
|
61243
61250
|
timeoutMs: engineOptions.timeoutMs,
|
|
61244
61251
|
...stdinData ? { stdin: stdinData } : {},
|
|
61245
|
-
...opts.install.length > 0 ? { installPackages: opts.install } : {}
|
|
61252
|
+
...opts.install.length > 0 ? { installPackages: opts.install } : {},
|
|
61253
|
+
fileExtension
|
|
61246
61254
|
};
|
|
61247
61255
|
if (opts.stream !== false) {
|
|
61248
61256
|
spinner.stop();
|
|
@@ -61254,11 +61262,11 @@ program2.command("run").description("Execute code in isol8").argument("[file]",
|
|
|
61254
61262
|
process.stderr.write(event.data);
|
|
61255
61263
|
} else if (event.type === "exit") {
|
|
61256
61264
|
if (event.data !== "0") {
|
|
61257
|
-
|
|
61265
|
+
exitCode = Number.parseInt(event.data, 10);
|
|
61258
61266
|
}
|
|
61259
61267
|
} else if (event.type === "error") {
|
|
61260
61268
|
console.error(`[ERR] ${event.data}`);
|
|
61261
|
-
|
|
61269
|
+
exitCode = 1;
|
|
61262
61270
|
}
|
|
61263
61271
|
}
|
|
61264
61272
|
} else {
|
|
@@ -61278,16 +61286,19 @@ program2.command("run").description("Execute code in isol8").argument("[file]",
|
|
|
61278
61286
|
console.error(`[INFO] Output written to ${opts.out}`);
|
|
61279
61287
|
}
|
|
61280
61288
|
if (result.exitCode !== 0) {
|
|
61281
|
-
|
|
61289
|
+
exitCode = result.exitCode;
|
|
61282
61290
|
}
|
|
61283
61291
|
}
|
|
61284
61292
|
} catch (err) {
|
|
61285
61293
|
spinner.stop();
|
|
61286
61294
|
throw err;
|
|
61287
61295
|
} finally {
|
|
61288
|
-
|
|
61296
|
+
const cleanupPromise = engine.stop();
|
|
61297
|
+
const timeoutPromise = new Promise((resolve3) => setTimeout(resolve3, 5000));
|
|
61298
|
+
await Promise.race([cleanupPromise, timeoutPromise]);
|
|
61289
61299
|
process.off("SIGINT", cleanup);
|
|
61290
61300
|
process.off("SIGTERM", cleanup);
|
|
61301
|
+
process.exit(exitCode);
|
|
61291
61302
|
}
|
|
61292
61303
|
});
|
|
61293
61304
|
program2.command("serve").description("Start the isol8 remote server").option("-p, --port <port>", "Port to listen on", "3000").option("-k, --key <key>", "API key for authentication").action(async (opts) => {
|
|
@@ -61481,9 +61492,15 @@ async function resolveRunInput(file, opts) {
|
|
|
61481
61492
|
...opts.pidsLimit ? { pidsLimit: Number.parseInt(opts.pidsLimit, 10) } : {},
|
|
61482
61493
|
...opts.writable ? { readonlyRootFs: false } : {},
|
|
61483
61494
|
...opts.maxOutput ? { maxOutputSize: Number.parseInt(opts.maxOutput, 10) } : {},
|
|
61484
|
-
...opts.sandboxSize ? { sandboxSize: opts.sandboxSize } : {},
|
|
61485
61495
|
...opts.tmpSize ? { tmpSize: opts.tmpSize } : {}
|
|
61486
61496
|
};
|
|
61497
|
+
let fileExtension;
|
|
61498
|
+
if (file) {
|
|
61499
|
+
const ext = file.substring(file.lastIndexOf("."));
|
|
61500
|
+
if (ext) {
|
|
61501
|
+
fileExtension = ext;
|
|
61502
|
+
}
|
|
61503
|
+
}
|
|
61487
61504
|
const secrets = {};
|
|
61488
61505
|
for (const s of opts.secret ?? []) {
|
|
61489
61506
|
const idx = s.indexOf("=");
|
|
@@ -61506,7 +61523,7 @@ async function resolveRunInput(file, opts) {
|
|
|
61506
61523
|
} else {
|
|
61507
61524
|
engine = new DockerIsol8(engineOptions, config.maxConcurrent);
|
|
61508
61525
|
}
|
|
61509
|
-
return { code, runtime, engineOptions, engine, stdinData };
|
|
61526
|
+
return { code, runtime, engineOptions, engine, stdinData, fileExtension };
|
|
61510
61527
|
}
|
|
61511
61528
|
function collect(value, previous) {
|
|
61512
61529
|
return previous.concat([value]);
|
|
@@ -61517,4 +61534,4 @@ if (!process.argv.slice(2).length) {
|
|
|
61517
61534
|
}
|
|
61518
61535
|
program2.parse();
|
|
61519
61536
|
|
|
61520
|
-
//# debugId=
|
|
61537
|
+
//# debugId=E455279A70D3A2C764756E2164756E21
|