@namzu/sandbox 26.0.0 → 27.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.
Files changed (83) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/README.md +20 -7
  3. package/dist/backends/firecracker/protocol.d.ts +46 -0
  4. package/dist/backends/firecracker/protocol.d.ts.map +1 -1
  5. package/dist/backends/firecracker/protocol.js +31 -0
  6. package/dist/backends/firecracker/protocol.js.map +1 -1
  7. package/dist/backends/firecracker/transport.d.ts +15 -1
  8. package/dist/backends/firecracker/transport.d.ts.map +1 -1
  9. package/dist/backends/firecracker/transport.js +16 -0
  10. package/dist/backends/firecracker/transport.js.map +1 -1
  11. package/dist/backends/kubernetes/allocation.d.ts +115 -0
  12. package/dist/backends/kubernetes/allocation.d.ts.map +1 -0
  13. package/dist/backends/kubernetes/allocation.js +130 -0
  14. package/dist/backends/kubernetes/allocation.js.map +1 -0
  15. package/dist/backends/kubernetes/egress-policy.d.ts +111 -35
  16. package/dist/backends/kubernetes/egress-policy.d.ts.map +1 -1
  17. package/dist/backends/kubernetes/egress-policy.js +81 -41
  18. package/dist/backends/kubernetes/egress-policy.js.map +1 -1
  19. package/dist/backends/kubernetes/identity.d.ts +129 -0
  20. package/dist/backends/kubernetes/identity.d.ts.map +1 -1
  21. package/dist/backends/kubernetes/identity.js +150 -0
  22. package/dist/backends/kubernetes/identity.js.map +1 -1
  23. package/dist/backends/kubernetes/index.d.ts +23 -1
  24. package/dist/backends/kubernetes/index.d.ts.map +1 -1
  25. package/dist/backends/kubernetes/index.js +22 -3
  26. package/dist/backends/kubernetes/index.js.map +1 -1
  27. package/dist/backends/kubernetes/objects.d.ts +76 -0
  28. package/dist/backends/kubernetes/objects.d.ts.map +1 -1
  29. package/dist/backends/kubernetes/objects.js +61 -0
  30. package/dist/backends/kubernetes/objects.js.map +1 -1
  31. package/dist/backends/kubernetes/per-sandbox-fence.d.ts +194 -0
  32. package/dist/backends/kubernetes/per-sandbox-fence.d.ts.map +1 -0
  33. package/dist/backends/kubernetes/per-sandbox-fence.js +522 -0
  34. package/dist/backends/kubernetes/per-sandbox-fence.js.map +1 -0
  35. package/dist/backends/kubernetes/per-sandbox-policy.d.ts +45 -3
  36. package/dist/backends/kubernetes/per-sandbox-policy.d.ts.map +1 -1
  37. package/dist/backends/kubernetes/per-sandbox-policy.js +98 -8
  38. package/dist/backends/kubernetes/per-sandbox-policy.js.map +1 -1
  39. package/dist/backends/kubernetes/sandbox.d.ts +4 -9
  40. package/dist/backends/kubernetes/sandbox.d.ts.map +1 -1
  41. package/dist/backends/kubernetes/sandbox.js +4 -9
  42. package/dist/backends/kubernetes/sandbox.js.map +1 -1
  43. package/dist/backends/kubernetes/transport.d.ts +108 -1
  44. package/dist/backends/kubernetes/transport.d.ts.map +1 -1
  45. package/dist/backends/kubernetes/transport.js +150 -6
  46. package/dist/backends/kubernetes/transport.js.map +1 -1
  47. package/dist/backends/kubernetes/workspace-allocate.d.ts +206 -0
  48. package/dist/backends/kubernetes/workspace-allocate.d.ts.map +1 -0
  49. package/dist/backends/kubernetes/workspace-allocate.js +332 -0
  50. package/dist/backends/kubernetes/workspace-allocate.js.map +1 -0
  51. package/dist/backends/kubernetes/workspace-observe.d.ts +187 -0
  52. package/dist/backends/kubernetes/workspace-observe.d.ts.map +1 -0
  53. package/dist/backends/kubernetes/workspace-observe.js +343 -0
  54. package/dist/backends/kubernetes/workspace-observe.js.map +1 -0
  55. package/dist/backends/kubernetes/workspace-per-sandbox.d.ts +94 -0
  56. package/dist/backends/kubernetes/workspace-per-sandbox.d.ts.map +1 -0
  57. package/dist/backends/kubernetes/workspace-per-sandbox.js +119 -0
  58. package/dist/backends/kubernetes/workspace-per-sandbox.js.map +1 -0
  59. package/dist/backends/kubernetes/workspace.d.ts +139 -5
  60. package/dist/backends/kubernetes/workspace.d.ts.map +1 -1
  61. package/dist/backends/kubernetes/workspace.js +434 -36
  62. package/dist/backends/kubernetes/workspace.js.map +1 -1
  63. package/dist/index.d.ts +83 -7
  64. package/dist/index.d.ts.map +1 -1
  65. package/dist/index.js +100 -6
  66. package/dist/index.js.map +1 -1
  67. package/package.json +3 -3
  68. package/src/backends/firecracker/protocol.ts +47 -0
  69. package/src/backends/firecracker/transport.ts +31 -0
  70. package/src/backends/kubernetes/allocation.ts +199 -0
  71. package/src/backends/kubernetes/egress-policy.ts +165 -42
  72. package/src/backends/kubernetes/identity.ts +210 -0
  73. package/src/backends/kubernetes/index.ts +61 -2
  74. package/src/backends/kubernetes/objects.ts +98 -0
  75. package/src/backends/kubernetes/per-sandbox-fence.ts +800 -0
  76. package/src/backends/kubernetes/per-sandbox-policy.ts +152 -17
  77. package/src/backends/kubernetes/sandbox.ts +4 -9
  78. package/src/backends/kubernetes/transport.ts +203 -4
  79. package/src/backends/kubernetes/workspace-allocate.ts +607 -0
  80. package/src/backends/kubernetes/workspace-observe.ts +590 -0
  81. package/src/backends/kubernetes/workspace-per-sandbox.ts +179 -0
  82. package/src/backends/kubernetes/workspace.ts +655 -34
  83. package/src/index.ts +193 -3
