kern-sandbox 0.2.13 → 0.2.15
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/index.js +35 -21
- package/package.json +1 -1
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.
|
|
39
|
+
const VERSION = "0.2.15";
|
|
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
|
|
@@ -1104,26 +1104,31 @@ function kernReportedOom(stderr) {
|
|
|
1104
1104
|
return false;
|
|
1105
1105
|
}
|
|
1106
1106
|
|
|
1107
|
+
/** The two prefixes kern's CLI writes AT COLUMN 0, which is the whole vocabulary of "kern is speaking".
|
|
1108
|
+
* `kern-cli/src/main.rs` reports every error through one `eprintln!("error: {}", ...)` and
|
|
1109
|
+
* `ui::scrub_message` indents every continuation line so a hostile value inside a message cannot forge a
|
|
1110
|
+
* line at column 0. Mirrors `_KERN_SPEAKING`.
|
|
1111
|
+
*
|
|
1112
|
+
* WHAT THIS REPLACED: a list of eleven message OPENINGS, each added after a caller measured a
|
|
1113
|
+
* `fault: null`. Enumerating the error texts of a binary with hundreds of them behind one printer cannot
|
|
1114
|
+
* be finished, and an external reviewer ended the argument with `image: ""`, whose
|
|
1115
|
+
* `error: bad image reference: empty` was in none of the eleven. */
|
|
1116
|
+
const KERN_SPEAKING = ["error: ", "kern:"];
|
|
1117
|
+
|
|
1118
|
+
/** True iff KERN ITSELF reported an error on this box, rather than the workload failing.
|
|
1119
|
+
*
|
|
1120
|
+
* It does NOT decide forgery from the text: a workload can print `error: anything` at column 0, and no
|
|
1121
|
+
* list of openings ever stopped that. The `KERN_STARTED_FD` byte does, and the callers pair it with this
|
|
1122
|
+
* predicate (`_runOne` drops a `startup_failed` when kern signalled a start; the kernel paths ask the
|
|
1123
|
+
* byte first). Mirrors `_looks_like_startup_failure`. */
|
|
1107
1124
|
function looksLikeStartupFailure(stderr) {
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
"error: registry:",
|
|
1113
|
-
"error: manifest:",
|
|
1114
|
-
"error: sandbox:",
|
|
1115
|
-
"error: box:",
|
|
1116
|
-
"error: oci:",
|
|
1117
|
-
"error: image:",
|
|
1118
|
-
];
|
|
1119
|
-
// The OOM sentence is skipped for a sharper reason than the benign notes: it is a report about a box
|
|
1120
|
-
// that RAN, and it is `kern:`-prefixed, so it used to satisfy this predicate. MEASURED, that is how a
|
|
1121
|
-
// real OOM on a resident kernel came back as `startup_failed` and was THROWN instead of returning an
|
|
1122
|
-
// `oom` fault.
|
|
1125
|
+
// kern's BENIGN lines are subtracted first, which is why this cannot be a bare prefix test: the
|
|
1126
|
+
// posture banner and `warning:`/`note:` carry `kern:` too. The OOM sentence is skipped for a sharper
|
|
1127
|
+
// reason: it is a report about a box that RAN, and MEASURED that is how a real OOM on a resident
|
|
1128
|
+
// kernel came back as `startup_failed` and was THROWN instead of returning an `oom` fault.
|
|
1123
1129
|
for (const line of stderr.split("\n")) {
|
|
1124
|
-
|
|
1125
|
-
if (
|
|
1126
|
-
if (s.includes("sandbox setup failed") || markers.some((m) => s.startsWith(m))) return true;
|
|
1130
|
+
if (isKernDiagnostic(line) || kernReportedOom(line)) continue;
|
|
1131
|
+
if (KERN_SPEAKING.some((m) => line.startsWith(m)) || line.includes("sandbox setup failed")) return true;
|
|
1127
1132
|
}
|
|
1128
1133
|
return false;
|
|
1129
1134
|
}
|
|
@@ -2805,7 +2810,13 @@ class Kernel {
|
|
|
2805
2810
|
`the code crashed: the cell died on signal ${workloadSignal} (${SIGNAL_NAMES[workloadSignal]}), which took the kernel box with it because the interpreter is its PID 1. The sandbox did not act; the next call reopens a kernel`,
|
|
2806
2811
|
rc,
|
|
2807
2812
|
];
|
|
2808
|
-
|
|
2813
|
+
// AND THE BYTE DECIDES WHETHER THE TEXT IS BELIEVED. kern writes the teardown payload only for a box
|
|
2814
|
+
// that existed, so `kernWrotePayload` is positive proof that this kernel STARTED and a
|
|
2815
|
+
// `startup_failed` here could only be a cell printing kern's prefix at column 0 and dying of
|
|
2816
|
+
// something else. The one-shot path gets this from `_runOne`, which drops the verdict when the start
|
|
2817
|
+
// byte is set; this path had no such guard, so the widened predicate gets it here.
|
|
2818
|
+
if (!kernWrotePayload && looksLikeStartupFailure(err))
|
|
2819
|
+
return ["startup_failed", "the kernel box failed to start", rc];
|
|
2809
2820
|
if (capSignal === 2)
|
|
2810
2821
|
return [
|
|
2811
2822
|
"killed",
|
|
@@ -3241,7 +3252,10 @@ class WarmBox {
|
|
|
3241
3252
|
if (oomVerdict(oomSignal, err, boxStarted)) {
|
|
3242
3253
|
type = "oom";
|
|
3243
3254
|
dflt = "the box exceeded its memory cap and was OOM-killed";
|
|
3244
|
-
} else if (looksLikeStartupFailure(err)) {
|
|
3255
|
+
} else if (!boxStarted && looksLikeStartupFailure(err)) {
|
|
3256
|
+
// `!boxStarted` for the reason `_kernelDeathFault` states: kern writes the teardown payload only
|
|
3257
|
+
// for a box that existed, so with the byte set this THROW would be a cell's own column-0 line
|
|
3258
|
+
// deciding that the box never came up.
|
|
3245
3259
|
throw new SandboxError(err.trim() || "the box failed to start");
|
|
3246
3260
|
} else if (capSignal === 2) {
|
|
3247
3261
|
dflt =
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kern-sandbox",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.15",
|
|
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",
|