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.cjs CHANGED
@@ -506,6 +506,9 @@ function normalizeSignal(spec) {
506
506
  const withPrefix = upper.startsWith("SIG") ? upper : "SIG" + upper;
507
507
  return withPrefix in exports.SIGNALS ? withPrefix : null;
508
508
  }
509
+ function signalNumber(name) {
510
+ return exports.SIGNALS[name] ?? 0;
511
+ }
509
512
  function exitCodeForSignal(sig) {
510
513
  return 128 + (exports.SIGNALS[sig] ?? 0);
511
514
  }
@@ -17817,7 +17820,10 @@ var Op = {
17817
17820
  getpeername: 1801,
17818
17821
  setsockopt: 1802,
17819
17822
  getsockopt: 1803,
17820
- socket_close: 1804
17823
+ socket_close: 1804,
17824
+ spawn: 2048,
17825
+ waitpid: 2049,
17826
+ kill: 2050
17821
17827
  };
17822
17828
  var Errno = {
17823
17829
  EPERM: 1,
@@ -17828,6 +17834,7 @@ var Errno = {
17828
17834
  ENXIO: 6,
17829
17835
  E2BIG: 7,
17830
17836
  EBADF: 9,
17837
+ ECHILD: 10,
17831
17838
  EAGAIN: 11,
17832
17839
  ENOMEM: 12,
17833
17840
  EACCES: 13,
@@ -17855,6 +17862,7 @@ var Errno = {
17855
17862
  ELOOP: 40,
17856
17863
  ENODATA: 61,
17857
17864
  ENOTSOCK: 88,
17865
+ EPROTONOSUPPORT: 93,
17858
17866
  EAFNOSUPPORT: 97,
17859
17867
  EADDRINUSE: 98,
17860
17868
  EADDRNOTAVAIL: 99,
@@ -17962,7 +17970,7 @@ var wheels_default = {
17962
17970
 
17963
17971
  // package.json
17964
17972
  var package_default = {
17965
- version: "0.1.66"};
17973
+ version: "0.1.68"};
17966
17974
 
17967
17975
  // src/runtime/python/config.ts
17968
17976
  var bundledManifest = {
@@ -18507,6 +18515,9 @@ function toPosixError(error) {
18507
18515
  };
18508
18516
  return new PosixError(code && mapped[code] ? mapped[code] : Errno.EIO, message);
18509
18517
  }
18518
+
18519
+ // src/runtime/python/backend.ts
18520
+ init_signals();
18510
18521
  var DescriptorTable = class _DescriptorTable {
18511
18522
  slots = /* @__PURE__ */ new Map();
18512
18523
  /** Descriptions this table shares with others, so close counts correctly. */
@@ -19160,6 +19171,9 @@ var MAX_TRANSFER = 8 * 1024 * 1024;
19160
19171
  var POLLIN = 1;
19161
19172
  var POLLOUT = 4;
19162
19173
  var POLLHUP = 16;
19174
+ var AF_INET = 2;
19175
+ var SOCK_STREAM = 1;
19176
+ var IPPROTO_TCP = 6;
19163
19177
  function createHostAbiServer(proc) {
19164
19178
  const files = new FileService(proc.vfs, proc.cred);
19165
19179
  const started = Date.now();
@@ -19397,6 +19411,46 @@ function createHostAbiServer(proc) {
19397
19411
  const joined = Object.entries(proc.env).map(([key, value]) => `${key}=${value}`).join("\0");
19398
19412
  return { status: 0, payload: new Writer().string(joined).finish() };
19399
19413
  }
19414
+ /* --------------------------------------------------------- processes */
19415
+ case Op.spawn: {
19416
+ const argv = [];
19417
+ for (let i = 0, n = r.u32(); i < n; i++) argv.push(r.string());
19418
+ const env2 = {};
19419
+ for (let i = 0, n = r.u32(); i < n; i++) {
19420
+ const entry = r.string();
19421
+ const split2 = entry.indexOf("=");
19422
+ if (split2 > 0) env2[entry.slice(0, split2)] = entry.slice(split2 + 1);
19423
+ }
19424
+ const cwd = r.string() || proc.cwd;
19425
+ const files2 = /* @__PURE__ */ new Map();
19426
+ for (let i = 0, n = r.u32(); i < n; i++) {
19427
+ const childFd = r.u32() | 0;
19428
+ const parentFd = r.u32() | 0;
19429
+ files2.set(childFd, proc.table.get(parentFd));
19430
+ }
19431
+ if (!proc.processes) throw new PosixError(Errno.ENOSYS);
19432
+ if (argv.length === 0) throw new PosixError(Errno.EINVAL);
19433
+ return { status: await proc.processes.spawn({ argv, env: env2, cwd: resolve3(cwd), files: files2 }) };
19434
+ }
19435
+ case Op.waitpid: {
19436
+ const pid = r.u32() | 0;
19437
+ const options = r.u32() | 0;
19438
+ if (!proc.processes) throw new PosixError(Errno.ENOSYS);
19439
+ const result = await Promise.race([
19440
+ proc.processes.wait(pid, options),
19441
+ aborted().then(() => {
19442
+ throw new PosixError(Errno.EINTR);
19443
+ })
19444
+ ]);
19445
+ return { status: 0, payload: new Writer().i32(result.pid).i32(result.status).finish() };
19446
+ }
19447
+ case Op.kill: {
19448
+ const pid = r.u32() | 0;
19449
+ const signal = r.u32() | 0;
19450
+ if (!proc.processes) throw new PosixError(Errno.ENOSYS);
19451
+ proc.processes.kill(pid, signal);
19452
+ return { status: 0 };
19453
+ }
19400
19454
  /* ---------------------------------------------------------- entropy */
19401
19455
  case Op.getrandom: {
19402
19456
  const length = Math.min(r.u32(), 65536);
@@ -19409,7 +19463,8 @@ function createHostAbiServer(proc) {
19409
19463
  const family = r.u32();
19410
19464
  const type = r.u32();
19411
19465
  const protocol = r.i32();
19412
- if (family !== 2 || (type & 15) !== 1 || protocol !== 0) throw new PosixError(Errno.EAFNOSUPPORT);
19466
+ if (family !== AF_INET || (type & 15) !== SOCK_STREAM) throw new PosixError(Errno.EAFNOSUPPORT);
19467
+ if (protocol !== 0 && protocol !== IPPROTO_TCP) throw new PosixError(Errno.EPROTONOSUPPORT);
19413
19468
  if (!proc.sockets) throw new PosixError(Errno.ENOSYS);
19414
19469
  return { status: proc.table.add(new SocketDescription(new VirtualTcpSocket(proc.sockets))) };
19415
19470
  }
@@ -19749,6 +19804,7 @@ async function startPythonProcess(options) {
19749
19804
  table.set(0, stdin);
19750
19805
  table.set(1, stdout);
19751
19806
  table.set(2, stderr);
19807
+ for (const [fd, description] of options.inherit ?? []) table.set(fd, description);
19752
19808
  const controller = new AbortController();
19753
19809
  const abort = () => controller.abort();
19754
19810
  options.signal.addEventListener("abort", abort, { once: true });
@@ -19762,7 +19818,8 @@ async function startPythonProcess(options) {
19762
19818
  env: options.env,
19763
19819
  cwd: options.cwd,
19764
19820
  signal: controller.signal,
19765
- sockets: options.sockets
19821
+ sockets: options.sockets,
19822
+ processes: options.processes
19766
19823
  });
19767
19824
  const buffers = createHostTransportBuffers();
19768
19825
  let fault = null;
@@ -20315,6 +20372,133 @@ raise SystemExit(entry())
20315
20372
  }
20316
20373
 
20317
20374
  // src/runtime/python/backend.ts
20375
+ var PENDING_INHERITANCE = /* @__PURE__ */ new Map();
20376
+ var INHERIT_TOKEN = "SBX_PYTHON_INHERIT";
20377
+ var WNOHANG = 1;
20378
+ function claimInheritance(env2) {
20379
+ const token = env2[INHERIT_TOKEN];
20380
+ if (!token) return void 0;
20381
+ const files = PENDING_INHERITANCE.get(token);
20382
+ PENDING_INHERITANCE.delete(token);
20383
+ delete env2[INHERIT_TOKEN];
20384
+ return files;
20385
+ }
20386
+ function waitStatus(proc) {
20387
+ if (proc.termSignal) return signalNumber(proc.termSignal) & 127;
20388
+ return ((proc.exitCode ?? 0) & 255) << 8;
20389
+ }
20390
+ function outputFor(description, fallback) {
20391
+ if (!description) return fallback;
20392
+ return {
20393
+ write(data) {
20394
+ description.write(typeof data === "string" ? new TextEncoder().encode(data) : data);
20395
+ },
20396
+ end() {
20397
+ },
20398
+ get closed() {
20399
+ return false;
20400
+ },
20401
+ isTTY: fallback.isTTY
20402
+ };
20403
+ }
20404
+ function createProcessService(ctx) {
20405
+ const children = /* @__PURE__ */ new Map();
20406
+ const exited = (proc) => proc.exitCode !== null || proc.termSignal !== null;
20407
+ return {
20408
+ async spawn(request) {
20409
+ const token = `${ctx.proc.pid}:${Math.random().toString(36).slice(2)}`;
20410
+ const extra = /* @__PURE__ */ new Map();
20411
+ for (const [fd, description] of request.files) {
20412
+ if (fd > 2) extra.set(fd, description);
20413
+ }
20414
+ const env2 = { ...request.env };
20415
+ if (extra.size > 0) {
20416
+ PENDING_INHERITANCE.set(token, extra);
20417
+ env2[INHERIT_TOKEN] = token;
20418
+ }
20419
+ const stdin = request.files.get(0);
20420
+ const argv = [containerProgram(ctx, request.argv[0] ?? ""), ...request.argv.slice(1)];
20421
+ const proc = ctx.kernel.spawn(argv, {
20422
+ cwd: request.cwd,
20423
+ env: env2,
20424
+ cred: ctx.cred,
20425
+ ppid: ctx.proc.pid,
20426
+ stdin: stdin ? descriptionInput(stdin) : void 0,
20427
+ stdout: outputFor(request.files.get(1), ctx.stdout),
20428
+ stderr: outputFor(request.files.get(2), ctx.stderr)
20429
+ });
20430
+ children.set(proc.pid, proc);
20431
+ void proc.wait().finally(() => PENDING_INHERITANCE.delete(token));
20432
+ return proc.pid;
20433
+ },
20434
+ async wait(pid, options) {
20435
+ const candidates = pid > 0 ? [children.get(pid)].filter((p) => p !== void 0) : [...children.values()];
20436
+ if (candidates.length === 0) throw new PosixError(Errno.ECHILD);
20437
+ const reap = (proc) => {
20438
+ children.delete(proc.pid);
20439
+ return { pid: proc.pid, status: waitStatus(proc) };
20440
+ };
20441
+ const done = candidates.find(exited);
20442
+ if (done) return reap(done);
20443
+ if (options & WNOHANG) return { pid: 0, status: 0 };
20444
+ await Promise.race(candidates.map((proc) => proc.wait()));
20445
+ const finished = candidates.find(exited);
20446
+ if (!finished) throw new PosixError(Errno.ECHILD);
20447
+ return reap(finished);
20448
+ },
20449
+ kill(pid, signal) {
20450
+ const proc = children.get(pid) ?? ctx.kernel.procs.get(pid);
20451
+ if (!proc) throw new PosixError(Errno.ESRCH);
20452
+ if (signal === 0) return;
20453
+ const name = exports.SIGNAL_NAMES[signal];
20454
+ if (!name) throw new PosixError(Errno.EINVAL);
20455
+ proc.deliver(name);
20456
+ }
20457
+ };
20458
+ }
20459
+ function containerProgram(ctx, program) {
20460
+ const resolvable = (name) => name !== "" && ctx.kernel.resolveExecutable(name, ctx.cwd, ctx.env, ctx.cred) !== null;
20461
+ if (resolvable(program)) return program;
20462
+ const base2 = program.slice(program.lastIndexOf("/") + 1);
20463
+ if (resolvable(base2)) return base2;
20464
+ if (base2.startsWith("python")) return "python3";
20465
+ return program;
20466
+ }
20467
+ function descriptionInput(description) {
20468
+ const read = async (size) => {
20469
+ for (; ; ) {
20470
+ try {
20471
+ const chunk = description.read(size);
20472
+ if (chunk.length === 0) return null;
20473
+ return chunk;
20474
+ } catch {
20475
+ await description.whenReady();
20476
+ }
20477
+ }
20478
+ };
20479
+ return {
20480
+ isTTY: false,
20481
+ interactive: false,
20482
+ read,
20483
+ async readAll() {
20484
+ const parts = [];
20485
+ for (; ; ) {
20486
+ const chunk = await read(65536);
20487
+ if (chunk === null) break;
20488
+ parts.push(chunk);
20489
+ }
20490
+ let total = 0;
20491
+ for (const part of parts) total += part.length;
20492
+ const out = new Uint8Array(total);
20493
+ let at = 0;
20494
+ for (const part of parts) {
20495
+ out.set(part, at);
20496
+ at += part.length;
20497
+ }
20498
+ return out;
20499
+ }
20500
+ };
20501
+ }
20318
20502
  function withSitePackages(env2) {
20319
20503
  const existing = env2.PYTHONPATH;
20320
20504
  return {
@@ -20355,6 +20539,8 @@ async function runOwnedPython(ctx, argv) {
20355
20539
  const { manifest, workerUrl } = pythonBackend();
20356
20540
  if (!manifest) throw new Error("no Python runtime manifest is configured");
20357
20541
  const mounts = containerMounts(ctx);
20542
+ const env2 = withSitePackages(ctx.env);
20543
+ const inherit = claimInheritance(env2);
20358
20544
  const process2 = await startPythonProcess({
20359
20545
  manifest,
20360
20546
  workerUrl: await resolveWorkerUrl(workerUrl),
@@ -20363,14 +20549,16 @@ async function runOwnedPython(ctx, argv) {
20363
20549
  pid: ctx.proc.pid,
20364
20550
  ppid: ctx.proc.ppid ?? 1,
20365
20551
  argv,
20366
- env: withSitePackages(ctx.env),
20552
+ env: env2,
20367
20553
  cwd: ctx.cwd,
20368
20554
  isTty: isTerminal(ctx),
20369
20555
  mounts,
20370
20556
  onStdout: (data) => ctx.stdout.write(data),
20371
20557
  onStderr: (data) => ctx.stderr.write(data),
20372
20558
  signal: ctx.signal,
20373
- sockets: ctx.kernel.pod.sockets
20559
+ sockets: ctx.kernel.pod.sockets,
20560
+ processes: createProcessService(ctx),
20561
+ inherit
20374
20562
  });
20375
20563
  void pumpStdin(ctx, process2);
20376
20564
  return process2.wait();