@torkbot/sandbox 0.1.0 → 0.2.0

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 (41) hide show
  1. package/README.md +237 -133
  2. package/dist/artifacts.d.ts +6 -0
  3. package/dist/artifacts.d.ts.map +1 -1
  4. package/dist/artifacts.js +58 -4
  5. package/dist/artifacts.js.map +1 -1
  6. package/dist/cli.js +2 -2
  7. package/dist/cli.js.map +1 -1
  8. package/dist/control-codec.d.ts +23 -1
  9. package/dist/control-codec.d.ts.map +1 -1
  10. package/dist/control-codec.js.map +1 -1
  11. package/dist/control.d.ts +16 -2
  12. package/dist/control.d.ts.map +1 -1
  13. package/dist/control.js +12 -29
  14. package/dist/control.js.map +1 -1
  15. package/dist/host-process.d.ts +3 -8
  16. package/dist/host-process.d.ts.map +1 -1
  17. package/dist/host-process.js +355 -28
  18. package/dist/host-process.js.map +1 -1
  19. package/dist/index.d.ts +104 -199
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +298 -268
  22. package/dist/index.js.map +1 -1
  23. package/dist/launch-options.d.ts +64 -0
  24. package/dist/launch-options.d.ts.map +1 -0
  25. package/dist/launch-options.js +2 -0
  26. package/dist/launch-options.js.map +1 -0
  27. package/dist/memory-fs.d.ts +3 -0
  28. package/dist/memory-fs.d.ts.map +1 -0
  29. package/dist/memory-fs.js +308 -0
  30. package/dist/memory-fs.js.map +1 -0
  31. package/dist/spawn-options.d.ts +7 -6
  32. package/dist/spawn-options.d.ts.map +1 -1
  33. package/dist/vfs.d.ts +2 -1
  34. package/dist/vfs.d.ts.map +1 -1
  35. package/dist/vfs.js +14 -0
  36. package/dist/vfs.js.map +1 -1
  37. package/package.json +3 -3
  38. package/dist/host-filesystem-tools.d.ts +0 -3
  39. package/dist/host-filesystem-tools.d.ts.map +0 -1
  40. package/dist/host-filesystem-tools.js +0 -330
  41. package/dist/host-filesystem-tools.js.map +0 -1
package/dist/control.d.ts CHANGED
@@ -1,7 +1,21 @@
1
- import type { SandboxControl, SandboxControlCommand, SandboxControlEvent } from "./index.ts";
1
+ import type { SandboxControlCommand, SandboxControlEvent } from "./control-codec.ts";
2
+ export interface SandboxControl extends Transport<SandboxControlEvent, SandboxControlCommand> {
3
+ exec(input: {
4
+ readonly id?: string;
5
+ readonly argv: readonly string[];
6
+ readonly env?: Record<string, string>;
7
+ }): Promise<Extract<SandboxControlEvent, {
8
+ type: "guest.exec.complete";
9
+ }>>;
10
+ }
11
+ export interface Transport<TIncoming = unknown, TOutgoing = unknown> {
12
+ readonly incoming: AsyncIterable<TIncoming>;
13
+ send(message: TOutgoing): Promise<void>;
14
+ close(): Promise<void>;
15
+ }
2
16
  export interface HostControlChannel {
17
+ readonly packets: AsyncIterable<Uint8Array>;
3
18
  writeControlPacket(packet: Uint8Array): void;
4
- tryReadControlPacket(): Uint8Array | null;
5
19
  }
