@namzu/sandbox 1.1.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 (69) hide show
  1. package/CHANGELOG.md +474 -0
  2. package/LICENSE.md +110 -0
  3. package/README.md +148 -0
  4. package/dist/backends/aci-standby-pool/index.d.ts +104 -0
  5. package/dist/backends/aci-standby-pool/index.d.ts.map +1 -0
  6. package/dist/backends/aci-standby-pool/index.js +425 -0
  7. package/dist/backends/aci-standby-pool/index.js.map +1 -0
  8. package/dist/backends/docker/__tests__/leaf-permissions.smoke.test.d.ts +40 -0
  9. package/dist/backends/docker/__tests__/leaf-permissions.smoke.test.d.ts.map +1 -0
  10. package/dist/backends/docker/__tests__/leaf-permissions.smoke.test.js +157 -0
  11. package/dist/backends/docker/__tests__/leaf-permissions.smoke.test.js.map +1 -0
  12. package/dist/backends/docker/index.d.ts +118 -0
  13. package/dist/backends/docker/index.d.ts.map +1 -0
  14. package/dist/backends/docker/index.js +645 -0
  15. package/dist/backends/docker/index.js.map +1 -0
  16. package/dist/backends/firecracker/__tests__/backend.test.d.ts +13 -0
  17. package/dist/backends/firecracker/__tests__/backend.test.d.ts.map +1 -0
  18. package/dist/backends/firecracker/__tests__/backend.test.js +353 -0
  19. package/dist/backends/firecracker/__tests__/backend.test.js.map +1 -0
  20. package/dist/backends/firecracker/__tests__/control-plane-mtls.test.d.ts +19 -0
  21. package/dist/backends/firecracker/__tests__/control-plane-mtls.test.d.ts.map +1 -0
  22. package/dist/backends/firecracker/__tests__/control-plane-mtls.test.js +201 -0
  23. package/dist/backends/firecracker/__tests__/control-plane-mtls.test.js.map +1 -0
  24. package/dist/backends/firecracker/__tests__/fixtures/mtls-pki.d.ts +39 -0
  25. package/dist/backends/firecracker/__tests__/fixtures/mtls-pki.d.ts.map +1 -0
  26. package/dist/backends/firecracker/__tests__/fixtures/mtls-pki.js +149 -0
  27. package/dist/backends/firecracker/__tests__/fixtures/mtls-pki.js.map +1 -0
  28. package/dist/backends/firecracker/__tests__/protocol.test.d.ts +6 -0
  29. package/dist/backends/firecracker/__tests__/protocol.test.d.ts.map +1 -0
  30. package/dist/backends/firecracker/__tests__/protocol.test.js +77 -0
  31. package/dist/backends/firecracker/__tests__/protocol.test.js.map +1 -0
  32. package/dist/backends/firecracker/__tests__/transport.test.d.ts +20 -0
  33. package/dist/backends/firecracker/__tests__/transport.test.d.ts.map +1 -0
  34. package/dist/backends/firecracker/__tests__/transport.test.js +449 -0
  35. package/dist/backends/firecracker/__tests__/transport.test.js.map +1 -0
  36. package/dist/backends/firecracker/index.d.ts +124 -0
  37. package/dist/backends/firecracker/index.d.ts.map +1 -0
  38. package/dist/backends/firecracker/index.js +334 -0
  39. package/dist/backends/firecracker/index.js.map +1 -0
  40. package/dist/backends/firecracker/protocol.d.ts +132 -0
  41. package/dist/backends/firecracker/protocol.d.ts.map +1 -0
  42. package/dist/backends/firecracker/protocol.js +112 -0
  43. package/dist/backends/firecracker/protocol.js.map +1 -0
  44. package/dist/backends/firecracker/transport.d.ts +251 -0
  45. package/dist/backends/firecracker/transport.d.ts.map +1 -0
  46. package/dist/backends/firecracker/transport.js +524 -0
  47. package/dist/backends/firecracker/transport.js.map +1 -0
  48. package/dist/index.d.ts +611 -0
  49. package/dist/index.d.ts.map +1 -0
  50. package/dist/index.js +376 -0
  51. package/dist/index.js.map +1 -0
  52. package/dist/index.test.d.ts +28 -0
  53. package/dist/index.test.d.ts.map +1 -0
  54. package/dist/index.test.js +670 -0
  55. package/dist/index.test.js.map +1 -0
  56. package/package.json +54 -0
  57. package/src/backends/aci-standby-pool/index.ts +602 -0
  58. package/src/backends/docker/__tests__/leaf-permissions.smoke.test.ts +169 -0
  59. package/src/backends/docker/index.ts +826 -0
  60. package/src/backends/firecracker/__tests__/backend.test.ts +418 -0
  61. package/src/backends/firecracker/__tests__/control-plane-mtls.test.ts +253 -0
  62. package/src/backends/firecracker/__tests__/fixtures/mtls-pki.ts +166 -0
  63. package/src/backends/firecracker/__tests__/protocol.test.ts +90 -0
  64. package/src/backends/firecracker/__tests__/transport.test.ts +526 -0
  65. package/src/backends/firecracker/index.ts +528 -0
  66. package/src/backends/firecracker/protocol.ts +191 -0
  67. package/src/backends/firecracker/transport.ts +667 -0
  68. package/src/index.test.ts +731 -0
  69. package/src/index.ts +930 -0