package/src/index.ts CHANGED
@@ -89,6 +89,27 @@ import {
89
89
  releaseKubernetesTaskSandboxes as releaseTaskSandboxesOnCluster,
90
90
  } from './backends/kubernetes/index.js'
91
91
  import type { KubernetesIngressConfig } from './backends/kubernetes/ingress-policy.js'
92
+ import {
93
+ type KubernetesExecutionProfile,
94
+ type KubernetesExecutionProfileOptions,
95
+ type KubernetesWorkspaceAllocateOptions,
96
+ type KubernetesWorkspaceAllocationRecoverOptions,
97
+ type KubernetesWorkspaceAllocationRecovery,
98
+ type KubernetesWorkspaceAllocationResult,
99
+ allocateKubernetesWorkspace as allocateWorkspaceOnCluster,
100
+ recoverKubernetesWorkspaceAllocation as recoverAllocationOnCluster,
101
+ resolveKubernetesExecutionProfile as resolveProfileOnCluster,
102
+ } from './backends/kubernetes/workspace-allocate.js'
103
+ import {
104
+ type KubernetesWorkspaceClosure,
105
+ type KubernetesWorkspaceInspectOptions,
106
+ type KubernetesWorkspaceInspection,
107
+ type KubernetesWorkspaceOpenOptions,
108
+ type KubernetesWorkspaceReconcileOptions,
109
+ inspectKubernetesWorkspace as inspectWorkspaceOnCluster,
110
+ openKubernetesWorkspace as openWorkspaceOnCluster,
111
+ reconcileKubernetesWorkspace as reconcileWorkspaceOnCluster,
112
+ } from './backends/kubernetes/workspace-observe.js'
92
113
  import {
93
114
  type KubernetesWorkspace,
94
115
  type KubernetesWorkspaceOptions,
@@ -208,6 +229,7 @@ export type {
208
229
  KubernetesEgressVerification,
209
230
  KubernetesOnlyEgressPolicy,
210
231
  KubernetesPerSandboxEgressConfig,
232
+ KubernetesPermittedHostsParam,
211
233
  } from './backends/kubernetes/egress-policy.js'
212
234
  // Per-sandbox egress — `config.egress.perSandbox`, which makes
213
235
  // `Sandbox.setNetworkPolicy` PRESENT on a kubernetes TASK handle instead of
@@ -221,20 +243,26 @@ export type {
221
243
  // `KubernetesOwnerUidMissingError` is the fourth, and the only one raised
222
244
  // from an ACQUIRE — the object this backend created reported no uid, so a
223
245
  // policy written for it would be an orphan.
224
- // `KubernetesWorkspacePerSandboxEgressConfigError` is the fifth: the same
225
- // option reaching `createKubernetesWorkspace`, whose handle never carries
226
- // `setNetworkPolicy` — refused there rather than accepted and ignored.
246
+ // `KubernetesWorkspacePerSandboxEgressConfigError` is deprecated: it used to
247
+ // refuse the same option on `createKubernetesWorkspace`, whose handle now
248
+ // carries `setNetworkPolicy`, so nothing throws it any more.
227
249
  // See `backends/kubernetes/per-sandbox-policy.ts` — and, for
228
250
  // `KubernetesNetworkPolicyHostError`, which the config-level translation
229
251
  // refuses the same entries with, `backends/kubernetes/egress-policy.ts`.
230
252
  export { KubernetesPerSandboxEgressConfigError } from './backends/kubernetes/egress-policy.js'
231
253
  export { KubernetesWorkspacePerSandboxEgressConfigError } from './backends/kubernetes/egress-policy.js'
232
254
  export { DEFAULT_PER_SANDBOX_EGRESS_LABEL_KEY } from './backends/kubernetes/egress-policy.js'
255
+ export { KUBERNETES_PER_SANDBOX_PROFILE_VARIANT } from './backends/kubernetes/workspace-per-sandbox.js'
256
+ export type { FenceObjectKind } from './backends/kubernetes/per-sandbox-fence.js'
233
257
  export {
258
+ KubernetesAdmissionFenceInertError,
234
259
  KubernetesAdmissionFenceMissingError,
235
260
  KubernetesAdmissionFenceUnreadableError,
236
261
  KubernetesNetworkPolicyHostError,
237
262
  KubernetesOwnerUidMissingError,
263
+ KubernetesPerSandboxPolicyNotRemovedError,
264
+ KubernetesPermittedHostsError,
265
+ KubernetesPermittedHostsParamError,
238
266
  PER_SANDBOX_POLICY_NAME_PREFIX,
239
267
  } from './backends/kubernetes/per-sandbox-policy.js'
240
268
  // The default label key `KubernetesEgressConfig.profile` is written under.
@@ -303,6 +331,10 @@ export {
303
331
  } from './backends/kubernetes/sandbox.js'
304
332
  export {
305
333
  KubernetesAgentAddressUnresolvableError,
334
+ // The guest agent compared its boot id with a pinned request's and refused
335
+ // before dispatching anything. Reaches a caller as
336
+ // `KubernetesGuestPinRefusedError` through a pinned view.
337
+ KubernetesAgentGuestMismatchError,
306
338
  // A guest that has fenced itself refuses one CALL here, not the
307
339
  // workspace: the Firecracker tier's mapping of the same refusal retires
308
340
  // the sandbox, which on a workspace would take the pod away from every
@@ -369,11 +401,16 @@ export type {
369
401
  } from './backends/kubernetes/workspace.js'
370
402
  export type { KubernetesQuiesceReport } from './backends/kubernetes/transport.js'
371
403
  export {
404
+ KubernetesQuiesceBusyError,
405
+ type KubernetesQuiesceBusyProcess,
406
+ type KubernetesQuiesceBusyRegistryEntry,
372
407
  KubernetesQuiesceUnconfirmedError,
373
408
  KubernetesQuiesceUnsupportedError,
374
409
  } from './backends/kubernetes/transport.js'
375
410
  export {
376
411
  QUIESCE_FEATURE,
412
+ PINNED_GUEST_FEATURE,
413
+ QUIESCE_IDLE_FEATURE,
377
414
  type QuiesceScope,
378
415
  type QuiescedProcess,
379
416
  } from './backends/firecracker/protocol.js'
@@ -518,15 +555,67 @@ export type {
518
555
  export type {
519
556
  KubernetesGuestEvidence,
520
557
  KubernetesGuestRestart,
558
+ KubernetesGuestPinRefusal,
521
559
  KubernetesGuestRestartReason,
560
+ KubernetesPinnedGuestIdentity,
561
+ KubernetesWorkspaceExpectedIdentity,
522
562
  KubernetesWorkspaceIdentity,
563
+ KubernetesWorkspaceIdentityMismatch,
523
564
  } from './backends/kubernetes/identity.js'
565
+ export type {
566
+ KubernetesObservedAllocation,
567
+ KubernetesWorkspaceAllocation,
568
+ KubernetesWorkspaceAllocationMismatch,
569
+ } from './backends/kubernetes/allocation.js'
570
+ export {
571
+ KubernetesExecutionProfileDriftError,
572
+ KubernetesWorkspaceAllocationConflictError,
573
+ KubernetesWorkspaceAllocationMismatchError,
574
+ } from './backends/kubernetes/allocation.js'
575
+ export type {
576
+ KubernetesAllocationUnknownReason,
577
+ KubernetesExecutionProfile,
578
+ KubernetesExecutionProfileOptions,
579
+ KubernetesWorkspaceAllocateOptions,
580
+ KubernetesWorkspaceAllocationReceipt,
581
+ KubernetesWorkspaceAllocationRecoverOptions,
582
+ KubernetesWorkspaceAllocationRecovery,
583
+ KubernetesWorkspaceAllocationResult,
584
+ KubernetesWorkspaceAllocationUnknown,
585
+ } from './backends/kubernetes/workspace-allocate.js'
586
+ export {
587
+ ALLOCATION_ID_ANNOTATION_KEY,
588
+ ALLOCATION_SCOPE_ANNOTATION_KEY,
589
+ EXECUTION_PROFILE_ANNOTATION_KEY,
590
+ } from './backends/kubernetes/objects.js'
591
+ export type {
592
+ KubernetesWorkspaceClosure,
593
+ KubernetesWorkspaceClosureState,
594
+ KubernetesWorkspaceInspectOptions,
595
+ KubernetesWorkspaceInspection,
596
+ KubernetesWorkspaceObservationOptions,
597
+ KubernetesWorkspaceOpenOptions,
598
+ KubernetesWorkspaceReconcileOptions,
599
+ } from './backends/kubernetes/workspace-observe.js'
600
+ export { KubernetesWorkspaceReadyTimeoutError } from './backends/kubernetes/workspace-observe.js'
601
+ // Pinning one guest: `workspace.pinGuest(identity)` and the two errors a host
602
+ // catches by class — an identity that cannot pin (nothing was created) and a
603
+ // pinned call that was refused (nothing ran).
604
+ export {
605
+ KubernetesGuestPinRefusedError,
606
+ KubernetesPinIncompleteError,
607
+ } from './backends/kubernetes/identity.js'
608
+ export type { KubernetesPinnedGuest } from './backends/kubernetes/workspace.js'
524
609
  export {
525
610
  // The command's outcome is unknown AND the guest it ran in is gone. A
526
611
  // subclass of `RemoteCancellationUnknownError`, so a host catching the
527
612
  // base class keeps catching it; what it adds is which guest the command
528
613
  // started on and which one is there now.
529
614
  KubernetesWorkspaceGuestGoneError,
615
+ // The workspace a host retained is not what stands under its name:
616
+ // another Sandbox uid, no Sandbox, another claim uid or owner. Raised by
617
+ // `openKubernetesWorkspace` before anything is created, woken or written.
618
+ KubernetesWorkspaceIdentityMismatchError,
530
619
  // A different Sandbox now stands under the workspace's deterministic
531
620
  // name, or none does. The handle refuses rather than following it — the
532
621
  // disk behind the name is not the disk it was opened on.
@@ -1716,6 +1805,107 @@ export async function suspendKubernetesWorkspace(
1716
1805
  await suspendWorkspaceOnCluster(kubernetesInternalConfig(config), workspaceId, options)
1717
1806
  }
1718
1807
 
1808
+ /**
1809
+ * Resolve and fingerprint what a workspace created from `config` would run —
1810
+ * the pod template with this backend's overlays, the template's disks, the
1811
+ * egress policy translated from `config.egress` and the ingress settings —
1812
+ * without creating anything. One GET: the SandboxTemplate — plus, when
1813
+ * `config.egress.perSandbox` is configured, the reads that prove its admission
1814
+ * fence (a configuration whose fence does not enforce is refused and yields no
1815
+ * fingerprint), and the result then carries `variant:
1816
+ * 'core/no-network+per-sandbox'`.
1817
+ *
1818
+ * Persist the result, then pass its `fingerprint` as
1819
+ * `allocation.executionProfile` to {@link allocateKubernetesWorkspace}.
1820
+ */
1821
+ export async function resolveKubernetesExecutionProfile(
1822
+ config: KubernetesBackendConfig,
1823
+ options?: KubernetesExecutionProfileOptions,
1824
+ ): Promise<KubernetesExecutionProfile> {
1825
+ return await resolveProfileOnCluster(kubernetesInternalConfig(config), options)
1826
+ }
1827
+
1828
+ /**
1829
+ * Create a workspace exactly once, bound to the allocation the host recorded
1830
+ * first. Unlike `createKubernetesWorkspace` it never adopts a same-name
1831
+ * object (typed `KubernetesWorkspaceAllocationConflictError`, nothing
1832
+ * touched), never resumes compute, and never retries the create.
1833
+ *
1834
+ * `{ outcome: 'created' }` carries a receipt with the new Sandbox's uid — an
1835
+ * acknowledgement, not readiness. `{ outcome: 'unknown' }` means the request
1836
+ * was sent and no usable reply came back; settle it with
1837
+ * `recoverKubernetesWorkspaceAllocation`.
1838
+ */
1839
+ export async function allocateKubernetesWorkspace(
1840
+ config: KubernetesBackendConfig,
1841
+ options: KubernetesWorkspaceAllocateOptions,
1842
+ ): Promise<KubernetesWorkspaceAllocationResult> {
1843
+ return await allocateWorkspaceOnCluster(kubernetesInternalConfig(config), options)
1844
+ }
1845
+
1846
+ /**
1847
+ * After an `unknown` allocation: one read-only GET, answered as `created`
1848
+ * (with the receipt), `absent` or `different`. See
1849
+ * `KubernetesWorkspaceAllocationRecovery` for what `absent` does and does not
1850
+ * promise.
1851
+ */
1852
+ export async function recoverKubernetesWorkspaceAllocation(
1853
+ config: KubernetesBackendConfig,
1854
+ options: KubernetesWorkspaceAllocationRecoverOptions,
1855
+ ): Promise<KubernetesWorkspaceAllocationRecovery> {
1856
+ return await recoverAllocationOnCluster(kubernetesInternalConfig(config), options)
1857
+ }
1858
+
1859
+ /**
1860
+ * Look at a workspace by id: its Sandbox uid, volume-claim uids, live pod,
1861
+ * operating mode and holder epoch. GET requests only — it never creates,
1862
+ * wakes, patches or deletes — and it resolves `undefined` when no Sandbox
1863
+ * stands under the id.
1864
+ *
1865
+ * `epoch` is required: a workspace held at a higher epoch belongs to another
1866
+ * process, and a superseded host is refused with
1867
+ * `KubernetesWorkspacePreconditionError` rather than shown it.
1868
+ */
1869
+ export async function inspectKubernetesWorkspace(
1870
+ config: KubernetesBackendConfig,
1871
+ workspaceId: string,
1872
+ options: KubernetesWorkspaceInspectOptions,
1873
+ ): Promise<KubernetesWorkspaceInspection | undefined> {
1874
+ return await inspectWorkspaceOnCluster(kubernetesInternalConfig(config), workspaceId, options)
1875
+ }
1876
+
1877
+ /**
1878
+ * Authenticate the identity a host retained against what stands under the
1879
+ * workspace id, and with `waitForReady` wait — under one `readyTimeoutMs`
1880
+ * deadline — for its volume claims and its guest. Never creates, wakes or
1881
+ * writes; a suspended workspace is returned as suspended.
1882
+ *
1883
+ * A different Sandbox or claim is `KubernetesWorkspaceIdentityMismatchError`;
1884
+ * a `resourceVersion` or `Ready` condition that moves while waiting is
1885
+ * ordinary progress and never is. Running out of time is
1886
+ * `KubernetesWorkspaceReadyTimeoutError`, and cancelling rejects with the
1887
+ * signal's reason.
1888
+ */
1889
+ export async function openKubernetesWorkspace(
1890
+ config: KubernetesBackendConfig,
1891
+ options: KubernetesWorkspaceOpenOptions,
1892
+ ): Promise<KubernetesWorkspaceInspection> {
1893
+ return await openWorkspaceOnCluster(kubernetesInternalConfig(config), options)
1894
+ }
1895
+
1896
+ /**
1897
+ * After a restart, what became of the workspace a host retained: `live`,
1898
+ * `suspended`, `absent` or `replaced`. One GET-only pass; a different Sandbox
1899
+ * or claim is the answer `replaced`, not an error, and a read that did not
1900
+ * answer rejects rather than reading as `absent`.
1901
+ */
1902
+ export async function reconcileKubernetesWorkspace(
1903
+ config: KubernetesBackendConfig,
1904
+ options: KubernetesWorkspaceReconcileOptions,
1905
+ ): Promise<KubernetesWorkspaceClosure> {
1906
+ return await reconcileWorkspaceOnCluster(kubernetesInternalConfig(config), options)
1907
+ }
1908
+
1719
1909
  /**
1720
1910
  * Recover a crashed host's task-path claims: LIST every `SandboxClaim`
1721
1911
  * carrying `options.labelSelector`, `DELETE` each, and report what was