kern-sandbox 0.2.20 → 0.2.22

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 +2 -2
  2. package/index.js +28 -9
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -164,8 +164,8 @@ Every relaxing option says so in its name or docs:
164
164
  - **mounts refused**: the host's own sources (`/`, `/etc`, `/root`, `/boot`, `/proc`, `/sys`, `/dev`,
165
165
  `$HOME`, the docker socket), any path with a **credential directory** in it (`.ssh`, `.aws`, `.gnupg`,
166
166
  `.kube`, `.docker`, `.azure`, `.password-store`, `.netrc`, `.git-credentials`, `.pypirc`, `.npmrc`),
167
- **kern's own state** (`$XDG_RUNTIME_DIR/kern`, the image cache, the config dir: the sandbox's control
168
- plane), and escaping targets.
167
+ **kern's own state** (`$XDG_RUNTIME_DIR/kern`, the image cache, the config dir, the data dir that
168
+ holds every named volume: the sandbox's control plane), and escaping targets.
169
169
  - **workspace I/O contained**: `writeFile`/`readFile` reject `..` escapes, open the final component
170
170
  `O_NOFOLLOW` so a symlink the box plants cannot redirect host I/O, and refuse anything that is not a
171
171
  REGULAR file (see the notes for the FIFO that made a read hang).
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.20";
39
+ const VERSION = "0.2.22";
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
@@ -456,16 +456,35 @@ const REFUSED_MOUNT_SOURCES = new Set([
456
456
  * follow the environment and a service manager moves them. */
457
457
  function kernStateDirs() {
458
458
  const uid = process.getuid();
459
- const runtime = process.env.XDG_RUNTIME_DIR || `/run/user/${uid}`;
460
459
  const home = os.homedir();
461
- const cache = process.env.XDG_CACHE_HOME || path.join(home, ".cache");
462
- const config = process.env.XDG_CONFIG_HOME || path.join(home, ".config");
463
- return [
464
- [path.join(runtime, "kern"), "kern's runtime state (the registry, instance dirs, netns handles and exit files of every box you are running)"],
465
- [`/run/user/${uid}/kern`, "kern's runtime state"],
466
- [path.join(cache, "kern"), "kern's image cache (a box that writes it poisons the rootfs a later box runs)"],
467
- [path.join(config, "kern"), "kern's configuration (the profiles a later box may be given)"],
460
+ // EACH DIRECTORY TWICE: where the environment says it is, AND where XDG says it is by default. The
461
+ // runtime dir was already spelled both ways; the other three were not, and a reviewer measured the
462
+ // consequence in one process - with `XDG_DATA_HOME=/tmp/xdh2`, `~/.local/share/kern` was ACCEPTED
463
+ // and still held `builds` and `volumes`. The variable answers "which kern will this SDK spawn",
464
+ // which is the right input for the guard, but data a previous run left on disk does not move with it.
465
+ //
466
+ // The DATA dir itself joined the list after the same reviewer took the refused two as the shape of
467
+ // the rule and looked for the rest: it holds `volumes/`, the CONTENT of every named volume on this
468
+ // host, and `builds/`, the records a later image is assembled from.
469
+ const known = [
470
+ [process.env.XDG_RUNTIME_DIR, `/run/user/${uid}`,
471
+ "kern's runtime state (the registry, instance dirs, netns handles and exit files of every box you are running)"],
472
+ [process.env.XDG_CACHE_HOME, path.join(home, ".cache"),
473
+ "kern's image cache (a box that writes it poisons the rootfs a later box runs)"],
474
+ [process.env.XDG_CONFIG_HOME, path.join(home, ".config"),
475
+ "kern's configuration (the profiles a later box may be given)"],
476
+ [process.env.XDG_DATA_HOME, path.join(home, ".local", "share"),
477
+ "kern's data (every named volume on this host, and the build records a later image is assembled from)"],
468
478
  ];
479
+ // A MAP, so the usual case where the variable IS the default collapses to one entry instead of
480
+ // listing the same directory twice with two different accounts of what it is.
481
+ const out = new Map();
482
+ for (const [configured, dflt, what] of known)
483
+ for (const base of [configured || dflt, dflt]) {
484
+ const dir = path.join(base, "kern");
485
+ if (!out.has(dir)) out.set(dir, what);
486
+ }
487
+ return [...out];
469
488
  }
470
489
 
471
490
  /** Credential directories, refused as a COMPONENT anywhere in the source. The set above is absolute
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kern-sandbox",
3
- "version": "0.2.20",
3
+ "version": "0.2.22",
4
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.",
5
5
  "keywords": [
6
6
  "sandbox",