@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
@@ -68,6 +68,19 @@ export interface KubernetesObjectMeta {
68
68
  * `k8s-client.ts` states still holds. See {@link buildHolderEpochPatch}.
69
69
  */
70
70
  readonly resourceVersion?: string
71
+ /**
72
+ * `metadata.generation`: bumped by the API server on every change to
73
+ * `spec`. Read only by the readiness observation, which compares it with a
74
+ * condition's `observedGeneration` so that a `Ready: True` the controller
75
+ * wrote for an EARLIER spec is not mistaken for the outcome of the latest
76
+ * one.
77
+ */
78
+ readonly generation?: number
79
+ /** Who owns this object. Read off a PVC, to tell the Sandbox's disk from a stranger's. */
80
+ readonly ownerReferences?: readonly {
81
+ readonly uid?: string
82
+ readonly controller?: boolean
83
+ }[]
71
84
  /**
72
85
  * Set the moment a DELETE is accepted, long before the object goes away.
73
86
  * A pod that carries one is on its way out and must never be bound to —
@@ -85,6 +98,12 @@ export interface KubernetesCondition {
85
98
  readonly reason?: string
86
99
  readonly message?: string
87
100
  readonly lastTransitionTime?: string
101
+ /**
102
+ * The `metadata.generation` the controller had seen when it wrote this
103
+ * condition. A condition whose value is below the object's current
104
+ * generation describes an earlier spec.
105
+ */
106
+ readonly observedGeneration?: number
88
107
  }
89
108
 
90
109
  /**
@@ -561,6 +580,70 @@ export function podTemplateHash(podTemplate: SandboxPodTemplate): string {
561
580
  return `sha256:${digest}`
562
581
  }
563
582
 
583
+ /**
584
+ * `sha256:<hex>` over any JSON-serialisable value, taken over its CANONICAL
585
+ * form: object keys sorted by code unit at every depth, `undefined` members
586
+ * dropped, arrays kept in order, then `JSON.stringify` with no whitespace.
587
+ *
588
+ * {@link podTemplateHash} and the execution-profile fingerprint both go
589
+ * through it, so two hosts on the same release computing it over the same
590
+ * content get the same string whatever order their objects were built in.
591
+ */
592
+ export function canonicalFingerprint(value: unknown): string {
593
+ const digest = createHash('sha256')
594
+ .update(JSON.stringify(canonicalJson(value)))
595
+ .digest('hex')
596
+ return `sha256:${digest}`
597
+ }
598
+
599
+ /**
600
+ * Backend-owned annotation carrying the ALLOCATION ID a workspace was created
601
+ * for by `allocateKubernetesWorkspace`: the host's own immutable identifier
602
+ * for "this allocation", chosen and persisted by the host BEFORE the create.
603
+ *
604
+ * Public contract. Written once, in the create POST, and never patched by
605
+ * this backend afterwards — a refresh, a resume, a suspend or an epoch write
606
+ * merges other annotations and leaves it alone. Absent on a workspace made
607
+ * by `createKubernetesWorkspace`.
608
+ *
609
+ * Same prefix as {@link HOLDER_EPOCH_ANNOTATION_KEY}.
610
+ */
611
+ export const ALLOCATION_ID_ANNOTATION_KEY = 'sandbox.namzu.ai/allocation-id'
612
+
613
+ /**
614
+ * Backend-owned annotation carrying the host's SCOPE FINGERPRINT for the
615
+ * allocation: an opaque string naming what the workspace is for (tenant,
616
+ * project, session — the host decides). The backend never interprets it; it
617
+ * only stores it and compares it for equality. Written with, and under the
618
+ * same rules as, {@link ALLOCATION_ID_ANNOTATION_KEY}.
619
+ */
620
+ export const ALLOCATION_SCOPE_ANNOTATION_KEY = 'sandbox.namzu.ai/allocation-scope'
621
+
622
+ /**
623
+ * Backend-owned annotation carrying the EXECUTION PROFILE FINGERPRINT the
624
+ * workspace was allocated under: the `sha256:<hex>` that
625
+ * `resolveKubernetesExecutionProfile` returns. Written with, and under the
626
+ * same rules as, {@link ALLOCATION_ID_ANNOTATION_KEY}.
627
+ */
628
+ export const EXECUTION_PROFILE_ANNOTATION_KEY = 'sandbox.namzu.ai/execution-profile'
629
+
630
+ /** What a Sandbox's allocation annotations say; each `undefined` when absent. */
631
+ export interface AllocationReading {
632
+ readonly id: string | undefined
633
+ readonly scopeFingerprint: string | undefined
634
+ readonly executionProfile: string | undefined
635
+ }
636
+
637
+ /** Read the three allocation annotations off an object's metadata. */
638
+ export function readAllocation(meta: KubernetesObjectMeta | undefined): AllocationReading {
639
+ const annotations = meta?.annotations
640
+ return {
641
+ id: annotations?.[ALLOCATION_ID_ANNOTATION_KEY],
642
+ scopeFingerprint: annotations?.[ALLOCATION_SCOPE_ANNOTATION_KEY],
643
+ executionProfile: annotations?.[EXECUTION_PROFILE_ANNOTATION_KEY],
644
+ }
645
+ }
646
+
564
647
  /**
565
648
  * One RFC 6902 operation, in the only three shapes this backend sends.
566
649
  *
@@ -621,6 +704,11 @@ export interface HolderEpochReading {
621
704
  readonly hasAnnotations: boolean
622
705
  /** `metadata.resourceVersion`, for the fallback `test` and a fenced DELETE. */
623
706
  readonly resourceVersion?: string
707
+ /**
708
+ * `metadata.uid` of the object this reading came from, so a write can
709
+ * refuse a same-name replacement off the very read it is conditioned on.
710
+ */
711
+ readonly sandboxUid?: string
624
712
  }
625
713
 
626
714
  /** Decimal, no sign, no padding, no exponent — what this backend writes. */
@@ -637,6 +725,7 @@ export function readHolderEpoch(meta: KubernetesObjectMeta | undefined): HolderE
637
725
  const base = {
638
726
  hasAnnotations: annotations !== undefined,
639
727
  ...(resourceVersion !== undefined ? { resourceVersion } : {}),
728
+ ...(typeof meta?.uid === 'string' && meta.uid !== '' ? { sandboxUid: meta.uid } : {}),
640
729
  }
641
730
  if (typeof stored !== 'string') return { ...base, epoch: 0 }
642
731
  if (!HOLDER_EPOCH_PATTERN.test(stored)) return { ...base, annotation: stored }
@@ -963,6 +1052,15 @@ export function validatingAdmissionPolicyBindingPath(name: string): string {
963
1052
  return `/apis/${ADMISSION_REGISTRATION_API_GROUP}/${ADMISSION_REGISTRATION_API_VERSION}/validatingadmissionpolicybindings/${segment(name)}`
964
1053
  }
965
1054
 
1055
+ /**
1056
+ * One core `ConfigMap`. Read by exactly one caller: the per-sandbox fence's
1057
+ * operator-pinned host set (`per-sandbox-fence.ts`), which the backend only
1058
+ * ever GETs.
1059
+ */
1060
+ export function configMapPath(namespace: string, name: string): string {
1061
+ return `/api/v1/namespaces/${segment(namespace)}/configmaps/${segment(name)}`
1062
+ }
1063
+
966
1064
  /**
967
1065
  * An `ownerReferences` entry, as this backend writes it.
968
1066
  *