@claxedo/sandbox-manager 0.9.0 → 0.10.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/README.md +233 -26
- package/dist/checkpoint-manager.d.ts +29 -4
- package/dist/checkpoint-manager.mjs +133 -24
- package/dist/command.d.ts +9 -2
- package/dist/command.mjs +8 -8
- package/dist/contract.d.ts +687 -0
- package/dist/driver-billing.d.ts +29 -0
- package/dist/driver-catalog.d.ts +42 -7
- package/dist/driver-catalog.mjs +115 -161
- package/dist/drivers/boat-client.d.ts +95 -0
- package/dist/drivers/boat-named-snapshots.d.ts +31 -0
- package/dist/drivers/boat-template.d.ts +49 -0
- package/dist/drivers/boat-template.mjs +1196 -0
- package/dist/drivers/boat.d.ts +64 -0
- package/dist/drivers/boat.mjs +990 -0
- package/dist/drivers/cloudflare.d.ts +3 -3
- package/dist/drivers/cloudflare.mjs +208 -147
- package/dist/drivers/docker.d.ts +4 -3
- package/dist/drivers/docker.mjs +154 -126
- package/dist/drivers/local-brokering.d.ts +14 -0
- package/dist/drivers/local-brokering.mjs +1029 -0
- package/dist/drivers/modal.d.ts +2 -2
- package/dist/drivers/modal.mjs +121 -111
- package/dist/drivers/transient-error.d.ts +2 -0
- package/dist/drivers/vercel.d.ts +3 -2
- package/dist/drivers/vercel.mjs +151 -115
- package/dist/egress-policy.d.ts +134 -0
- package/dist/egress-warnings.d.ts +22 -0
- package/dist/garbage-collect.d.ts +14 -0
- package/dist/hosted-network-policy.d.ts +9 -2
- package/dist/hosted-network-policy.mjs +218 -1
- package/dist/image-name.d.ts +12 -2
- package/dist/image-name.mjs +14 -5
- package/dist/image.d.ts +1 -20
- package/dist/image.mjs +11 -88
- package/dist/index.d.ts +8 -578
- package/dist/index.mjs +1379 -320
- package/dist/lease-failure.d.ts +173 -0
- package/dist/lease-lifecycle.d.ts +65 -0
- package/dist/lease-retry-wait.d.ts +8 -0
- package/dist/lease-start.d.ts +21 -0
- package/dist/lease-types.d.ts +4 -3
- package/dist/manager.d.ts +2 -0
- package/dist/runtime-env.d.ts +4 -2
- package/dist/runtime-env.mjs +37 -2
- package/dist/runtime-snapshot.d.ts +49 -0
- package/dist/runtime-version.d.ts +9 -0
- package/dist/runtime-version.mjs +2 -0
- package/dist/service-url-exposure.d.ts +0 -1
- package/dist/service-url-exposure.mjs +0 -9
- package/dist/start-fresh.d.ts +17 -0
- package/dist/start-telemetry.d.ts +37 -0
- package/dist/stores/memory.d.ts +1 -1
- package/dist/stores/memory.mjs +63 -52
- package/package.json +26 -42
- package/dist/daytona-allow-list.d.ts +0 -16
- package/dist/daytona-allow-list.mjs +0 -11
- package/dist/drivers/box.d.ts +0 -52
- package/dist/drivers/box.mjs +0 -574
- package/dist/drivers/daytona.d.ts +0 -163
- package/dist/drivers/daytona.mjs +0 -683
- package/dist/drivers/exe.d.ts +0 -26
- package/dist/drivers/exe.mjs +0 -492
- package/dist/drivers/fetch-bridge.d.ts +0 -10
- package/dist/drivers/fetch-bridge.mjs +0 -126
- package/dist/lease-policy.d.ts +0 -52
- package/dist/lease-policy.mjs +0 -290
package/dist/index.d.ts
CHANGED
|
@@ -1,580 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
export
|
|
1
|
+
export * from "./contract";
|
|
2
|
+
export * from "./egress-policy";
|
|
3
|
+
export * from "./driver-billing";
|
|
4
|
+
export * from "./lease-failure";
|
|
5
|
+
export * from "./lease-retry-wait";
|
|
6
6
|
export * from "./checkpoint-manager";
|
|
7
7
|
export * from "./hosted-network-policy";
|
|
8
|
-
export
|
|
9
|
-
export
|
|
10
|
-
export type
|
|
11
|
-
export type SandboxCaptureSourceBehavior = "not-applicable" | "preserved" | "stopped" | "deleted";
|
|
12
|
-
export type SandboxRestoreMountBehavior = "not-applicable" | "same-resource" | "copy-on-write" | "new-resource";
|
|
13
|
-
export type SandboxPersistenceCapabilities = {
|
|
14
|
-
resume: "same-sandbox" | "replacement-restore";
|
|
15
|
-
capture: SandboxCaptureScope;
|
|
16
|
-
clone: boolean;
|
|
17
|
-
captureSource: SandboxCaptureSourceBehavior;
|
|
18
|
-
retention: "not-applicable" | "provider-managed" | "explicit";
|
|
19
|
-
restoreMount: SandboxRestoreMountBehavior;
|
|
20
|
-
};
|
|
21
|
-
export declare function validateSandboxPersistenceCapabilities(input: SandboxPersistenceCapabilities): {
|
|
22
|
-
valid: false;
|
|
23
|
-
reason: string;
|
|
24
|
-
} | {
|
|
25
|
-
reason?: undefined;
|
|
26
|
-
valid: true;
|
|
27
|
-
};
|
|
28
|
-
export type SandboxCheckpointReference = {
|
|
29
|
-
id: string;
|
|
30
|
-
providerReference: string;
|
|
31
|
-
sourceEpoch: number;
|
|
32
|
-
capturedAt: number;
|
|
33
|
-
metadata: {
|
|
34
|
-
scope: Exclude<SandboxCaptureScope, "none">;
|
|
35
|
-
sourceBehavior: Exclude<SandboxCaptureSourceBehavior, "not-applicable">;
|
|
36
|
-
retentionExpiresAt?: number;
|
|
37
|
-
restoreMount: Exclude<SandboxRestoreMountBehavior, "not-applicable">;
|
|
38
|
-
};
|
|
39
|
-
};
|
|
40
|
-
type SandboxRestoreIdentity = {
|
|
41
|
-
checkpointId: string;
|
|
42
|
-
sourceEpoch: number;
|
|
43
|
-
};
|
|
44
|
-
export type SandboxRestoreStatus = (SandboxRestoreIdentity & {
|
|
45
|
-
state: "pending";
|
|
46
|
-
requestedAt: number;
|
|
47
|
-
}) | (SandboxRestoreIdentity & {
|
|
48
|
-
state: "restoring";
|
|
49
|
-
requestedAt: number;
|
|
50
|
-
startedAt: number;
|
|
51
|
-
}) | (SandboxRestoreIdentity & {
|
|
52
|
-
state: "ready";
|
|
53
|
-
requestedAt: number;
|
|
54
|
-
startedAt: number;
|
|
55
|
-
completedAt: number;
|
|
56
|
-
}) | (SandboxRestoreIdentity & {
|
|
57
|
-
state: "failed";
|
|
58
|
-
requestedAt: number;
|
|
59
|
-
startedAt?: number;
|
|
60
|
-
failedAt: number;
|
|
61
|
-
error: string;
|
|
62
|
-
});
|
|
63
|
-
export type SandboxDriverMetadata = {
|
|
64
|
-
/** Where the sandbox driver code can execute. This is not sandbox infrastructure. */
|
|
65
|
-
driverRunsIn: Array<"worker" | "node" | "local">;
|
|
66
|
-
/** What `SandboxManager.stop()` actually does to the driver-owned resource. */
|
|
67
|
-
hostStopBehavior: "not-supported" | "suspends-host" | "terminates-host";
|
|
68
|
-
/** Whether a stopped/stale lease can resume the same driver-owned resource. */
|
|
69
|
-
hostResumeBehavior: "same-host" | "replacement-host";
|
|
70
|
-
/** How the control plane reaches the sandbox target returned by the driver. */
|
|
71
|
-
targetAccess: "relay" | "loopback";
|
|
72
|
-
/**
|
|
73
|
-
* How the driver can honor a `SandboxBrokeredSecret` — a credential the
|
|
74
|
-
* sandbox may USE for outbound requests but must NEVER be able to READ.
|
|
75
|
-
*
|
|
76
|
-
* - `"native"` — the provider brokers it on egress to the allowlisted hosts
|
|
77
|
-
* with no extra infrastructure of ours: Daytona secret placeholders,
|
|
78
|
-
* Vercel firewall header transforms, Cloudflare outbound handlers reading
|
|
79
|
-
* the value from KV. The driver installs it during `ensureHost`.
|
|
80
|
-
* - `"none"` — no way to keep the value out of sandbox processes. The
|
|
81
|
-
* provider may still have an encrypted secret STORE (e.g. Modal secrets),
|
|
82
|
-
* but it is exposed as a readable env var, which cannot satisfy the
|
|
83
|
-
* never-readable contract.
|
|
84
|
-
*/
|
|
85
|
-
secretBrokering: SandboxSecretBrokering;
|
|
86
|
-
/**
|
|
87
|
-
* How the driver can enforce a RESTRICTED `SandboxNetworkPolicy` — i.e.
|
|
88
|
-
* whether the sandbox's outbound network can actually be contained.
|
|
89
|
-
*
|
|
90
|
-
* A `SandboxNetworkPolicy` states the same allowance in up to two encodings:
|
|
91
|
-
* `hosts` (names) and `cidrs` (addresses). A driver contains egress if it
|
|
92
|
-
* enforces AT LEAST ONE encoding the policy carries and blocks everything
|
|
93
|
-
* else; the encodings are alternatives, not additive requirements.
|
|
94
|
-
*
|
|
95
|
-
* - `"hosts-and-cidrs"` — the provider filters by name AND by address
|
|
96
|
-
* (Daytona: `domainAllowList` + `networkAllowList`).
|
|
97
|
-
* - `"hosts"` — the provider filters by hostname only (Vercel firewall).
|
|
98
|
-
* - `"none"` — the driver cannot express an egress allowlist. This covers
|
|
99
|
-
* BOTH drivers that throw when handed a restricted policy (exe, docker,
|
|
100
|
-
* box, and modal for host policy) AND — more dangerously — drivers that
|
|
101
|
-
* silently ignore `net` and run wide open (cloudflare, the fetch bridge).
|
|
102
|
-
* Modal is `"none"` even though it can cut the network entirely: a total
|
|
103
|
-
* blackout is not an allowlist and cannot serve a workspace that has to
|
|
104
|
-
* clone a repo and reach a model provider.
|
|
105
|
-
*
|
|
106
|
-
* The manager reads this to decide what the driver is handed:
|
|
107
|
-
* `sandboxEgressDisposition` enforces where it can and WITHHOLDS (loudly)
|
|
108
|
-
* where it cannot. See `SandboxEgressDisposition` for the posture and
|
|
109
|
-
* `public-docs/sandbox-egress.md` for the operator-facing consequence.
|
|
110
|
-
*/
|
|
111
|
-
egressControl: SandboxEgressControl;
|
|
112
|
-
persistence: SandboxPersistenceCapabilities;
|
|
113
|
-
};
|
|
114
|
-
/** @see SandboxDriverMetadata.egressControl */
|
|
115
|
-
export type SandboxEgressControl = "none" | "hosts" | "hosts-and-cidrs";
|
|
116
|
-
/**
|
|
117
|
-
* What the manager does with a caller's `net` for a given driver.
|
|
118
|
-
*
|
|
119
|
-
* Owner directive (2026-07-28): *"for egress in sandbox enforce where we can
|
|
120
|
-
* and document where we cant."* That replaces the previous fail-closed refusal
|
|
121
|
-
* for drivers with no egress control at all — provisioning now proceeds, and
|
|
122
|
-
* the gap is made loud instead of fatal.
|
|
123
|
-
*
|
|
124
|
-
* - `"enforce"` — the driver gets the policy verbatim and contains the
|
|
125
|
-
* sandbox. Also the answer when the caller asked for no containment
|
|
126
|
-
* (absent / `allow-all`), which is nothing to enforce.
|
|
127
|
-
* - `"withhold"` — the driver declares `egressControl: "none"`, so there is no
|
|
128
|
-
* containment to be had. The policy is NOT handed down: half the `"none"`
|
|
129
|
-
* drivers throw on a restricted policy (exe, docker, modal, box) and the
|
|
130
|
-
* other half silently drop it (cloudflare, the fetch bridge). Withholding at
|
|
131
|
-
* the manager means the throwing drivers never see one — their throws stay
|
|
132
|
-
* in place as their own last line of defence — and the silently-dropping
|
|
133
|
-
* ones stop pretending. The sandbox comes up with UNRESTRICTED egress, which
|
|
134
|
-
* is a real exposure, so the manager warns (see `onEgressUnenforced`).
|
|
135
|
-
* - `"refuse"` — the driver HAS egress control but cannot express this
|
|
136
|
-
* particular policy's encoding (a hosts-only driver handed an address-only
|
|
137
|
-
* allowlist). Deliberately still fail-closed: this is a composition mistake
|
|
138
|
-
* on an otherwise-enforcing driver, and degrading it to "withhold" would
|
|
139
|
-
* weaken the enforcing path. `hostedSandboxNetworkPolicy` only ever emits
|
|
140
|
-
* hosts, so no production path reaches it.
|
|
141
|
-
*
|
|
142
|
-
* Pure, like `validateSandboxPersistenceCapabilities`, so the manager, the
|
|
143
|
-
* composition layer, and tests can all ask the same question.
|
|
144
|
-
*/
|
|
145
|
-
export type SandboxEgressDisposition = {
|
|
146
|
-
action: "enforce";
|
|
147
|
-
} | {
|
|
148
|
-
action: "withhold";
|
|
149
|
-
reason: "sandbox_egress_uncontained";
|
|
150
|
-
} | {
|
|
151
|
-
action: "refuse";
|
|
152
|
-
reason: "sandbox_egress_policy_unenforceable";
|
|
153
|
-
};
|
|
154
|
-
/** @see SandboxEgressDisposition */
|
|
155
|
-
export declare function sandboxEgressDisposition(control: SandboxEgressControl, net: SandboxNetworkPolicy | undefined): SandboxEgressDisposition;
|
|
156
|
-
/**
|
|
157
|
-
* Emitted whenever a restricted egress policy is withheld because the composed
|
|
158
|
-
* driver declares no egress control. This is the "document where we can't" half
|
|
159
|
-
* of the directive expressed at runtime: an unrestricted sandbox that nobody
|
|
160
|
-
* was told about is the original finding, so the degrade is never silent.
|
|
161
|
-
*
|
|
162
|
-
* Two phases, because a per-create line is easy to miss in request logs:
|
|
163
|
-
* - `"composition"` — once per `createSandboxManager` per driver, at boot.
|
|
164
|
-
* - `"ensure"` — every time a caller's policy is actually withheld, naming the
|
|
165
|
-
* workspace and the allowlist that did not take effect.
|
|
166
|
-
*/
|
|
167
|
-
export type SandboxEgressUnenforcedEvent = {
|
|
168
|
-
phase: "composition" | "ensure";
|
|
169
|
-
reason: "sandbox_egress_uncontained";
|
|
170
|
-
/** `SandboxDriver.id` of the composed driver. */
|
|
171
|
-
driver: string;
|
|
172
|
-
/** Always `"none"` today — carried so a sink can group without re-deriving. */
|
|
173
|
-
egressControl: SandboxEgressControl;
|
|
174
|
-
/** Ready-to-log sentence. Sinks that only forward text can use this alone. */
|
|
175
|
-
message: string;
|
|
176
|
-
/** Present on `"ensure"`. */
|
|
177
|
-
workspaceId?: string;
|
|
178
|
-
/** The allowlist the caller asked for and did NOT get. Present on `"ensure"`. */
|
|
179
|
-
requested?: SandboxNetworkPolicy;
|
|
180
|
-
};
|
|
181
|
-
/**
|
|
182
|
-
* A credential the SANDBOX must be able to USE for outbound requests but must
|
|
183
|
-
* NEVER be able to READ. Unlike `env` (plaintext, readable — reserved for
|
|
184
|
-
* credentials the agent is trusted with, e.g. the user's own model
|
|
185
|
-
* subscription), a brokered secret's `value` never enters the sandbox: the
|
|
186
|
-
* provider injects it on egress to `hosts` only. Non-model credentials
|
|
187
|
-
* (connection tokens, deploy tokens) belong here.
|
|
188
|
-
*
|
|
189
|
-
* Guarantees enforced by the manager: brokered secrets are never written to
|
|
190
|
-
* labels, never logged, and never captured in a driver snapshot. A driver
|
|
191
|
-
* whose `metadata.secretBrokering` is not `"native"` cannot honor them and the
|
|
192
|
-
* manager refuses to provision (fail-closed).
|
|
193
|
-
*/
|
|
194
|
-
export type SandboxBrokeredSecret = {
|
|
195
|
-
/** Env var name the sandbox references (Daytona placeholder key). */
|
|
196
|
-
name: string;
|
|
197
|
-
/** The secret material. Never enters the sandbox in plaintext. */
|
|
198
|
-
value: string;
|
|
199
|
-
/** Egress allowlist: the only hosts for which the value is substituted/injected. */
|
|
200
|
-
hosts: string[];
|
|
201
|
-
/**
|
|
202
|
-
* When set, the value is injected as this HTTP header on egress to `hosts`
|
|
203
|
-
* (required for the Vercel firewall-transform model). When omitted, the
|
|
204
|
-
* driver exposes the credential via its native placeholder mechanism for
|
|
205
|
-
* the sandbox to attach itself (Daytona).
|
|
206
|
-
*/
|
|
207
|
-
header?: string;
|
|
208
|
-
/**
|
|
209
|
-
* The authentication scheme `header` carries, when it has one (`Bearer`).
|
|
210
|
-
*
|
|
211
|
-
* A driver that WRITES the whole header composes `"<scheme> <value>"`; one
|
|
212
|
-
* that SUBSTITUTES a placeholder the sandbox already wrote after the scheme
|
|
213
|
-
* ignores it, because the scheme is in the request before the value is.
|
|
214
|
-
*/
|
|
215
|
-
scheme?: string;
|
|
216
|
-
/**
|
|
217
|
-
* The methods and path prefixes the credential may be attached to, on top of
|
|
218
|
-
* `hosts`. A vendor host serves far more than the routes a turn needs —
|
|
219
|
-
* api.anthropic.com also answers the organization-admin API — and everything
|
|
220
|
-
* sharing the sandbox reaches the same host.
|
|
221
|
-
*
|
|
222
|
-
* Optional so a producer that has not been taught to state a policy still
|
|
223
|
-
* type-checks, and fails closed instead: a driver that can express them
|
|
224
|
-
* attaches the credential only within them, so an absent or empty policy
|
|
225
|
-
* names a host and nothing else, and nothing is spendable at a host alone. A
|
|
226
|
-
* driver whose provider cannot express them documents that it drops them,
|
|
227
|
-
* and the host allowlist is all the containment there is.
|
|
228
|
-
*/
|
|
229
|
-
methods?: readonly string[];
|
|
230
|
-
pathPrefixes?: readonly string[];
|
|
231
|
-
};
|
|
232
|
-
/**
|
|
233
|
-
* What the sandbox presents so a header-injecting driver recognizes the request
|
|
234
|
-
* as one asking for that secret.
|
|
235
|
-
*
|
|
236
|
-
* Carries no authority: the value is attached at the edge, keyed by the host
|
|
237
|
-
* and this string, and the string itself is never accepted by a vendor. The
|
|
238
|
-
* Cloudflare sandbox Worker is deployed on its own and cannot depend on this
|
|
239
|
-
* package, so it matches on its own copy of the prefix; a driver minting
|
|
240
|
-
* anything else sends every brokered request upstream bare, which is what
|
|
241
|
-
* `brokered-placeholder.test.ts` exists to catch.
|
|
242
|
-
*/
|
|
243
|
-
export declare function brokeredSecretPlaceholder(name: string): string;
|
|
244
|
-
/**
|
|
245
|
-
* The environment a header-injecting driver must add so the sandbox can present
|
|
246
|
-
* each secret. Daytona is absent from this: its own mount fills the same
|
|
247
|
-
* variables with the placeholder it substitutes, and an env entry would shadow
|
|
248
|
-
* it with a string Daytona does not know.
|
|
249
|
-
*/
|
|
250
|
-
export declare function brokeredPlaceholderEnv(secrets: readonly SandboxBrokeredSecret[] | undefined): Record<string, string>;
|
|
251
|
-
export type SandboxExposure = {
|
|
252
|
-
kind: "loopback";
|
|
253
|
-
} | {
|
|
254
|
-
kind: "relay";
|
|
255
|
-
} | {
|
|
256
|
-
kind: "private-network";
|
|
257
|
-
} | {
|
|
258
|
-
kind: "embedded";
|
|
259
|
-
};
|
|
260
|
-
export type SandboxLeaseStatus = "acquiring" | "ready" | "unavailable" | "stopped" | "destroyed";
|
|
261
|
-
export type SandboxLease = {
|
|
262
|
-
workspaceId: string;
|
|
263
|
-
homeRegion: SandboxRegion;
|
|
264
|
-
driver: string;
|
|
265
|
-
epoch: number;
|
|
266
|
-
status: SandboxLeaseStatus;
|
|
267
|
-
retryCount: number;
|
|
268
|
-
updatedAt: number;
|
|
269
|
-
createdAt: number;
|
|
270
|
-
sandboxId?: string;
|
|
271
|
-
url?: string;
|
|
272
|
-
hostId?: string;
|
|
273
|
-
driverResourceId?: string;
|
|
274
|
-
nextRetryAt?: number;
|
|
275
|
-
lastError?: string;
|
|
276
|
-
lastHeartbeatAt?: number;
|
|
277
|
-
lastActivityAt?: number;
|
|
278
|
-
labels?: Record<string, string>;
|
|
279
|
-
checkpoint?: SandboxCheckpointReference;
|
|
280
|
-
persistence?: SandboxPersistenceCapabilities;
|
|
281
|
-
restore?: SandboxRestoreStatus;
|
|
282
|
-
};
|
|
283
|
-
export type SandboxLeaseAcquireInput = {
|
|
284
|
-
homeRegion: SandboxRegion;
|
|
285
|
-
driver: string;
|
|
286
|
-
staleAfterMs: number;
|
|
287
|
-
now?: number;
|
|
288
|
-
};
|
|
289
|
-
export type SandboxLeaseAcquireResult = {
|
|
290
|
-
acquired: true;
|
|
291
|
-
lease: SandboxLease;
|
|
292
|
-
} | {
|
|
293
|
-
acquired: false;
|
|
294
|
-
lease: SandboxLease;
|
|
295
|
-
retryAfterMs: number;
|
|
296
|
-
};
|
|
297
|
-
export type SandboxLeasePatch = Partial<Pick<SandboxLease, "status" | "sandboxId" | "url" | "hostId" | "driverResourceId" | "retryCount" | "lastHeartbeatAt" | "lastActivityAt" | "labels">> & {
|
|
298
|
-
/** `null` clears the stored value; `undefined` leaves it unchanged. */
|
|
299
|
-
nextRetryAt?: number | null;
|
|
300
|
-
/** `null` clears the stored value; `undefined` leaves it unchanged. */
|
|
301
|
-
lastError?: string | null;
|
|
302
|
-
/** `null` clears the stored value; `undefined` leaves it unchanged. */
|
|
303
|
-
checkpoint?: SandboxCheckpointReference | null;
|
|
304
|
-
/** `null` clears the stored value; `undefined` leaves it unchanged. */
|
|
305
|
-
persistence?: SandboxPersistenceCapabilities | null;
|
|
306
|
-
/** `null` clears the stored value; `undefined` leaves it unchanged. */
|
|
307
|
-
restore?: SandboxRestoreStatus | null;
|
|
308
|
-
};
|
|
309
|
-
/**
|
|
310
|
-
* Canonical SandboxLeasePatch merge semantics shared by every lease store driver:
|
|
311
|
-
* absent/`undefined` keeps the current value, `null` clears it.
|
|
312
|
-
*/
|
|
313
|
-
export declare function applySandboxLeasePatch(current: SandboxLease, patch: SandboxLeasePatch, updatedAt: number): SandboxLease;
|
|
314
|
-
export type SandboxLeaseStore = {
|
|
315
|
-
acquire: (workspaceId: string, input: SandboxLeaseAcquireInput) => Promise<SandboxLeaseAcquireResult>;
|
|
316
|
-
update: (workspaceId: string, expectedEpoch: number, patch: SandboxLeasePatch) => Promise<SandboxLease | undefined>;
|
|
317
|
-
recordFailure: (workspaceId: string, expectedEpoch: number, error: string, nextRetryAt?: number) => Promise<SandboxLease | undefined>;
|
|
318
|
-
release: (workspaceId: string) => Promise<void>;
|
|
319
|
-
get: (workspaceId: string) => Promise<SandboxLease | undefined>;
|
|
320
|
-
list: () => Promise<SandboxLease[]>;
|
|
321
|
-
};
|
|
322
|
-
export type SandboxNetworkPolicy = {
|
|
323
|
-
mode: "allow-all" | "restricted";
|
|
324
|
-
hosts?: string[];
|
|
325
|
-
cidrs?: string[];
|
|
326
|
-
};
|
|
327
|
-
/** Brokered destinations are the minimum egress needed to use the credential. */
|
|
328
|
-
export declare function sandboxNetworkPolicyWithBrokeredHosts(policy: SandboxNetworkPolicy, secrets: readonly SandboxBrokeredSecret[] | undefined): SandboxNetworkPolicy;
|
|
329
|
-
export type SandboxBootSource = {
|
|
330
|
-
kind: "image";
|
|
331
|
-
image: string;
|
|
332
|
-
} | {
|
|
333
|
-
kind: "driver-snapshot";
|
|
334
|
-
snapshotId: string;
|
|
335
|
-
} | {
|
|
336
|
-
kind: "default";
|
|
337
|
-
};
|
|
338
|
-
export type SandboxSource = {
|
|
339
|
-
kind: "git";
|
|
340
|
-
repoUrl: string;
|
|
341
|
-
branch?: string;
|
|
342
|
-
} | {
|
|
343
|
-
kind: "empty";
|
|
344
|
-
};
|
|
345
|
-
export type SandboxDriverEnsureInput = {
|
|
346
|
-
workspaceId: string;
|
|
347
|
-
hostId?: string;
|
|
348
|
-
homeRegion: SandboxRegion;
|
|
349
|
-
epoch: number;
|
|
350
|
-
labels: Record<string, string>;
|
|
351
|
-
bootSource?: SandboxBootSource;
|
|
352
|
-
workspaceRoot?: string;
|
|
353
|
-
runtimeCwd?: string;
|
|
354
|
-
workspaceRuntimePort?: number;
|
|
355
|
-
env?: Record<string, string>;
|
|
356
|
-
/** Brokered secrets: injected on egress, never readable inside the sandbox. */
|
|
357
|
-
secrets?: SandboxBrokeredSecret[];
|
|
358
|
-
source?: SandboxSource;
|
|
359
|
-
exposure?: SandboxExposure;
|
|
360
|
-
/**
|
|
361
|
-
* Egress policy. Omitted means allow-all, which is only appropriate for a
|
|
362
|
-
* single-tenant deployment the operator already trusts.
|
|
363
|
-
*
|
|
364
|
-
* A driver can rely on this being ABSENT whenever it declares
|
|
365
|
-
* `egressControl: "none"`: the manager withholds the policy rather than hand
|
|
366
|
-
* it to a driver that would either throw on it or silently drop it. A driver
|
|
367
|
-
* that receives a restricted policy here is one that declared it can enforce
|
|
368
|
-
* it. @see SandboxEgressDisposition
|
|
369
|
-
*/
|
|
370
|
-
net?: SandboxNetworkPolicy;
|
|
371
|
-
/** Optional snapshot/image to boot from (user-supplied or pre-built). */
|
|
372
|
-
snapshot?: string;
|
|
373
|
-
};
|
|
374
|
-
export type SandboxTarget = {
|
|
375
|
-
workspaceId?: string;
|
|
376
|
-
sandboxId: string;
|
|
377
|
-
url: string;
|
|
378
|
-
hostId: string;
|
|
379
|
-
driverResourceId?: string;
|
|
380
|
-
labels?: Record<string, string>;
|
|
381
|
-
driver?: {
|
|
382
|
-
id: string;
|
|
383
|
-
resourceId: string;
|
|
384
|
-
metadata?: Record<string, string>;
|
|
385
|
-
};
|
|
386
|
-
};
|
|
387
|
-
export type SandboxSnapshotResult = {
|
|
388
|
-
snapshotId: string;
|
|
389
|
-
};
|
|
390
|
-
export type SandboxCommandResult = {
|
|
391
|
-
stdout: string;
|
|
392
|
-
stderr: string;
|
|
393
|
-
exitCode: number;
|
|
394
|
-
};
|
|
395
|
-
export type SandboxDriver = {
|
|
396
|
-
id: string;
|
|
397
|
-
metadata: SandboxDriverMetadata;
|
|
398
|
-
ensureHost: (input: SandboxDriverEnsureInput) => Promise<SandboxTarget | {
|
|
399
|
-
provisioning: true;
|
|
400
|
-
retryAfterMs: number;
|
|
401
|
-
}>;
|
|
402
|
-
resumeHost?: (input: {
|
|
403
|
-
lease: SandboxLease;
|
|
404
|
-
ensure: SandboxDriverEnsureInput;
|
|
405
|
-
}) => Promise<SandboxTarget | {
|
|
406
|
-
provisioning: true;
|
|
407
|
-
retryAfterMs: number;
|
|
408
|
-
}>;
|
|
409
|
-
list?: () => Promise<SandboxTarget[]>;
|
|
410
|
-
touch?: (target: SandboxTarget) => Promise<void>;
|
|
411
|
-
suspend?: (target: SandboxTarget) => Promise<void>;
|
|
412
|
-
stop?: (target: SandboxTarget) => Promise<void>;
|
|
413
|
-
destroy?: (target: SandboxTarget) => Promise<void>;
|
|
414
|
-
snapshot?: (target: SandboxTarget) => Promise<SandboxSnapshotResult>;
|
|
415
|
-
inspect?: (target: SandboxTarget) => Promise<SandboxTarget | undefined>;
|
|
416
|
-
exec?: (target: SandboxTarget, command: string) => Promise<SandboxCommandResult>;
|
|
417
|
-
clone?: (target: SandboxTarget, input: {
|
|
418
|
-
name: string;
|
|
419
|
-
}) => Promise<SandboxTarget>;
|
|
420
|
-
};
|
|
421
|
-
export type SandboxManager = {
|
|
422
|
-
ensure: (workspaceId: string, input: SandboxManagerInput) => Promise<SandboxEnsureResult>;
|
|
423
|
-
register: (workspaceId: string, input: SandboxRegisterInput) => Promise<SandboxMutationResult>;
|
|
424
|
-
heartbeat: (workspaceId: string, input: SandboxHeartbeatInput) => Promise<SandboxMutationResult>;
|
|
425
|
-
target: (workspaceId: string) => Promise<SandboxTargetResult>;
|
|
426
|
-
touch: (workspaceId: string) => Promise<SandboxTouchResult>;
|
|
427
|
-
snapshot: (workspaceId: string) => Promise<SandboxSnapshotManagerResult>;
|
|
428
|
-
checkpoint: (workspaceId: string, input: SandboxCheckpointCaptureInput) => Promise<SandboxCheckpointResult>;
|
|
429
|
-
restore: (workspaceId: string, input: SandboxCheckpointRestoreInput) => Promise<SandboxCheckpointResult>;
|
|
430
|
-
stop: (workspaceId: string) => Promise<SandboxMutationResult>;
|
|
431
|
-
destroy: (workspaceId: string) => Promise<SandboxMutationResult>;
|
|
432
|
-
release: (workspaceId: string) => Promise<{
|
|
433
|
-
released: boolean;
|
|
434
|
-
}>;
|
|
435
|
-
garbageCollect: () => Promise<SandboxGarbageCollectResult>;
|
|
436
|
-
list: () => Promise<SandboxLease[]>;
|
|
437
|
-
};
|
|
438
|
-
export type SandboxManagerInput = {
|
|
439
|
-
homeRegion: SandboxRegion;
|
|
440
|
-
hostId?: string;
|
|
441
|
-
labels?: Record<string, string>;
|
|
442
|
-
bootSource?: SandboxBootSource;
|
|
443
|
-
workspaceRoot?: string;
|
|
444
|
-
runtimeCwd?: string;
|
|
445
|
-
workspaceRuntimePort?: number;
|
|
446
|
-
env?: Record<string, string>;
|
|
447
|
-
/** Brokered secrets: injected on egress, never readable inside the sandbox. */
|
|
448
|
-
secrets?: SandboxBrokeredSecret[];
|
|
449
|
-
source?: SandboxSource;
|
|
450
|
-
exposure?: SandboxExposure;
|
|
451
|
-
/**
|
|
452
|
-
* @see SandboxDriverEnsureInput.net — enforced by a capable driver, withheld
|
|
453
|
-
* (with a warning) by one that declares `egressControl: "none"`.
|
|
454
|
-
*/
|
|
455
|
-
net?: SandboxNetworkPolicy;
|
|
456
|
-
snapshot?: string;
|
|
457
|
-
};
|
|
458
|
-
export type SandboxRegisterInput = {
|
|
459
|
-
epoch?: number;
|
|
460
|
-
ok: boolean;
|
|
461
|
-
status?: string;
|
|
462
|
-
sandboxId?: string | null;
|
|
463
|
-
url?: string | null;
|
|
464
|
-
hostId?: string | null;
|
|
465
|
-
driverResourceId?: string | null;
|
|
466
|
-
active?: boolean;
|
|
467
|
-
now?: number;
|
|
468
|
-
};
|
|
469
|
-
export type SandboxHeartbeatInput = SandboxRegisterInput;
|
|
470
|
-
/**
|
|
471
|
-
* What a provisioning cycle is actually doing, for honest progress UI.
|
|
472
|
-
* `restore` = booting a replacement restored from the workspace's snapshot
|
|
473
|
-
* (files come back), `resume` = restarting the same paused resource,
|
|
474
|
-
* `cold-start` = a fresh sandbox with no prior state to bring back (first
|
|
475
|
-
* boot, or nothing snapshot-able survived).
|
|
476
|
-
*/
|
|
477
|
-
export type SandboxBootMode = "restore" | "resume" | "cold-start";
|
|
478
|
-
export type SandboxEnsureResult = ({
|
|
479
|
-
status: "ready";
|
|
480
|
-
} & SandboxTarget & {
|
|
481
|
-
epoch: number;
|
|
482
|
-
homeRegion: SandboxRegion;
|
|
483
|
-
}) | {
|
|
484
|
-
status: "provisioning";
|
|
485
|
-
retryAfterMs: number;
|
|
486
|
-
epoch: number;
|
|
487
|
-
homeRegion: SandboxRegion;
|
|
488
|
-
bootMode?: SandboxBootMode;
|
|
489
|
-
} | {
|
|
490
|
-
status: "unavailable";
|
|
491
|
-
retryAfterMs?: number;
|
|
492
|
-
error?: string;
|
|
493
|
-
epoch?: number;
|
|
494
|
-
homeRegion: SandboxRegion;
|
|
495
|
-
};
|
|
496
|
-
export type SandboxTargetResult = ({
|
|
497
|
-
status: "ready";
|
|
498
|
-
} & SandboxTarget & {
|
|
499
|
-
epoch: number;
|
|
500
|
-
homeRegion: SandboxRegion;
|
|
501
|
-
}) | {
|
|
502
|
-
status: "unavailable";
|
|
503
|
-
reason: string;
|
|
504
|
-
};
|
|
505
|
-
export type SandboxTouchResult = {
|
|
506
|
-
touched: boolean;
|
|
507
|
-
status: SandboxLeaseStatus | "missing";
|
|
508
|
-
};
|
|
509
|
-
export type SandboxMutationResult = {
|
|
510
|
-
ok: true;
|
|
511
|
-
status: SandboxLeaseStatus;
|
|
512
|
-
} | {
|
|
513
|
-
ok: false;
|
|
514
|
-
reason: string;
|
|
515
|
-
};
|
|
516
|
-
export type SandboxSnapshotManagerResult = ({
|
|
517
|
-
ok: true;
|
|
518
|
-
} & SandboxSnapshotResult) | {
|
|
519
|
-
ok: false;
|
|
520
|
-
reason: string;
|
|
521
|
-
};
|
|
522
|
-
export type SandboxGarbageCollectResult = {
|
|
523
|
-
destroyed: SandboxTarget[];
|
|
524
|
-
kept: SandboxTarget[];
|
|
525
|
-
skipped: Array<{
|
|
526
|
-
target: SandboxTarget;
|
|
527
|
-
reason: string;
|
|
528
|
-
}>;
|
|
529
|
-
failed: Array<{
|
|
530
|
-
target: SandboxTarget;
|
|
531
|
-
error: string;
|
|
532
|
-
}>;
|
|
533
|
-
/**
|
|
534
|
-
* Set when the driver cannot enumerate provider state, so the four arrays
|
|
535
|
-
* above mean "we could not look" rather than "nothing is orphaned". Absent on
|
|
536
|
-
* a real sweep. Callers must treat it as a FAILED sweep: four empty arrays
|
|
537
|
-
* reported as success is the exact defect finding B1 names.
|
|
538
|
-
*/
|
|
539
|
-
listingUnsupported?: true;
|
|
540
|
-
/** Driver id, so an ops report can name which driver could not look. */
|
|
541
|
-
driver?: string;
|
|
542
|
-
};
|
|
543
|
-
/**
|
|
544
|
-
* A driver's `list()` may throw this shape to say "my backing service cannot
|
|
545
|
-
* enumerate", as distinct from "listing failed this time". `garbageCollect()`
|
|
546
|
-
* converts it into `listingUnsupported` (a loud, non-fatal capability gap);
|
|
547
|
-
* every other error propagates as a real sweep failure.
|
|
548
|
-
*
|
|
549
|
-
* Structural rather than an `instanceof` check on purpose: drivers are published
|
|
550
|
-
* as separate entry points and bundlers duplicate class identities, so a
|
|
551
|
-
* nominal check would silently fall through to "transient failure" in exactly
|
|
552
|
-
* the deployment that needs the distinction.
|
|
553
|
-
*/
|
|
554
|
-
export type SandboxListingUnsupported = {
|
|
555
|
-
listingUnsupported: true;
|
|
556
|
-
};
|
|
557
|
-
export declare function isSandboxListingUnsupported(err: unknown): err is SandboxListingUnsupported;
|
|
558
|
-
export type SandboxManagerOptions = {
|
|
559
|
-
leaseStore: SandboxLeaseStore;
|
|
560
|
-
driver: SandboxDriver;
|
|
561
|
-
staleAfterMs?: number;
|
|
562
|
-
retryAfterMs?: number;
|
|
563
|
-
retryDelayMs?: (retryCount: number) => number;
|
|
564
|
-
maxRetryCount?: number;
|
|
565
|
-
retryCapCooldownMs?: number;
|
|
566
|
-
now?: () => number;
|
|
567
|
-
appLabel?: string;
|
|
568
|
-
/**
|
|
569
|
-
* Sink for the loud half of "enforce where we can, document where we can't".
|
|
570
|
-
* Called at composition time and again every time a restricted policy is
|
|
571
|
-
* withheld from a driver that cannot enforce it.
|
|
572
|
-
*
|
|
573
|
-
* Defaults to `console.warn(event.message)`. Pass your own to route the gap
|
|
574
|
-
* into a telemetry pipeline instead — but note the default is deliberately
|
|
575
|
-
* unconditional: an operator who never wires a sink still gets the warning.
|
|
576
|
-
* Pass `() => {}` only if you have another way to surface it.
|
|
577
|
-
*/
|
|
578
|
-
onEgressUnenforced?: (event: SandboxEgressUnenforcedEvent) => void;
|
|
579
|
-
};
|
|
580
|
-
export declare function createSandboxManager(options: SandboxManagerOptions): SandboxManager;
|
|
8
|
+
export * from "./runtime-snapshot";
|
|
9
|
+
export { createSandboxManager } from "./manager";
|
|
10
|
+
export type { SandboxLifecycleEvent, SandboxStopCause } from "./lease-lifecycle";
|