sandboxedjs 0.1.66 → 0.1.68

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/dist/index.js CHANGED
@@ -489,6 +489,9 @@ function normalizeSignal(spec) {
489
489
  const withPrefix = upper.startsWith("SIG") ? upper : "SIG" + upper;
490
490
  return withPrefix in SIGNALS ? withPrefix : null;
491
491
  }
492
+ function signalNumber(name) {
493
+ return SIGNALS[name] ?? 0;
494
+ }
492
495
  function exitCodeForSignal(sig) {
493
496
  return 128 + (SIGNALS[sig] ?? 0);
494
497
  }
@@ -17800,7 +17803,10 @@ var Op = {
17800
17803
  getpeername: 1801,
17801
17804
  setsockopt: 1802,
17802
17805
  getsockopt: 1803,
17803
- socket_close: 1804
17806
+ socket_close: 1804,
17807
+ spawn: 2048,
17808
+ waitpid: 2049,
17809
+ kill: 2050
17804
17810
  };
17805
17811
  var Errno = {
17806
17812
  EPERM: 1,
@@ -17811,6 +17817,7 @@ var Errno = {
17811
17817
  ENXIO: 6,
17812
17818
  E2BIG: 7,
17813
17819
  EBADF: 9,
17820
+ ECHILD: 10,
17814
17821
  EAGAIN: 11,
17815
17822
  ENOMEM: 12,
17816
17823
  EACCES: 13,
@@ -17838,6 +17845,7 @@ var Errno = {
17838
17845
  ELOOP: 40,
17839
17846
  ENODATA: 61,
17840
17847
  ENOTSOCK: 88,
17848
+ EPROTONOSUPPORT: 93,
17841
17849
  EAFNOSUPPORT: 97,
17842
17850
  EADDRINUSE: 98,
17843
17851
  EADDRNOTAVAIL: 99,
@@ -17945,7 +17953,7 @@ var wheels_default = {
17945
17953
 
17946
17954
  // package.json
17947
17955
  var package_default = {
17948
- version: "0.1.66"};
17956
+ version: "0.1.68"};
17949
17957
 
17950
17958
  // src/runtime/python/config.ts
17951
17959
  var bundledManifest = {
@@ -18490,6 +18498,9 @@ function toPosixError(error) {
18490
18498
  };
18491
18499
  return new PosixError(code && mapped[code] ? mapped[code] : Errno.EIO, message);
18492
18500
  }
18501
+
18502
+ // src/runtime/python/backend.ts
18503
+ init_signals();
18493
18504
  var DescriptorTable = class _DescriptorTable {
18494
18505
  slots = /* @__PURE__ */ new Map();
18495
18506
  /** Descriptions this table shares with others, so close counts correctly. */
@@ -19143,6 +19154,9 @@ var MAX_TRANSFER = 8 * 1024 * 1024;
19143
19154
  var POLLIN = 1;
19144
19155
  var POLLOUT = 4;
19145
19156
  var POLLHUP = 16;
19157
+ var AF_INET = 2;
19158
+ var SOCK_STREAM = 1;
19159
+ var IPPROTO_TCP = 6;
19146
19160
  function createHostAbiServer(proc) {
19147
19161
  const files = new FileService(proc.vfs, proc.cred);
19148
19162
  const started = Date.now();
@@ -19380,6 +19394,46 @@ function createHostAbiServer(proc) {
19380
19394
  const joined = Object.entries(proc.env).map(([key, value]) => `${key}=${value}`).join("\0");
19381
19395
  return { status: 0, payload: new Writer().string(joined).finish() };
19382
19396
  }
19397
+ /* --------------------------------------------------------- processes */
19398
+ case Op.spawn: {
19399
+ const argv = [];
19400
+ for (let i = 0, n = r.u32(); i < n; i++) argv.push(r.string());
19401
+ const env2 = {};
19402
+ for (let i = 0, n = r.u32(); i < n; i++) {
19403
+ const entry = r.string();
19404
+ const split2 = entry.indexOf("=");
19405
+ if (split2 > 0) env2[entry.slice(0, split2)] = entry.slice(split2 + 1);
19406
+ }
19407
+ const cwd = r.string() || proc.cwd;
19408
+ const files2 = /* @__PURE__ */ new Map();
19409
+ for (let i = 0, n = r.u32(); i < n; i++) {
19410
+ const childFd = r.u32() | 0;
19411
+ const parentFd = r.u32() | 0;
19412
+ files2.set(childFd, proc.table.get(parentFd));
19413
+ }
19414
+ if (!proc.processes) throw new PosixError(Errno.ENOSYS);
19415
+ if (argv.length === 0) throw new PosixError(Errno.EINVAL);
19416
+ return { status: await proc.processes.spawn({ argv, env: env2, cwd: resolve3(cwd), files: files2 }) };
19417
+ }
19418
+ case Op.waitpid: {
19419
+ const pid = r.u32() | 0;
19420
+ const options = r.u32() | 0;
19421
+ if (!proc.processes) throw new PosixError(Errno.ENOSYS);
19422
+ const result = await Promise.race([
19423
+ proc.processes.wait(pid, options),
19424
+ aborted().then(() => {
19425
+ throw new PosixError(Errno.EINTR);
19426
+ })
19427
+ ]);
19428
+ return { status: 0, payload: new Writer().i32(result.pid).i32(result.status).finish() };
19429
+ }
19430
+ case Op.kill: {
19431
+ const pid = r.u32() | 0;
19432
+ const signal = r.u32() | 0;
19433
+ if (!proc.processes) throw new PosixError(Errno.ENOSYS);
19434
+ proc.processes.kill(pid, signal);
19435
+ return { status: 0 };
19436
+ }
19383
19437
  /* ---------------------------------------------------------- entropy */
19384
19438
  case Op.getrandom: {
19385
19439
  const length = Math.min(r.u32(), 65536);
@@ -19392,7 +19446,8 @@ function createHostAbiServer(proc) {
19392
19446
  const family = r.u32();
19393
19447
  const type = r.u32();
19394
19448
  const protocol = r.i32();
19395
- if (family !== 2 || (type & 15) !== 1 || protocol !== 0) throw new PosixError(Errno.EAFNOSUPPORT);
19449
+ if (family !== AF_INET || (type & 15) !== SOCK_STREAM) throw new PosixError(Errno.EAFNOSUPPORT);
19450
+ if (protocol !== 0 && protocol !== IPPROTO_TCP) throw new PosixError(Errno.EPROTONOSUPPORT);
19396
19451
  if (!proc.sockets) throw new PosixError(Errno.ENOSYS);
19397
19452
  return { status: proc.table.add(new SocketDescription(new VirtualTcpSocket(proc.sockets))) };
19398
19453
  }
@@ -19732,6 +19787,7 @@ async function startPythonProcess(options) {
19732
19787
  table.set(0, stdin);
19733
19788
  table.set(1, stdout);
19734
19789
  table.set(2, stderr);
19790
+ for (const [fd, description] of options.inherit ?? []) table.set(fd, description);
19735
19791
  const controller = new AbortController();
19736
19792
  const abort = () => controller.abort();
19737
19793
  options.signal.addEventListener("abort", abort, { once: true });
@@ -19745,7 +19801,8 @@ async function startPythonProcess(options) {
19745
19801
  env: options.env,
19746
19802
  cwd: options.cwd,
19747
19803
  signal: controller.signal,
19748
- sockets: options.sockets
19804
+ sockets: options.sockets,
19805
+ processes: options.processes
19749
19806
  });
19750
19807
  const buffers = createHostTransportBuffers();
19751
19808
  let fault = null;
@@ -20298,6 +20355,133 @@ raise SystemExit(entry())
20298
20355
  }
20299
20356
 
20300
20357
  // src/runtime/python/backend.ts
20358
+ var PENDING_INHERITANCE = /* @__PURE__ */ new Map();
20359
+ var INHERIT_TOKEN = "SBX_PYTHON_INHERIT";
20360
+ var WNOHANG = 1;
20361
+ function claimInheritance(env2) {
20362
+ const token = env2[INHERIT_TOKEN];
20363
+ if (!token) return void 0;
20364
+ const files = PENDING_INHERITANCE.get(token);
20365
+ PENDING_INHERITANCE.delete(token);
20366
+ delete env2[INHERIT_TOKEN];
20367
+ return files;
20368
+ }
20369
+ function waitStatus(proc) {
20370
+ if (proc.termSignal) return signalNumber(proc.termSignal) & 127;
20371
+ return ((proc.exitCode ?? 0) & 255) << 8;
20372
+ }
20373
+ function outputFor(description, fallback) {
20374
+ if (!description) return fallback;
20375
+ return {
20376
+ write(data) {
20377
+ description.write(typeof data === "string" ? new TextEncoder().encode(data) : data);
20378
+ },
20379
+ end() {
20380
+ },
20381
+ get closed() {
20382
+ return false;
20383
+ },
20384
+ isTTY: fallback.isTTY
20385
+ };
20386
+ }
20387
+ function createProcessService(ctx) {
20388
+ const children = /* @__PURE__ */ new Map();
20389
+ const exited = (proc) => proc.exitCode !== null || proc.termSignal !== null;
20390
+ return {
20391
+ async spawn(request) {
20392
+ const token = `${ctx.proc.pid}:${Math.random().toString(36).slice(2)}`;
20393
+ const extra = /* @__PURE__ */ new Map();
20394
+ for (const [fd, description] of request.files) {
20395
+ if (fd > 2) extra.set(fd, description);
20396
+ }
20397
+ const env2 = { ...request.env };
20398
+ if (extra.size > 0) {
20399
+ PENDING_INHERITANCE.set(token, extra);
20400
+ env2[INHERIT_TOKEN] = token;
20401
+ }
20402
+ const stdin = request.files.get(0);
20403
+ const argv = [containerProgram(ctx, request.argv[0] ?? ""), ...request.argv.slice(1)];
20404
+ const proc = ctx.kernel.spawn(argv, {
20405
+ cwd: request.cwd,
20406
+ env: env2,
20407
+ cred: ctx.cred,
20408
+ ppid: ctx.proc.pid,
20409
+ stdin: stdin ? descriptionInput(stdin) : void 0,
20410
+ stdout: outputFor(request.files.get(1), ctx.stdout),
20411
+ stderr: outputFor(request.files.get(2), ctx.stderr)
20412
+ });
20413
+ children.set(proc.pid, proc);
20414
+ void proc.wait().finally(() => PENDING_INHERITANCE.delete(token));
20415
+ return proc.pid;
20416
+ },
20417
+ async wait(pid, options) {
20418
+ const candidates = pid > 0 ? [children.get(pid)].filter((p) => p !== void 0) : [...children.values()];
20419
+ if (candidates.length === 0) throw new PosixError(Errno.ECHILD);
20420
+ const reap = (proc) => {
20421
+ children.delete(proc.pid);
20422
+ return { pid: proc.pid, status: waitStatus(proc) };
20423
+ };
20424
+ const done = candidates.find(exited);
20425
+ if (done) return reap(done);
20426
+ if (options & WNOHANG) return { pid: 0, status: 0 };
20427
+ await Promise.race(candidates.map((proc) => proc.wait()));
20428
+ const finished = candidates.find(exited);
20429
+ if (!finished) throw new PosixError(Errno.ECHILD);
20430
+ return reap(finished);
20431
+ },
20432
+ kill(pid, signal) {
20433
+ const proc = children.get(pid) ?? ctx.kernel.procs.get(pid);
20434
+ if (!proc) throw new PosixError(Errno.ESRCH);
20435
+ if (signal === 0) return;
20436
+ const name = SIGNAL_NAMES[signal];
20437
+ if (!name) throw new PosixError(Errno.EINVAL);
20438
+ proc.deliver(name);
20439
+ }
20440
+ };
20441
+ }
20442
+ function containerProgram(ctx, program) {
20443
+ const resolvable = (name) => name !== "" && ctx.kernel.resolveExecutable(name, ctx.cwd, ctx.env, ctx.cred) !== null;
20444
+ if (resolvable(program)) return program;
20445
+ const base2 = program.slice(program.lastIndexOf("/") + 1);
20446
+ if (resolvable(base2)) return base2;
20447
+ if (base2.startsWith("python")) return "python3";
20448
+ return program;
20449
+ }
20450
+ function descriptionInput(description) {
20451
+ const read = async (size) => {
20452
+ for (; ; ) {
20453
+ try {
20454
+ const chunk = description.read(size);
20455
+ if (chunk.length === 0) return null;
20456
+ return chunk;
20457
+ } catch {
20458
+ await description.whenReady();
20459
+ }
20460
+ }
20461
+ };
20462
+ return {
20463
+ isTTY: false,
20464
+ interactive: false,
20465
+ read,
20466
+ async readAll() {
20467
+ const parts = [];
20468
+ for (; ; ) {
20469
+ const chunk = await read(65536);
20470
+ if (chunk === null) break;
20471
+ parts.push(chunk);
20472
+ }
20473
+ let total = 0;
20474
+ for (const part of parts) total += part.length;
20475
+ const out = new Uint8Array(total);
20476
+ let at = 0;
20477
+ for (const part of parts) {
20478
+ out.set(part, at);
20479
+ at += part.length;
20480
+ }
20481
+ return out;
20482
+ }
20483
+ };
20484
+ }
20301
20485
  function withSitePackages(env2) {
20302
20486
  const existing = env2.PYTHONPATH;
20303
20487
  return {
@@ -20338,6 +20522,8 @@ async function runOwnedPython(ctx, argv) {
20338
20522
  const { manifest, workerUrl } = pythonBackend();
20339
20523
  if (!manifest) throw new Error("no Python runtime manifest is configured");
20340
20524
  const mounts = containerMounts(ctx);
20525
+ const env2 = withSitePackages(ctx.env);
20526
+ const inherit = claimInheritance(env2);
20341
20527
  const process2 = await startPythonProcess({
20342
20528
  manifest,
20343
20529
  workerUrl: await resolveWorkerUrl(workerUrl),
@@ -20346,14 +20532,16 @@ async function runOwnedPython(ctx, argv) {
20346
20532
  pid: ctx.proc.pid,
20347
20533
  ppid: ctx.proc.ppid ?? 1,
20348
20534
  argv,
20349
- env: withSitePackages(ctx.env),
20535
+ env: env2,
20350
20536
  cwd: ctx.cwd,
20351
20537
  isTty: isTerminal(ctx),
20352
20538
  mounts,
20353
20539
  onStdout: (data) => ctx.stdout.write(data),
20354
20540
  onStderr: (data) => ctx.stderr.write(data),
20355
20541
  signal: ctx.signal,
20356
- sockets: ctx.kernel.pod.sockets
20542
+ sockets: ctx.kernel.pod.sockets,
20543
+ processes: createProcessService(ctx),
20544
+ inherit
20357
20545
  });
20358
20546
  void pumpStdin(ctx, process2);
20359
20547
  return process2.wait();