kern-sandbox 0.1.36 → 0.1.38

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 +57 -0
  2. package/index.js +1 -1
  3. package/package.json +1 -4
package/README.md CHANGED
@@ -249,6 +249,63 @@ explicit flags that **override** a profile's values (and the `memoryMb` default
249
249
  `memory`, so pass `memoryMb: null` to let the profile apply). The **MCP server** (`kern-mcp`, for Claude
250
250
  Desktop / Cursor) ships in the Python package `kern-sandbox` (`pip install kern-sandbox`).
251
251
 
252
+ ## Egress: the setting between no network and the host's
253
+
254
+ `network: false` gives the run phase no network and `network: true` gives it the host's. `egressAllow`
255
+ is the middle one, and usually the one an agent wants:
256
+
257
+ ```js
258
+ await withSandbox({ egressAllow: ["pypi.org", "files.pythonhosted.org"] }, async (sbx) => { /* ... */ });
259
+ ```
260
+
261
+ The box stays in its own network namespace and reaches the internet only through kern's filtering
262
+ proxy, which permits those domains and nothing else: a workload can fetch from an index you chose and
263
+ cannot exfiltrate elsewhere. Mutually exclusive with `network: true`. The `setup` box keeps full
264
+ network to install dependencies; the allowlist governs the run phase, which is the one executing code
265
+ you did not read.
266
+
267
+ `kernel()` returns a `Kernel`, and a refused mount throws `MountRefused` rather than the generic
268
+ `SandboxError`, so a caller can tell "this sandbox will not do that" from "the sandbox broke".
269
+ `DEFAULT_TMPFS_MB` and `version` are exported for callers that assert on them.
270
+
271
+ ## Prewarming: a box ready before the call arrives
272
+
273
+ `prewarm: N` keeps N boxes started in advance, each holding a booted interpreter that has run nothing,
274
+ so a `runCode` claims one instead of paying for a box start plus an interpreter boot. Measured on
275
+ `python:3.12-slim`, six calls each: **14.2 ms p50 by default against 0.8 ms with `prewarm: 4`**, and
276
+ 30.9 ms against 0.9 for the first call.
277
+
278
+ The refill runs while your agent thinks, so it is off the caller's clock. That also says when it buys
279
+ nothing: if calls arrive faster than the pool refills, the pool empties and you are back to the
280
+ default cost. N is the burst you want covered, not a throughput knob.
281
+
282
+ Each prewarmed box serves ONE call and is discarded, so the isolation is unchanged: a fresh box per
283
+ call, network off, the same caps. Only the moment of creation moves. That is the difference from
284
+ `kernel()`, which deliberately shares one process across cells.
285
+
286
+ ```js
287
+ await withSandbox({ image: "python:3.12-slim", prewarm: 4 }, async (sbx) => {
288
+ const r = await sbx.runCode("print(1)"); // served from the pool
289
+ });
290
+ ```
291
+
292
+ The pool key includes the image, the caps and the profiles, so a session with different settings never
293
+ receives a box built for another one.
294
+
295
+ ## Run pi's coding tools in a box
296
+
297
+ [`integrations/pi`](https://github.com/getkern/kern/tree/main/integrations/pi) is an extension for
298
+ [pi](https://github.com/earendil-works/pi) built on THIS binding: it routes pi's built-in `bash`,
299
+ `read`, `write`, `edit`, `ls`, `grep` and `find` tools into a kern box. The working directory is
300
+ mounted at `/workspace`, so edits write through to the host and everything else a command touches dies
301
+ with the box. pi's default posture is no sandbox: it runs as the user who launched it.
302
+
303
+ The two halves are not confined by the same thing, and the extension's README says which is which:
304
+ `bash` runs INSIDE the box (namespaces, seccomp allowlist, cgroup caps), while `read` and the staging
305
+ half of `write` are host filesystem calls guarded by this binding's `O_NOFOLLOW` and its
306
+ `/proc/self/fd` containment check. Needs Linux, the `kern` binary, and **Node 22 or newer**: pi's own
307
+ package manager imports `globSync` from `node:fs`, which landed in 22.
308
+
252
309
  ## Charts, rich results, live output, and checkpoints
253
310
 
254
311
  **Rich results (the "code interpreter" pattern).** `runCode` runs Python by default, and like a
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.1.36";
39
+ const VERSION = "0.1.38";
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,6 +1,6 @@
1
1
  {
2
2
  "name": "kern-sandbox",
3
- "version": "0.1.36",
3
+ "version": "0.1.38",
4
4
  "description": "kern is a fast, rootless sandbox and virtual resource runtime for any workload, including untrusted and AI-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.",
5
5
  "keywords": [
6
6
  "sandbox",
@@ -38,9 +38,6 @@
38
38
  "scripts": {
39
39
  "test": "node --test"
40
40
  },
41
- "dependencies": {
42
- "kern-sandbox": "file:../../../../../../tmp/kern-sandbox-0.1.36.tgz"
43
- },
44
41
  "os": [
45
42
  "linux"
46
43
  ]