isol8 0.4.3 → 0.5.1
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 +88 -22
- package/dist/cli.js.map +9 -8
- 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/image-builder.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/dist/sshcrypto-0209sx47.node +0 -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
|
@@ -6929,11 +6929,6 @@ 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
|
-
|
|
6937
6932
|
// node_modules/ssh2/lib/protocol/crypto/poly1305.js
|
|
6938
6933
|
var require_poly1305 = __commonJS((exports, module) => {
|
|
6939
6934
|
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";
|
|
@@ -7420,7 +7415,7 @@ var require_crypto = __commonJS((exports, module) => {
|
|
|
7420
7415
|
var ChaChaPolyDecipher;
|
|
7421
7416
|
var GenericDecipher;
|
|
7422
7417
|
try {
|
|
7423
|
-
binding =
|
|
7418
|
+
binding = (()=>{throw new Error("Cannot require module "+"./crypto/build/Release/sshcrypto.node");})();
|
|
7424
7419
|
({
|
|
7425
7420
|
AESGCMCipher,
|
|
7426
7421
|
ChaChaPolyCipher,
|
|
@@ -54798,7 +54793,8 @@ function mergeConfig(defaults, overrides) {
|
|
|
54798
54793
|
dependencies: {
|
|
54799
54794
|
...defaults.dependencies,
|
|
54800
54795
|
...overrides.dependencies
|
|
54801
|
-
}
|
|
54796
|
+
},
|
|
54797
|
+
debug: overrides.debug ?? defaults.debug
|
|
54802
54798
|
};
|
|
54803
54799
|
}
|
|
54804
54800
|
var DEFAULT_CONFIG;
|
|
@@ -54821,7 +54817,8 @@ var init_config = __esm(() => {
|
|
|
54821
54817
|
autoPrune: true,
|
|
54822
54818
|
maxContainerAgeMs: 3600000
|
|
54823
54819
|
},
|
|
54824
|
-
dependencies: {}
|
|
54820
|
+
dependencies: {},
|
|
54821
|
+
debug: false
|
|
54825
54822
|
};
|
|
54826
54823
|
});
|
|
54827
54824
|
|
|
@@ -54978,6 +54975,37 @@ var init_runtime = __esm(() => {
|
|
|
54978
54975
|
RuntimeRegistry.register(DenoAdapter);
|
|
54979
54976
|
});
|
|
54980
54977
|
|
|
54978
|
+
// src/utils/logger.ts
|
|
54979
|
+
var exports_logger = {};
|
|
54980
|
+
__export(exports_logger, {
|
|
54981
|
+
logger: () => logger
|
|
54982
|
+
});
|
|
54983
|
+
|
|
54984
|
+
class Logger {
|
|
54985
|
+
debugMode = false;
|
|
54986
|
+
setDebug(enabled) {
|
|
54987
|
+
this.debugMode = enabled;
|
|
54988
|
+
}
|
|
54989
|
+
debug(...args) {
|
|
54990
|
+
if (this.debugMode) {
|
|
54991
|
+
console.log("[DEBUG]", ...args);
|
|
54992
|
+
}
|
|
54993
|
+
}
|
|
54994
|
+
info(...args) {
|
|
54995
|
+
console.log(...args);
|
|
54996
|
+
}
|
|
54997
|
+
warn(...args) {
|
|
54998
|
+
console.warn("[WARN]", ...args);
|
|
54999
|
+
}
|
|
55000
|
+
error(...args) {
|
|
55001
|
+
console.error("[ERROR]", ...args);
|
|
55002
|
+
}
|
|
55003
|
+
}
|
|
55004
|
+
var logger;
|
|
55005
|
+
var init_logger = __esm(() => {
|
|
55006
|
+
logger = new Logger;
|
|
55007
|
+
});
|
|
55008
|
+
|
|
54981
55009
|
// src/engine/concurrency.ts
|
|
54982
55010
|
class Semaphore {
|
|
54983
55011
|
max;
|
|
@@ -55086,26 +55114,32 @@ class ContainerPool {
|
|
|
55086
55114
|
...this.createOptions,
|
|
55087
55115
|
Image: image
|
|
55088
55116
|
});
|
|
55117
|
+
logger.debug(`[Pool] Container ${container.id} created for image: ${image}`);
|
|
55089
55118
|
await container.start();
|
|
55119
|
+
logger.debug(`[Pool] Container ${container.id} started`);
|
|
55090
55120
|
return container;
|
|
55091
55121
|
}
|
|
55092
55122
|
replenish(image) {
|
|
55093
55123
|
if (this.replenishing.has(image)) {
|
|
55124
|
+
logger.debug(`[Pool] Replenishment for ${image} already in progress`);
|
|
55094
55125
|
return;
|
|
55095
55126
|
}
|
|
55096
55127
|
this.replenishing.add(image);
|
|
55128
|
+
logger.debug(`[Pool] Starting background replenishment for image: ${image}`);
|
|
55097
55129
|
const promise = this.createContainer(image).then((container) => {
|
|
55098
55130
|
const pool = this.pools.get(image) ?? [];
|
|
55099
55131
|
if (pool.length < this.poolSize) {
|
|
55100
55132
|
pool.push({ container, createdAt: Date.now() });
|
|
55101
55133
|
this.pools.set(image, pool);
|
|
55134
|
+
logger.debug(`[Pool] Replenished container ${container.id} added to pool for ${image}. Pool size: ${pool.length}`);
|
|
55102
55135
|
} else {
|
|
55136
|
+
logger.debug(`[Pool] Replenished container ${container.id} not needed (pool for ${image} is full), destroying`);
|
|
55103
55137
|
container.remove({ force: true }).catch((err) => {
|
|
55104
|
-
|
|
55138
|
+
logger.error(`[Pool] Error destroying unneeded replenished container ${container.id}:`, err);
|
|
55105
55139
|
});
|
|
55106
55140
|
}
|
|
55107
55141
|
}).catch((err) => {
|
|
55108
|
-
|
|
55142
|
+
logger.error(`[Pool] Error during replenishment for ${image}:`, err);
|
|
55109
55143
|
}).finally(() => {
|
|
55110
55144
|
this.replenishing.delete(image);
|
|
55111
55145
|
this.pendingReplenishments.delete(promise);
|
|
@@ -55113,6 +55147,9 @@ class ContainerPool {
|
|
|
55113
55147
|
this.pendingReplenishments.add(promise);
|
|
55114
55148
|
}
|
|
55115
55149
|
}
|
|
55150
|
+
var init_pool = __esm(() => {
|
|
55151
|
+
init_logger();
|
|
55152
|
+
});
|
|
55116
55153
|
|
|
55117
55154
|
// src/engine/utils.ts
|
|
55118
55155
|
var exports_utils = {};
|
|
@@ -55309,7 +55346,7 @@ function getInstallCommand(runtime, packages) {
|
|
|
55309
55346
|
}
|
|
55310
55347
|
async function installPackages(container, runtime, packages) {
|
|
55311
55348
|
const cmd = getInstallCommand(runtime, packages);
|
|
55312
|
-
|
|
55349
|
+
logger.debug(`Installing packages: ${JSON.stringify(cmd)}`);
|
|
55313
55350
|
const env2 = [
|
|
55314
55351
|
"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
55352
|
];
|
|
@@ -55373,6 +55410,7 @@ class DockerIsol8 {
|
|
|
55373
55410
|
semaphore;
|
|
55374
55411
|
sandboxSize;
|
|
55375
55412
|
tmpSize;
|
|
55413
|
+
persist;
|
|
55376
55414
|
container = null;
|
|
55377
55415
|
persistentRuntime = null;
|
|
55378
55416
|
pool = null;
|
|
@@ -55392,6 +55430,10 @@ class DockerIsol8 {
|
|
|
55392
55430
|
this.semaphore = new Semaphore(maxConcurrent);
|
|
55393
55431
|
this.sandboxSize = options.sandboxSize ?? "512m";
|
|
55394
55432
|
this.tmpSize = options.tmpSize ?? "256m";
|
|
55433
|
+
this.persist = options.persist ?? false;
|
|
55434
|
+
if (options.debug) {
|
|
55435
|
+
logger.setDebug(true);
|
|
55436
|
+
}
|
|
55395
55437
|
}
|
|
55396
55438
|
async start() {}
|
|
55397
55439
|
async stop() {
|
|
@@ -55499,9 +55541,13 @@ class DockerIsol8 {
|
|
|
55499
55541
|
const execStream = await exec.start({ Tty: false });
|
|
55500
55542
|
yield* this.streamExecOutput(execStream, exec, container, timeoutMs);
|
|
55501
55543
|
} finally {
|
|
55502
|
-
|
|
55503
|
-
|
|
55504
|
-
}
|
|
55544
|
+
if (this.persist) {
|
|
55545
|
+
logger.debug(`[Persist] Leaving container running for inspection: ${container.id}`);
|
|
55546
|
+
} else {
|
|
55547
|
+
try {
|
|
55548
|
+
await container.remove({ force: true });
|
|
55549
|
+
} catch {}
|
|
55550
|
+
}
|
|
55505
55551
|
}
|
|
55506
55552
|
} finally {
|
|
55507
55553
|
this.semaphore.release();
|
|
@@ -55589,7 +55635,11 @@ class DockerIsol8 {
|
|
|
55589
55635
|
...req.outputPaths ? { files: await this.retrieveFiles(container, req.outputPaths) } : {}
|
|
55590
55636
|
};
|
|
55591
55637
|
} finally {
|
|
55592
|
-
|
|
55638
|
+
if (this.persist) {
|
|
55639
|
+
logger.debug(`[Persist] Leaving container running for inspection: ${container.id}`);
|
|
55640
|
+
} else {
|
|
55641
|
+
await this.pool.release(container, image);
|
|
55642
|
+
}
|
|
55593
55643
|
}
|
|
55594
55644
|
}
|
|
55595
55645
|
async executePersistent(req) {
|
|
@@ -55889,6 +55939,8 @@ class DockerIsol8 {
|
|
|
55889
55939
|
var import_dockerode, SANDBOX_WORKDIR = "/sandbox", MAX_OUTPUT_BYTES, PROXY_PORT = 8118, PROXY_STARTUP_TIMEOUT_MS = 5000, PROXY_POLL_INTERVAL_MS = 100;
|
|
55890
55940
|
var init_docker = __esm(() => {
|
|
55891
55941
|
init_runtime();
|
|
55942
|
+
init_logger();
|
|
55943
|
+
init_pool();
|
|
55892
55944
|
import_dockerode = __toESM(require_docker(), 1);
|
|
55893
55945
|
MAX_OUTPUT_BYTES = 1024 * 1024;
|
|
55894
55946
|
});
|
|
@@ -57665,7 +57717,7 @@ var init_server = __esm(() => {
|
|
|
57665
57717
|
});
|
|
57666
57718
|
|
|
57667
57719
|
// src/cli.ts
|
|
57668
|
-
import { existsSync as
|
|
57720
|
+
import { existsSync as existsSync3, readFileSync as readFileSync2, writeFileSync } from "node:fs";
|
|
57669
57721
|
import { homedir as homedir2 } from "node:os";
|
|
57670
57722
|
import { join as join2, resolve as resolve2 } from "node:path";
|
|
57671
57723
|
|
|
@@ -61061,7 +61113,15 @@ init_docker();
|
|
|
61061
61113
|
|
|
61062
61114
|
// src/engine/image-builder.ts
|
|
61063
61115
|
init_runtime();
|
|
61064
|
-
|
|
61116
|
+
import { existsSync as existsSync2 } from "node:fs";
|
|
61117
|
+
function resolveDockerDir() {
|
|
61118
|
+
const fromBundled = new URL("../docker", import.meta.url).pathname;
|
|
61119
|
+
if (existsSync2(fromBundled)) {
|
|
61120
|
+
return fromBundled;
|
|
61121
|
+
}
|
|
61122
|
+
return new URL("../../docker", import.meta.url).pathname;
|
|
61123
|
+
}
|
|
61124
|
+
var DOCKERFILE_DIR = resolveDockerDir();
|
|
61065
61125
|
async function buildBaseImages(docker, onProgress) {
|
|
61066
61126
|
const runtimes = RuntimeRegistry.list();
|
|
61067
61127
|
for (const adapter of runtimes) {
|
|
@@ -61231,7 +61291,7 @@ program2.command("setup").description("Check Docker and build isol8 images").opt
|
|
|
61231
61291
|
console.log(`
|
|
61232
61292
|
[DONE] Setup complete!`);
|
|
61233
61293
|
});
|
|
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) => {
|
|
61294
|
+
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
61295
|
const { code, runtime, engineOptions, engine, stdinData, fileExtension } = await resolveRunInput(file, opts);
|
|
61236
61296
|
const cleanup = async () => {
|
|
61237
61297
|
await engine.stop();
|
|
@@ -61330,7 +61390,7 @@ program2.command("config").description("Show the resolved isol8 configuration").
|
|
|
61330
61390
|
join2(resolve2(process.cwd()), "isol8.config.json"),
|
|
61331
61391
|
join2(homedir2(), ".isol8", "config.json")
|
|
61332
61392
|
];
|
|
61333
|
-
const loadedFrom = searchPaths.find((p) =>
|
|
61393
|
+
const loadedFrom = searchPaths.find((p) => existsSync3(p));
|
|
61334
61394
|
if (opts.json) {
|
|
61335
61395
|
console.log(JSON.stringify(config, null, 2));
|
|
61336
61396
|
return;
|
|
@@ -61455,7 +61515,7 @@ async function resolveRunInput(file, opts) {
|
|
|
61455
61515
|
runtime = opts.runtime ?? "python";
|
|
61456
61516
|
} else if (file) {
|
|
61457
61517
|
const filePath = resolve2(file);
|
|
61458
|
-
if (!
|
|
61518
|
+
if (!existsSync3(filePath)) {
|
|
61459
61519
|
console.error(`[ERR] File not found: ${file}`);
|
|
61460
61520
|
process.exit(1);
|
|
61461
61521
|
}
|
|
@@ -61492,8 +61552,14 @@ async function resolveRunInput(file, opts) {
|
|
|
61492
61552
|
...opts.pidsLimit ? { pidsLimit: Number.parseInt(opts.pidsLimit, 10) } : {},
|
|
61493
61553
|
...opts.writable ? { readonlyRootFs: false } : {},
|
|
61494
61554
|
...opts.maxOutput ? { maxOutputSize: Number.parseInt(opts.maxOutput, 10) } : {},
|
|
61495
|
-
...opts.tmpSize ? { tmpSize: opts.tmpSize } : {}
|
|
61555
|
+
...opts.tmpSize ? { tmpSize: opts.tmpSize } : {},
|
|
61556
|
+
debug: opts.debug ?? config.debug,
|
|
61557
|
+
persist: opts.persist ?? false
|
|
61496
61558
|
};
|
|
61559
|
+
if (engineOptions.debug) {
|
|
61560
|
+
const { logger: logger2 } = await Promise.resolve().then(() => (init_logger(), exports_logger));
|
|
61561
|
+
logger2.setDebug(true);
|
|
61562
|
+
}
|
|
61497
61563
|
let fileExtension;
|
|
61498
61564
|
if (file) {
|
|
61499
61565
|
const ext = file.substring(file.lastIndexOf("."));
|
|
@@ -61534,4 +61600,4 @@ if (!process.argv.slice(2).length) {
|
|
|
61534
61600
|
}
|
|
61535
61601
|
program2.parse();
|
|
61536
61602
|
|
|
61537
|
-
//# debugId=
|
|
61603
|
+
//# debugId=E350C5AB2EA12EB364756E2164756E21
|