@namzu/sandbox 26.0.0 → 28.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 +62 -7
  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
@@ -0,0 +1,187 @@
1
+ /**
2
+ * Looking at a retained workspace by its exact identity, without creating,
3
+ * waking or writing anything.
4
+ *
5
+ * `createKubernetesWorkspace` is create-or-adopt: handed an id it POSTs, and
6
+ * on a 409 adopts whatever stands there and resumes it. That is the right
7
+ * verb for "give me a workspace" and the wrong one for a host that restarted
8
+ * and wants to know whether the workspace it recorded last week is still the
9
+ * workspace under that name — the question has to be answered BEFORE a pod is
10
+ * started for what might be a stranger's disk.
11
+ *
12
+ * Three verbs, all GET-only:
13
+ *
14
+ * - {@link inspectKubernetesWorkspace} — what is there, and who holds it.
15
+ * - {@link openKubernetesWorkspace} — authenticate a retained identity, and
16
+ * optionally wait, under one deadline, for its claims and its guest.
17
+ * - {@link reconcileKubernetesWorkspace} — after a restart: live, suspended,
18
+ * absent or replaced.
19
+ *
20
+ * ## Ownership and readiness are separate questions
21
+ *
22
+ * Ownership is decided by uids and by nothing else: the Sandbox's
23
+ * `metadata.uid`, each volume claim's uid, and who owns each claim. A
24
+ * `resourceVersion` that moved, a `Ready` condition that flipped and a
25
+ * condition left over from an earlier generation are the controller working,
26
+ * and none of them is ever read as a change of owner. Readiness is a bounded
27
+ * poll on top of an ownership check that runs again on every pass, so a
28
+ * replacement that lands while waiting is still a refusal.
29
+ */
30
+ import { type KubernetesObservedAllocation, type KubernetesWorkspaceAllocation } from './allocation.js';
31
+ import { type KubernetesWorkspaceExpectedIdentity, type KubernetesWorkspaceIdentity, type KubernetesWorkspaceIdentityMismatch } from './identity.js';
32
+ import { type KubernetesBackendInternalConfig } from './index.js';
33
+ /** What every verb here takes besides its own fields. */
34
+ export interface KubernetesWorkspaceObservationOptions {
35
+ readonly signal?: AbortSignal;
36
+ }
37
+ /** {@link inspectKubernetesWorkspace}'s options. */
38
+ export interface KubernetesWorkspaceInspectOptions extends KubernetesWorkspaceObservationOptions {
39
+ /**
40
+ * The allocation this host expects. A Sandbox under the id whose
41
+ * allocation annotations or copied pod template differ is refused with
42
+ * `KubernetesWorkspaceAllocationMismatchError`; absence still resolves
43
+ * `undefined`, because there is nothing to compare.
44
+ */
45
+ readonly expectedAllocation?: KubernetesWorkspaceAllocation;
46
+ /**
47
+ * The holder epoch this reader acts under. A workspace held at a HIGHER
48
+ * epoch refuses it with `KubernetesWorkspacePreconditionError`: a
49
+ * superseded host must not conclude anything about a workspace that
50
+ * belongs to another process now. Nothing is written either way.
51
+ */
52
+ readonly epoch: number;
53
+ }
54
+ /** What one read-only look at a workspace found. */
55
+ export interface KubernetesWorkspaceInspection {
56
+ readonly workspaceId: string;
57
+ readonly sandboxName: string;
58
+ readonly operatingMode: 'Running' | 'Suspended';
59
+ /**
60
+ * The disk and the guest, as the cluster reports them now.
61
+ * `volumeClaimUids` holds the claims that exist; `podUid` is the live pod
62
+ * and is `undefined` for a suspended workspace; `guestBootId` is always
63
+ * `undefined` — nothing here dials the guest.
64
+ */
65
+ readonly identity: KubernetesWorkspaceIdentity;
66
+ /** The stored holder epoch; `0` for a workspace that never carried one. */
67
+ readonly holderEpoch: number;
68
+ /**
69
+ * The allocation annotations as stored; every field `undefined` for a
70
+ * workspace not made by `allocateKubernetesWorkspace`.
71
+ */
72
+ readonly allocation: KubernetesObservedAllocation;
73
+ /**
74
+ * The Sandbox reports `Ready` for its CURRENT generation AND a live pod
75
+ * stands under it. A `Ready: True` the controller wrote for an earlier
76
+ * generation does not count.
77
+ */
78
+ readonly ready: boolean;
79
+ /** `volumeClaimTemplates` entries whose PVC does not exist (yet). */
80
+ readonly missingVolumeClaims: readonly string[];
81
+ }
82
+ /** {@link openKubernetesWorkspace}'s options. */
83
+ export interface KubernetesWorkspaceOpenOptions extends KubernetesWorkspaceObservationOptions {
84
+ readonly workspaceId: string;
85
+ /** The identity the host retained. The Sandbox uid is required. */
86
+ readonly identity: KubernetesWorkspaceExpectedIdentity;
87
+ /** The holder epoch this host acts under — see {@link KubernetesWorkspaceInspectOptions.epoch}. */
88
+ readonly epoch: number;
89
+ /**
90
+ * The allocation this host expects, checked after the Sandbox uid: a
91
+ * mismatch is `KubernetesWorkspaceAllocationMismatchError`.
92
+ */
93
+ readonly expectedAllocation?: KubernetesWorkspaceAllocation;
94
+ /**
95
+ * Poll, under ONE deadline (`readyTimeoutMs`), until every volume claim
96
+ * exists and the guest is ready. A suspended workspace is returned at
97
+ * once — opening never wakes anything, so there is nothing to wait for.
98
+ * Omitted or `false`, one pass is made and the result says what was
99
+ * missing.
100
+ */
101
+ readonly waitForReady?: boolean;
102
+ }
103
+ /** {@link reconcileKubernetesWorkspace}'s options. */
104
+ export interface KubernetesWorkspaceReconcileOptions extends KubernetesWorkspaceObservationOptions {
105
+ readonly workspaceId: string;
106
+ readonly identity: KubernetesWorkspaceExpectedIdentity;
107
+ /** When given, a workspace held at a higher epoch refuses the reconcile. */
108
+ readonly epoch?: number;
109
+ /**
110
+ * The allocation this host expects. Checked after the identity, so a
111
+ * `replaced` answer still wins; a Sandbox that IS the retained one but
112
+ * carries a different allocation or template content throws
113
+ * `KubernetesWorkspaceAllocationMismatchError`.
114
+ */
115
+ readonly expectedAllocation?: KubernetesWorkspaceAllocation;
116
+ }
117
+ /**
118
+ * What stands under a retained identity now.
119
+ *
120
+ * - `live` — the same Sandbox, `Running`.
121
+ * - `suspended` — the same Sandbox, `Suspended`; its disk is intact.
122
+ * - `absent` — no Sandbox stands under the name at all.
123
+ * - `replaced` — a different Sandbox, or a different volume claim, stands
124
+ * there; `mismatch` says which. The retained workspace is gone.
125
+ */
126
+ export type KubernetesWorkspaceClosureState = 'live' | 'suspended' | 'absent' | 'replaced';
127
+ export interface KubernetesWorkspaceClosure {
128
+ readonly state: KubernetesWorkspaceClosureState;
129
+ readonly workspaceId: string;
130
+ readonly sandboxName: string;
131
+ /** What was observed. Absent for `absent`; the STRANGER's for `replaced`. */
132
+ readonly identity?: KubernetesWorkspaceIdentity;
133
+ /** Why the state is `replaced`. */
134
+ readonly mismatch?: KubernetesWorkspaceIdentityMismatch;
135
+ }
136
+ /** The wait ran out before the workspace was ready. Ownership was never in doubt. */
137
+ export declare class KubernetesWorkspaceReadyTimeoutError extends Error {
138
+ readonly workspaceId: string;
139
+ readonly sandboxName: string;
140
+ readonly timeoutMs: number;
141
+ /** What the last pass was still waiting for. */
142
+ readonly waitingFor: readonly ('volume-claims' | 'ready-condition' | 'pod')[];
143
+ /** The last pass, so a caller can see how far it got. */
144
+ readonly lastObserved: KubernetesWorkspaceInspection;
145
+ readonly name = "KubernetesWorkspaceReadyTimeoutError";
146
+ constructor(workspaceId: string, sandboxName: string, timeoutMs: number,
147
+ /** What the last pass was still waiting for. */
148
+ waitingFor: readonly ('volume-claims' | 'ready-condition' | 'pod')[],
149
+ /** The last pass, so a caller can see how far it got. */
150
+ lastObserved: KubernetesWorkspaceInspection);
151
+ }
152
+ /**
153
+ * Read what stands under a workspace id: its Sandbox uid, its claim uids, its
154
+ * pod and its operating mode, and who holds it. GET requests only — nothing
155
+ * is created, woken, patched or deleted — and `undefined` when no Sandbox
156
+ * stands there.
157
+ *
158
+ * Needs `get` on `sandboxes`, `persistentvolumeclaims` and `pods`. A failed
159
+ * read rejects as itself: an unanswered request is never reported as a
160
+ * workspace that is absent.
161
+ */
162
+ export declare function inspectKubernetesWorkspace(config: KubernetesBackendInternalConfig, workspaceId: string, options: KubernetesWorkspaceInspectOptions): Promise<KubernetesWorkspaceInspection | undefined>;
163
+ /**
164
+ * Authenticate a retained identity against what stands under the workspace
165
+ * id, and — with `waitForReady` — wait for it to be usable. Never creates,
166
+ * wakes or writes.
167
+ *
168
+ * Refuses with {@link KubernetesWorkspaceIdentityMismatchError} when the
169
+ * Sandbox is gone or has another uid, or a claim has another uid or another
170
+ * owner, and with `KubernetesWorkspacePreconditionError` when the workspace
171
+ * is held at a higher epoch. The waiting form repeats both checks on every
172
+ * pass and retains every claim uid it has seen, so a replacement that lands
173
+ * mid-wait is a refusal rather than a longer wait. Cancelling `signal`
174
+ * rejects with its reason; running out of `readyTimeoutMs` rejects with
175
+ * {@link KubernetesWorkspaceReadyTimeoutError}. The three never share a class.
176
+ */
177
+ export declare function openKubernetesWorkspace(config: KubernetesBackendInternalConfig, options: KubernetesWorkspaceOpenOptions): Promise<KubernetesWorkspaceInspection>;
178
+ /**
179
+ * After a restart: what became of the workspace a host retained? One
180
+ * GET-only pass, answered as a closure state rather than thrown.
181
+ *
182
+ * A different Sandbox or claim is `replaced`, not an error, because for a
183
+ * host closing its books that IS the answer. A read that did not answer
184
+ * rejects as itself — it is never mapped to `absent`.
185
+ */
186
+ export declare function reconcileKubernetesWorkspace(config: KubernetesBackendInternalConfig, options: KubernetesWorkspaceReconcileOptions): Promise<KubernetesWorkspaceClosure>;
187
+ //# sourceMappingURL=workspace-observe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace-observe.d.ts","sourceRoot":"","sources":["../../../src/backends/kubernetes/workspace-observe.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,343 @@
1
+ /**
2
+ * Looking at a retained workspace by its exact identity, without creating,
3
+ * waking or writing anything.
4
+ *
5
+ * `createKubernetesWorkspace` is create-or-adopt: handed an id it POSTs, and
6
+ * on a 409 adopts whatever stands there and resumes it. That is the right
7
+ * verb for "give me a workspace" and the wrong one for a host that restarted
8
+ * and wants to know whether the workspace it recorded last week is still the
9
+ * workspace under that name — the question has to be answered BEFORE a pod is
10
+ * started for what might be a stranger's disk.
11
+ *
12
+ * Three verbs, all GET-only:
13
+ *
14
+ * - {@link inspectKubernetesWorkspace} — what is there, and who holds it.
15
+ * - {@link openKubernetesWorkspace} — authenticate a retained identity, and
16
+ * optionally wait, under one deadline, for its claims and its guest.
17
+ * - {@link reconcileKubernetesWorkspace} — after a restart: live, suspended,
18
+ * absent or replaced.
19
+ *
20
+ * ## Ownership and readiness are separate questions
21
+ *
22
+ * Ownership is decided by uids and by nothing else: the Sandbox's
23
+ * `metadata.uid`, each volume claim's uid, and who owns each claim. A
24
+ * `resourceVersion` that moved, a `Ready` condition that flipped and a
25
+ * condition left over from an earlier generation are the controller working,
26
+ * and none of them is ever read as a change of owner. Readiness is a bounded
27
+ * poll on top of an ownership check that runs again on every pass, so a
28
+ * replacement that lands while waiting is still a refusal.
29
+ */
30
+ import { OperationDeadline, OperationDeadlineExpired } from '../readiness.js';
31
+ import { KubernetesWorkspaceAllocationMismatchError, assertAllocation, firstAllocationMismatch, observedAllocation, } from './allocation.js';
32
+ import { KubernetesWorkspaceIdentityMismatchError, } from './identity.js';
33
+ import { clientAccess, clientOptions, resolveKubernetesReadiness, } from './index.js';
34
+ import { KubernetesAlreadyGoneError, createKubernetesClient, } from './k8s-client.js';
35
+ import { READY_CONDITION, isPodLive, persistentVolumeClaimPath, podPath, readHolderEpoch, sandboxPath, } from './objects.js';
36
+ import { KubernetesWorkspacePreconditionError, assertHolderEpoch, workspaceSandboxName, } from './workspace.js';
37
+ /** The wait ran out before the workspace was ready. Ownership was never in doubt. */
38
+ export class KubernetesWorkspaceReadyTimeoutError extends Error {
39
+ workspaceId;
40
+ sandboxName;
41
+ timeoutMs;
42
+ waitingFor;
43
+ lastObserved;
44
+ name = 'KubernetesWorkspaceReadyTimeoutError';
45
+ constructor(workspaceId, sandboxName, timeoutMs,
46
+ /** What the last pass was still waiting for. */
47
+ waitingFor,
48
+ /** The last pass, so a caller can see how far it got. */
49
+ lastObserved) {
50
+ super(`kubernetes: workspace ${workspaceId} (Sandbox ${sandboxName}) was the retained workspace on every pass but was not ready ${timeoutMs}ms later — still waiting for ${waitingFor.join(', ')}. Ownership is not in question: this is the controller not having finished, and nothing was created or woken to hurry it.`);
51
+ this.workspaceId = workspaceId;
52
+ this.sandboxName = sandboxName;
53
+ this.timeoutMs = timeoutMs;
54
+ this.waitingFor = waitingFor;
55
+ this.lastObserved = lastObserved;
56
+ }
57
+ }
58
+ async function readOrGone(client, path, signal) {
59
+ try {
60
+ return await client.request('GET', path, undefined, signal);
61
+ }
62
+ catch (err) {
63
+ if (err instanceof KubernetesAlreadyGoneError)
64
+ return undefined;
65
+ throw err;
66
+ }
67
+ }
68
+ /**
69
+ * One GET pass: the Sandbox, each of its claims, the pod behind the name.
70
+ * `undefined` is "no Sandbox"; every other failure travels out as itself, so
71
+ * a read that did not answer is never reported as a workspace that is gone.
72
+ */
73
+ async function observe(client, namespace, name, signal) {
74
+ const sandbox = await readOrGone(client, sandboxPath(namespace, name), signal);
75
+ if (sandbox === undefined)
76
+ return undefined;
77
+ const sandboxUid = sandbox.metadata?.uid;
78
+ const claims = new Map();
79
+ const claimNames = [];
80
+ for (const entry of sandbox.spec?.volumeClaimTemplates ?? []) {
81
+ const claimName = entry?.metadata?.name;
82
+ if (typeof claimName !== 'string' || claimName === '')
83
+ continue;
84
+ claimNames.push(claimName);
85
+ const claim = await readOrGone(client, persistentVolumeClaimPath(namespace, name, claimName), signal);
86
+ const uid = claim?.metadata?.uid;
87
+ if (typeof uid !== 'string' || uid === '')
88
+ continue;
89
+ const owners = claim?.metadata?.ownerReferences ?? [];
90
+ // Only a claim that NAMES owners and names none of them this Sandbox is
91
+ // foreign; one with no owner list says nothing, and refusing it would
92
+ // refuse a cluster that simply does not report them.
93
+ const foreign = sandboxUid !== undefined && owners.length > 0 && !owners.some((o) => o?.uid === sandboxUid);
94
+ claims.set(claimName, { uid, ownedByOtherSandbox: foreign });
95
+ }
96
+ const pod = await readOrGone(client, podPath(namespace, name), signal);
97
+ return { sandbox, sandboxUid, claims, claimNames, pod };
98
+ }
99
+ function operatingModeOf(sandbox) {
100
+ return sandbox.spec?.operatingMode === 'Suspended' ? 'Suspended' : 'Running';
101
+ }
102
+ /**
103
+ * `Ready` is true AND is about the object's current spec. The controller
104
+ * keeps a `Ready: True` it wrote for an earlier generation visible after a
105
+ * spec change, and reading that as the new outcome is how a wake gets
106
+ * reported ready while its pod is still being replaced.
107
+ */
108
+ function isReadyForCurrentGeneration(sandbox) {
109
+ const condition = sandbox.status?.conditions?.find((c) => c.type === READY_CONDITION);
110
+ if (condition?.status !== 'True')
111
+ return false;
112
+ const generation = sandbox.metadata?.generation;
113
+ const observed = condition.observedGeneration;
114
+ return !(generation !== undefined && observed !== undefined && observed < generation);
115
+ }
116
+ function inspectionOf(workspaceId, name, seen) {
117
+ const livePod = isPodLive(seen.pod) ? seen.pod : undefined;
118
+ const podUid = livePod?.metadata?.uid;
119
+ const uids = {};
120
+ for (const [claimName, claim] of seen.claims)
121
+ uids[claimName] = claim.uid;
122
+ const mode = operatingModeOf(seen.sandbox);
123
+ return {
124
+ workspaceId,
125
+ sandboxName: name,
126
+ operatingMode: mode,
127
+ identity: {
128
+ sandboxUid: seen.sandboxUid,
129
+ volumeClaimUids: uids,
130
+ podUid: mode === 'Suspended' ? undefined : podUid,
131
+ guestBootId: undefined,
132
+ },
133
+ holderEpoch: readHolderEpoch(seen.sandbox.metadata).epoch ?? 0,
134
+ allocation: observedAllocation(seen.sandbox),
135
+ ready: mode === 'Running' &&
136
+ isReadyForCurrentGeneration(seen.sandbox) &&
137
+ typeof podUid === 'string' &&
138
+ podUid !== '',
139
+ missingVolumeClaims: seen.claimNames.filter((n) => !seen.claims.has(n)),
140
+ };
141
+ }
142
+ /**
143
+ * The first way `seen` is not the retained workspace, or `undefined`.
144
+ *
145
+ * `claimUids` is every claim uid trusted so far: the retained ones, and every
146
+ * one a previous pass of the same wait saw. A claim that is not there yet is
147
+ * not a mismatch; one that is there with a DIFFERENT uid than one already
148
+ * trusted is.
149
+ */
150
+ function firstMismatch(retained, claimUids, seen) {
151
+ if (seen.sandboxUid !== retained.sandboxUid) {
152
+ return { kind: 'sandbox-uid', expected: retained.sandboxUid, actual: seen.sandboxUid };
153
+ }
154
+ for (const [claimName, claim] of seen.claims) {
155
+ const trusted = claimUids[claimName];
156
+ if (trusted !== undefined && trusted !== claim.uid) {
157
+ return { kind: 'volume-claim-uid', expected: trusted, actual: claim.uid, claim: claimName };
158
+ }
159
+ if (claim.ownedByOtherSandbox) {
160
+ return {
161
+ kind: 'volume-claim-owner',
162
+ expected: retained.sandboxUid,
163
+ actual: claim.uid,
164
+ claim: claimName,
165
+ };
166
+ }
167
+ }
168
+ return undefined;
169
+ }
170
+ function assertRetained(identity, where) {
171
+ if (typeof identity?.sandboxUid !== 'string' || identity.sandboxUid === '') {
172
+ throw new TypeError(`kubernetes: ${where} needs identity.sandboxUid, a non-empty string — without it there is nothing to authenticate.`);
173
+ }
174
+ }
175
+ function assertEpochAllows(operation, workspaceId, name, epoch, sandbox) {
176
+ const reading = readHolderEpoch(sandbox.metadata);
177
+ if (reading.epoch !== undefined && reading.epoch <= epoch)
178
+ return;
179
+ throw new KubernetesWorkspacePreconditionError(operation, workspaceId, name, epoch, reading.epoch, reading.annotation);
180
+ }
181
+ function assertExpectedAllocation(workspaceId, name, sandbox, expected) {
182
+ if (expected === undefined)
183
+ return;
184
+ const mismatch = firstAllocationMismatch(sandbox, expected);
185
+ if (mismatch === undefined)
186
+ return;
187
+ throw new KubernetesWorkspaceAllocationMismatchError(workspaceId, name, mismatch.kind, mismatch.expected, mismatch.actual);
188
+ }
189
+ function clientFor(config) {
190
+ return createKubernetesClient(clientAccess(config), clientOptions(config));
191
+ }
192
+ /**
193
+ * Read what stands under a workspace id: its Sandbox uid, its claim uids, its
194
+ * pod and its operating mode, and who holds it. GET requests only — nothing
195
+ * is created, woken, patched or deleted — and `undefined` when no Sandbox
196
+ * stands there.
197
+ *
198
+ * Needs `get` on `sandboxes`, `persistentvolumeclaims` and `pods`. A failed
199
+ * read rejects as itself: an unanswered request is never reported as a
200
+ * workspace that is absent.
201
+ */
202
+ export async function inspectKubernetesWorkspace(config, workspaceId, options) {
203
+ options.signal?.throwIfAborted();
204
+ const epoch = assertHolderEpoch(options.epoch, 'inspectKubernetesWorkspace');
205
+ if (epoch === undefined) {
206
+ throw new TypeError('kubernetes: inspectKubernetesWorkspace needs an epoch.');
207
+ }
208
+ if (options.expectedAllocation !== undefined) {
209
+ assertAllocation(options.expectedAllocation, 'inspectKubernetesWorkspace');
210
+ }
211
+ const name = workspaceSandboxName(workspaceId);
212
+ const seen = await observe(clientFor(config), config.namespace, name, options.signal);
213
+ if (seen === undefined)
214
+ return undefined;
215
+ assertEpochAllows('inspectKubernetesWorkspace', workspaceId, name, epoch, seen.sandbox);
216
+ assertExpectedAllocation(workspaceId, name, seen.sandbox, options.expectedAllocation);
217
+ return inspectionOf(workspaceId, name, seen);
218
+ }
219
+ /**
220
+ * Authenticate a retained identity against what stands under the workspace
221
+ * id, and — with `waitForReady` — wait for it to be usable. Never creates,
222
+ * wakes or writes.
223
+ *
224
+ * Refuses with {@link KubernetesWorkspaceIdentityMismatchError} when the
225
+ * Sandbox is gone or has another uid, or a claim has another uid or another
226
+ * owner, and with `KubernetesWorkspacePreconditionError` when the workspace
227
+ * is held at a higher epoch. The waiting form repeats both checks on every
228
+ * pass and retains every claim uid it has seen, so a replacement that lands
229
+ * mid-wait is a refusal rather than a longer wait. Cancelling `signal`
230
+ * rejects with its reason; running out of `readyTimeoutMs` rejects with
231
+ * {@link KubernetesWorkspaceReadyTimeoutError}. The three never share a class.
232
+ */
233
+ export async function openKubernetesWorkspace(config, options) {
234
+ options.signal?.throwIfAborted();
235
+ const { workspaceId } = options;
236
+ assertRetained(options.identity, 'openKubernetesWorkspace');
237
+ if (options.expectedAllocation !== undefined) {
238
+ assertAllocation(options.expectedAllocation, 'openKubernetesWorkspace');
239
+ }
240
+ const epoch = assertHolderEpoch(options.epoch, 'openKubernetesWorkspace');
241
+ if (epoch === undefined)
242
+ throw new TypeError('kubernetes: openKubernetesWorkspace needs an epoch.');
243
+ const name = workspaceSandboxName(workspaceId);
244
+ const client = clientFor(config);
245
+ const trusted = { ...(options.identity.volumeClaimUids ?? {}) };
246
+ const wait = options.waitForReady === true;
247
+ const readiness = resolveKubernetesReadiness(config);
248
+ const deadline = new OperationDeadline(readiness.timeoutMs, `kubernetes workspace ${name} open`, options.signal);
249
+ const pass = async (signal) => {
250
+ const seen = await observe(client, config.namespace, name, signal);
251
+ if (seen === undefined) {
252
+ throw new KubernetesWorkspaceIdentityMismatchError(workspaceId, name, 'sandbox-absent', options.identity.sandboxUid, undefined);
253
+ }
254
+ const mismatch = firstMismatch(options.identity, trusted, seen);
255
+ if (mismatch !== undefined) {
256
+ throw new KubernetesWorkspaceIdentityMismatchError(workspaceId, name, mismatch.kind, mismatch.expected, mismatch.actual, mismatch.claim);
257
+ }
258
+ assertEpochAllows('openKubernetesWorkspace', workspaceId, name, epoch, seen.sandbox);
259
+ assertExpectedAllocation(workspaceId, name, seen.sandbox, options.expectedAllocation);
260
+ for (const [claimName, claim] of seen.claims)
261
+ trusted[claimName] = claim.uid;
262
+ return inspectionOf(workspaceId, name, seen);
263
+ };
264
+ if (!wait)
265
+ return await pass(options.signal);
266
+ let last;
267
+ while (deadline.remainingMs() > 0) {
268
+ try {
269
+ last = await deadline.run((signal) => pass(signal));
270
+ }
271
+ catch (err) {
272
+ if (err instanceof OperationDeadlineExpired)
273
+ break;
274
+ throw err;
275
+ }
276
+ if (last.operatingMode === 'Suspended')
277
+ return last;
278
+ if (last.missingVolumeClaims.length === 0 && last.ready)
279
+ return last;
280
+ try {
281
+ await deadline.delay(readiness.pollIntervalMs);
282
+ }
283
+ catch (err) {
284
+ if (err instanceof OperationDeadlineExpired)
285
+ break;
286
+ throw err;
287
+ }
288
+ }
289
+ options.signal?.throwIfAborted();
290
+ if (last === undefined) {
291
+ // The deadline expired before the first pass answered. That is an
292
+ // unanswered read, not a workspace that is not ready, and it is said so.
293
+ throw new OperationDeadlineExpired(`kubernetes workspace ${name} open`);
294
+ }
295
+ throw new KubernetesWorkspaceReadyTimeoutError(workspaceId, name, readiness.timeoutMs, [
296
+ ...(last.missingVolumeClaims.length > 0 ? ['volume-claims'] : []),
297
+ ...(last.identity.podUid === undefined ? ['pod'] : []),
298
+ ...(last.ready ? [] : ['ready-condition']),
299
+ ], last);
300
+ }
301
+ /**
302
+ * After a restart: what became of the workspace a host retained? One
303
+ * GET-only pass, answered as a closure state rather than thrown.
304
+ *
305
+ * A different Sandbox or claim is `replaced`, not an error, because for a
306
+ * host closing its books that IS the answer. A read that did not answer
307
+ * rejects as itself — it is never mapped to `absent`.
308
+ */
309
+ export async function reconcileKubernetesWorkspace(config, options) {
310
+ options.signal?.throwIfAborted();
311
+ const { workspaceId } = options;
312
+ assertRetained(options.identity, 'reconcileKubernetesWorkspace');
313
+ if (options.expectedAllocation !== undefined) {
314
+ assertAllocation(options.expectedAllocation, 'reconcileKubernetesWorkspace');
315
+ }
316
+ const epoch = assertHolderEpoch(options.epoch, 'reconcileKubernetesWorkspace');
317
+ const name = workspaceSandboxName(workspaceId);
318
+ const seen = await observe(clientFor(config), config.namespace, name, options.signal);
319
+ if (seen === undefined)
320
+ return { state: 'absent', workspaceId, sandboxName: name };
321
+ const inspection = inspectionOf(workspaceId, name, seen);
322
+ const mismatch = firstMismatch(options.identity, { ...(options.identity.volumeClaimUids ?? {}) }, seen);
323
+ if (mismatch !== undefined) {
324
+ return {
325
+ state: 'replaced',
326
+ workspaceId,
327
+ sandboxName: name,
328
+ identity: inspection.identity,
329
+ mismatch: mismatch.kind,
330
+ };
331
+ }
332
+ if (epoch !== undefined) {
333
+ assertEpochAllows('reconcileKubernetesWorkspace', workspaceId, name, epoch, seen.sandbox);
334
+ }
335
+ assertExpectedAllocation(workspaceId, name, seen.sandbox, options.expectedAllocation);
336
+ return {
337
+ state: inspection.operatingMode === 'Suspended' ? 'suspended' : 'live',
338
+ workspaceId,
339
+ sandboxName: name,
340
+ identity: inspection.identity,
341
+ };
342
+ }
343
+ //# sourceMappingURL=workspace-observe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace-observe.js","sourceRoot":"","sources":["../../../src/backends/kubernetes/workspace-observe.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Per-sandbox egress on a workspace: the pieces `createKubernetesWorkspace`,
3
+ * `allocateKubernetesWorkspace` and a workspace handle share.
4
+ *
5
+ * ## The shape, and where it differs from a task sandbox
6
+ *
7
+ * - **Label.** The per-sandbox selector label rides on the workspace's
8
+ * directly created `Sandbox` pod template, composed by
9
+ * `composeAdditionalPodLabels` beside the egress profile. Its VALUE is the
10
+ * Sandbox's own name, `namzu-ws-<workspaceId>`: deterministic, known before
11
+ * the POST, and stable across a suspend and a resume, because a resume
12
+ * patches `operatingMode` and the pod template (labels included) is carried
13
+ * by the object, not by the pod.
14
+ * - **Owner.** The `Sandbox` itself. A policy names it in `ownerReferences`
15
+ * with its `metadata.uid`, so deleting the workspace (`destroy({ deleteDisk:
16
+ * true })`, `deleteKubernetesWorkspace`) lets the cluster's garbage
17
+ * collector remove every policy it owns. The default `destroy()` only
18
+ * suspends, keeps the object, and so keeps the policy.
19
+ * - **Name.** `namzu-sbx-<sandbox uid>`, the same rule as a task sandbox. The
20
+ * workspace NAME is deterministic and its uid is not, so a workspace deleted
21
+ * and created again under the same name selects by the same label value
22
+ * and owns a policy of a different name.
23
+ *
24
+ * ## Suspend and resume
25
+ *
26
+ * The behaviour is one rule, applied on every path that is about to run the
27
+ * workspace's pod: a resume, and an open of an existing workspace.
28
+ *
29
+ * 1. The admission fence is re-verified from scratch (never from a memo). A
30
+ * fence that is missing or would not enforce REFUSES the resume, before
31
+ * the patch: the workspace stays suspended, which is the only state that
32
+ * is safe without the fence, and nothing is written.
33
+ * 2. Every per-sandbox policy in the namespace that selects this workspace
34
+ * (name prefix `namzu-sbx-`, selector label value equal to the Sandbox's
35
+ * name) and that this Sandbox does not own (no `ownerReferences` entry of
36
+ * kind `Sandbox` with this name and the uid the cluster reports NOW) is
37
+ * deleted. Such a policy belongs to a workspace that was deleted and
38
+ * created again under the same name and has not been garbage-collected
39
+ * yet; left alone it would grant the new workspace what the old one's
40
+ * consent covered.
41
+ * 3. A policy this Sandbox owns is KEPT, unchanged. A suspend is not a
42
+ * revocation: the grant was admitted by the fence when it was written and
43
+ * the resumed pod carries the same label, so the policy applies to it
44
+ * again. A host that wants the grant gone calls `setNetworkPolicy({
45
+ * allowedHosts: [] })` (which deletes it) before it suspends.
46
+ *
47
+ * A freshly created workspace gets step 2 after the create reply, with the uid
48
+ * the reply carried.
49
+ *
50
+ * ## What is NOT proven here
51
+ *
52
+ * That any of it is enforced. Enforcement is the CNI's data plane: it needs a
53
+ * cluster running Cilium, the same as the task path.
54
+ */
55
+ import type { KubernetesEgressConfig, KubernetesPerSandboxEgressConfig } from './egress-policy.js';
56
+ import { type KubernetesClient } from './k8s-client.js';
57
+ import { type PerSandboxPolicyFence } from './per-sandbox-policy.js';
58
+ /** The profile variant a workspace with per-sandbox egress configured carries. */
59
+ export declare const KUBERNETES_PER_SANDBOX_PROFILE_VARIANT = "core/no-network+per-sandbox";
60
+ /**
61
+ * The extra pod-label map a workspace named `sandboxName` contributes to
62
+ * `composeAdditionalPodLabels`, or `undefined` when `perSandbox` is not
63
+ * configured, which is what keeps that workspace's request log unchanged.
64
+ */
65
+ export declare function perSandboxWorkspaceLabels(egress: KubernetesEgressConfig | undefined, sandboxName: string): Readonly<Record<string, string>> | undefined;
66
+ /** `labels` without the per-sandbox key `extra` carries; `labels` itself when there is none. */
67
+ export declare function withoutPerSandboxLabel(labels: Readonly<Record<string, string>>, extra: Readonly<Record<string, string>> | undefined): Readonly<Record<string, string>>;
68
+ /**
69
+ * The names of the per-sandbox policies this workspace's label selects and
70
+ * its Sandbox does not own. Read only.
71
+ */
72
+ export declare function findForeignPerSandboxPolicies(client: KubernetesClient, namespace: string, labelKey: string, sandboxName: string, ownerUid: string, signal?: AbortSignal): Promise<readonly string[]>;
73
+ /** What {@link reverifyPerSandboxEgress} needs. */
74
+ export interface PerSandboxReverification {
75
+ readonly client: KubernetesClient;
76
+ readonly namespace: string;
77
+ readonly sandboxName: string;
78
+ /** The uid the cluster reports for the Sandbox NOW. */
79
+ readonly ownerUid: string;
80
+ readonly egress: KubernetesEgressConfig & {
81
+ readonly perSandbox: KubernetesPerSandboxEgressConfig;
82
+ };
83
+ /** A fence whose memo has not been used yet. */
84
+ readonly fence: PerSandboxPolicyFence;
85
+ readonly signal?: AbortSignal;
86
+ }
87
+ /**
88
+ * Steps 1 and 2 of the resume rule above: prove the fence, then delete the
89
+ * policies that select this workspace and that its Sandbox does not own.
90
+ * Returns the names it deleted. Throws the fence's own refusal, having
91
+ * written nothing, when the fence does not verify.
92
+ */
93
+ export declare function reverifyPerSandboxEgress(options: PerSandboxReverification): Promise<readonly string[]>;
94
+ //# sourceMappingURL=workspace-per-sandbox.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace-per-sandbox.d.ts","sourceRoot":"","sources":["../../../src/backends/kubernetes/workspace-per-sandbox.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AAEH,OAAO,KAAK,EAAE,sBAAsB,EAAE,gCAAgC,EAAE,MAAM,oBAAoB,CAAA;AAElG,OAAO,EAA8B,KAAK,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAEnF,OAAO,EAAkC,KAAK,qBAAqB,EAAE,MAAM,yBAAyB,CAAA;AAEpG,kFAAkF;AAClF,eAAO,MAAM,sCAAsC,gCAAgC,CAAA;AAEnF;;;;GAIG;AACH,wBAAgB,yBAAyB,CACxC,MAAM,EAAE,sBAAsB,GAAG,SAAS,EAC1C,WAAW,EAAE,MAAM,GACjB,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,CAG9C;AAED,gGAAgG;AAChG,wBAAgB,sBAAsB,CACrC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,EACxC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,GACjD,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAGlC;AAmBD;;;GAGG;AACH,wBAAsB,6BAA6B,CAClD,MAAM,EAAE,gBAAgB,EACxB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,WAAW,GAClB,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC,CAkB5B;AAED,mDAAmD;AACnD,MAAM,WAAW,wBAAwB;IACxC,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAA;IACjC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,uDAAuD;IACvD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,MAAM,EAAE,sBAAsB,GAAG;QACzC,QAAQ,CAAC,UAAU,EAAE,gCAAgC,CAAA;KACrD,CAAA;IACD,gDAAgD;IAChD,QAAQ,CAAC,KAAK,EAAE,qBAAqB,CAAA;IACrC,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAA;CAC7B;AAED;;;;;GAKG;AACH,wBAAsB,wBAAwB,CAC7C,OAAO,EAAE,wBAAwB,GAC/B,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC,CAqB5B"}