@@ -0,0 +1,251 @@
1
+ /**
2
+ * Host-side vsock transport + dialer for the Firecracker in-VM agent.
3
+ *
4
+ * This is the NEW code the §2.2 decision calls for. The docker/ACI
5
+ * backends reach the agent over HTTP with `fetch`; **Node `fetch`
6
+ * cannot dial `AF_VSOCK`**, and across an FC snapshot resume a TCP
7
+ * control channel is dead-on-arrival (FC `snapshot-support.md`: TCP
8
+ * connection state does not survive a resume; the **vsock LISTEN
9
+ * socket** does). So the FC control channel is a framed stream over
10
+ * vsock, and that framing + the resume-survival hardening live here.
11
+ *
12
+ * ## One wire, two transports
13
+ * The message FORMAT (NDJSON exec events + base64 file-IO) is shared
14
+ * with the HTTP backends via `protocol.ts`. This module owns only the
15
+ * TRANSPORT: how a request crosses the wire and how a response is
16
+ * framed back.
17
+ *
18
+ * Framing: a length-prefixed envelope per message —
19
+ * `<8-hex-digit big-endian byte length>\n<utf8 JSON payload>`
20
+ * The newline after the hex length lets a reader find the boundary
21
+ * without a fixed header struct, and the explicit length means a
22
+ * payload that itself contains newlines (NDJSON exec output) is read
23
+ * whole, not split. Exec replies are a SEQUENCE of framed NDJSON
24
+ * lines terminated by a zero-length frame; file-IO replies are a
25
+ * single framed JSON object.
26
+ *
27
+ * ## How vsock is actually dialed from Node
28
+ * Node has no `AF_VSOCK` socket family. The production path therefore
29
+ * follows exactly what the in-situ bench already proved: the guest
30
+ * agent's vsock stream is bridged to a **host-side unix-domain
31
+ * socket** (the bench relays guest `AF_VSOCK` → host CID:port → a host
32
+ * unix socket; FC's own vsock device exposes a host-side unix socket
33
+ * rendezvous, `UDS + "CONNECT <port>"`). So the host dialer ALWAYS
34
+ * terminates on a `net.connect({ path })` unix socket:
35
+ * - `kind: 'unix'` — connect directly to `path` (local/dev + tests).
36
+ * - `kind: 'vsock'` — connect to the FC vsock device's host unix
37
+ * socket `udsPath`, then send the firecracker hybrid-vsock
38
+ * handshake line `CONNECT <port>\n` and await the `OK <hostport>`
39
+ * ack before framing application traffic.
40
+ * Both land on the same `net.Socket`, so the unix-socket stand-in in
41
+ * the tests exercises the identical framing/heartbeat/reconnect code
42
+ * the vsock path runs — the only delta is the one-line CONNECT
43
+ * handshake, which is covered by its own assertion.
44
+ *
45
+ * ## Resume survival (the hard invariant, FC #4713 / loopholelabs)
46
+ * On resume the guest vsock driver closes all existing connections and
47
+ * the `TRANSPORT_RESET` event may NOT be delivered, so a host read can
48
+ * hang. The agent re-LISTENs after every resume; the host dialer
49
+ * carries a per-attempt connect/handshake **timeout + retry budget**
50
+ * so a dropped reset cannot wedge first-exec — the dialer simply
51
+ * re-dials. Every request opens a fresh connection (no long-lived
52
+ * socket to be silently severed by a resume), which makes the
53
+ * transport resume-survivable by construction.
54
+ */
55
+ import type { SandboxExecResult } from '@namzu/sdk';
56
+ import { type ExecRequest, type ReadFileRequest, type WriteFileRequest } from './protocol.js';
57
+ /**
58
+ * An addressable agent endpoint. The orchestrator hands one of these
59
+ * back per sandbox (`create()` response → `vsock endpoint`).
60
+ *
61
+ * - `unix` — a host unix-domain socket the agent (or a relay) is
62
+ * listening on. The local/dev path and the test stand-in.
63
+ * - `vsock` — a Firecracker hybrid-vsock device exposed as a host
64
+ * unix socket at `udsPath`; `port` is the guest AF_VSOCK port the
65
+ * agent listens on (the fixed contract port baked into the golden
66
+ * rootfs). The dialer connects to `udsPath` then issues the
67
+ * `CONNECT <port>` handshake.
68
+ * - `mtls` — a per-FC-host mTLS RELAY daemon reachable over the
69
+ * network at `host:port` (the owning host's private VNet IP + the
70
+ * bridge port). The dialer `tls.connect`s the relay presenting the
71
+ * fleet client cert, verifies the relay's server cert
72
+ * (`rejectUnauthorized: true`), then writes a single routing
73
+ * preamble line `SANDBOX <sandboxId>\n`. The relay terminates mTLS,
74
+ * resolves `sandboxId` to the host-local jailed `v.sock`, dials it,
75
+ * and issues the guest `CONNECT 1024` handshake ITSELF — so the
76
+ * caller does NOT write the `CONNECT` line. After the preamble the
77
+ * relay is a verbatim byte pump, so the IDENTICAL 8-hex/NDJSON
78
+ * framing + heartbeat + retry runs unchanged over the TLS socket
79
+ * (`tls.TLSSocket` is a `net.Socket`). The container-app NEVER sees
80
+ * a host-local `udsPath`; the cert material is injected by the
81
+ * Vandal host layer, never returned by the orchestrator.
82
+ */
83
+ export type SandboxAgentHandle = {
84
+ readonly kind: 'unix';
85
+ readonly path: string;
86
+ } | {
87
+ readonly kind: 'vsock';
88
+ readonly udsPath: string;
89
+ readonly port: number;
90
+ } | {
91
+ readonly kind: 'mtls';
92
+ readonly host: string;
93
+ readonly port: number;
94
+ readonly sandboxId: string;
95
+ readonly tls: {
96
+ readonly ca: string | Buffer;
97
+ readonly cert: string | Buffer;
98
+ readonly key: string | Buffer;
99
+ readonly servername?: string;
100
+ };
101
+ };
102
+ /**
103
+ * The mTLS cert material the consumer injects onto a wire `mtls` handle (the
104
+ * `tls` block of the transport handle). Read from the consumer's runtime (the
105
+ * Vandal host layer's `VANDAL_SANDBOX_FC_TLS_*`), NEVER returned by the
106
+ * orchestrator — the leak-prevention boundary.
107
+ */
108
+ export interface MtlsClientMaterial {
109
+ readonly ca: string | Buffer;
110
+ readonly cert: string | Buffer;
111
+ readonly key: string | Buffer;
112
+ readonly servername?: string;
113
+ }
114
+ /**
115
+ * The WIRE shape of an agent handle as the orchestrator returns it. Identical
116
+ * to {@link SandboxAgentHandle} EXCEPT the `mtls` arm omits the `tls` cert
117
+ * block: the orchestrator returns only host/port/sandboxId, and the consumer
118
+ * (Vandal host layer) merges the cert material in (see `normalizeHandle`)
119
+ * before constructing the transport. The `unix`/`vsock` arms are unchanged
120
+ * (they carry no cert material).
121
+ */
122
+ export type WireSandboxAgentHandle = {
123
+ readonly kind: 'unix';
124
+ readonly path: string;
125
+ } | {
126
+ readonly kind: 'vsock';
127
+ readonly udsPath: string;
128
+ readonly port: number;
129
+ } | {
130
+ readonly kind: 'mtls';
131
+ readonly host: string;
132
+ readonly port: number;
133
+ readonly sandboxId: string;
134
+ };
135
+ /**
136
+ * A framed request. `op` selects the agent handler; the HTTP worker
137
+ * used the URL path (`/execute`, `/read-file`, `/write-file`,
138
+ * `/healthz`) — over vsock the same selector rides in the framed JSON.
139
+ */
140
+ export type AgentRequest = {
141
+ readonly op: 'execute';
142
+ readonly body: ExecRequest;
143
+ } | {
144
+ readonly op: 'read-file';
145
+ readonly body: ReadFileRequest;
146
+ } | {
147
+ readonly op: 'write-file';
148
+ readonly body: WriteFileRequest;
149
+ } | {
150
+ readonly op: 'healthz';
151
+ };
152
+ export interface VsockTransportOptions {
153
+ /** Per-attempt connect + handshake timeout. Default 5000ms. */
154
+ readonly connectTimeoutMs?: number;
155
+ /** Total time budget for connect retries (resume survival). Default 30000ms. */
156
+ readonly connectRetryBudgetMs?: number;
157
+ /** Backoff between connect retries. Default 100ms. */
158
+ readonly connectRetryIntervalMs?: number;
159
+ /**
160
+ * Idle read timeout once connected and the request is sent. Guards
161
+ * the FC #4713 "read hangs because TRANSPORT_RESET was not
162
+ * delivered" case: if no byte arrives within this window the
163
+ * transport tears the socket down and the caller's retry re-dials
164
+ * against the agent's fresh listen socket. Default 60000ms.
165
+ */
166
+ readonly readIdleTimeoutMs?: number;
167
+ }
168
+ declare function frame(payload: string): Buffer;
169
+ /**
170
+ * Incremental frame reader. Feed it socket chunks; it yields complete
171
+ * payloads. A zero-length frame is the exec stream terminator and is
172
+ * surfaced as an empty string so the caller can stop.
173
+ */
174
+ declare class FrameReader {
175
+ private buf;
176
+ push(chunk: Buffer): string[];
177
+ }
178
+ /**
179
+ * The transport. One instance per sandbox handle; every request opens
180
+ * a fresh connection (resume-survivable — no socket lingers across a
181
+ * resume to be silently severed). All four ops + the heartbeat go
182
+ * through {@link request} / {@link execute}.
183
+ */
184
+ export declare class VsockAgentTransport {
185
+ private readonly handle;
186
+ private readonly connectTimeoutMs;
187
+ private readonly connectRetryBudgetMs;
188
+ private readonly connectRetryIntervalMs;
189
+ private readonly readIdleTimeoutMs;
190
+ constructor(handle: SandboxAgentHandle, options?: VsockTransportOptions);
191
+ /**
192
+ * Dial the agent with the resume-survival retry budget. Resolves a
193
+ * connected, post-handshake socket. Retries connect/handshake
194
+ * failures (ECONNREFUSED while the agent re-listens after a resume,
195
+ * a dropped CONNECT ack) until the budget is exhausted.
196
+ */
197
+ private dial;
198
+ private connectOnce;
199
+ /**
200
+ * Dial the per-FC-host mTLS relay for an `mtls` handle.
201
+ *
202
+ * This is a pure TRANSPORT substitution for the `net.connect` arms:
203
+ * it `tls.connect`s the relay (presenting the fleet client cert and
204
+ * verifying the relay's server cert, `rejectUnauthorized: true`),
205
+ * asserts `socket.authorized`, then writes the single routing
206
+ * preamble line `SANDBOX <sandboxId>\n`. It does NOT write the guest
207
+ * `CONNECT 1024` line — the relay issues that host-side toward the
208
+ * jailed `v.sock`. The relay does NOT send an ack line: after the
209
+ * preamble it is a verbatim byte pump, so the caller hands the
210
+ * post-preamble socket straight up to the IDENTICAL framing loop the
211
+ * unix/vsock arms use (a `tls.TLSSocket` IS a `net.Socket`). The
212
+ * connect-retry budget, idle timeout, and the "fresh connection per
213
+ * request" resume-survival invariant are inherited unchanged.
214
+ *
215
+ * INTEGRATE CONTRACT (must match the relay, Track B): NO ack line.
216
+ * The relay reads `SANDBOX <id>\n`, then bridges; it writes nothing
217
+ * back until the agent does. If the relay is ever changed to emit an
218
+ * `OK` ack first, this arm must await that line (mirroring the vsock
219
+ * CONNECT-ack path) before resolving — today it does not.
220
+ */
221
+ private connectOnceMtls;
222
+ /**
223
+ * Send one framed request and read one framed JSON reply (file-IO +
224
+ * healthz). Applies the read-idle timeout so a post-resume hung read
225
+ * is torn down rather than wedging the caller.
226
+ */
227
+ request<T>(req: AgentRequest): Promise<T>;
228
+ /**
229
+ * Send an `/execute` and accumulate the streamed NDJSON frames into a
230
+ * {@link SandboxExecResult} via the shared {@link ExecResultAccumulator}.
231
+ * The agent terminates the stream with a zero-length frame.
232
+ */
233
+ execute(body: ExecRequest): Promise<SandboxExecResult>;
234
+ /** Liveness probe. Returns true on an `{ ok: true }` healthz reply. */
235
+ healthz(): Promise<boolean>;
236
+ /**
237
+ * Poll the agent until a healthz succeeds or the timeout elapses.
238
+ * Mirrors the HTTP `waitForWorkerReady`, but over the vsock dialer
239
+ * (which already carries connect retry) — used by the backend's
240
+ * post-create readiness fence.
241
+ */
242
+ waitForReady(timeoutMs: number, pollIntervalMs: number): Promise<void>;
243
+ writeFile(path: string, content: Buffer): Promise<void>;
244
+ readFile(path: string): Promise<Buffer>;
245
+ }
246
+ export declare const __framing: {
247
+ frame: typeof frame;
248
+ FrameReader: typeof FrameReader;
249
+ };
250
+ export {};
251
+ //# sourceMappingURL=transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../../src/backends/firecracker/transport.ts"],"names":[],"mappings":"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"}