isol8 0.4.3 → 0.5.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 +2 -0
- package/dist/cli.js +75 -12
- package/dist/cli.js.map +8 -7
- package/dist/index.js +55 -11
- package/dist/index.js.map +7 -6
- package/dist/src/config.d.ts.map +1 -1
- package/dist/src/engine/docker.d.ts +1 -0
- package/dist/src/engine/docker.d.ts.map +1 -1
- package/dist/src/engine/pool.d.ts.map +1 -1
- package/dist/src/types.d.ts +12 -0
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/utils/logger.d.ts +32 -0
- package/dist/src/utils/logger.d.ts.map +1 -0
- package/package.json +1 -1
- package/schema/isol8.config.schema.json +5 -0
package/README.md
CHANGED
|
@@ -104,6 +104,8 @@ isol8 run script.py --host http://server:3000 --key my-api-key
|
|
|
104
104
|
| `--out <file>` | Write stdout to file | — |
|
|
105
105
|
| `--no-stream` | Disable real-time output streaming | `false` |
|
|
106
106
|
| `--persistent` | Keep container alive between runs | `false` |
|
|
107
|
+
| `--persist` | Keep container after execution for inspection/debugging | `false` |
|
|
108
|
+
| `--debug` | Enable debug logging for internal engine operations | `false` |
|
|
107
109
|
| `--timeout <ms>` | Execution timeout in milliseconds | `30000` |
|
|
108
110
|
| `--memory <limit>` | Memory limit (e.g. `512m`, `1g`) | `512m` |
|
|
109
111
|
| `--cpu <limit>` | CPU limit as fraction (e.g. `0.5`, `2.0`) | `1.0` |
|
package/dist/cli.js
CHANGED
|
@@ -54798,7 +54798,8 @@ function mergeConfig(defaults, overrides) {
|
|
|
54798
54798
|
dependencies: {
|
|
54799
54799
|
...defaults.dependencies,
|
|
54800
54800
|
...overrides.dependencies
|
|
54801
|
-
}
|
|
54801
|
+
},
|
|
54802
|
+
debug: overrides.debug ?? defaults.debug
|
|
54802
54803
|
};
|
|
54803
54804
|
}
|
|
54804
54805
|
var DEFAULT_CONFIG;
|
|
@@ -54821,7 +54822,8 @@ var init_config = __esm(() => {
|
|
|
54821
54822
|
autoPrune: true,
|
|
54822
54823
|
maxContainerAgeMs: 3600000
|
|
54823
54824
|
},
|
|
54824
|
-
dependencies: {}
|
|
54825
|
+
dependencies: {},
|
|
54826
|
+
debug: false
|
|
54825
54827
|
};
|
|
54826
54828
|
});
|
|
54827
54829
|
|
|
@@ -54978,6 +54980,37 @@ var init_runtime = __esm(() => {
|
|
|
54978
54980
|
RuntimeRegistry.register(DenoAdapter);
|
|
54979
54981
|
});
|
|
54980
54982
|
|
|
54983
|
+
// src/utils/logger.ts
|
|
54984
|
+
var exports_logger = {};
|
|
54985
|
+
__export(exports_logger, {
|
|
54986
|
+
logger: () => logger
|
|
54987
|
+
});
|
|
54988
|
+
|
|
54989
|
+
class Logger {
|
|
54990
|
+
debugMode = false;
|
|
54991
|
+
setDebug(enabled) {
|
|
54992
|
+
this.debugMode = enabled;
|
|
54993
|
+
}
|
|
54994
|
+
debug(...args) {
|
|
54995
|
+
if (this.debugMode) {
|
|
54996
|
+
console.log("[DEBUG]", ...args);
|
|
54997
|
+
}
|
|
54998
|
+
}
|
|
54999
|
+
info(...args) {
|
|
55000
|
+
console.log(...args);
|
|
55001
|
+
}
|
|
55002
|
+
warn(...args) {
|
|
55003
|
+
console.warn("[WARN]", ...args);
|
|
55004
|
+
}
|
|
55005
|
+
error(...args) {
|
|
55006
|
+
console.error("[ERROR]", ...args);
|
|
55007
|
+
}
|
|
55008
|
+
}
|
|
55009
|
+
var logger;
|
|
55010
|
+
var init_logger = __esm(() => {
|
|
55011
|
+
logger = new Logger;
|
|
55012
|
+
});
|
|
55013
|
+
|
|
54981
55014
|
// src/engine/concurrency.ts
|
|
54982
55015
|
class Semaphore {
|
|
54983
55016
|
max;
|
|
@@ -55086,26 +55119,32 @@ class ContainerPool {
|
|
|
55086
55119
|
...this.createOptions,
|
|
55087
55120
|
Image: image
|
|
55088
55121
|
});
|
|
55122
|
+
logger.debug(`[Pool] Container ${container.id} created for image: ${image}`);
|
|
55089
55123
|
await container.start();
|
|
55124
|
+
logger.debug(`[Pool] Container ${container.id} started`);
|
|
55090
55125
|
return container;
|
|
55091
55126
|
}
|
|
55092
55127
|
replenish(image) {
|
|
55093
55128
|
if (this.replenishing.has(image)) {
|
|
55129
|
+
logger.debug(`[Pool] Replenishment for ${image} already in progress`);
|
|
55094
55130
|
return;
|
|
55095
55131
|
}
|
|
55096
55132
|
this.replenishing.add(image);
|
|
55133
|
+
logger.debug(`[Pool] Starting background replenishment for image: ${image}`);
|
|
55097
55134
|
const promise = this.createContainer(image).then((container) => {
|
|
55098
55135
|
const pool = this.pools.get(image) ?? [];
|
|
55099
55136
|
if (pool.length < this.poolSize) {
|
|
55100
55137
|
pool.push({ container, createdAt: Date.now() });
|
|
55101
55138
|
this.pools.set(image, pool);
|
|
55139
|
+
logger.debug(`[Pool] Replenished container ${container.id} added to pool for ${image}. Pool size: ${pool.length}`);
|
|
55102
55140
|
} else {
|
|
55141
|
+
logger.debug(`[Pool] Replenished container ${container.id} not needed (pool for ${image} is full), destroying`);
|
|
55103
55142
|
container.remove({ force: true }).catch((err) => {
|
|
55104
|
-
|
|
55143
|
+
logger.error(`[Pool] Error destroying unneeded replenished container ${container.id}:`, err);
|
|
55105
55144
|
});
|
|
55106
55145
|
}
|
|
55107
55146
|
}).catch((err) => {
|
|
55108
|
-
|
|
55147
|
+
logger.error(`[Pool] Error during replenishment for ${image}:`, err);
|
|
55109
55148
|
}).finally(() => {
|
|
55110
55149
|
this.replenishing.delete(image);
|
|
55111
55150
|
this.pendingReplenishments.delete(promise);
|
|
@@ -55113,6 +55152,9 @@ class ContainerPool {
|
|
|
55113
55152
|
this.pendingReplenishments.add(promise);
|
|
55114
55153
|
}
|
|
55115
55154
|
}
|
|
55155
|
+
var init_pool = __esm(() => {
|
|
55156
|
+
init_logger();
|
|
55157
|
+
});
|
|
55116
55158
|
|
|
55117
55159
|
// src/engine/utils.ts
|
|
55118
55160
|
var exports_utils = {};
|
|
@@ -55309,7 +55351,7 @@ function getInstallCommand(runtime, packages) {
|
|
|
55309
55351
|
}
|
|
55310
55352
|
async function installPackages(container, runtime, packages) {
|
|
55311
55353
|
const cmd = getInstallCommand(runtime, packages);
|
|
55312
|
-
|
|
55354
|
+
logger.debug(`Installing packages: ${JSON.stringify(cmd)}`);
|
|
55313
55355
|
const env2 = [
|
|
55314
55356
|
"PATH=/sandbox/.local/bin:/sandbox/.npm-global/bin:/sandbox/.bun-global/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin"
|
|
55315
55357
|
];
|
|
@@ -55373,6 +55415,7 @@ class DockerIsol8 {
|
|
|
55373
55415
|
semaphore;
|
|
55374
55416
|
sandboxSize;
|
|
55375
55417
|
tmpSize;
|
|
55418
|
+
persist;
|
|
55376
55419
|
container = null;
|
|
55377
55420
|
persistentRuntime = null;
|
|
55378
55421
|
pool = null;
|
|
@@ -55392,6 +55435,10 @@ class DockerIsol8 {
|
|
|
55392
55435
|
this.semaphore = new Semaphore(maxConcurrent);
|
|
55393
55436
|
this.sandboxSize = options.sandboxSize ?? "512m";
|
|
55394
55437
|
this.tmpSize = options.tmpSize ?? "256m";
|
|
55438
|
+
this.persist = options.persist ?? false;
|
|
55439
|
+
if (options.debug) {
|
|
55440
|
+
logger.setDebug(true);
|
|
55441
|
+
}
|
|
55395
55442
|
}
|
|
55396
55443
|
async start() {}
|
|
55397
55444
|
async stop() {
|
|
@@ -55499,9 +55546,13 @@ class DockerIsol8 {
|
|
|
55499
55546
|
const execStream = await exec.start({ Tty: false });
|
|
55500
55547
|
yield* this.streamExecOutput(execStream, exec, container, timeoutMs);
|
|
55501
55548
|
} finally {
|
|
55502
|
-
|
|
55503
|
-
|
|
55504
|
-
}
|
|
55549
|
+
if (this.persist) {
|
|
55550
|
+
logger.debug(`[Persist] Leaving container running for inspection: ${container.id}`);
|
|
55551
|
+
} else {
|
|
55552
|
+
try {
|
|
55553
|
+
await container.remove({ force: true });
|
|
55554
|
+
} catch {}
|
|
55555
|
+
}
|
|
55505
55556
|
}
|
|
55506
55557
|
} finally {
|
|
55507
55558
|
this.semaphore.release();
|
|
@@ -55589,7 +55640,11 @@ class DockerIsol8 {
|
|
|
55589
55640
|
...req.outputPaths ? { files: await this.retrieveFiles(container, req.outputPaths) } : {}
|
|
55590
55641
|
};
|
|
55591
55642
|
} finally {
|
|
55592
|
-
|
|
55643
|
+
if (this.persist) {
|
|
55644
|
+
logger.debug(`[Persist] Leaving container running for inspection: ${container.id}`);
|
|
55645
|
+
} else {
|
|
55646
|
+
await this.pool.release(container, image);
|
|
55647
|
+
}
|
|
55593
55648
|
}
|
|
55594
55649
|
}
|
|
55595
55650
|
async executePersistent(req) {
|
|
@@ -55889,6 +55944,8 @@ class DockerIsol8 {
|
|
|
55889
55944
|
var import_dockerode, SANDBOX_WORKDIR = "/sandbox", MAX_OUTPUT_BYTES, PROXY_PORT = 8118, PROXY_STARTUP_TIMEOUT_MS = 5000, PROXY_POLL_INTERVAL_MS = 100;
|
|
55890
55945
|
var init_docker = __esm(() => {
|
|
55891
55946
|
init_runtime();
|
|
55947
|
+
init_logger();
|
|
55948
|
+
init_pool();
|
|
55892
55949
|
import_dockerode = __toESM(require_docker(), 1);
|
|
55893
55950
|
MAX_OUTPUT_BYTES = 1024 * 1024;
|
|
55894
55951
|
});
|
|
@@ -61231,7 +61288,7 @@ program2.command("setup").description("Check Docker and build isol8 images").opt
|
|
|
61231
61288
|
console.log(`
|
|
61232
61289
|
[DONE] Setup complete!`);
|
|
61233
61290
|
});
|
|
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) => {
|
|
61291
|
+
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").option("--debug", "Enable debug logging").option("--persist", "Keep container running after execution for inspection").action(async (file, opts) => {
|
|
61235
61292
|
const { code, runtime, engineOptions, engine, stdinData, fileExtension } = await resolveRunInput(file, opts);
|
|
61236
61293
|
const cleanup = async () => {
|
|
61237
61294
|
await engine.stop();
|
|
@@ -61492,8 +61549,14 @@ async function resolveRunInput(file, opts) {
|
|
|
61492
61549
|
...opts.pidsLimit ? { pidsLimit: Number.parseInt(opts.pidsLimit, 10) } : {},
|
|
61493
61550
|
...opts.writable ? { readonlyRootFs: false } : {},
|
|
61494
61551
|
...opts.maxOutput ? { maxOutputSize: Number.parseInt(opts.maxOutput, 10) } : {},
|
|
61495
|
-
...opts.tmpSize ? { tmpSize: opts.tmpSize } : {}
|
|
61552
|
+
...opts.tmpSize ? { tmpSize: opts.tmpSize } : {},
|
|
61553
|
+
debug: opts.debug ?? config.debug,
|
|
61554
|
+
persist: opts.persist ?? false
|
|
61496
61555
|
};
|
|
61556
|
+
if (engineOptions.debug) {
|
|
61557
|
+
const { logger: logger2 } = await Promise.resolve().then(() => (init_logger(), exports_logger));
|
|
61558
|
+
logger2.setDebug(true);
|
|
61559
|
+
}
|
|
61497
61560
|
let fileExtension;
|
|
61498
61561
|
if (file) {
|
|
61499
61562
|
const ext = file.substring(file.lastIndexOf("."));
|
|
@@ -61534,4 +61597,4 @@ if (!process.argv.slice(2).length) {
|
|
|
61534
61597
|
}
|
|
61535
61598
|
program2.parse();
|
|
61536
61599
|
|
|
61537
|
-
//# debugId=
|
|
61600
|
+
//# debugId=9AD6B80BEBAE034064756E2164756E21
|