isol8 0.4.2 → 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 +5 -2
- package/dist/cli.js +104 -23
- package/dist/cli.js.map +11 -10
- package/dist/index.js +67 -17
- package/dist/index.js.map +10 -9
- 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/runtime/adapter.d.ts +4 -1
- package/dist/src/runtime/adapter.d.ts.map +1 -1
- package/dist/src/types.d.ts +17 -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/dist/sshcrypto-0209sx47.node +0 -0
- package/package.json +1 -1
- package/schema/isol8.config.schema.json +5 -0
package/dist/index.js
CHANGED
|
@@ -146,7 +146,8 @@ var DEFAULT_CONFIG = {
|
|
|
146
146
|
autoPrune: true,
|
|
147
147
|
maxContainerAgeMs: 3600000
|
|
148
148
|
},
|
|
149
|
-
dependencies: {}
|
|
149
|
+
dependencies: {},
|
|
150
|
+
debug: false
|
|
150
151
|
};
|
|
151
152
|
function loadConfig(cwd) {
|
|
152
153
|
const searchPaths = [
|
|
@@ -180,7 +181,8 @@ function mergeConfig(defaults, overrides) {
|
|
|
180
181
|
dependencies: {
|
|
181
182
|
...defaults.dependencies,
|
|
182
183
|
...overrides.dependencies
|
|
183
|
-
}
|
|
184
|
+
},
|
|
185
|
+
debug: overrides.debug ?? defaults.debug
|
|
184
186
|
};
|
|
185
187
|
}
|
|
186
188
|
// src/engine/docker.ts
|
|
@@ -192,9 +194,12 @@ import Docker from "dockerode";
|
|
|
192
194
|
var adapters = new Map;
|
|
193
195
|
var extensionMap = new Map;
|
|
194
196
|
var RuntimeRegistry = {
|
|
195
|
-
register(adapter) {
|
|
197
|
+
register(adapter, aliases = []) {
|
|
196
198
|
adapters.set(adapter.name, adapter);
|
|
197
199
|
extensionMap.set(adapter.getFileExtension(), adapter);
|
|
200
|
+
for (const ext of aliases) {
|
|
201
|
+
extensionMap.set(ext, adapter);
|
|
202
|
+
}
|
|
198
203
|
},
|
|
199
204
|
get(name) {
|
|
200
205
|
const adapter = adapters.get(name);
|
|
@@ -280,7 +285,7 @@ var NodeAdapter = {
|
|
|
280
285
|
return ["node", "-e", code];
|
|
281
286
|
},
|
|
282
287
|
getFileExtension() {
|
|
283
|
-
return ".
|
|
288
|
+
return ".mjs";
|
|
284
289
|
}
|
|
285
290
|
};
|
|
286
291
|
|
|
@@ -301,11 +306,34 @@ var PythonAdapter = {
|
|
|
301
306
|
|
|
302
307
|
// src/runtime/index.ts
|
|
303
308
|
RuntimeRegistry.register(PythonAdapter);
|
|
304
|
-
RuntimeRegistry.register(NodeAdapter);
|
|
309
|
+
RuntimeRegistry.register(NodeAdapter, [".js", ".cjs"]);
|
|
305
310
|
RuntimeRegistry.register(BunAdapter);
|
|
306
311
|
RuntimeRegistry.register(bashAdapter);
|
|
307
312
|
RuntimeRegistry.register(DenoAdapter);
|
|
308
313
|
|
|
314
|
+
// src/utils/logger.ts
|
|
315
|
+
class Logger {
|
|
316
|
+
debugMode = false;
|
|
317
|
+
setDebug(enabled) {
|
|
318
|
+
this.debugMode = enabled;
|
|
319
|
+
}
|
|
320
|
+
debug(...args) {
|
|
321
|
+
if (this.debugMode) {
|
|
322
|
+
console.log("[DEBUG]", ...args);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
info(...args) {
|
|
326
|
+
console.log(...args);
|
|
327
|
+
}
|
|
328
|
+
warn(...args) {
|
|
329
|
+
console.warn("[WARN]", ...args);
|
|
330
|
+
}
|
|
331
|
+
error(...args) {
|
|
332
|
+
console.error("[ERROR]", ...args);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
var logger = new Logger;
|
|
336
|
+
|
|
309
337
|
// src/engine/concurrency.ts
|
|
310
338
|
class Semaphore {
|
|
311
339
|
max;
|
|
@@ -414,26 +442,32 @@ class ContainerPool {
|
|
|
414
442
|
...this.createOptions,
|
|
415
443
|
Image: image
|
|
416
444
|
});
|
|
445
|
+
logger.debug(`[Pool] Container ${container.id} created for image: ${image}`);
|
|
417
446
|
await container.start();
|
|
447
|
+
logger.debug(`[Pool] Container ${container.id} started`);
|
|
418
448
|
return container;
|
|
419
449
|
}
|
|
420
450
|
replenish(image) {
|
|
421
451
|
if (this.replenishing.has(image)) {
|
|
452
|
+
logger.debug(`[Pool] Replenishment for ${image} already in progress`);
|
|
422
453
|
return;
|
|
423
454
|
}
|
|
424
455
|
this.replenishing.add(image);
|
|
456
|
+
logger.debug(`[Pool] Starting background replenishment for image: ${image}`);
|
|
425
457
|
const promise = this.createContainer(image).then((container) => {
|
|
426
458
|
const pool = this.pools.get(image) ?? [];
|
|
427
459
|
if (pool.length < this.poolSize) {
|
|
428
460
|
pool.push({ container, createdAt: Date.now() });
|
|
429
461
|
this.pools.set(image, pool);
|
|
462
|
+
logger.debug(`[Pool] Replenished container ${container.id} added to pool for ${image}. Pool size: ${pool.length}`);
|
|
430
463
|
} else {
|
|
464
|
+
logger.debug(`[Pool] Replenished container ${container.id} not needed (pool for ${image} is full), destroying`);
|
|
431
465
|
container.remove({ force: true }).catch((err) => {
|
|
432
|
-
|
|
466
|
+
logger.error(`[Pool] Error destroying unneeded replenished container ${container.id}:`, err);
|
|
433
467
|
});
|
|
434
468
|
}
|
|
435
469
|
}).catch((err) => {
|
|
436
|
-
|
|
470
|
+
logger.error(`[Pool] Error during replenishment for ${image}:`, err);
|
|
437
471
|
}).finally(() => {
|
|
438
472
|
this.replenishing.delete(image);
|
|
439
473
|
this.pendingReplenishments.delete(promise);
|
|
@@ -632,7 +666,7 @@ function getInstallCommand(runtime, packages) {
|
|
|
632
666
|
}
|
|
633
667
|
async function installPackages(container, runtime, packages) {
|
|
634
668
|
const cmd = getInstallCommand(runtime, packages);
|
|
635
|
-
|
|
669
|
+
logger.debug(`Installing packages: ${JSON.stringify(cmd)}`);
|
|
636
670
|
const env = [
|
|
637
671
|
"PATH=/sandbox/.local/bin:/sandbox/.npm-global/bin:/sandbox/.bun-global/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin"
|
|
638
672
|
];
|
|
@@ -696,6 +730,7 @@ class DockerIsol8 {
|
|
|
696
730
|
semaphore;
|
|
697
731
|
sandboxSize;
|
|
698
732
|
tmpSize;
|
|
733
|
+
persist;
|
|
699
734
|
container = null;
|
|
700
735
|
persistentRuntime = null;
|
|
701
736
|
pool = null;
|
|
@@ -715,6 +750,10 @@ class DockerIsol8 {
|
|
|
715
750
|
this.semaphore = new Semaphore(maxConcurrent);
|
|
716
751
|
this.sandboxSize = options.sandboxSize ?? "512m";
|
|
717
752
|
this.tmpSize = options.tmpSize ?? "256m";
|
|
753
|
+
this.persist = options.persist ?? false;
|
|
754
|
+
if (options.debug) {
|
|
755
|
+
logger.setDebug(true);
|
|
756
|
+
}
|
|
718
757
|
}
|
|
719
758
|
async start() {}
|
|
720
759
|
async stop() {
|
|
@@ -790,7 +829,8 @@ class DockerIsol8 {
|
|
|
790
829
|
if (this.network === "filtered") {
|
|
791
830
|
await startProxy(container, this.networkFilter);
|
|
792
831
|
}
|
|
793
|
-
const
|
|
832
|
+
const ext = req.fileExtension ?? adapter.getFileExtension();
|
|
833
|
+
const filePath = `${SANDBOX_WORKDIR}/main${ext}`;
|
|
794
834
|
await writeFileViaExec(container, filePath, req.code);
|
|
795
835
|
if (req.installPackages?.length) {
|
|
796
836
|
await installPackages(container, req.runtime, req.installPackages);
|
|
@@ -821,9 +861,13 @@ class DockerIsol8 {
|
|
|
821
861
|
const execStream = await exec.start({ Tty: false });
|
|
822
862
|
yield* this.streamExecOutput(execStream, exec, container, timeoutMs);
|
|
823
863
|
} finally {
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
}
|
|
864
|
+
if (this.persist) {
|
|
865
|
+
logger.debug(`[Persist] Leaving container running for inspection: ${container.id}`);
|
|
866
|
+
} else {
|
|
867
|
+
try {
|
|
868
|
+
await container.remove({ force: true });
|
|
869
|
+
} catch {}
|
|
870
|
+
}
|
|
827
871
|
}
|
|
828
872
|
} finally {
|
|
829
873
|
this.semaphore.release();
|
|
@@ -864,7 +908,8 @@ class DockerIsol8 {
|
|
|
864
908
|
if (this.network === "filtered") {
|
|
865
909
|
await startProxy(container, this.networkFilter);
|
|
866
910
|
}
|
|
867
|
-
const
|
|
911
|
+
const ext = req.fileExtension ?? adapter.getFileExtension();
|
|
912
|
+
const filePath = `${SANDBOX_WORKDIR}/main${ext}`;
|
|
868
913
|
await writeFileViaExec(container, filePath, req.code);
|
|
869
914
|
if (req.installPackages?.length) {
|
|
870
915
|
await installPackages(container, req.runtime, req.installPackages);
|
|
@@ -910,7 +955,11 @@ class DockerIsol8 {
|
|
|
910
955
|
...req.outputPaths ? { files: await this.retrieveFiles(container, req.outputPaths) } : {}
|
|
911
956
|
};
|
|
912
957
|
} finally {
|
|
913
|
-
|
|
958
|
+
if (this.persist) {
|
|
959
|
+
logger.debug(`[Persist] Leaving container running for inspection: ${container.id}`);
|
|
960
|
+
} else {
|
|
961
|
+
await this.pool.release(container, image);
|
|
962
|
+
}
|
|
914
963
|
}
|
|
915
964
|
}
|
|
916
965
|
async executePersistent(req) {
|
|
@@ -921,7 +970,8 @@ class DockerIsol8 {
|
|
|
921
970
|
} else if (this.persistentRuntime?.name !== adapter.name) {
|
|
922
971
|
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.`);
|
|
923
972
|
}
|
|
924
|
-
const
|
|
973
|
+
const ext = req.fileExtension ?? adapter.getFileExtension();
|
|
974
|
+
const filePath = `${SANDBOX_WORKDIR}/exec_${Date.now()}${ext}`;
|
|
925
975
|
if (this.readonlyRootFs) {
|
|
926
976
|
await writeFileViaExec(this.container, filePath, req.code);
|
|
927
977
|
} else {
|
|
@@ -1383,7 +1433,7 @@ function createServer(options) {
|
|
|
1383
1433
|
// package.json
|
|
1384
1434
|
var package_default = {
|
|
1385
1435
|
name: "isol8",
|
|
1386
|
-
version: "0.4.
|
|
1436
|
+
version: "0.4.3",
|
|
1387
1437
|
description: "Secure code execution engine for AI agents",
|
|
1388
1438
|
author: "Illusion47586",
|
|
1389
1439
|
license: "MIT",
|
|
@@ -1501,4 +1551,4 @@ export {
|
|
|
1501
1551
|
BunAdapter
|
|
1502
1552
|
};
|
|
1503
1553
|
|
|
1504
|
-
//# debugId=
|
|
1554
|
+
//# debugId=BFAE8F3A0F89B57E64756E2164756E21
|