kern-sandbox 0.2.25 → 0.2.26

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.
Files changed (3) hide show
  1. package/README.md +19 -6
  2. package/index.js +1 -1
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -12,10 +12,17 @@ kernel-enforced sandbox out of one static binary, with no daemon, no VM and no c
12
12
  tool-call, a model's generated snippet, a CI step: code that runs before anyone reads it gets its own
13
13
  box, and the box is thrown away after.
14
14
 
15
- Network off, memory and PID caps the kernel enforces, capabilities dropped, a deny-by-default seccomp
16
- allowlist, and a wall-clock deadline the binding applies from **outside** the box, so code that hangs
17
- cannot outlive it. Dependency-free: it shells out to the `kern` binary and does not re-implement
18
- isolation in JavaScript.
15
+ Network off, memory and PID caps the kernel enforces **where your host delegates them**,
16
+ capabilities dropped, a deny-by-default seccomp allowlist, and a wall-clock deadline the binding
17
+ applies from **outside** the box, so code that hangs cannot outlive it. Whether the caps bind is a property of your
18
+ HOST, not of kern: they need a delegated cgroup, which a desktop session has and a bare root shell
19
+ in a container often does not. `kern doctor` says which you have, and `requireLimits: true` makes an
20
+ unenforceable cap FATAL: the box refuses to start rather than run uncapped. It arrives the way every
21
+ other refusal does, as `fault.type === "startup_failed"` on the result, NOT as an exception from the
22
+ constructor, so a caller that only catches exceptions will walk past it.
23
+
24
+ Dependency-free: it shells out to the `kern` binary and does not re-implement isolation in
25
+ JavaScript.
19
26
 
20
27
  **Your loop reads a field, not a stack trace.** A timeout, an OOM-kill, a blocked syscall or a missing
21
28
  interpreter each arrive as a typed `fault` on the result, beside stdout and the exit code, so the
@@ -254,11 +261,16 @@ or Redis connection under `egressAllow` cannot resolve its host. For a database,
254
261
  `prewarm: N` keeps N boxes started in advance, each holding a booted interpreter that has run nothing,
255
262
  and refills in the background while your agent thinks. Measured on `python:3.12-slim`:
256
263
 
257
- | | first call | p50 within the burst |
264
+ | `runCode` | first call | p50 within the burst |
258
265
  |---|---:|---:|
259
266
  | default | 30.9 ms | 14.2 ms |
260
267
  | `prewarm: 4` | 0.9 ms | **0.8 ms** |
261
268
 
269
+ **The number is `runCode`, not `run()`.** A prewarmed box holds a BOOTED INTERPRETER, so what the
270
+ pool removes is the interpreter's cost and not the box's. `run(["true"])` starts a fresh box either
271
+ way and reads the same either way: measured, 4.74 ms with the pool against 4.67 ms without it. Time
272
+ the wrong call and prewarming looks like a no-op.
273
+
262
274
  **The pool covers a burst, not a rate**, and it refills in the background: past N the cost returns to
263
275
  the default, and a call made immediately after construction pays the default until the boxes exist.
264
276
 
@@ -323,7 +335,8 @@ hostile or belongs to someone else. It costs what a machine costs: measured here
323
335
  0.43.0 on the same laptop, half a second per command in a live sandbox and about three seconds to
324
336
  create one, against 2 ms and 4 ms for kern, with `uname -r` inside reading its own kernel there and
325
337
  the host's here. kern is for the OTHER job, the one an agent loop does a thousand times: a cell per
326
- call, network off, memory and pids the kernel enforces, a deadline applied from outside the box.
338
+ call, network off, memory and pids the kernel enforces where the host delegates them, a
339
+ deadline applied from outside the box.
327
340
  Pick by which job you have, not by the ratio.
328
341
 
329
342
  **What the box does NOT hide from the code inside it.** The caps are real and the kernel enforces
package/index.js CHANGED
@@ -36,7 +36,7 @@ const crypto = require("crypto");
36
36
  const zlib = require("zlib");
37
37
  const { spawn, spawnSync } = require("child_process");
38
38
 
39
- const VERSION = "0.2.25";
39
+ const VERSION = "0.2.26";
40
40
 
41
41
  const DEFAULT_IMAGE = "python:3.12-slim";
42
42
  const WORKSPACE = "/workspace"; // where the persistent workspace is mounted inside every box
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "kern-sandbox",
3
- "version": "0.2.25",
4
- "description": "kern is a fast, rootless sandbox and virtual resource runtime for any workload, including untrusted and LLM-generated code; kern-sandbox is its Node/TypeScript binding. Run untrusted or agent-generated code (Python/JS/Bash) in a real, kernel-enforced box in single-digit milliseconds, with no cloud, no account and no VM.",
3
+ "version": "0.2.26",
4
+ "description": "kern is a fast, rootless sandbox and virtual resource runtime for any workload, including untrusted and LLM-generated code; kern-sandbox is its Node/TypeScript binding. Run untrusted or agent-generated code (Python/JS/Bash) in a real, kernel-enforced box, one per call, with no cloud, no account and no VM.",
5
5
  "keywords": [
6
6
  "sandbox",
7
7
  "kern",