isol8 0.6.2 → 0.7.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 +22 -16
- package/dist/cli.js +87 -20
- package/dist/docker/Dockerfile +4 -2
- package/dist/docker/seccomp-profile.json +67 -0
- package/dist/index.js +72 -10
- package/dist/src/config.d.ts.map +1 -1
- package/dist/src/engine/docker.d.ts +3 -0
- package/dist/src/engine/docker.d.ts.map +1 -1
- package/dist/src/engine/pool.d.ts +3 -2
- package/dist/src/engine/pool.d.ts.map +1 -1
- package/dist/src/types.d.ts +20 -0
- package/dist/src/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/schema/isol8.config.schema.json +20 -0
package/README.md
CHANGED
|
@@ -177,7 +177,7 @@ const result = await isol8.execute({
|
|
|
177
177
|
|
|
178
178
|
console.log(result.stdout); // "Hello from isol8!"
|
|
179
179
|
console.log(result.exitCode); // 0
|
|
180
|
-
console.log(result.durationMs); // ~
|
|
180
|
+
console.log(result.durationMs); // ~38-69ms (warm pool)
|
|
181
181
|
|
|
182
182
|
await isol8.stop();
|
|
183
183
|
```
|
|
@@ -304,9 +304,14 @@ Add the `$schema` property to get autocompletion, validation, and inline documen
|
|
|
304
304
|
"autoPrune": true,
|
|
305
305
|
"maxContainerAgeMs": 3600000
|
|
306
306
|
},
|
|
307
|
+
"dependencies": {
|
|
308
|
+
"python": ["numpy", "pandas"],
|
|
307
309
|
"dependencies": {
|
|
308
310
|
"python": ["numpy", "pandas"],
|
|
309
311
|
"node": ["lodash"]
|
|
312
|
+
},
|
|
313
|
+
"security": {
|
|
314
|
+
"seccomp": "safety"
|
|
310
315
|
}
|
|
311
316
|
}
|
|
312
317
|
```
|
|
@@ -323,11 +328,11 @@ Each run creates a new `DockerIsol8` instance, executes, and tears down.
|
|
|
323
328
|
|
|
324
329
|
| Runtime | Min | Median | Max | Avg |
|
|
325
330
|
|---------|-----|--------|-----|-----|
|
|
326
|
-
| Python |
|
|
327
|
-
| Node.js |
|
|
328
|
-
| Bun |
|
|
329
|
-
| Deno |
|
|
330
|
-
| Bash |
|
|
331
|
+
| Python | 111ms | 120ms | 188ms | 140ms |
|
|
332
|
+
| Node.js | 114ms | 126ms | 178ms | 130ms |
|
|
333
|
+
| Bun | 104ms | 121ms | 196ms | 139ms |
|
|
334
|
+
| Deno | 112ms | 122ms | 199ms | 139ms |
|
|
335
|
+
| Bash | 104ms | 114ms | 152ms | 121ms |
|
|
331
336
|
|
|
332
337
|
### Warm Pool (reused engine)
|
|
333
338
|
|
|
@@ -335,11 +340,11 @@ A single `DockerIsol8` instance reused across 5 runs. The first run is cold (poo
|
|
|
335
340
|
|
|
336
341
|
| Runtime | Cold | Warm Avg | Warm Min | Speedup |
|
|
337
342
|
|---------|------|----------|----------|---------|
|
|
338
|
-
| Python |
|
|
339
|
-
| Node.js |
|
|
340
|
-
| Bun |
|
|
341
|
-
| Deno |
|
|
342
|
-
| Bash |
|
|
343
|
+
| Python | 198ms | 56ms | 49ms | 4.1x |
|
|
344
|
+
| Node.js | 145ms | 69ms | 60ms | 2.4x |
|
|
345
|
+
| Bun | 152ms | 51ms | 45ms | 3.4x |
|
|
346
|
+
| Deno | 128ms | 62ms | 54ms | 2.4x |
|
|
347
|
+
| Bash | 124ms | 43ms | 38ms | 3.3x |
|
|
343
348
|
|
|
344
349
|
### Execution Phase Breakdown
|
|
345
350
|
|
|
@@ -347,10 +352,10 @@ Where time is spent in the container lifecycle (raw Docker API, no pool):
|
|
|
347
352
|
|
|
348
353
|
| Runtime | Create | Start | Write | Exec Setup | Run | Cleanup | Total |
|
|
349
354
|
|---------|--------|-------|-------|------------|-----|---------|-------|
|
|
350
|
-
| Python |
|
|
351
|
-
| Node.js |
|
|
352
|
-
| Bun |
|
|
353
|
-
| Bash |
|
|
355
|
+
| Python | 69ms | 52ms | 19ms | 1ms | 22ms | 51ms | 213ms |
|
|
356
|
+
| Node.js | 47ms | 41ms | 15ms | 1ms | 30ms | 36ms | 169ms |
|
|
357
|
+
| Bun | 55ms | 42ms | 15ms | 1ms | 18ms | 37ms | 166ms |
|
|
358
|
+
| Bash | 50ms | 50ms | 14ms | 1ms | 13ms | 43ms | 172ms |
|
|
354
359
|
|
|
355
360
|
Run benchmarks yourself:
|
|
356
361
|
|
|
@@ -365,11 +370,12 @@ bun run bench:detailed # Phase breakdown
|
|
|
365
370
|
| Layer | Protection |
|
|
366
371
|
|-------|-----------|
|
|
367
372
|
| **Filesystem** | Read-only root, writable `/sandbox` (tmpfs, 512MB, exec allowed), writable `/tmp` (tmpfs, 256MB, noexec) |
|
|
368
|
-
| **Processes** | PID limit (default 64), `no-new-privileges` |
|
|
373
|
+
| **Processes** | PID limit (default 64), `no-new-privileges`, non-root `sandbox` user, all user processes killed between pool reuses |
|
|
369
374
|
| **Resources** | CPU (1 core), memory (512MB), execution timeout (30s) |
|
|
370
375
|
| **Network** | Disabled by default; optional proxy-based filtering |
|
|
371
376
|
| **Output** | Truncated at 1MB; secrets masked from stdout/stderr |
|
|
372
377
|
| **Isolation** | Each execution in its own container (ephemeral) or exec (persistent) |
|
|
378
|
+
| **Seccomp** | Default "safety" profile blocks dangerous syscalls (mount, swap, ptrace) but allows others for compatibility; configurable via `security.seccomp` |
|
|
373
379
|
|
|
374
380
|
### Container Filesystem
|
|
375
381
|
|
package/dist/cli.js
CHANGED
|
@@ -6929,6 +6929,11 @@ var require_utils2 = __commonJS((exports, module) => {
|
|
|
6929
6929
|
};
|
|
6930
6930
|
});
|
|
6931
6931
|
|
|
6932
|
+
// node_modules/ssh2/lib/protocol/crypto/build/Release/sshcrypto.node
|
|
6933
|
+
var require_sshcrypto = __commonJS((exports, module) => {
|
|
6934
|
+
module.exports = __require("./sshcrypto-0209sx47.node");
|
|
6935
|
+
});
|
|
6936
|
+
|
|
6932
6937
|
// node_modules/ssh2/lib/protocol/crypto/poly1305.js
|
|
6933
6938
|
var require_poly1305 = __commonJS((exports, module) => {
|
|
6934
6939
|
var __dirname = "/home/runner/work/isol8/isol8/node_modules/ssh2/lib/protocol/crypto", __filename = "/home/runner/work/isol8/isol8/node_modules/ssh2/lib/protocol/crypto/poly1305.js";
|
|
@@ -7415,7 +7420,7 @@ var require_crypto = __commonJS((exports, module) => {
|
|
|
7415
7420
|
var ChaChaPolyDecipher;
|
|
7416
7421
|
var GenericDecipher;
|
|
7417
7422
|
try {
|
|
7418
|
-
binding = (
|
|
7423
|
+
binding = require_sshcrypto();
|
|
7419
7424
|
({
|
|
7420
7425
|
AESGCMCipher,
|
|
7421
7426
|
ChaChaPolyCipher,
|
|
@@ -54794,6 +54799,10 @@ function mergeConfig(defaults, overrides) {
|
|
|
54794
54799
|
...defaults.dependencies,
|
|
54795
54800
|
...overrides.dependencies
|
|
54796
54801
|
},
|
|
54802
|
+
security: {
|
|
54803
|
+
seccomp: overrides.security?.seccomp ?? defaults.security.seccomp,
|
|
54804
|
+
customProfilePath: overrides.security?.customProfilePath ?? defaults.security.customProfilePath
|
|
54805
|
+
},
|
|
54797
54806
|
debug: overrides.debug ?? defaults.debug
|
|
54798
54807
|
};
|
|
54799
54808
|
}
|
|
@@ -54818,6 +54827,9 @@ var init_config = __esm(() => {
|
|
|
54818
54827
|
maxContainerAgeMs: 3600000
|
|
54819
54828
|
},
|
|
54820
54829
|
dependencies: {},
|
|
54830
|
+
security: {
|
|
54831
|
+
seccomp: "strict"
|
|
54832
|
+
},
|
|
54821
54833
|
debug: false
|
|
54822
54834
|
};
|
|
54823
54835
|
});
|
|
@@ -55075,6 +55087,15 @@ class ContainerPool {
|
|
|
55075
55087
|
return;
|
|
55076
55088
|
}
|
|
55077
55089
|
try {
|
|
55090
|
+
const killExec = await container.exec({
|
|
55091
|
+
Cmd: ["sh", "-c", "pkill -9 -u sandbox 2>/dev/null; true"]
|
|
55092
|
+
});
|
|
55093
|
+
await killExec.start({ Detach: true });
|
|
55094
|
+
let killInfo = await killExec.inspect();
|
|
55095
|
+
while (killInfo.Running) {
|
|
55096
|
+
await new Promise((r) => setTimeout(r, 5));
|
|
55097
|
+
killInfo = await killExec.inspect();
|
|
55098
|
+
}
|
|
55078
55099
|
const cleanExec = await container.exec({
|
|
55079
55100
|
Cmd: ["sh", "-c", "rm -rf /sandbox/* /sandbox/.[!.]* 2>/dev/null; true"]
|
|
55080
55101
|
});
|
|
@@ -55259,12 +55280,14 @@ __export(exports_docker, {
|
|
|
55259
55280
|
DockerIsol8: () => DockerIsol8
|
|
55260
55281
|
});
|
|
55261
55282
|
import { randomUUID } from "node:crypto";
|
|
55283
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
|
|
55262
55284
|
import { PassThrough } from "node:stream";
|
|
55263
55285
|
async function writeFileViaExec(container, filePath, content) {
|
|
55264
55286
|
const data = typeof content === "string" ? Buffer.from(content, "utf-8") : content;
|
|
55265
55287
|
const b64 = data.toString("base64");
|
|
55266
55288
|
const exec = await container.exec({
|
|
55267
|
-
Cmd: ["sh", "-c", `printf '%s' '${b64}' | base64 -d > ${filePath}`]
|
|
55289
|
+
Cmd: ["sh", "-c", `printf '%s' '${b64}' | base64 -d > ${filePath}`],
|
|
55290
|
+
User: "sandbox"
|
|
55268
55291
|
});
|
|
55269
55292
|
await exec.start({ Detach: true });
|
|
55270
55293
|
let info2 = await exec.inspect();
|
|
@@ -55280,7 +55303,8 @@ async function readFileViaExec(container, filePath) {
|
|
|
55280
55303
|
const exec = await container.exec({
|
|
55281
55304
|
Cmd: ["base64", filePath],
|
|
55282
55305
|
AttachStdout: true,
|
|
55283
|
-
AttachStderr: true
|
|
55306
|
+
AttachStderr: true,
|
|
55307
|
+
User: "sandbox"
|
|
55284
55308
|
});
|
|
55285
55309
|
const stream = await exec.start({ Tty: false });
|
|
55286
55310
|
const chunks = [];
|
|
@@ -55375,7 +55399,8 @@ async function installPackages(container, runtime, packages) {
|
|
|
55375
55399
|
Cmd: cmd,
|
|
55376
55400
|
AttachStdout: true,
|
|
55377
55401
|
AttachStderr: true,
|
|
55378
|
-
Env: env2
|
|
55402
|
+
Env: env2,
|
|
55403
|
+
User: runtime === "bash" ? "root" : "sandbox"
|
|
55379
55404
|
});
|
|
55380
55405
|
const stream = await exec.start({ Detach: false, Tty: false });
|
|
55381
55406
|
return new Promise((resolve2, reject) => {
|
|
@@ -55418,6 +55443,7 @@ class DockerIsol8 {
|
|
|
55418
55443
|
semaphore;
|
|
55419
55444
|
sandboxSize;
|
|
55420
55445
|
tmpSize;
|
|
55446
|
+
security;
|
|
55421
55447
|
persist;
|
|
55422
55448
|
container = null;
|
|
55423
55449
|
persistentRuntime = null;
|
|
@@ -55439,6 +55465,7 @@ class DockerIsol8 {
|
|
|
55439
55465
|
this.sandboxSize = options.sandboxSize ?? "512m";
|
|
55440
55466
|
this.tmpSize = options.tmpSize ?? "256m";
|
|
55441
55467
|
this.persist = options.persist ?? false;
|
|
55468
|
+
this.security = options.security ?? { seccomp: "strict" };
|
|
55442
55469
|
if (options.debug) {
|
|
55443
55470
|
logger.setDebug(true);
|
|
55444
55471
|
}
|
|
@@ -55544,7 +55571,8 @@ class DockerIsol8 {
|
|
|
55544
55571
|
Env: this.buildEnv(req.env),
|
|
55545
55572
|
AttachStdout: true,
|
|
55546
55573
|
AttachStderr: true,
|
|
55547
|
-
WorkingDir: SANDBOX_WORKDIR
|
|
55574
|
+
WorkingDir: SANDBOX_WORKDIR,
|
|
55575
|
+
User: "sandbox"
|
|
55548
55576
|
});
|
|
55549
55577
|
const execStream = await exec.start({ Tty: false });
|
|
55550
55578
|
yield* this.streamExecOutput(execStream, exec, container, timeoutMs);
|
|
@@ -55623,7 +55651,8 @@ class DockerIsol8 {
|
|
|
55623
55651
|
Env: this.buildEnv(req.env),
|
|
55624
55652
|
AttachStdout: true,
|
|
55625
55653
|
AttachStderr: true,
|
|
55626
|
-
WorkingDir: SANDBOX_WORKDIR
|
|
55654
|
+
WorkingDir: SANDBOX_WORKDIR,
|
|
55655
|
+
User: "sandbox"
|
|
55627
55656
|
});
|
|
55628
55657
|
const start = performance.now();
|
|
55629
55658
|
const execStream = await exec.start({ Tty: false });
|
|
@@ -55696,7 +55725,8 @@ class DockerIsol8 {
|
|
|
55696
55725
|
Env: execEnv,
|
|
55697
55726
|
AttachStdout: true,
|
|
55698
55727
|
AttachStderr: true,
|
|
55699
|
-
WorkingDir: SANDBOX_WORKDIR
|
|
55728
|
+
WorkingDir: SANDBOX_WORKDIR,
|
|
55729
|
+
User: "sandbox"
|
|
55700
55730
|
});
|
|
55701
55731
|
const start = performance.now();
|
|
55702
55732
|
const execStream = await exec.start({ Tty: false });
|
|
@@ -55766,9 +55796,9 @@ class DockerIsol8 {
|
|
|
55766
55796
|
ReadonlyRootfs: this.readonlyRootFs,
|
|
55767
55797
|
Tmpfs: {
|
|
55768
55798
|
"/tmp": `rw,noexec,nosuid,nodev,size=${this.tmpSize}`,
|
|
55769
|
-
[SANDBOX_WORKDIR]: `rw,exec,nosuid,nodev,size=${this.sandboxSize}`
|
|
55799
|
+
[SANDBOX_WORKDIR]: `rw,exec,nosuid,nodev,size=${this.sandboxSize},uid=100,gid=101`
|
|
55770
55800
|
},
|
|
55771
|
-
SecurityOpt:
|
|
55801
|
+
SecurityOpt: this.buildSecurityOpts()
|
|
55772
55802
|
};
|
|
55773
55803
|
if (this.network === "filtered") {
|
|
55774
55804
|
config.NetworkMode = "bridge";
|
|
@@ -55777,6 +55807,43 @@ class DockerIsol8 {
|
|
|
55777
55807
|
}
|
|
55778
55808
|
return config;
|
|
55779
55809
|
}
|
|
55810
|
+
buildSecurityOpts() {
|
|
55811
|
+
const opts = ["no-new-privileges"];
|
|
55812
|
+
if (this.security.seccomp === "unconfined") {
|
|
55813
|
+
opts.push("seccomp=unconfined");
|
|
55814
|
+
return opts;
|
|
55815
|
+
}
|
|
55816
|
+
if (this.security.seccomp === "custom" && this.security.customProfilePath) {
|
|
55817
|
+
try {
|
|
55818
|
+
const profile = readFileSync2(this.security.customProfilePath, "utf-8");
|
|
55819
|
+
opts.push(`seccomp=${profile}`);
|
|
55820
|
+
} catch (e) {
|
|
55821
|
+
logger.error(`Failed to load custom seccomp profile: ${e}`);
|
|
55822
|
+
}
|
|
55823
|
+
return opts;
|
|
55824
|
+
}
|
|
55825
|
+
try {
|
|
55826
|
+
const profile = this.loadDefaultSeccompProfile();
|
|
55827
|
+
if (profile) {
|
|
55828
|
+
opts.push(`seccomp=${profile}`);
|
|
55829
|
+
}
|
|
55830
|
+
} catch (e) {
|
|
55831
|
+
logger.error(`Failed to load default seccomp profile: ${e}`);
|
|
55832
|
+
}
|
|
55833
|
+
return opts;
|
|
55834
|
+
}
|
|
55835
|
+
loadDefaultSeccompProfile() {
|
|
55836
|
+
const devPath = new URL("../../docker/seccomp-profile.json", import.meta.url);
|
|
55837
|
+
if (existsSync2(devPath)) {
|
|
55838
|
+
return readFileSync2(devPath, "utf-8");
|
|
55839
|
+
}
|
|
55840
|
+
const prodPath = new URL("./docker/seccomp-profile.json", import.meta.url);
|
|
55841
|
+
if (existsSync2(prodPath)) {
|
|
55842
|
+
return readFileSync2(prodPath, "utf-8");
|
|
55843
|
+
}
|
|
55844
|
+
logger.warn("Could not locate default seccomp profile. Running without seccomp filter.");
|
|
55845
|
+
return null;
|
|
55846
|
+
}
|
|
55780
55847
|
buildEnv(extra) {
|
|
55781
55848
|
const env2 = [
|
|
55782
55849
|
"PYTHONUNBUFFERED=1",
|
|
@@ -55958,7 +56025,7 @@ var package_default;
|
|
|
55958
56025
|
var init_package = __esm(() => {
|
|
55959
56026
|
package_default = {
|
|
55960
56027
|
name: "isol8",
|
|
55961
|
-
version: "0.6.
|
|
56028
|
+
version: "0.6.2",
|
|
55962
56029
|
description: "Secure code execution engine for AI agents",
|
|
55963
56030
|
author: "Illusion47586",
|
|
55964
56031
|
license: "MIT",
|
|
@@ -57881,9 +57948,9 @@ var init_server = __esm(() => {
|
|
|
57881
57948
|
// src/cli.ts
|
|
57882
57949
|
import {
|
|
57883
57950
|
chmodSync,
|
|
57884
|
-
existsSync as
|
|
57951
|
+
existsSync as existsSync4,
|
|
57885
57952
|
mkdirSync,
|
|
57886
|
-
readFileSync as
|
|
57953
|
+
readFileSync as readFileSync3,
|
|
57887
57954
|
renameSync,
|
|
57888
57955
|
unlinkSync,
|
|
57889
57956
|
writeFileSync
|
|
@@ -61283,10 +61350,10 @@ init_docker();
|
|
|
61283
61350
|
|
|
61284
61351
|
// src/engine/image-builder.ts
|
|
61285
61352
|
init_runtime();
|
|
61286
|
-
import { existsSync as
|
|
61353
|
+
import { existsSync as existsSync3 } from "node:fs";
|
|
61287
61354
|
function resolveDockerDir() {
|
|
61288
61355
|
const fromBundled = new URL("../docker", import.meta.url).pathname;
|
|
61289
|
-
if (
|
|
61356
|
+
if (existsSync3(fromBundled)) {
|
|
61290
61357
|
return fromBundled;
|
|
61291
61358
|
}
|
|
61292
61359
|
return new URL("../../docker", import.meta.url).pathname;
|
|
@@ -61638,7 +61705,7 @@ function getServerBinaryName() {
|
|
|
61638
61705
|
return `isol8-server-${resolvedOs}-${resolvedArch}`;
|
|
61639
61706
|
}
|
|
61640
61707
|
async function getServerBinaryVersion(binaryPath) {
|
|
61641
|
-
if (!
|
|
61708
|
+
if (!existsSync4(binaryPath)) {
|
|
61642
61709
|
logger.debug(`[Serve] No binary found at ${binaryPath}`);
|
|
61643
61710
|
return null;
|
|
61644
61711
|
}
|
|
@@ -61683,7 +61750,7 @@ async function downloadServerBinary(binaryPath) {
|
|
|
61683
61750
|
} catch (err) {
|
|
61684
61751
|
spinner.fail("Failed to download server binary");
|
|
61685
61752
|
const tmpPath = `${binaryPath}.tmp`;
|
|
61686
|
-
if (
|
|
61753
|
+
if (existsSync4(tmpPath)) {
|
|
61687
61754
|
unlinkSync(tmpPath);
|
|
61688
61755
|
}
|
|
61689
61756
|
throw err;
|
|
@@ -61737,7 +61804,7 @@ program2.command("config").description("Show the resolved isol8 configuration").
|
|
|
61737
61804
|
join2(resolve2(process.cwd()), "isol8.config.json"),
|
|
61738
61805
|
join2(homedir2(), ".isol8", "config.json")
|
|
61739
61806
|
];
|
|
61740
|
-
const loadedFrom = searchPaths.find((p) =>
|
|
61807
|
+
const loadedFrom = searchPaths.find((p) => existsSync4(p));
|
|
61741
61808
|
logger.debug(`[Config] Config source: ${loadedFrom ?? "defaults"}`);
|
|
61742
61809
|
logger.debug(`[Config] Resolved config: ${JSON.stringify(config)}`);
|
|
61743
61810
|
if (opts.json) {
|
|
@@ -61872,11 +61939,11 @@ async function resolveRunInput(file, opts) {
|
|
|
61872
61939
|
} else if (file) {
|
|
61873
61940
|
const filePath = resolve2(file);
|
|
61874
61941
|
logger.debug(`[Run] Reading file: ${filePath}`);
|
|
61875
|
-
if (!
|
|
61942
|
+
if (!existsSync4(filePath)) {
|
|
61876
61943
|
console.error(`[ERR] File not found: ${file}`);
|
|
61877
61944
|
process.exit(1);
|
|
61878
61945
|
}
|
|
61879
|
-
code =
|
|
61946
|
+
code = readFileSync3(filePath, "utf-8");
|
|
61880
61947
|
if (opts.runtime) {
|
|
61881
61948
|
runtime = opts.runtime;
|
|
61882
61949
|
logger.debug(`[Run] Runtime specified: ${runtime}`);
|
|
@@ -61959,4 +62026,4 @@ if (!process.argv.slice(2).length) {
|
|
|
61959
62026
|
}
|
|
61960
62027
|
program2.parse();
|
|
61961
62028
|
|
|
61962
|
-
//# debugId=
|
|
62029
|
+
//# debugId=F86C7DBAE803AC0664756E2164756E21
|
package/dist/docker/Dockerfile
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# ── Base ──────────────────────────────────────────────────────────────
|
|
2
2
|
FROM alpine:3.21 AS base
|
|
3
|
-
RUN apk add --no-cache tini curl ca-certificates
|
|
3
|
+
RUN apk add --no-cache tini curl ca-certificates \
|
|
4
|
+
&& addgroup -S sandbox && adduser -S sandbox -G sandbox -h /sandbox
|
|
4
5
|
COPY proxy.mjs /usr/local/bin/proxy.mjs
|
|
5
6
|
RUN chmod +x /usr/local/bin/proxy.mjs
|
|
6
7
|
WORKDIR /sandbox
|
|
@@ -26,7 +27,8 @@ CMD ["bun"]
|
|
|
26
27
|
|
|
27
28
|
# ── Deno ──────────────────────────────────────────────────────────────
|
|
28
29
|
FROM denoland/deno:alpine AS deno
|
|
29
|
-
RUN apk add --no-cache tini curl ca-certificates
|
|
30
|
+
RUN apk add --no-cache tini curl ca-certificates \
|
|
31
|
+
&& addgroup -S sandbox && adduser -S sandbox -G sandbox -h /sandbox
|
|
30
32
|
COPY proxy.mjs /usr/local/bin/proxy.mjs
|
|
31
33
|
RUN chmod +x /usr/local/bin/proxy.mjs
|
|
32
34
|
WORKDIR /sandbox
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"defaultAction": "SCMP_ACT_ALLOW",
|
|
3
|
+
"architectures": [
|
|
4
|
+
"SCMP_ARCH_X86_64",
|
|
5
|
+
"SCMP_ARCH_X86",
|
|
6
|
+
"SCMP_ARCH_X32",
|
|
7
|
+
"SCMP_ARCH_AARCH64"
|
|
8
|
+
],
|
|
9
|
+
"syscalls": [
|
|
10
|
+
{
|
|
11
|
+
"names": [
|
|
12
|
+
"acct",
|
|
13
|
+
"add_key",
|
|
14
|
+
"bpf",
|
|
15
|
+
"clock_adjtime",
|
|
16
|
+
"clock_settime",
|
|
17
|
+
"create_module",
|
|
18
|
+
"delete_module",
|
|
19
|
+
"finit_module",
|
|
20
|
+
"get_mempolicy",
|
|
21
|
+
"init_module",
|
|
22
|
+
"ioperm",
|
|
23
|
+
"iopl",
|
|
24
|
+
"kcmp",
|
|
25
|
+
"kexec_file_load",
|
|
26
|
+
"kexec_load",
|
|
27
|
+
"keyctl",
|
|
28
|
+
"lookup_dcookie",
|
|
29
|
+
"mbind",
|
|
30
|
+
"mount",
|
|
31
|
+
"move_pages",
|
|
32
|
+
"name_to_handle_at",
|
|
33
|
+
"open_by_handle_at",
|
|
34
|
+
"perf_event_open",
|
|
35
|
+
"pivot_root",
|
|
36
|
+
"process_vm_readv",
|
|
37
|
+
"process_vm_writev",
|
|
38
|
+
"ptrace",
|
|
39
|
+
"query_module",
|
|
40
|
+
"quotactl",
|
|
41
|
+
"reboot",
|
|
42
|
+
"request_key",
|
|
43
|
+
"set_mempolicy",
|
|
44
|
+
"setns",
|
|
45
|
+
"settimeofday",
|
|
46
|
+
"stime",
|
|
47
|
+
"swapon",
|
|
48
|
+
"swapoff",
|
|
49
|
+
"sysfs",
|
|
50
|
+
"syslog",
|
|
51
|
+
"umount",
|
|
52
|
+
"umount2",
|
|
53
|
+
"unshare",
|
|
54
|
+
"uselib",
|
|
55
|
+
"userfaultfd",
|
|
56
|
+
"ustat",
|
|
57
|
+
"vm86",
|
|
58
|
+
"vm86old"
|
|
59
|
+
],
|
|
60
|
+
"action": "SCMP_ACT_ERRNO",
|
|
61
|
+
"args": [],
|
|
62
|
+
"comment": "",
|
|
63
|
+
"includes": {},
|
|
64
|
+
"excludes": {}
|
|
65
|
+
}
|
|
66
|
+
]
|
|
67
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -263,6 +263,15 @@ class ContainerPool {
|
|
|
263
263
|
return;
|
|
264
264
|
}
|
|
265
265
|
try {
|
|
266
|
+
const killExec = await container.exec({
|
|
267
|
+
Cmd: ["sh", "-c", "pkill -9 -u sandbox 2>/dev/null; true"]
|
|
268
|
+
});
|
|
269
|
+
await killExec.start({ Detach: true });
|
|
270
|
+
let killInfo = await killExec.inspect();
|
|
271
|
+
while (killInfo.Running) {
|
|
272
|
+
await new Promise((r) => setTimeout(r, 5));
|
|
273
|
+
killInfo = await killExec.inspect();
|
|
274
|
+
}
|
|
266
275
|
const cleanExec = await container.exec({
|
|
267
276
|
Cmd: ["sh", "-c", "rm -rf /sandbox/* /sandbox/.[!.]* 2>/dev/null; true"]
|
|
268
277
|
});
|
|
@@ -439,13 +448,15 @@ __export(exports_docker, {
|
|
|
439
448
|
DockerIsol8: () => DockerIsol8
|
|
440
449
|
});
|
|
441
450
|
import { randomUUID } from "node:crypto";
|
|
451
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
|
|
442
452
|
import { PassThrough } from "node:stream";
|
|
443
453
|
import Docker from "dockerode";
|
|
444
454
|
async function writeFileViaExec(container, filePath, content) {
|
|
445
455
|
const data = typeof content === "string" ? Buffer.from(content, "utf-8") : content;
|
|
446
456
|
const b64 = data.toString("base64");
|
|
447
457
|
const exec = await container.exec({
|
|
448
|
-
Cmd: ["sh", "-c", `printf '%s' '${b64}' | base64 -d > ${filePath}`]
|
|
458
|
+
Cmd: ["sh", "-c", `printf '%s' '${b64}' | base64 -d > ${filePath}`],
|
|
459
|
+
User: "sandbox"
|
|
449
460
|
});
|
|
450
461
|
await exec.start({ Detach: true });
|
|
451
462
|
let info = await exec.inspect();
|
|
@@ -461,7 +472,8 @@ async function readFileViaExec(container, filePath) {
|
|
|
461
472
|
const exec = await container.exec({
|
|
462
473
|
Cmd: ["base64", filePath],
|
|
463
474
|
AttachStdout: true,
|
|
464
|
-
AttachStderr: true
|
|
475
|
+
AttachStderr: true,
|
|
476
|
+
User: "sandbox"
|
|
465
477
|
});
|
|
466
478
|
const stream = await exec.start({ Tty: false });
|
|
467
479
|
const chunks = [];
|
|
@@ -556,7 +568,8 @@ async function installPackages(container, runtime, packages) {
|
|
|
556
568
|
Cmd: cmd,
|
|
557
569
|
AttachStdout: true,
|
|
558
570
|
AttachStderr: true,
|
|
559
|
-
Env: env
|
|
571
|
+
Env: env,
|
|
572
|
+
User: runtime === "bash" ? "root" : "sandbox"
|
|
560
573
|
});
|
|
561
574
|
const stream = await exec.start({ Detach: false, Tty: false });
|
|
562
575
|
return new Promise((resolve2, reject) => {
|
|
@@ -599,6 +612,7 @@ class DockerIsol8 {
|
|
|
599
612
|
semaphore;
|
|
600
613
|
sandboxSize;
|
|
601
614
|
tmpSize;
|
|
615
|
+
security;
|
|
602
616
|
persist;
|
|
603
617
|
container = null;
|
|
604
618
|
persistentRuntime = null;
|
|
@@ -620,6 +634,7 @@ class DockerIsol8 {
|
|
|
620
634
|
this.sandboxSize = options.sandboxSize ?? "512m";
|
|
621
635
|
this.tmpSize = options.tmpSize ?? "256m";
|
|
622
636
|
this.persist = options.persist ?? false;
|
|
637
|
+
this.security = options.security ?? { seccomp: "strict" };
|
|
623
638
|
if (options.debug) {
|
|
624
639
|
logger.setDebug(true);
|
|
625
640
|
}
|
|
@@ -725,7 +740,8 @@ class DockerIsol8 {
|
|
|
725
740
|
Env: this.buildEnv(req.env),
|
|
726
741
|
AttachStdout: true,
|
|
727
742
|
AttachStderr: true,
|
|
728
|
-
WorkingDir: SANDBOX_WORKDIR
|
|
743
|
+
WorkingDir: SANDBOX_WORKDIR,
|
|
744
|
+
User: "sandbox"
|
|
729
745
|
});
|
|
730
746
|
const execStream = await exec.start({ Tty: false });
|
|
731
747
|
yield* this.streamExecOutput(execStream, exec, container, timeoutMs);
|
|
@@ -804,7 +820,8 @@ class DockerIsol8 {
|
|
|
804
820
|
Env: this.buildEnv(req.env),
|
|
805
821
|
AttachStdout: true,
|
|
806
822
|
AttachStderr: true,
|
|
807
|
-
WorkingDir: SANDBOX_WORKDIR
|
|
823
|
+
WorkingDir: SANDBOX_WORKDIR,
|
|
824
|
+
User: "sandbox"
|
|
808
825
|
});
|
|
809
826
|
const start = performance.now();
|
|
810
827
|
const execStream = await exec.start({ Tty: false });
|
|
@@ -877,7 +894,8 @@ class DockerIsol8 {
|
|
|
877
894
|
Env: execEnv,
|
|
878
895
|
AttachStdout: true,
|
|
879
896
|
AttachStderr: true,
|
|
880
|
-
WorkingDir: SANDBOX_WORKDIR
|
|
897
|
+
WorkingDir: SANDBOX_WORKDIR,
|
|
898
|
+
User: "sandbox"
|
|
881
899
|
});
|
|
882
900
|
const start = performance.now();
|
|
883
901
|
const execStream = await exec.start({ Tty: false });
|
|
@@ -947,9 +965,9 @@ class DockerIsol8 {
|
|
|
947
965
|
ReadonlyRootfs: this.readonlyRootFs,
|
|
948
966
|
Tmpfs: {
|
|
949
967
|
"/tmp": `rw,noexec,nosuid,nodev,size=${this.tmpSize}`,
|
|
950
|
-
[SANDBOX_WORKDIR]: `rw,exec,nosuid,nodev,size=${this.sandboxSize}`
|
|
968
|
+
[SANDBOX_WORKDIR]: `rw,exec,nosuid,nodev,size=${this.sandboxSize},uid=100,gid=101`
|
|
951
969
|
},
|
|
952
|
-
SecurityOpt:
|
|
970
|
+
SecurityOpt: this.buildSecurityOpts()
|
|
953
971
|
};
|
|
954
972
|
if (this.network === "filtered") {
|
|
955
973
|
config.NetworkMode = "bridge";
|
|
@@ -958,6 +976,43 @@ class DockerIsol8 {
|
|
|
958
976
|
}
|
|
959
977
|
return config;
|
|
960
978
|
}
|
|
979
|
+
buildSecurityOpts() {
|
|
980
|
+
const opts = ["no-new-privileges"];
|
|
981
|
+
if (this.security.seccomp === "unconfined") {
|
|
982
|
+
opts.push("seccomp=unconfined");
|
|
983
|
+
return opts;
|
|
984
|
+
}
|
|
985
|
+
if (this.security.seccomp === "custom" && this.security.customProfilePath) {
|
|
986
|
+
try {
|
|
987
|
+
const profile = readFileSync2(this.security.customProfilePath, "utf-8");
|
|
988
|
+
opts.push(`seccomp=${profile}`);
|
|
989
|
+
} catch (e) {
|
|
990
|
+
logger.error(`Failed to load custom seccomp profile: ${e}`);
|
|
991
|
+
}
|
|
992
|
+
return opts;
|
|
993
|
+
}
|
|
994
|
+
try {
|
|
995
|
+
const profile = this.loadDefaultSeccompProfile();
|
|
996
|
+
if (profile) {
|
|
997
|
+
opts.push(`seccomp=${profile}`);
|
|
998
|
+
}
|
|
999
|
+
} catch (e) {
|
|
1000
|
+
logger.error(`Failed to load default seccomp profile: ${e}`);
|
|
1001
|
+
}
|
|
1002
|
+
return opts;
|
|
1003
|
+
}
|
|
1004
|
+
loadDefaultSeccompProfile() {
|
|
1005
|
+
const devPath = new URL("../../docker/seccomp-profile.json", import.meta.url);
|
|
1006
|
+
if (existsSync2(devPath)) {
|
|
1007
|
+
return readFileSync2(devPath, "utf-8");
|
|
1008
|
+
}
|
|
1009
|
+
const prodPath = new URL("./docker/seccomp-profile.json", import.meta.url);
|
|
1010
|
+
if (existsSync2(prodPath)) {
|
|
1011
|
+
return readFileSync2(prodPath, "utf-8");
|
|
1012
|
+
}
|
|
1013
|
+
logger.warn("Could not locate default seccomp profile. Running without seccomp filter.");
|
|
1014
|
+
return null;
|
|
1015
|
+
}
|
|
961
1016
|
buildEnv(extra) {
|
|
962
1017
|
const env = [
|
|
963
1018
|
"PYTHONUNBUFFERED=1",
|
|
@@ -1282,6 +1337,9 @@ var DEFAULT_CONFIG = {
|
|
|
1282
1337
|
maxContainerAgeMs: 3600000
|
|
1283
1338
|
},
|
|
1284
1339
|
dependencies: {},
|
|
1340
|
+
security: {
|
|
1341
|
+
seccomp: "strict"
|
|
1342
|
+
},
|
|
1285
1343
|
debug: false
|
|
1286
1344
|
};
|
|
1287
1345
|
function loadConfig(cwd) {
|
|
@@ -1317,6 +1375,10 @@ function mergeConfig(defaults, overrides) {
|
|
|
1317
1375
|
...defaults.dependencies,
|
|
1318
1376
|
...overrides.dependencies
|
|
1319
1377
|
},
|
|
1378
|
+
security: {
|
|
1379
|
+
seccomp: overrides.security?.seccomp ?? defaults.security.seccomp,
|
|
1380
|
+
customProfilePath: overrides.security?.customProfilePath ?? defaults.security.customProfilePath
|
|
1381
|
+
},
|
|
1320
1382
|
debug: overrides.debug ?? defaults.debug
|
|
1321
1383
|
};
|
|
1322
1384
|
}
|
|
@@ -1331,7 +1393,7 @@ init_logger();
|
|
|
1331
1393
|
// package.json
|
|
1332
1394
|
var package_default = {
|
|
1333
1395
|
name: "isol8",
|
|
1334
|
-
version: "0.6.
|
|
1396
|
+
version: "0.6.2",
|
|
1335
1397
|
description: "Secure code execution engine for AI agents",
|
|
1336
1398
|
author: "Illusion47586",
|
|
1337
1399
|
license: "MIT",
|
|
@@ -1660,4 +1722,4 @@ export {
|
|
|
1660
1722
|
BunAdapter
|
|
1661
1723
|
};
|
|
1662
1724
|
|
|
1663
|
-
//# debugId=
|
|
1725
|
+
//# debugId=1AFCD54347509D5A64756E2164756E21
|
package/dist/src/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE3C;;;GAGG;AACH,QAAA,MAAM,cAAc,EAAE,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE3C;;;GAGG;AACH,QAAA,MAAM,cAAc,EAAE,WAuBrB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,UAAU,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,WAAW,CAepD;AAmCD,OAAO,EAAE,cAAc,EAAE,CAAC"}
|
|
@@ -43,6 +43,7 @@ export declare class DockerIsol8 implements Isol8Engine {
|
|
|
43
43
|
private readonly semaphore;
|
|
44
44
|
private readonly sandboxSize;
|
|
45
45
|
private readonly tmpSize;
|
|
46
|
+
private readonly security;
|
|
46
47
|
private readonly persist;
|
|
47
48
|
private container;
|
|
48
49
|
private persistentRuntime;
|
|
@@ -96,6 +97,8 @@ export declare class DockerIsol8 implements Isol8Engine {
|
|
|
96
97
|
private startPersistentContainer;
|
|
97
98
|
private getAdapter;
|
|
98
99
|
private buildHostConfig;
|
|
100
|
+
private buildSecurityOpts;
|
|
101
|
+
private loadDefaultSeccompProfile;
|
|
99
102
|
private buildEnv;
|
|
100
103
|
private streamExecOutput;
|
|
101
104
|
private collectExecOutput;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"docker.d.ts","sourceRoot":"","sources":["../../../src/engine/docker.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"docker.d.ts","sourceRoot":"","sources":["../../../src/engine/docker.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,MAAM,MAAM,WAAW,CAAC;AAG/B,OAAO,KAAK,EACV,gBAAgB,EAChB,eAAe,EACf,WAAW,EAEX,YAAY,EAIZ,WAAW,EACZ,MAAM,UAAU,CAAC;AAoPlB,2HAA2H;AAC3H,MAAM,WAAW,kBAAmB,SAAQ,YAAY;IACtD,oFAAoF;IACpF,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;;;GAcG;AACH,qBAAa,WAAY,YAAW,WAAW;IAC7C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAY;IACjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAc;IACtC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAsB;IACrD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAU;IACzC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAyB;IACjD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IACtC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IAEjC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAiB;IAC1C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAU;IAElC,OAAO,CAAC,SAAS,CAAiC;IAClD,OAAO,CAAC,iBAAiB,CAA+B;IACxD,OAAO,CAAC,IAAI,CAA8B;IAE1C;;;OAGG;gBACS,OAAO,GAAE,kBAAuB,EAAE,aAAa,SAAK;IAwBhE;;;OAGG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAK5B,kFAAkF;IAC5E,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAuB3B;;;OAGG;IACG,OAAO,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,CAAC;IAW9D;;;;;;;OAOG;IACG,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAYpE;;;;;;OAMG;IACG,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAmB5C,6GAA6G;IAC7G,IAAI,WAAW,IAAI,MAAM,GAAG,IAAI,CAE/B;IAED;;;OAGG;IACI,aAAa,CAAC,GAAG,EAAE,gBAAgB,GAAG,aAAa,CAAC,WAAW,CAAC;YAqFzD,YAAY;YAcZ,gBAAgB;YAyGhB,iBAAiB;YA8FjB,aAAa;YAkBb,oBAAoB;YASpB,wBAAwB;IA2BtC,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,eAAe;IAsBvB,OAAO,CAAC,iBAAiB;IA+BzB,OAAO,CAAC,yBAAyB;IAyBjC,OAAO,CAAC,QAAQ;YAmCD,gBAAgB;YA8EjB,iBAAiB;IA8D/B,OAAO,CAAC,iBAAiB;IAYzB;;;;;;;;;;;;;;;;;;;;OAoBG;WACU,OAAO,CAClB,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;CA2BlE"}
|
|
@@ -37,8 +37,9 @@ export declare class ContainerPool {
|
|
|
37
37
|
*/
|
|
38
38
|
acquire(image: string): Promise<Docker.Container>;
|
|
39
39
|
/**
|
|
40
|
-
* Return a container to the pool after use.
|
|
41
|
-
*
|
|
40
|
+
* Return a container to the pool after use. All processes owned by the
|
|
41
|
+
* `sandbox` user are killed, and the `/sandbox` tmpfs is wiped clean
|
|
42
|
+
* so the container is ready for the next execution.
|
|
42
43
|
* If the pool is full, the container is destroyed instead.
|
|
43
44
|
*/
|
|
44
45
|
release(container: Docker.Container, image: string): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pool.d.ts","sourceRoot":"","sources":["../../../src/engine/pool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,MAAM,MAAM,WAAW,CAAC;AAGpC,4CAA4C;AAC5C,MAAM,WAAW,WAAW;IAC1B,8BAA8B;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,wDAAwD;IACxD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yDAAyD;IACzD,aAAa,EAAE,IAAI,CAAC,MAAM,CAAC,sBAAsB,EAAE,OAAO,CAAC,CAAC;CAC7D;AAOD;;;GAGG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA+C;IAC7E,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAkC;IACxD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAqB;IAClD,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAA4B;gBAEtD,OAAO,EAAE,WAAW;IAMhC;;;;OAIG;IACG,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC;IAcvD
|
|
1
|
+
{"version":3,"file":"pool.d.ts","sourceRoot":"","sources":["../../../src/engine/pool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,MAAM,MAAM,WAAW,CAAC;AAGpC,4CAA4C;AAC5C,MAAM,WAAW,WAAW;IAC1B,8BAA8B;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,wDAAwD;IACxD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yDAAyD;IACzD,aAAa,EAAE,IAAI,CAAC,MAAM,CAAC,sBAAsB,EAAE,OAAO,CAAC,CAAC;CAC7D;AAOD;;;GAGG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA+C;IAC7E,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAkC;IACxD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAqB;IAClD,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAA4B;gBAEtD,OAAO,EAAE,WAAW;IAMhC;;;;OAIG;IACG,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC;IAcvD;;;;;OAKG;IACG,OAAO,CAAC,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA8CxE;;;OAGG;IACG,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBxC;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YAgBd,eAAe;IAW7B,2DAA2D;IAC3D,OAAO,CAAC,SAAS;CAuClB"}
|
package/dist/src/types.d.ts
CHANGED
|
@@ -156,6 +156,8 @@ export interface Isol8Options {
|
|
|
156
156
|
* @default false
|
|
157
157
|
*/
|
|
158
158
|
persist?: boolean;
|
|
159
|
+
/** Security settings. */
|
|
160
|
+
security?: SecurityConfig;
|
|
159
161
|
}
|
|
160
162
|
/**
|
|
161
163
|
* The core isol8 engine abstraction. Both {@link DockerIsol8} and {@link RemoteIsol8}
|
|
@@ -245,6 +247,20 @@ export interface Isol8Dependencies {
|
|
|
245
247
|
/** Bash packages to install via apk (Alpine). */
|
|
246
248
|
bash?: string[];
|
|
247
249
|
}
|
|
250
|
+
/**
|
|
251
|
+
* Security configuration for the execution environment.
|
|
252
|
+
*/
|
|
253
|
+
export interface SecurityConfig {
|
|
254
|
+
/**
|
|
255
|
+
* Seccomp profile mode.
|
|
256
|
+
* - "strict": Use the default strict profile (default).
|
|
257
|
+
* - "unconfined": Do not apply any seccomp profile.
|
|
258
|
+
* - "custom": Use the profile at `customProfilePath`.
|
|
259
|
+
*/
|
|
260
|
+
seccomp?: "strict" | "unconfined" | "custom";
|
|
261
|
+
/** Path to a custom seccomp profile JSON file. Required if seccomp is "custom". */
|
|
262
|
+
customProfilePath?: string;
|
|
263
|
+
}
|
|
248
264
|
/**
|
|
249
265
|
* Top-level configuration schema for isol8.
|
|
250
266
|
*
|
|
@@ -265,6 +281,8 @@ export interface Isol8Config {
|
|
|
265
281
|
cleanup: Isol8Cleanup;
|
|
266
282
|
/** Runtime-specific packages to bake into custom Docker images. */
|
|
267
283
|
dependencies: Isol8Dependencies;
|
|
284
|
+
/** Security settings. */
|
|
285
|
+
security: SecurityConfig;
|
|
268
286
|
/** Enable debug logging. @default false */
|
|
269
287
|
debug: boolean;
|
|
270
288
|
}
|
|
@@ -287,5 +305,7 @@ export interface Isol8UserConfig {
|
|
|
287
305
|
cleanup?: Partial<Isol8Cleanup>;
|
|
288
306
|
/** Runtime-specific packages to bake into custom Docker images. */
|
|
289
307
|
dependencies?: Isol8Dependencies;
|
|
308
|
+
/** Security settings. */
|
|
309
|
+
security?: SecurityConfig;
|
|
290
310
|
}
|
|
291
311
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/src/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -140,6 +140,10 @@
|
|
|
140
140
|
}
|
|
141
141
|
},
|
|
142
142
|
"type": "object"
|
|
143
|
+
},
|
|
144
|
+
"security": {
|
|
145
|
+
"$ref": "#/definitions/SecurityConfig",
|
|
146
|
+
"description": "Security settings."
|
|
143
147
|
}
|
|
144
148
|
},
|
|
145
149
|
"type": "object"
|
|
@@ -148,6 +152,22 @@
|
|
|
148
152
|
"description": "Network access mode for isol8 containers.\n\n- `\"none\"` — All network access blocked (default, most secure).\n- `\"host\"` — Full host network access (use with caution).\n- `\"filtered\"` — HTTP/HTTPS traffic routed through a proxy that enforces whitelist/blacklist regex rules on hostnames.",
|
|
149
153
|
"enum": ["none", "host", "filtered"],
|
|
150
154
|
"type": "string"
|
|
155
|
+
},
|
|
156
|
+
"SecurityConfig": {
|
|
157
|
+
"additionalProperties": false,
|
|
158
|
+
"description": "Security configuration for the execution environment.",
|
|
159
|
+
"properties": {
|
|
160
|
+
"customProfilePath": {
|
|
161
|
+
"description": "Path to a custom seccomp profile JSON file. Required if seccomp is \"custom\".",
|
|
162
|
+
"type": "string"
|
|
163
|
+
},
|
|
164
|
+
"seccomp": {
|
|
165
|
+
"description": "Seccomp profile mode.\n- \"strict\": Use the default strict profile (default).\n- \"unconfined\": Do not apply any seccomp profile.\n- \"custom\": Use the profile at `customProfilePath`.",
|
|
166
|
+
"enum": ["strict", "unconfined", "custom"],
|
|
167
|
+
"type": "string"
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
"type": "object"
|
|
151
171
|
}
|
|
152
172
|
}
|
|
153
173
|
}
|