6
20
  export declare class HostControlTransport implements SandboxControl {
7
21
  #private;
@@ -1 +1 @@
1
- {"version":3,"file":"control.d.ts","sourceRoot":"","sources":["../src/control.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,qBAAqB,EACrB,mBAAmB,EACpB,MAAM,YAAY,CAAC;AAMpB,MAAM,WAAW,kBAAkB;IACjC,kBAAkB,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAAC;IAC7C,oBAAoB,IAAI,UAAU,GAAG,IAAI,CAAC;CAC3C;AAED,qBAAa,oBAAqB,YAAW,cAAc;;IACzD,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,mBAAmB,CAAC,CAAC;IAWtD,YAAY,OAAO,GAAE;QACnB,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;QAC7B,QAAQ,CAAC,OAAO,CAAC,EAAE,kBAAkB,CAAC;KAClC,EAeL;IAEK,IAAI,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CAMxD;IAEK,IAAI,CAAC,KAAK,EAAE;QAChB,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;QACjC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KACvC,GAAG,OAAO,CAAC,OAAO,CAAC,mBAAmB,EAAE;QAAE,IAAI,EAAE,qBAAqB,CAAA;KAAE,CAAC,CAAC,CAqBzE;IAEK,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAQ3B;IAED,IAAI,CAAC,KAAK,EAAE,mBAAmB,GAAG,IAAI,CAGrC;CAuEF"}
1
+ {"version":3,"file":"control.d.ts","sourceRoot":"","sources":["../src/control.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,qBAAqB,EACrB,mBAAmB,EACpB,MAAM,oBAAoB,CAAC;AAM5B,MAAM,WAAW,cAAe,SAAQ,SAAS,CAAC,mBAAmB,EAAE,qBAAqB,CAAC;IAC3F,IAAI,CAAC,KAAK,EAAE;QACV,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;QACjC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KACvC,GAAG,OAAO,CAAC,OAAO,CAAC,mBAAmB,EAAE;QAAE,IAAI,EAAE,qBAAqB,CAAA;KAAE,CAAC,CAAC,CAAC;CAC5E;AAED,MAAM,WAAW,SAAS,CAAC,SAAS,GAAG,OAAO,EAAE,SAAS,GAAG,OAAO;IACjE,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC;IAC5C,IAAI,CAAC,OAAO,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC;IAC5C,kBAAkB,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAAC;CAC9C;AAED,qBAAa,oBAAqB,YAAW,cAAc;;IACzD,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,mBAAmB,CAAC,CAAC;IAWtD,YAAY,OAAO,GAAE;QACnB,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;QAC7B,QAAQ,CAAC,OAAO,CAAC,EAAE,kBAAkB,CAAC;KAClC,EAeL;IAEK,IAAI,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CAMxD;IAEK,IAAI,CAAC,KAAK,EAAE;QAChB,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;QACjC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KACvC,GAAG,OAAO,CAAC,OAAO,CAAC,mBAAmB,EAAE;QAAE,IAAI,EAAE,qBAAqB,CAAA;KAAE,CAAC,CAAC,CAqBzE;IAEK,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAQ3B;IAED,IAAI,CAAC,KAAK,EAAE,mBAAmB,GAAG,IAAI,CAGrC;CA4DF"}
package/dist/control.js CHANGED
@@ -72,34 +72,23 @@ export class HostControlTransport {
72
72
  }
73
73
  }
74
74
  async #pumpIncoming() {
75
- while (!this.#closed && this.#channel !== null) {
76
- let packet;
77
- try {
78
- packet = this.#channel.tryReadControlPacket();
79
- }
80
- catch (error) {
81
- if (this.#closed) {
82
- return;
83
- }
84
- this.#fail(error);
85
- return;
86
- }
87
- if (packet !== null) {
75
+ if (this.#channel === null) {
76
+ return;
77
+ }
78
+ try {
79
+ for await (const packet of this.#channel.packets) {
88
80
  if (this.#closed) {
89
81
  return;
90
82
  }
91
- let event;
92
- try {
93
- event = decodeControlEvent(packet);
94
- }
95
- catch (error) {
96
- this.#fail(error);
97
- return;
98
- }
83
+ const event = decodeControlEvent(packet);
99
84
  this.#dispatchEvent(event);
100
- continue;
101
85
  }
102
- await sleep(10);
86
+ }
87
+ catch (error) {
88
+ if (this.#closed) {
89
+ return;
90
+ }
91
+ this.#fail(error);
103
92
  }
104
93
  }
105
94
  #dispatchEvent(event) {
@@ -129,12 +118,6 @@ export class HostControlTransport {
129
118
  this.#pendingExec.clear();
130
119
  }
131
120
  }
132
- function sleep(ms) {
133
- return new Promise((resolve) => {
134
- const timeout = setTimeout(resolve, ms);
135
- timeout.unref();
136
- });
137
- }
138
121
  class AsyncQueue {
139
122
  #values = [];
140
123
  #waiters = [];
@@ -1 +1 @@
1
- {"version":3,"file":"control.js","sourceRoot":"","sources":["../src/control.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"control.js","sourceRoot":"","sources":["../src/control.ts"],"names":[],"mappings":"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"}
@@ -1,19 +1,14 @@
1
1
  import { hostBinaryPath } from "./artifacts.ts";
2
2
  import type { HostControlChannel } from "./control.ts";
3
3
  import type { HostSpawnSandboxOptions } from "./spawn-options.ts";
4
- import type { SandboxOptions, SandboxHttpRequestHook, SandboxHttpRequestSelector } from "./index.ts";
5
- type RegisteredHttpRequestHeadersHook = {
6
- readonly selector: SandboxHttpRequestSelector;
7
- readonly hook: SandboxHttpRequestHook;
8
- active: boolean;
9
- };
4
+ import type { InternalSandboxOptions, RegisteredHttpRequestHeadersHook } from "./launch-options.ts";
10
5
  export declare class HostProcessSandboxVm implements HostControlChannel {
11
6
  #private;
12
7
  readonly hasControlSocket = true;
8
+ readonly packets: AsyncIterable<Uint8Array>;
13
9
  private constructor();
14
- static spawn(options: SandboxOptions, hostOptions: HostSpawnSandboxOptions, requestHeaderHooks?: Map<string, RegisteredHttpRequestHeadersHook>): Promise<HostProcessSandboxVm>;
10
+ static spawn(options: InternalSandboxOptions, hostOptions: HostSpawnSandboxOptions, requestHeaderHooks?: Map<string, RegisteredHttpRequestHeadersHook>): Promise<HostProcessSandboxVm>;
15
11
  writeControlPacket(packet: Uint8Array): void;
16
- tryReadControlPacket(): Uint8Array | null;
17
12
  close(): Promise<void>;
18
13
  terminateHostForTest(): Promise<void>;
19
14
  }
@@ -1 +1 @@
1
- {"version":3,"file":"host-process.d.ts","sourceRoot":"","sources":["../src/host-process.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAElE,OAAO,KAAK,EACV,cAAc,EAGd,sBAAsB,EACtB,0BAA0B,EAC3B,MAAM,YAAY,CAAC;AAEpB,KAAK,gCAAgC,GAAG;IACtC,QAAQ,CAAC,QAAQ,EAAE,0BAA0B,CAAC;IAC9C,QAAQ,CAAC,IAAI,EAAE,sBAAsB,CAAC;IACtC,MAAM,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,qBAAa,oBAAqB,YAAW,kBAAkB;;IAC7D,QAAQ,CAAC,gBAAgB,QAAQ;IAcjC,OAAO,eAyCN;IAED,OAAa,KAAK,CAChB,OAAO,EAAE,cAAc,EACvB,WAAW,EAAE,uBAAuB,EACpC,kBAAkB,GAAE,GAAG,CAAC,MAAM,EAAE,gCAAgC,CAAa,GAC5E,OAAO,CAAC,oBAAoB,CAAC,CAoB/B;IAED,kBAAkB,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAG3C;IAED,oBAAoB,IAAI,UAAU,GAAG,IAAI,CAGxC;IAEK,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CA0B3B;IAEK,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC,CAiB1C;CAiXF;AAED,OAAO,EAAE,cAAc,EAAE,CAAC"}
1
+ {"version":3,"file":"host-process.d.ts","sourceRoot":"","sources":["../src/host-process.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,cAAc,EAAyB,MAAM,gBAAgB,CAAC;AACvE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAQlE,OAAO,KAAK,EACV,sBAAsB,EACtB,gCAAgC,EACjC,MAAM,qBAAqB,CAAC;AAI7B,qBAAa,oBAAqB,YAAW,kBAAkB;;IAC7D,QAAQ,CAAC,gBAAgB,QAAQ;IACjC,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC;IAiB5C,OAAO,eA6CN;IAED,OAAa,KAAK,CAChB,OAAO,EAAE,sBAAsB,EAC/B,WAAW,EAAE,uBAAuB,EACpC,kBAAkB,GAAE,GAAG,CAAC,MAAM,EAAE,gCAAgC,CAAa,GAC5E,OAAO,CAAC,oBAAoB,CAAC,CAyB/B;IAED,kBAAkB,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAG3C;IAEK,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CA4B3B;IAEK,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC,CAiB1C;CAqhBF;AA2BD,OAAO,EAAE,cAAc,EAAE,CAAC"}
@@ -1,15 +1,20 @@
1
1
  import { spawn } from "node:child_process";
2
2
  import { once } from "node:events";
3
3
  import { Binary, BSON } from "bson";
4
- import { hostBinaryPath } from "./artifacts.js";
4
+ import { hostBinaryPath, macosHostSigningError } from "./artifacts.js";
5
5
  import { isSandboxWritableFileSystem } from "./vfs.js";
6
+ const DEFAULT_LAUNCH_TIMEOUT_MS = 60_000;
6
7
  export class HostProcessSandboxVm {
7
8
  hasControlSocket = true;
9
+ packets;
8
10
  #child;
9
11
  #options;
10
- #packets = [];
11
- #hostPacketWaiters = [];
12
+ #packets = new AsyncQueue();
13
+ #packetActivity = new AsyncSignal();
14
+ #launchReady = new AsyncSignal("sandbox-host launch acknowledgement closed");
12
15
  #hostFs = new Map();
16
+ #rootBlockStore;
17
+ #rootBlockStoreContext;
13
18
  #requestHeaderHooks;
14
19
  #buffer = new Uint8Array();
15
20
  #stderr = "";
@@ -19,11 +24,12 @@ export class HostProcessSandboxVm {
19
24
  constructor(child, options, requestHeaderHooks) {
20
25
  this.#child = child;
21
26
  this.#options = options;
27
+ this.packets = this.#packets;
22
28
  this.#requestHeaderHooks = requestHeaderHooks;
29
+ this.#rootBlockStore = options.rootfs.storage?.blockStore;
30
+ this.#rootBlockStoreContext = options.rootfs.storage?.context;
23
31
  for (const mount of options.mounts ?? []) {
24
- if (mount.kind === "virtual-fs") {
25
- this.#hostFs.set(mount.path, mount.fileSystem);
26
- }
32
+ this.#hostFs.set(mount.path, mount.fileSystem);
27
33
  }
28
34
  child.stdout.on("data", (chunk) => {
29
35
  this.#receive(chunk);
@@ -48,12 +54,16 @@ export class HostProcessSandboxVm {
48
54
  ? `sandbox-host exited with ${code ?? "unknown status"}`
49
55
  : `sandbox-host exited from signal ${signal}`;
50
56
  this.#exitError = new Error(this.#stderr.length === 0 ? exitText : `${exitText}\n${this.#stderr}`);
57
+ this.#packets.close(this.#exitError);
58
+ this.#packetActivity.close(this.#exitError);
59
+ this.#launchReady.close(this.#exitError);
51
60
  });
52
61
  }
53
62
  static async spawn(options, hostOptions, requestHeaderHooks = new Map()) {
54
63
  let vm;
64
+ const hostPath = hostBinaryPath();
55
65
  try {
56
- const child = spawn(hostBinaryPath(), ["--stdio"], {
66
+ const child = spawn(hostPath, ["--stdio"], {
57
67
  stdio: ["pipe", "pipe", "pipe"],
58
68
  });
59
69
  vm = new HostProcessSandboxVm(child, options, requestHeaderHooks);
@@ -69,6 +79,10 @@ export class HostProcessSandboxVm {
69
79
  }
70
80
  catch (error) {
71
81
  await vm?.close();
82
+ const signingError = macosHostSigningError(hostPath);
83
+ if (signingError !== null) {
84
+ throw signingError;
85
+ }
72
86
  throw error;
73
87
  }
74
88
  }
@@ -76,15 +90,13 @@ export class HostProcessSandboxVm {
76
90
  this.#assertOpen();
77
91
  this.#writeToHost(packet);
78
92
  }
79
- tryReadControlPacket() {
80
- this.#assertOpen();
81
- return this.#packets.shift() ?? null;
82
- }
83
93
  async close() {
84
94
  if (this.#closed) {
85
95
  return;
86
96
  }
87
97
  this.#closed = true;
98
+ this.#packets.close();
99
+ this.#packetActivity.close();
88
100
  const exited = this.#child.exitCode !== null || this.#child.signalCode !== null
89
101
  ? Promise.resolve()
90
102
  : once(this.#child, "exit").then(() => undefined);
@@ -173,8 +185,11 @@ export class HostProcessSandboxVm {
173
185
  }
174
186
  const packet = this.#buffer.slice(0, packetLength);
175
187
  this.#buffer = this.#buffer.slice(packetLength);
176
- this.#notifyHostPacket();
188
+ this.#packetActivity.notify();
177
189
  if (!this.#routeHostPacket(packet)) {
190
+ if (isInitReadyPacket(packet)) {
191
+ this.#launchReady.notify();
192
+ }
178
193
  this.#packets.push(packet);
179
194
  }
180
195
  }
@@ -198,10 +213,19 @@ export class HostProcessSandboxVm {
198
213
  && type !== "host.vfs.unlink"
199
214
  && type !== "host.vfs.rmdir"
200
215
  && type !== "host.vfs.rename"
216
+ && type !== "host.vfs.link"
201
217
  && type !== "host.vfs.symlink"
202
218
  && type !== "host.vfs.readlink"
219
+ && type !== "host.vfs.setxattr"
220
+ && type !== "host.vfs.getxattr"
221
+ && type !== "host.vfs.listxattr"
222
+ && type !== "host.vfs.removexattr"
203
223
  && type !== "host.http.requestHeaders"
204
- && type !== "host.http.activeRequestHeaderHooks") {
224
+ && type !== "host.http.activeRequestHeaderHooks"
225
+ && type !== "host.block.list"
226
+ && type !== "host.block.read"
227
+ && type !== "host.block.write"
228
+ && type !== "host.block.flush") {
205
229
  return false;
206
230
  }
207
231
  if (type === "host.http.requestHeaders") {
@@ -210,6 +234,12 @@ export class HostProcessSandboxVm {
210
234
  else if (type === "host.http.activeRequestHeaderHooks") {
211
235
  void this.#handleActiveRequestHeaderHooks(document);
212
236
  }
237
+ else if (type === "host.block.list"
238
+ || type === "host.block.read"
239
+ || type === "host.block.write"
240
+ || type === "host.block.flush") {
241
+ void this.#handleBlockStoreRequest(document);
242
+ }
213
243
  else {
214
244
  void this.#handleVirtualFsRequest(document);
215
245
  }
@@ -416,6 +446,18 @@ export class HostProcessSandboxVm {
416
446
  }));
417
447
  return;
418
448
  }
449
+ case "host.vfs.link": {
450
+ const posix = assertPosixFileSystem(fileSystem, mountPath);
451
+ const from = assertString(document.from, "from");
452
+ const to = assertString(document.to, "to");
453
+ this.#tryWriteToHost(encodePacket({
454
+ type: "host.vfs.response",
455
+ id,
456
+ ok: true,
457
+ stat: await posix.link(from, to),
458
+ }));
459
+ return;
460
+ }
419
461
  case "host.vfs.symlink": {
420
462
  const path = assertString(document.path, "path");
421
463
  const posix = assertPosixFileSystem(fileSystem, mountPath);
@@ -440,6 +482,83 @@ export class HostProcessSandboxVm {
440
482
  }));
441
483
  return;
442
484
  }
485
+ case "host.vfs.setxattr": {
486
+ const path = assertString(document.path, "path");
487
+ const name = assertString(document.name, "name");
488
+ const value = binaryField(document.value, "value");
489
+ const flags = assertNumber(document.flags, "flags");
490
+ const posix = assertPosixFileSystem(fileSystem, mountPath);
491
+ await posix.setxattr(path, name, value, flags);
492
+ this.#tryWriteToHost(encodePacket({
493
+ type: "host.vfs.response",
494
+ id,
495
+ ok: true,
496
+ }));
497
+ return;
498
+ }
499
+ case "host.vfs.getxattr": {
500
+ const path = assertString(document.path, "path");
501
+ const name = assertString(document.name, "name");
502
+ const size = assertNumber(document.size, "size");
503
+ const posix = assertPosixFileSystem(fileSystem, mountPath);
504
+ const value = await posix.getxattr(path, name);
505
+ if (size === 0) {
506
+ this.#tryWriteToHost(encodePacket({
507
+ type: "host.vfs.response",
508
+ id,
509
+ ok: true,
510
+ count: value.byteLength,
511
+ }));
512
+ return;
513
+ }
514
+ if (value.byteLength > size) {
515
+ throw new Error("xattr value is larger than requested size");
516
+ }
517
+ this.#tryWriteToHost(encodePacket({
518
+ type: "host.vfs.response",
519
+ id,
520
+ ok: true,
521
+ value: new Binary(value),
522
+ }));
523
+ return;
524
+ }
525
+ case "host.vfs.listxattr": {
526
+ const path = assertString(document.path, "path");
527
+ const size = assertNumber(document.size, "size");
528
+ const posix = assertPosixFileSystem(fileSystem, mountPath);
529
+ const names = encodeXattrNameList(await posix.listxattr(path));
530
+ if (size === 0) {
531
+ this.#tryWriteToHost(encodePacket({
532
+ type: "host.vfs.response",
533
+ id,
534
+ ok: true,
535
+ count: names.byteLength,
536
+ }));
537
+ return;
538
+ }
539
+ if (names.byteLength > size) {
540
+ throw new Error("xattr name list is larger than requested size");
541
+ }
542
+ this.#tryWriteToHost(encodePacket({
543
+ type: "host.vfs.response",
544
+ id,
545
+ ok: true,
546
+ names: new Binary(names),
547
+ }));
548
+ return;
549
+ }
550
+ case "host.vfs.removexattr": {
551
+ const path = assertString(document.path, "path");
552
+ const name = assertString(document.name, "name");
553
+ const posix = assertPosixFileSystem(fileSystem, mountPath);
554
+ await posix.removexattr(path, name);
555
+ this.#tryWriteToHost(encodePacket({
556
+ type: "host.vfs.response",
557
+ id,
558
+ ok: true,
559
+ }));
560
+ return;
561
+ }
443
562
  }
