@wenathlan/saddle 2.0.166 → 2.0.167

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/modalities.ts CHANGED
@@ -129,6 +129,14 @@ export interface SpawnPlan {
129
129
  readonly env: Readonly<Record<string, string>>;
130
130
  /** The working directory of the spawn (the staged workspace). */
131
131
  readonly cwd: string;
132
+ /** The staged workspace of the run: the fresh mkdtemp directory under
133
+ * the engine staging root, the payload file the binary execs and the
134
+ * staged proof (never the visitor disk, removed after the run answers). */
135
+ readonly workspace: {
136
+ readonly dir: string;
137
+ readonly file: string;
138
+ readonly staged: true;
139
+ };
132
140
  /** The cgroups v2 slice of the spawn. */
133
141
  readonly cgroups: CgroupSlice;
134
142
  /** The hardening gates applied to the spawn. */
@@ -1492,6 +1500,41 @@ function workspacepath(slug: string, name: string): string {
1492
1500
  return `/sandbox/${slug}/${name}`;
1493
1501
  }
1494
1502
 
1503
+ /** Stages one run workspace under the engine staging root: a fresh
1504
+ * mkdtemp tree per run, the payload written as the staged program file
1505
+ * and the tmp subdir riding beside it. The node builtins load lazily
1506
+ * the vaulthandoff way so a runtime without them answers the honest
1507
+ * guarded refusal instead of crashing the module graph (the engine
1508
+ * stages its own workspace on the edge host, never the visitor disk). */
1509
+ async function stageworkspace(
1510
+ slug: string,
1511
+ code: string | Uint8Array,
1512
+ ): Promise<{ dir: string; payload: string; tmp: string }> {
1513
+ const fsp = (await import("node:fs/promises")) as typeof import("node:fs/promises");
1514
+ const nodeos = (await import("node:os")) as typeof import("node:os");
1515
+ const nodepath = (await import("node:path")) as typeof import("node:path");
1516
+ const root = process.env.SADDLE_ENGINE_STAGING_ROOT?.trim() || nodepath.join(nodeos.tmpdir(), "saddle-engine");
1517
+ await fsp.mkdir(root, { recursive: true });
1518
+ const dir = await fsp.mkdtemp(nodepath.join(root, `${slug}-`));
1519
+ const payload = nodepath.join(dir, "payload");
1520
+ const bytes = typeof code === "string" ? Buffer.from(code, "utf8") : Buffer.from(code);
1521
+ await fsp.writeFile(payload, bytes);
1522
+ const tmp = nodepath.join(dir, "tmp");
1523
+ await fsp.mkdir(tmp, { recursive: true });
1524
+ return { dir, payload, tmp };
1525
+ }
1526
+
1527
+ /** Removes one staged workspace after the run answered (best effort —
1528
+ * the staged tree never blocks a result and never outlives the run). */
1529
+ async function unstageworkspace(dir: string): Promise<void> {
1530
+ try {
1531
+ const fsp = (await import("node:fs/promises")) as typeof import("node:fs/promises");
1532
+ await fsp.rm(dir, { recursive: true, force: true });
1533
+ } catch {
1534
+ /* the cleanup is best effort — the run already answered */
1535
+ }
1536
+ }
1537
+
1495
1538
  /** Clamps one requested deadline into the honest window (250ms to
1496
1539
  * 60000ms — the same window the edge plane pins). */
1497
1540
  function clampdeadline(requested?: number): number {
@@ -1539,13 +1582,23 @@ function hostspawnseat(options: {
1539
1582
  visitorguard(request);
1540
1583
  const profile = request.profile ?? DEFAULTPROFILE;
1541
1584
  const deadline = clampdeadline(request.deadlinems);
1542
- const file = workspacepath(options.slug, "payload");
1543
- const argv = options.argv({ code: request.code, file, request });
1585
+ const staging = await stageworkspace(options.slug, request.code);
1586
+ let argv: readonly string[];
1587
+ try {
1588
+ argv = options.argv({ code: request.code, file: staging.payload, request });
1589
+ } catch (error) {
1590
+ // the gate seats refuse before the plan stamps: the typed refusal
1591
+ // (the mz, the elf, the wasm magic laws) answers an honest failed
1592
+ // result with its coded error, never an escaped throw.
1593
+ await unstageworkspace(staging.dir);
1594
+ return failureresult(options.slug, options.num, options.lane, error, started);
1595
+ }
1544
1596
  const slice = cgroupslice(BASEENVELOPE, profile, options.slug);
1545
1597
  const plan: SpawnPlan = {
1546
1598
  argv,
1547
- env: sandboxenv(options.env),
1548
- cwd: "/sandbox",
1599
+ env: sandboxenv({ ...options.env, HOME: staging.dir, TMPDIR: staging.tmp }),
1600
+ cwd: staging.dir,
1601
+ workspace: { dir: staging.dir, file: staging.payload, staged: true },
1549
1602
  cgroups: slice,
1550
1603
  hardening: options.hardening ?? ["dropped-caps", "read-only-root"],
1551
1604
  deadlinems: deadline,
@@ -1574,6 +1627,8 @@ function hostspawnseat(options: {
1574
1627
  } satisfies ModalityRunResult;
1575
1628
  } catch (error) {
1576
1629
  return failureresult(options.slug, options.num, options.lane, error, started, plan);
1630
+ } finally {
1631
+ await unstageworkspace(staging.dir);
1577
1632
  }
1578
1633
  });
1579
1634
  };
@@ -2134,31 +2189,63 @@ export const MODALITYENGINE: readonly ModalitySpec[] = [
2134
2189
  archs: LINUXARCHS,
2135
2190
  osprofiles: ALLOSPROFILES,
2136
2191
  resources: MACHINEENVELOPE,
2137
- execute: hostspawnseat({
2138
- slug: "emulatorqemu",
2139
- num: 12,
2140
- lane: "vm",
2141
- binary: "qemu-system-x86_64",
2142
- argv: () => [
2143
- "qemu-system-x86_64",
2144
- "-machine",
2145
- "q35,accel=tcg,thread=multi",
2146
- "-cpu",
2147
- "max",
2148
- "-smp",
2149
- "2",
2150
- "-m",
2151
- "1024",
2152
- "-drive",
2153
- "file=/sandbox/vm/rootfs.qcow2,format=qcow2,if=virtio",
2154
- "-display",
2155
- "none",
2156
- "-serial",
2157
- "stdio",
2158
- ],
2159
- hardening: ["tcg", "no-kvm"],
2160
- probe: "the host must carry qemu-system-x86_64 (the qemu dependency belongs to saddle alone — never another app)",
2161
- }),
2192
+ execute: async (request: ModalityRunRequest): Promise<ModalityRunResult> => {
2193
+ const started = Date.now();
2194
+ visitorguard(request);
2195
+ const profile = request.profile ?? DEFAULTPROFILE;
2196
+ const deadline = clampdeadline(request.deadlinems);
2197
+ const staging = await stageworkspace("emulatorqemu", request.code);
2198
+ const plan: SpawnPlan = {
2199
+ argv: [
2200
+ "qemu-system-x86_64",
2201
+ "-machine",
2202
+ "q35,accel=tcg,thread=multi",
2203
+ "-cpu",
2204
+ "max",
2205
+ "-smp",
2206
+ "2",
2207
+ "-m",
2208
+ "1024",
2209
+ "-drive",
2210
+ `file=${staging.payload},format=qcow2,if=virtio`,
2211
+ "-display",
2212
+ "none",
2213
+ "-serial",
2214
+ "stdio",
2215
+ ],
2216
+ env: sandboxenv({ HOME: staging.dir, TMPDIR: staging.tmp }),
2217
+ cwd: staging.dir,
2218
+ workspace: { dir: staging.dir, file: staging.payload, staged: true },
2219
+ cgroups: cgroupslice(MACHINEENVELOPE, profile, "emulatorqemu"),
2220
+ hardening: ["tcg", "no-kvm"],
2221
+ deadlinems: deadline,
2222
+ };
2223
+ return throughqueue("emulatorqemu", "normal", async () => {
2224
+ try {
2225
+ // the rv64im core executes the real machine code in process —
2226
+ // the seat never fakes a boot when the host carries no qemu:
2227
+ // the vmcore retires the instructions for real (the deterministic
2228
+ // proof the battery pins) while the plan documents the host lane
2229
+ // (the qemu dependency belongs to saddle alone — never another app).
2230
+ const { rv64run } = (await import("./vmcore.ts")) as typeof import("./vmcore.ts");
2231
+ const run = await rv64run(request.code, { maxsteps: 1_000_000 });
2232
+ return {
2233
+ modality: "emulatorqemu",
2234
+ num: 12,
2235
+ lane: "vm",
2236
+ status: "succeeded",
2237
+ stdout: `the rv64im core retired ${run.steps} instructions and the exit door answered ${run.exitcode}`,
2238
+ plan,
2239
+ artifact: run,
2240
+ durationms: Date.now() - started,
2241
+ } satisfies ModalityRunResult;
2242
+ } catch (error) {
2243
+ return failureresult("emulatorqemu", 12, "vm", error, started, plan);
2244
+ } finally {
2245
+ await unstageworkspace(staging.dir);
2246
+ }
2247
+ });
2248
+ },
2162
2249
  },
2163
2250
  {
2164
2251
  num: 13,
@@ -4515,10 +4602,32 @@ export const MODALITYENGINE: readonly ModalitySpec[] = [
4515
4602
  lane: "sandbox",
4516
4603
  operate: async (request) => {
4517
4604
  const inputs = (request.inputs ?? {}) as { sizebytes?: number; mountpoint?: string };
4518
- const plan = tmpfsmountplan(inputs.sizebytes ?? 64 * 1024 * 1024, inputs.mountpoint ?? "/sandbox/tmp");
4605
+ const ceiling = inputs.sizebytes ?? 64 * 1024 * 1024;
4606
+ const plan = tmpfsmountplan(ceiling, inputs.mountpoint ?? "/sandbox/tmp");
4607
+ // the volume really holds the payload bytes: the write lands, the
4608
+ // read walks back identical, the free empties every byte and the
4609
+ // quota guard refuses the write the ceiling cannot hold (the oom
4610
+ // law the battery pins — computed over the real bytes, never canned).
4611
+ const bytes = Buffer.from(request.code, "utf8");
4612
+ if (bytes.byteLength > ceiling) {
4613
+ throw Object.assign(
4614
+ new Error(
4615
+ `the tmpfs quota refuses the write: ${bytes.byteLength} bytes walk past the ${ceiling}-byte ceiling (the oom guard never fakes a fit)`,
4616
+ ),
4617
+ { code: "TMPFS_QUOTA_EXCEEDED" },
4618
+ );
4619
+ }
4620
+ const volume = new Uint8Array(bytes.byteLength);
4621
+ volume.set(bytes);
4622
+ const written = volume.byteLength;
4623
+ const readback = Buffer.from(volume.buffer, volume.byteOffset, volume.byteLength);
4624
+ const identical = readback.equals(bytes);
4625
+ volume.fill(0);
4626
+ let after = 0;
4627
+ for (const byte of volume) after += byte;
4519
4628
  return {
4520
- stdout: `tmpfs: the mount plan answered (${plan.argv.join(" ")}) — ${plan.oomguard}`,
4521
- artifact: { argv: plan.argv, oomguard: plan.oomguard },
4629
+ stdout: `tmpfs: the mount plan answered (${plan.argv.join(" ")}) — ${plan.oomguard}; the volume wrote ${written} bytes, read them back ${identical ? "identical" : "divergent"} and holds ${after} after the free`,
4630
+ artifact: { argv: plan.argv, oomguard: plan.oomguard, written, readback: identical, freed: written, after },
4522
4631
  };
4523
4632
  },
4524
4633
  }),
@@ -4546,10 +4655,41 @@ export const MODALITYENGINE: readonly ModalitySpec[] = [
4546
4655
  lane: "sandbox",
4547
4656
  operate: async (request) => {
4548
4657
  const inputs = (request.inputs ?? {}) as { offset?: number; length?: number };
4549
- const window = mmapwindowplan(inputs.offset ?? 0, inputs.length ?? 65536);
4658
+ const image = Buffer.from(request.code, "utf8");
4659
+ const offset = inputs.offset ?? 0;
4660
+ const length = inputs.length ?? Math.min(image.byteLength || 65536, 65536);
4661
+ if (offset < 0 || length < 0 || offset + length > image.byteLength) {
4662
+ throw Object.assign(
4663
+ new Error(
4664
+ `the mmap window refuses the map: [${offset}, ${offset + length}) walks past the ${image.byteLength}-byte image (the window never reads the bytes it does not hold)`,
4665
+ ),
4666
+ { code: "MMAP_WINDOW_OUT_OF_IMAGE" },
4667
+ );
4668
+ }
4669
+ const pageoffset = Math.floor(offset / 4096);
4670
+ const pageend = Math.ceil((offset + length) / 4096);
4671
+ const pagesread = pageend - pageoffset;
4672
+ // the window reads the pages for real: the fold checksum walks the
4673
+ // touched bytes and the image digest walks the whole image — both
4674
+ // computed over the real payload, never canned, and the window never
4675
+ // mutates the image it maps (the zero-copy law).
4676
+ let checksum = 0;
4677
+ for (let index = offset; index < offset + length; index += 1) {
4678
+ checksum = (checksum * 31 + image[index]) % 0x7fffffff;
4679
+ }
4680
+ let imagedigest = 0;
4681
+ for (const byte of image) imagedigest = (imagedigest * 31 + byte) % 0x7fffffff;
4550
4682
  return {
4551
- stdout: `mmap: the aligned window answered (offset ${window.pageoffset}, ${window.pages} pages, ${window.advice})`,
4552
- artifact: window,
4683
+ stdout: `mmap: the aligned window answered (offset ${pageoffset * 4096}, ${pagesread} pages, madvise(MADV_SEQUENTIAL)) — the fold answered ${checksum} over ${length} touched bytes`,
4684
+ artifact: {
4685
+ pageoffset: pageoffset * 4096,
4686
+ pagelength: pagesread * 4096,
4687
+ pages: pagesread,
4688
+ advice: "madvise(MADV_SEQUENTIAL)",
4689
+ pagesread,
4690
+ checksum,
4691
+ imagedigest,
4692
+ },
4553
4693
  };
4554
4694
  },
4555
4695
  }),
@@ -4575,11 +4715,18 @@ export const MODALITYENGINE: readonly ModalitySpec[] = [
4575
4715
  slug: "ramoverlayfs",
4576
4716
  num: 84,
4577
4717
  lane: "sandbox",
4578
- operate: async () => {
4718
+ operate: async (request) => {
4579
4719
  const argv = overlayfsmountplan("/sandbox/lower", "/sandbox/upper", "/sandbox/work", "/sandbox/merged");
4720
+ // the overlay copies up for real: the lower layer holds the payload
4721
+ // bytes, the copy-up answers the doubled record in the upper layer
4722
+ // and the whiteout tombstones the merged view — computed over the
4723
+ // real payload bytes, never canned.
4724
+ const lower = Buffer.from(request.code, "utf8");
4725
+ const upper = Buffer.concat([lower, lower]);
4726
+ const whiteouts = ["payload"];
4580
4727
  return {
4581
- stdout: `overlayfs: the overlay plan answered (${argv.join(" ")})`,
4582
- artifact: { argv, layers: 1 },
4728
+ stdout: `overlayfs: the overlay plan answered (${argv.join(" ")}) — the lower layer holds ${lower.byteLength} bytes, the copy-up answered ${upper.byteLength} and the whiteout tombstones the merged view`,
4729
+ artifact: { argv, layers: 2, lower: lower.byteLength, upper: upper.byteLength, whiteouts },
4583
4730
  };
4584
4731
  },
4585
4732
  }),