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 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 = require_sshcrypto();
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
- console.error(`[Pool] Error destroying unneeded replenished container ${container.id}:`, err);
55138
+ logger.error(`[Pool] Error destroying unneeded replenished container ${container.id}:`, err);
55105
55139
  });
55106
55140
  }
55107
55141
  }).catch((err) => {
55108
- console.error(`[Pool] Error during replenishment for ${image}:`, err);
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
- console.error(`[DEBUG] Installing packages: ${JSON.stringify(cmd)}`);
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
- try {
55503
- await container.remove({ force: true });
55504
- } catch {}
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
- await this.pool.release(container, image);
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 existsSync2, readFileSync as readFileSync2, writeFileSync } from "node:fs";
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
- var DOCKERFILE_DIR = new URL("../../docker", import.meta.url).pathname;
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) => existsSync2(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 (!existsSync2(filePath)) {
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=E455279A70D3A2C764756E2164756E21
61603
+ //# debugId=E350C5AB2EA12EB364756E2164756E21