444
563
  }
445
564
  catch (error) {
@@ -451,27 +570,107 @@ export class HostProcessSandboxVm {
451
570
  }));
452
571
  }
453
572
  }
454
- async #waitForLaunch() {
455
- if (this.#packets.length > 0) {
456
- return;
573
+ async #handleBlockStoreRequest(document) {
574
+ const id = typeof document.id === "string" ? document.id : "";
575
+ try {
576
+ const blockStore = this.#rootBlockStore;
577
+ const blockStoreContext = this.#rootBlockStoreContext;
578
+ if (blockStore === undefined || blockStoreContext === undefined) {
579
+ throw new Error("root block store is not configured");
580
+ }
581
+ switch (document.type) {
582
+ case "host.block.list": {
583
+ this.#tryWriteToHost(encodePacket({
584
+ type: "host.block.response",
585
+ id,
586
+ ok: true,
587
+ blocks: (await blockStore.list(blockStoreContext)).map((block) => block.toString()),
588
+ }));
589
+ return;
590
+ }
591
+ case "host.block.read": {
592
+ const chunks = await blockStore.read({
593
+ start: BigInt(assertString(document.start, "start")),
594
+ count: assertNumber(document.count, "count"),
595
+ }, blockStoreContext);
596
+ this.#tryWriteToHost(encodePacket({
597
+ type: "host.block.response",
598
+ id,
599
+ ok: true,
600
+ chunks: chunks.map((chunk) => ({
601
+ start: chunk.start.toString(),
602
+ data: new Binary(chunk.data),
603
+ })),
604
+ }));
605
+ return;
606
+ }
607
+ case "host.block.write": {
608
+ const chunks = assertDocumentArray(document.chunks, "chunks").map((chunk) => ({
609
+ start: BigInt(assertString(chunk.start, "chunks.start")),
610
+ data: binaryField(chunk.data, "chunks.data"),
611
+ }));
612
+ await blockStore.write(chunks, blockStoreContext);
613
+ this.#tryWriteToHost(encodePacket({
614
+ type: "host.block.response",
615
+ id,
616
+ ok: true,
617
+ }));
618
+ return;
619
+ }
620
+ case "host.block.flush": {
621
+ await blockStore.flush?.(blockStoreContext);
622
+ this.#tryWriteToHost(encodePacket({
623
+ type: "host.block.response",
624
+ id,
625
+ ok: true,
626
+ }));
627
+ return;
628
+ }
629
+ }
457
630
  }
