@namzu/sandbox 13.0.0 → 14.0.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.
- package/CHANGELOG.md +309 -0
- package/README.md +151 -0
- package/dist/backends/firecracker/protocol.d.ts +22 -0
- package/dist/backends/firecracker/protocol.d.ts.map +1 -1
- package/dist/backends/firecracker/protocol.js.map +1 -1
- package/dist/backends/firecracker/transport.d.ts +104 -9
- package/dist/backends/firecracker/transport.d.ts.map +1 -1
- package/dist/backends/firecracker/transport.js +139 -13
- package/dist/backends/firecracker/transport.js.map +1 -1
- package/dist/backends/kubernetes/egress-policy.d.ts +219 -0
- package/dist/backends/kubernetes/egress-policy.d.ts.map +1 -0
- package/dist/backends/kubernetes/egress-policy.js +314 -0
- package/dist/backends/kubernetes/egress-policy.js.map +1 -0
- package/dist/backends/kubernetes/index.d.ts +374 -0
- package/dist/backends/kubernetes/index.d.ts.map +1 -0
- package/dist/backends/kubernetes/index.js +671 -0
- package/dist/backends/kubernetes/index.js.map +1 -0
- package/dist/backends/kubernetes/k8s-client.d.ts +125 -0
- package/dist/backends/kubernetes/k8s-client.d.ts.map +1 -0
- package/dist/backends/kubernetes/k8s-client.js +246 -0
- package/dist/backends/kubernetes/k8s-client.js.map +1 -0
- package/dist/backends/kubernetes/lease.d.ts +119 -0
- package/dist/backends/kubernetes/lease.d.ts.map +1 -0
- package/dist/backends/kubernetes/lease.js +151 -0
- package/dist/backends/kubernetes/lease.js.map +1 -0
- package/dist/backends/kubernetes/objects.d.ts +282 -0
- package/dist/backends/kubernetes/objects.d.ts.map +1 -0
- package/dist/backends/kubernetes/objects.js +156 -0
- package/dist/backends/kubernetes/objects.js.map +1 -0
- package/dist/backends/kubernetes/privilege-probe.d.ts +136 -0
- package/dist/backends/kubernetes/privilege-probe.d.ts.map +1 -0
- package/dist/backends/kubernetes/privilege-probe.js +185 -0
- package/dist/backends/kubernetes/privilege-probe.js.map +1 -0
- package/dist/backends/kubernetes/sandbox.d.ts +123 -0
- package/dist/backends/kubernetes/sandbox.d.ts.map +1 -0
- package/dist/backends/kubernetes/sandbox.js +299 -0
- package/dist/backends/kubernetes/sandbox.js.map +1 -0
- package/dist/backends/kubernetes/transport.d.ts +122 -0
- package/dist/backends/kubernetes/transport.d.ts.map +1 -0
- package/dist/backends/kubernetes/transport.js +197 -0
- package/dist/backends/kubernetes/transport.js.map +1 -0
- package/dist/backends/kubernetes/workspace.d.ts +381 -0
- package/dist/backends/kubernetes/workspace.d.ts.map +1 -0
- package/dist/backends/kubernetes/workspace.js +1064 -0
- package/dist/backends/kubernetes/workspace.js.map +1 -0
- package/dist/index.d.ts +132 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +102 -34
- package/dist/index.js.map +1 -1
- package/dist/testing/sandbox-conformance.d.ts +193 -0
- package/dist/testing/sandbox-conformance.d.ts.map +1 -0
- package/dist/testing/sandbox-conformance.js +465 -0
- package/dist/testing/sandbox-conformance.js.map +1 -0
- package/package.json +5 -4
- package/src/backends/firecracker/protocol.ts +27 -0
- package/src/backends/firecracker/transport.ts +199 -28
- package/src/backends/kubernetes/egress-policy.ts +437 -0
- package/src/backends/kubernetes/index.ts +1012 -0
- package/src/backends/kubernetes/k8s-client.ts +352 -0
- package/src/backends/kubernetes/lease.ts +198 -0
- package/src/backends/kubernetes/objects.ts +363 -0
- package/src/backends/kubernetes/privilege-probe.ts +261 -0
- package/src/backends/kubernetes/sandbox.ts +395 -0
- package/src/backends/kubernetes/transport.ts +286 -0
- package/src/backends/kubernetes/workspace.ts +1386 -0
- package/src/index.ts +257 -35
- package/src/testing/sandbox-conformance.ts +667 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sandbox-conformance.js","sourceRoot":"","sources":["../../src/testing/sandbox-conformance.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@namzu/sandbox",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "14.0.0",
|
|
4
4
|
"description": "Pluggable sandbox provider for @namzu/sdk. Process-level isolation (bubblewrap on Linux, Seatbelt on macOS, via @anthropic-ai/sandbox-runtime) for developer dev loops; container-level isolation (HTTP worker + a loopback-bound egress proxy that allows by resolved address and brokers outbound credentials so they never enter the sandbox) for multi-tenant production. Backend selected at construction time; the SDK consumes both through the same SandboxProvider interface.",
|
|
5
5
|
"license": "FSL-1.1-MIT",
|
|
6
6
|
"engines": {
|
|
@@ -46,19 +46,20 @@
|
|
|
46
46
|
"provenance": true
|
|
47
47
|
},
|
|
48
48
|
"peerDependencies": {
|
|
49
|
-
"@namzu/sdk": "^
|
|
49
|
+
"@namzu/sdk": "^40.0.0"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@biomejs/biome": "^1.9.4",
|
|
53
53
|
"@types/node": "^22.19.17",
|
|
54
54
|
"typescript": "^5.5.0",
|
|
55
55
|
"vitest": "^3.2.6",
|
|
56
|
-
"
|
|
56
|
+
"yaml": "^2.9.0",
|
|
57
|
+
"@namzu/sdk": "^40.0.0"
|
|
57
58
|
},
|
|
58
59
|
"scripts": {
|
|
59
60
|
"build": "tsc --build",
|
|
60
61
|
"dev": "tsc --build --watch",
|
|
61
|
-
"lint": "biome check src/ worker/ agent/",
|
|
62
|
+
"lint": "biome check src/ worker/ agent/ k8s/",
|
|
62
63
|
"lint:fix": "biome check --write src/",
|
|
63
64
|
"format": "biome format --write src/",
|
|
64
65
|
"test": "vitest run --passWithNoTests",
|
|
@@ -19,6 +19,33 @@ import type { SandboxExecOptions, SandboxExecResult } from '@namzu/sdk'
|
|
|
19
19
|
|
|
20
20
|
import { RemoteCommandError, RemoteProtocolError } from '../remote-execution-controller.js'
|
|
21
21
|
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
// Credential — the one optional field every request envelope may carry
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* The per-instance credential a framed request may present, mixed into
|
|
28
|
+
* the request envelope alongside its `op`.
|
|
29
|
+
*
|
|
30
|
+
* Absent on the vsock and unix transports: that control channel is
|
|
31
|
+
* host↔guest only and never traverses guest egress, so the guest agent
|
|
32
|
+
* authenticates nothing there and this field is simply never written.
|
|
33
|
+
* A guest reached over a ROUTED network has no such boundary, so it is
|
|
34
|
+
* started with a per-instance token (`NAMZU_AGENT_BIND_TOKEN`, fed the
|
|
35
|
+
* pod's own identity by its orchestrator) and refuses every op but
|
|
36
|
+
* `healthz` that does not present exactly that value — from the first
|
|
37
|
+
* frame, since the agent dispatches a connection on its first frame and
|
|
38
|
+
* there is no handshake to defer the check to.
|
|
39
|
+
*
|
|
40
|
+
* The field is OPTIONAL and additive, so a host that never sets it
|
|
41
|
+
* speaks the same wire it always did and
|
|
42
|
+
* `FIRECRACKER_AGENT_PROTOCOL_VERSION` is deliberately unchanged: this
|
|
43
|
+
* needs no coupled golden-image and host rollout.
|
|
44
|
+
*/
|
|
45
|
+
export interface AgentRequestCredential {
|
|
46
|
+
readonly token?: string
|
|
47
|
+
}
|
|
48
|
+
|
|
22
49
|
// ---------------------------------------------------------------------------
|
|
23
50
|
// Exec — request + the NDJSON event shapes (verbatim from worker/server.js)
|
|
24
51
|
// ---------------------------------------------------------------------------
|
|
@@ -73,6 +73,7 @@ import {
|
|
|
73
73
|
RemoteProtocolError,
|
|
74
74
|
} from '../remote-execution-controller.js'
|
|
75
75
|
import {
|
|
76
|
+
type AgentRequestCredential,
|
|
76
77
|
type ExecRequest,
|
|
77
78
|
ExecResultAccumulator,
|
|
78
79
|
type ReadFileRequest,
|
|
@@ -117,6 +118,18 @@ import {
|
|
|
117
118
|
* (`tls.TLSSocket` is a `net.Socket`). The container-app NEVER sees
|
|
118
119
|
* a host-local `udsPath`; the cert material is injected by the
|
|
119
120
|
* Vandal host layer, never returned by the orchestrator.
|
|
121
|
+
* - `tcp` — the guest agent listening directly on a routed pod
|
|
122
|
+
* network (the kubernetes backend). The dialer does a plain
|
|
123
|
+
* `net.connect({ host, port })` — no relay, no routing preamble, no
|
|
124
|
+
* ack: there is nothing between the host and the guest's own listen
|
|
125
|
+
* socket to route through, so the framing loop starts on the very
|
|
126
|
+
* first byte, exactly as the `unix` arm's does. `host` may be a
|
|
127
|
+
* Service FQDN rather than a literal IP; every call dials fresh (see
|
|
128
|
+
* `dial()` below), so DNS is re-resolved on every request and a
|
|
129
|
+
* resumed pod's new address is picked up for free. `token` rides in
|
|
130
|
+
* each request envelope (see `AgentRequestCredential` in
|
|
131
|
+
* `protocol.ts`) because a routed listener authenticates what the
|
|
132
|
+
* vsock/unix control channel never had to.
|
|
120
133
|
*/
|
|
121
134
|
export type SandboxAgentHandle =
|
|
122
135
|
| { readonly kind: 'unix'; readonly path: string }
|
|
@@ -133,6 +146,7 @@ export type SandboxAgentHandle =
|
|
|
133
146
|
readonly servername?: string
|
|
134
147
|
}
|
|
135
148
|
}
|
|
149
|
+
| { readonly kind: 'tcp'; readonly host: string; readonly port: number; readonly token?: string }
|
|
136
150
|
|
|
137
151
|
/**
|
|
138
152
|
* The mTLS cert material the consumer injects onto a wire `mtls` handle (the
|
|
@@ -148,12 +162,17 @@ export interface MtlsClientMaterial {
|
|
|
148
162
|
}
|
|
149
163
|
|
|
150
164
|
/**
|
|
151
|
-
* The WIRE shape of an agent handle as the orchestrator
|
|
152
|
-
* to {@link SandboxAgentHandle} EXCEPT the `mtls`
|
|
153
|
-
* block: the orchestrator returns only
|
|
154
|
-
* (Vandal host layer) merges the
|
|
155
|
-
*
|
|
156
|
-
* (they carry no cert
|
|
165
|
+
* The WIRE shape of an agent handle as the FIRECRACKER orchestrator
|
|
166
|
+
* returns it. Identical to {@link SandboxAgentHandle} EXCEPT the `mtls`
|
|
167
|
+
* arm omits the `tls` cert block: the orchestrator returns only
|
|
168
|
+
* host/port/sandboxId, and the consumer (Vandal host layer) merges the
|
|
169
|
+
* cert material in (see `normalizeHandle`) before constructing the
|
|
170
|
+
* transport. The `unix`/`vsock` arms are unchanged (they carry no cert
|
|
171
|
+
* material). There is deliberately no `tcp` arm here: that kind belongs
|
|
172
|
+
* to the kubernetes backend, which builds its {@link SandboxAgentHandle}
|
|
173
|
+
* directly (host/port from the claimed Sandbox's status, token from the
|
|
174
|
+
* pod's own identity) and never goes through this orchestrator wire
|
|
175
|
+
* shape or `normalizeHandle`.
|
|
157
176
|
*/
|
|
158
177
|
export type WireSandboxAgentHandle =
|
|
159
178
|
| { readonly kind: 'unix'; readonly path: string }
|
|
@@ -174,7 +193,7 @@ export type WireSandboxAgentHandle =
|
|
|
174
193
|
* used the URL path (`/execute`, `/read-file`, `/write-file`,
|
|
175
194
|
* `/healthz`) — over vsock the same selector rides in the framed JSON.
|
|
176
195
|
*/
|
|
177
|
-
export type AgentRequest =
|
|
196
|
+
export type AgentRequest = (
|
|
178
197
|
| { readonly op: 'execute'; readonly body: ExecRequest }
|
|
179
198
|
| { readonly op: 'reserve-execution' }
|
|
180
199
|
| {
|
|
@@ -186,6 +205,12 @@ export type AgentRequest =
|
|
|
186
205
|
| { readonly op: 'terminal'; readonly body: TerminalOpenRequest }
|
|
187
206
|
| { readonly op: 'tcp-connect'; readonly body: TcpConnectRequest }
|
|
188
207
|
| { readonly op: 'healthz' }
|
|
208
|
+
) &
|
|
209
|
+
// Intersected, not repeated per arm: the credential is orthogonal to
|
|
210
|
+
// the op, and every arm may carry it. Optional and additive, so a host
|
|
211
|
+
// that writes no token speaks the wire it always did — see
|
|
212
|
+
// {@link AgentRequestCredential}.
|
|
213
|
+
AgentRequestCredential
|
|
189
214
|
|
|
190
215
|
export interface VsockTransportOptions {
|
|
191
216
|
/** Per-attempt connect + handshake timeout. Default 5000ms. */
|
|
@@ -202,6 +227,15 @@ export interface VsockTransportOptions {
|
|
|
202
227
|
* against the agent's fresh listen socket. Default 60000ms.
|
|
203
228
|
*/
|
|
204
229
|
readonly readIdleTimeoutMs?: number
|
|
230
|
+
/**
|
|
231
|
+
* Fires once per successful dial with how long the connect took, in
|
|
232
|
+
* milliseconds. Never fires with the handle's `token` or any request
|
|
233
|
+
* content — a bare number. Used by callers that build their own
|
|
234
|
+
* `RemoteExecutionAdapter` on top of this transport (the kubernetes
|
|
235
|
+
* backend's `KubernetesAgentTransport`) to attribute wall time; the
|
|
236
|
+
* vsock/mtls/unix arms are free to ignore it.
|
|
237
|
+
*/
|
|
238
|
+
readonly onDial?: (durationMs: number) => void
|
|
205
239
|
}
|
|
206
240
|
|
|
207
241
|
const DEFAULT_CONNECT_TIMEOUT_MS = 5_000
|
|
@@ -217,6 +251,39 @@ const EXECUTION_TRANSPORT_GRACE_MS = 10_000
|
|
|
217
251
|
const POST_RESPONSE_CLOSE_TIMEOUT_MS = 1_000
|
|
218
252
|
const MAX_TIMER_DELAY_MS = 2_147_483_647
|
|
219
253
|
|
|
254
|
+
/**
|
|
255
|
+
* The guest agent's default pre-auth frame ceiling for a routed (`tcp`)
|
|
256
|
+
* connection — mirrors `agent.cjs`'s `MAX_PREAUTH_FRAME_BYTES`
|
|
257
|
+
* (`NAMZU_AGENT_MAX_PREAUTH_FRAME_BYTES`, default 8 MiB). The gate on
|
|
258
|
+
* that side cannot run until a whole frame is parsed (the credential
|
|
259
|
+
* rides inside the envelope), so it bounds what an UNAUTHENTICATED
|
|
260
|
+
* connection's first frame may announce. This transport dials fresh per
|
|
261
|
+
* call — there is no persistent, already-authenticated connection to
|
|
262
|
+
* reuse — so EVERY `tcp` request is that connection's first frame, and
|
|
263
|
+
* this ceiling is therefore the effective per-request budget, not just
|
|
264
|
+
* a one-time cost paid on first use.
|
|
265
|
+
*
|
|
266
|
+
* Checked here, client-side, BEFORE dialing: an oversized request fails
|
|
267
|
+
* fast with a clear error instead of opening a connection the guest is
|
|
268
|
+
* going to refuse anyway. Chunking a `write-file` body across multiple
|
|
269
|
+
* frames would lift this ceiling; it is a documented follow-up, not
|
|
270
|
+
* implemented by this transport.
|
|
271
|
+
*/
|
|
272
|
+
export const TCP_PREAUTH_FRAME_LIMIT_BYTES = 8 * 1024 * 1024
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Thrown when a `tcp`-handle request's framed envelope (op + body +
|
|
276
|
+
* token) would exceed {@link TCP_PREAUTH_FRAME_LIMIT_BYTES}. Named so a
|
|
277
|
+
* caller can distinguish "this body needs chunking" from every other
|
|
278
|
+
* transport failure.
|
|
279
|
+
*/
|
|
280
|
+
export class AgentPreauthFrameTooLargeError extends Error {
|
|
281
|
+
constructor(message: string) {
|
|
282
|
+
super(message)
|
|
283
|
+
this.name = 'AgentPreauthFrameTooLargeError'
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
220
287
|
/** Exact guest wire version accepted by this Firecracker transport. */
|
|
221
288
|
export const FIRECRACKER_AGENT_PROTOCOL_VERSION = REMOTE_EXECUTION_PROTOCOL_VERSION
|
|
222
289
|
|
|
@@ -286,6 +353,7 @@ export class VsockAgentTransport {
|
|
|
286
353
|
private readonly connectRetryBudgetMs: number
|
|
287
354
|
private readonly connectRetryIntervalMs: number
|
|
288
355
|
private readonly readIdleTimeoutMs: number
|
|
356
|
+
private readonly onDial?: (durationMs: number) => void
|
|
289
357
|
private readonly executionController: RemoteExecutionController<
|
|
290
358
|
Pick<ExecRequest, 'stdin' | 'maxOutputBytes'>
|
|
291
359
|
>
|
|
@@ -297,6 +365,7 @@ export class VsockAgentTransport {
|
|
|
297
365
|
this.connectRetryIntervalMs =
|
|
298
366
|
options.connectRetryIntervalMs ?? DEFAULT_CONNECT_RETRY_INTERVAL_MS
|
|
299
367
|
this.readIdleTimeoutMs = options.readIdleTimeoutMs ?? DEFAULT_READ_IDLE_TIMEOUT_MS
|
|
368
|
+
this.onDial = options.onDial
|
|
300
369
|
const adapter: RemoteExecutionAdapter<Pick<ExecRequest, 'stdin' | 'maxOutputBytes'>> = {
|
|
301
370
|
label: 'framed microVM agent',
|
|
302
371
|
reserve: async (signal) => await this.reserveExecution(signal),
|
|
@@ -330,11 +399,14 @@ export class VsockAgentTransport {
|
|
|
330
399
|
*/
|
|
331
400
|
private async dial(signal?: AbortSignal): Promise<net.Socket> {
|
|
332
401
|
const deadline = Date.now() + this.connectRetryBudgetMs
|
|
402
|
+
const dialStartedAt = Date.now()
|
|
333
403
|
let lastErr: unknown
|
|
334
404
|
for (;;) {
|
|
335
405
|
signal?.throwIfAborted()
|
|
336
406
|
try {
|
|
337
|
-
|
|
407
|
+
const socket = await this.connectOnce(signal)
|
|
408
|
+
this.onDial?.(Date.now() - dialStartedAt)
|
|
409
|
+
return socket
|
|
338
410
|
} catch (err) {
|
|
339
411
|
if (signal?.aborted) throw signal.reason
|
|
340
412
|
lastErr = err
|
|
@@ -353,6 +425,7 @@ export class VsockAgentTransport {
|
|
|
353
425
|
private connectOnce(signal?: AbortSignal): Promise<net.Socket> {
|
|
354
426
|
const handle = this.handle
|
|
355
427
|
if (handle.kind === 'mtls') return this.connectOnceMtls(handle, signal)
|
|
428
|
+
if (handle.kind === 'tcp') return this.connectOnceTcp(handle, signal)
|
|
356
429
|
return new Promise<net.Socket>((resolve, reject) => {
|
|
357
430
|
const path = handle.kind === 'unix' ? handle.path : handle.udsPath
|
|
358
431
|
const socket = net.connect({ path })
|
|
@@ -508,12 +581,89 @@ export class VsockAgentTransport {
|
|
|
508
581
|
})
|
|
509
582
|
}
|
|
510
583
|
|
|
584
|
+
/**
|
|
585
|
+
* Dial a `tcp` handle: a plain `net.connect({ host, port })`. NO
|
|
586
|
+
* routing preamble and NO ack — there is no relay to route through
|
|
587
|
+
* and no handshake line the guest expects, so the socket is handed
|
|
588
|
+
* to the framing loop the instant it connects, exactly like the
|
|
589
|
+
* `unix` arm above (whose body this deliberately does not touch).
|
|
590
|
+
*/
|
|
591
|
+
private connectOnceTcp(
|
|
592
|
+
handle: Extract<SandboxAgentHandle, { kind: 'tcp' }>,
|
|
593
|
+
signal?: AbortSignal,
|
|
594
|
+
): Promise<net.Socket> {
|
|
595
|
+
return new Promise<net.Socket>((resolve, reject) => {
|
|
596
|
+
const socket = net.connect({ host: handle.host, port: handle.port })
|
|
597
|
+
let settled = false
|
|
598
|
+
const fail = (err: Error) => {
|
|
599
|
+
if (settled) return
|
|
600
|
+
settled = true
|
|
601
|
+
clearTimeout(timer)
|
|
602
|
+
signal?.removeEventListener('abort', abort)
|
|
603
|
+
socket.destroy()
|
|
604
|
+
reject(err)
|
|
605
|
+
}
|
|
606
|
+
const abort = () => fail(signalError(signal))
|
|
607
|
+
const timer = setTimeout(
|
|
608
|
+
() => fail(new Error(`connect/handshake timed out after ${this.connectTimeoutMs}ms`)),
|
|
609
|
+
this.connectTimeoutMs,
|
|
610
|
+
)
|
|
611
|
+
timer.unref()
|
|
612
|
+
|
|
613
|
+
socket.once('error', fail)
|
|
614
|
+
if (signal?.aborted) {
|
|
615
|
+
abort()
|
|
616
|
+
return
|
|
617
|
+
}
|
|
618
|
+
signal?.addEventListener('abort', abort, { once: true })
|
|
619
|
+
|
|
620
|
+
socket.once('connect', () => {
|
|
621
|
+
if (settled) return
|
|
622
|
+
settled = true
|
|
623
|
+
clearTimeout(timer)
|
|
624
|
+
signal?.removeEventListener('abort', abort)
|
|
625
|
+
socket.removeListener('error', fail)
|
|
626
|
+
resolve(socket)
|
|
627
|
+
})
|
|
628
|
+
})
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
/**
|
|
632
|
+
* Fold the handle's credential into a request envelope. Only the
|
|
633
|
+
* `tcp` arm carries a token — the vsock/unix/mtls control channels
|
|
634
|
+
* are host↔guest only and the agent authenticates nothing there, so
|
|
635
|
+
* a request built for those arms passes through unchanged.
|
|
636
|
+
*/
|
|
637
|
+
private withCredential(req: AgentRequest): AgentRequest {
|
|
638
|
+
if (this.handle.kind === 'tcp' && this.handle.token !== undefined) {
|
|
639
|
+
return { ...req, token: this.handle.token }
|
|
640
|
+
}
|
|
641
|
+
return req
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
/**
|
|
645
|
+
* Refuse an oversized `tcp` envelope BEFORE dialing. See
|
|
646
|
+
* {@link TCP_PREAUTH_FRAME_LIMIT_BYTES}. A no-op for every other
|
|
647
|
+
* handle kind, which the guest never gates on frame size pre-auth.
|
|
648
|
+
*/
|
|
649
|
+
private assertPreauthBudget(payload: string): void {
|
|
650
|
+
if (this.handle.kind !== 'tcp') return
|
|
651
|
+
const size = Buffer.byteLength(payload, 'utf8')
|
|
652
|
+
if (size <= TCP_PREAUTH_FRAME_LIMIT_BYTES) return
|
|
653
|
+
throw new AgentPreauthFrameTooLargeError(
|
|
654
|
+
`kubernetes tcp transport: request envelope is ${size} bytes, which exceeds the ${TCP_PREAUTH_FRAME_LIMIT_BYTES}-byte limit the guest agent enforces on an unauthenticated connection's first frame (NAMZU_AGENT_MAX_PREAUTH_FRAME_BYTES, default 8 MiB). Every tcp request dials a fresh connection, so this request WOULD be that connection's first frame. Chunking a large body across multiple frames is not implemented; reduce the payload or raise the deployment's NAMZU_AGENT_MAX_PREAUTH_FRAME_BYTES.`,
|
|
655
|
+
)
|
|
656
|
+
}
|
|
657
|
+
|
|
511
658
|
/**
|
|
512
659
|
* Send one framed request and read one framed JSON reply (file-IO +
|
|
513
660
|
* healthz). Applies the read-idle timeout so a post-resume hung read
|
|
514
661
|
* is torn down rather than wedging the caller.
|
|
515
662
|
*/
|
|
516
663
|
async request<T>(req: AgentRequest, signal?: AbortSignal): Promise<T> {
|
|
664
|
+
const envelope = this.withCredential(req)
|
|
665
|
+
const payload = JSON.stringify(envelope)
|
|
666
|
+
this.assertPreauthBudget(payload)
|
|
517
667
|
const socket = await this.dial(signal)
|
|
518
668
|
return await new Promise<T>((resolve, reject) => {
|
|
519
669
|
const reader = new FrameReader()
|
|
@@ -581,7 +731,7 @@ export class VsockAgentTransport {
|
|
|
581
731
|
}
|
|
582
732
|
signal?.addEventListener('abort', abort, { once: true })
|
|
583
733
|
idle.bump()
|
|
584
|
-
socket.write(frame(
|
|
734
|
+
socket.write(frame(payload))
|
|
585
735
|
})
|
|
586
736
|
}
|
|
587
737
|
|
|
@@ -595,6 +745,9 @@ export class VsockAgentTransport {
|
|
|
595
745
|
opts?: SandboxExecOptions,
|
|
596
746
|
signal?: AbortSignal,
|
|
597
747
|
): Promise<SandboxExecResult> {
|
|
748
|
+
const envelope = this.withCredential({ op: 'execute', body } satisfies AgentRequest)
|
|
749
|
+
const payload = JSON.stringify(envelope)
|
|
750
|
+
this.assertPreauthBudget(payload)
|
|
598
751
|
const socket = await this.dial(signal)
|
|
599
752
|
const start = Date.now()
|
|
600
753
|
return await new Promise<SandboxExecResult>((resolve, reject) => {
|
|
@@ -687,7 +840,7 @@ export class VsockAgentTransport {
|
|
|
687
840
|
return
|
|
688
841
|
}
|
|
689
842
|
signal?.addEventListener('abort', abort, { once: true })
|
|
690
|
-
socket.write(frame(
|
|
843
|
+
socket.write(frame(payload))
|
|
691
844
|
})
|
|
692
845
|
}
|
|
693
846
|
|
|
@@ -732,6 +885,27 @@ export class VsockAgentTransport {
|
|
|
732
885
|
return await this.executionController.exec(command, argv, opts)
|
|
733
886
|
}
|
|
734
887
|
|
|
888
|
+
/**
|
|
889
|
+
* The raw `/execute` primitive with NO admission/reservation
|
|
890
|
+
* semantics: dial, send one framed request, accumulate the streamed
|
|
891
|
+
* NDJSON reply. Public (unlike the identical-in-spirit
|
|
892
|
+
* {@link reserveExecution}/{@link cancelExecution}, reached through
|
|
893
|
+
* the already-public {@link request}) so a caller running its OWN
|
|
894
|
+
* {@link RemoteExecutionController} — the kubernetes backend's
|
|
895
|
+
* adapter — can reuse this exact dial + framing rather than
|
|
896
|
+
* reimplementing it, while still supplying that controller its own
|
|
897
|
+
* `reserve`/`cancel`/`execute` triple as {@link RemoteExecutionAdapter}
|
|
898
|
+
* requires. Callers that just want a reserve-before-admission `exec`
|
|
899
|
+
* should use {@link execute} or {@link exec} instead.
|
|
900
|
+
*/
|
|
901
|
+
async executeStreamed(
|
|
902
|
+
body: ExecRequest,
|
|
903
|
+
opts?: SandboxExecOptions,
|
|
904
|
+
signal?: AbortSignal,
|
|
905
|
+
): Promise<SandboxExecResult> {
|
|
906
|
+
return await this.executeRaw(body, opts, signal)
|
|
907
|
+
}
|
|
908
|
+
|
|
735
909
|
private async reserveExecution(signal: AbortSignal): Promise<unknown> {
|
|
736
910
|
const response = await this.request<Record<string, unknown>>(
|
|
737
911
|
{ op: 'reserve-execution' },
|
|
@@ -848,7 +1022,6 @@ export class VsockAgentTransport {
|
|
|
848
1022
|
* the session and its authenticated WebSocket attachment.
|
|
849
1023
|
*/
|
|
850
1024
|
async openTerminal(options: OpenTerminalOptions): Promise<TerminalSession> {
|
|
851
|
-
const socket = await this.dial()
|
|
852
1025
|
const request: TerminalOpenRequest = {
|
|
853
1026
|
...(options.command !== undefined ? { command: options.command } : {}),
|
|
854
1027
|
...(options.args !== undefined ? { args: options.args } : {}),
|
|
@@ -857,6 +1030,11 @@ export class VsockAgentTransport {
|
|
|
857
1030
|
cols: options.size.cols,
|
|
858
1031
|
rows: options.size.rows,
|
|
859
1032
|
}
|
|
1033
|
+
const openPayload = JSON.stringify(
|
|
1034
|
+
this.withCredential({ op: 'terminal', body: request } satisfies AgentRequest),
|
|
1035
|
+
)
|
|
1036
|
+
this.assertPreauthBudget(openPayload)
|
|
1037
|
+
const socket = await this.dial()
|
|
860
1038
|
|
|
861
1039
|
return await new Promise<TerminalSession>((resolve, reject) => {
|
|
862
1040
|
const KILL_GRACE_MS = 5_000
|
|
@@ -986,14 +1164,7 @@ export class VsockAgentTransport {
|
|
|
986
1164
|
finish(new Error('vsock transport: terminal socket closed before exit')),
|
|
987
1165
|
)
|
|
988
1166
|
idle.bump()
|
|
989
|
-
socket.write(
|
|
990
|
-
frame(
|
|
991
|
-
JSON.stringify({
|
|
992
|
-
op: 'terminal',
|
|
993
|
-
body: request,
|
|
994
|
-
} satisfies AgentRequest),
|
|
995
|
-
),
|
|
996
|
-
)
|
|
1167
|
+
socket.write(frame(openPayload))
|
|
997
1168
|
})
|
|
998
1169
|
}
|
|
999
1170
|
|
|
@@ -1006,8 +1177,12 @@ export class VsockAgentTransport {
|
|
|
1006
1177
|
if (host !== '127.0.0.1' && host !== '::1') {
|
|
1007
1178
|
throw new Error('firecracker TCP connections are restricted to guest loopback')
|
|
1008
1179
|
}
|
|
1009
|
-
const socket = await this.dial()
|
|
1010
1180
|
const request: TcpConnectRequest = { host, port: options.port }
|
|
1181
|
+
const openPayload = JSON.stringify(
|
|
1182
|
+
this.withCredential({ op: 'tcp-connect', body: request } satisfies AgentRequest),
|
|
1183
|
+
)
|
|
1184
|
+
this.assertPreauthBudget(openPayload)
|
|
1185
|
+
const socket = await this.dial()
|
|
1011
1186
|
|
|
1012
1187
|
return await new Promise<SandboxTcpConnection>((resolve, reject) => {
|
|
1013
1188
|
const reader = new FrameReader()
|
|
@@ -1127,14 +1302,7 @@ export class VsockAgentTransport {
|
|
|
1127
1302
|
finish(ready ? null : new Error('vsock TCP socket closed before readiness')),
|
|
1128
1303
|
)
|
|
1129
1304
|
idle.bump()
|
|
1130
|
-
socket.write(
|
|
1131
|
-
frame(
|
|
1132
|
-
JSON.stringify({
|
|
1133
|
-
op: 'tcp-connect',
|
|
1134
|
-
body: request,
|
|
1135
|
-
} satisfies AgentRequest),
|
|
1136
|
-
),
|
|
1137
|
-
)
|
|
1305
|
+
socket.write(frame(openPayload))
|
|
1138
1306
|
})
|
|
1139
1307
|
}
|
|
1140
1308
|
}
|
|
@@ -1214,6 +1382,9 @@ function describeHandle(handle: SandboxAgentHandle): string {
|
|
|
1214
1382
|
return `vsock:${handle.udsPath}#${handle.port}`
|
|
1215
1383
|
case 'mtls':
|
|
1216
1384
|
return `mtls:${handle.host}:${handle.port}/${handle.sandboxId}`
|
|
1385
|
+
case 'tcp':
|
|
1386
|
+
// Never the token: this string lands in thrown error messages.
|
|
1387
|
+
return `tcp:${handle.host}:${handle.port}`
|
|
1217
1388
|
}
|
|
1218
1389
|
}
|
|
1219
1390
|
|