631
+ catch (error) {
632
+ this.#tryWriteToHost(encodePacket({
633
+ type: "host.block.response",
634
+ id,
635
+ ok: false,
636
+ error: error instanceof Error ? error.message : String(error),
637
+ }));
638
+ }
639
+ }
640
+ async #waitForLaunch() {
641
+ const timeoutMs = launchTimeoutMs();
458
642
  await Promise.race([
459
- new Promise((resolvePromise) => {
460
- this.#hostPacketWaiters.push(resolvePromise);
461
- }),
643
+ this.#launchReady.wait(),
462
644
  once(this.#child, "exit").then(() => {
463
645
  throw this.#exitError ?? new Error("sandbox-host exited before VM launch completed");
464
646
  }),
465
- delay(10_000).then(() => {
466
- throw new Error("sandbox-host did not produce a launch acknowledgement");
647
+ unrefDelay(timeoutMs).then(() => {
648
+ throw new Error(`sandbox-host did not produce a launch acknowledgement within ${timeoutMs}ms`);
467
649
  }),
468
650
  ]);
469
651
  }
470
- #notifyHostPacket() {
471
- const waiters = this.#hostPacketWaiters.splice(0);
472
- for (const waiter of waiters) {
473
- waiter();
474
- }
652
+ }
653
+ function launchTimeoutMs() {
654
+ const value = process.env.SANDBOX_LAUNCH_TIMEOUT_MS;
655
+ if (value === undefined || value.length === 0) {
656
+ return DEFAULT_LAUNCH_TIMEOUT_MS;
657
+ }
658
+ const parsed = Number(value);
659
+ if (!Number.isSafeInteger(parsed) || parsed <= 0) {
660
+ throw new Error(`SANDBOX_LAUNCH_TIMEOUT_MS must be a positive integer, got ${value}`);
661
+ }
662
+ return parsed;
663
+ }
664
+ function encodeXattrNameList(names) {
665
+ return new TextEncoder().encode(names.map((name) => `${name}\0`).join(""));
666
+ }
667
+ function isInitReadyPacket(packet) {
668
+ try {
669
+ const document = BSON.deserialize(packet.slice(4));
670
+ return document.type === "init.ready";
671
+ }
672
+ catch {
673
+ return false;
475
674
  }
476
675
  }
477
676
  export { hostBinaryPath };
@@ -505,6 +704,12 @@ function assertHeaderPairs(value, field) {
505
704
  }
506
705
  return value;
507
706
  }
707
+ function assertDocumentArray(value, field) {
708
+ if (!Array.isArray(value) || value.some((entry) => entry === null || typeof entry !== "object")) {
709
+ throw new Error(`host request ${field} must be documents`);
710
+ }
711
+ return value;
712
+ }
508
713
  function trackHeaderMutations(headers) {
509
714
  let mutated = false;
510
715
  const set = headers.set.bind(headers);
@@ -571,8 +776,13 @@ function assertPosixFileSystem(fileSystem, mountPath) {
571
776
  || typeof candidate.unlink !== "function"
572
777
  || typeof candidate.rmdir !== "function"
573
778
  || typeof candidate.rename !== "function"
779
+ || typeof candidate.link !== "function"
574
780
  || typeof candidate.symlink !== "function"
575
- || typeof candidate.readlink !== "function") {
781
+ || typeof candidate.readlink !== "function"
782
+ || typeof candidate.setxattr !== "function"
783
+ || typeof candidate.getxattr !== "function"
784
+ || typeof candidate.listxattr !== "function"
785
+ || typeof candidate.removexattr !== "function") {
576
786
  throw new Error(`host filesystem mount does not support POSIX mutations: ${mountPath}`);
577
787
  }
578
788
  return candidate;
@@ -580,6 +790,118 @@ function assertPosixFileSystem(fileSystem, mountPath) {
580
790
  function delay(milliseconds) {
581
791
  return new Promise((resolvePromise) => setTimeout(resolvePromise, milliseconds));
582
792
  }
793
+ function unrefDelay(milliseconds) {
794
+ return new Promise((resolvePromise) => {
795
+ const timeout = setTimeout(resolvePromise, milliseconds);
796
+ timeout.unref();
797
+ });
798
+ }
799
+ class AsyncQueue {
800
+ #values = [];
801
+ #nextWaiters = [];
802
+ #closed = false;
803
+ #error;
804
+ get length() {
805
+ return this.#values.length;
806
+ }
807
+ push(value) {
808
+ if (this.#closed) {
809
+ return;
810
+ }
811
+ const nextWaiter = this.#nextWaiters.shift();
812
+ if (nextWaiter !== undefined) {
813
+ nextWaiter.resolve({ value, done: false });
814
+ }
815
+ else {
816
+ this.#values.push(value);
817
+ }
818
+ }
819
+ close(error) {
820
+ if (this.#closed) {
821
+ return;
822
+ }
823
+ this.#closed = true;
824
+ this.#error = error;
825
+ for (const waiter of this.#nextWaiters.splice(0)) {
826
+ if (error === undefined) {
827
+ waiter.resolve({ value: undefined, done: true });
828
+ }
829
+ else {
830
+ waiter.reject(error);
831
+ }
832
+ }
833
+ }
834
+ [Symbol.asyncIterator]() {
835
+ return {
836
+ next: async () => {
837
+ const value = this.#values.shift();
838
+ if (value !== undefined) {
839
+ return { value, done: false };
840
+ }
841
+ if (this.#closed) {
842
+ if (this.#error !== undefined) {
843
+ throw this.#error;
844
+ }
845
+ return { value: undefined, done: true };
846
+ }
847
+ return await new Promise((resolve, reject) => {
848
+ this.#nextWaiters.push({
849
+ resolve,
850
+ reject,
851
+ });
852
+ });
853
+ },
854
+ };
855
+ }
856
+ }
857
+ class AsyncSignal {
858
+ #waiters = [];
859
+ #closedMessage;
860
+ #signaled = false;
861
+ #closed = false;
862
+ #error;
863
+ constructor(closedMessage = "sandbox-host packet activity closed") {
864
+ this.#closedMessage = closedMessage;
865
+ }
866
+ notify() {
867
+ if (this.#closed) {
868
+ return;
869
+ }
870
+ this.#signaled = true;
871
+ for (const waiter of this.#waiters.splice(0)) {
872
+ waiter.resolve();
873
+ }
874
+ }
875
+ close(error) {
876
+ if (this.#closed) {
877
+ return;
878
+ }
879
+ this.#closed = true;
880
+ this.#error = error;
881
+ for (const waiter of this.#waiters.splice(0)) {
882
+ if (error === undefined) {
883
+ waiter.resolve();
884
+ }
885
+ else {
886
+ waiter.reject(error);
887
+ }
888
+ }
889
+ }
890
+ async wait() {
891
+ if (this.#signaled) {
892
+ return;
893
+ }
894
+ if (this.#closed) {
895
+ if (this.#error !== undefined) {
896
+ throw this.#error;
897
+ }
898
+ throw new Error(this.#closedMessage);
899
+ }
900
+ return await new Promise((resolve, reject) => {
901
+ this.#waiters.push({ resolve, reject });
902
+ });
903
+ }
904
+ }
583
905
  function encodeHostSpawn(options) {
584
906
  return encodePacket({
585
907
  type: "host.spawn",
@@ -591,7 +913,12 @@ function encodeHostSpawn(options) {
591
913
  rootfsPath: options.rootfs.path,
592
914
  rootfsReadonly: options.rootfs.readonly,
593
915
  rootfsFormat: options.rootfs.format,
594
- rootfsOverlayMode: options.rootfsOverlay?.mode,
916
+ rootfsStorage: options.rootfs.storage === undefined
917
+ ? undefined
918
+ : {
919
+ kind: options.rootfs.storage.kind,
920
+ blockSize: options.rootfs.storage.blockSize,
921
+ },
595
922
  mounts: options.mounts ?? [],
596
923
  networkOutbound: options.network?.outbound,
597
924
  networkHttp: options.network?.http === undefined ? undefined : options.network.http,