@stigmer/server 3.18.0-dev.20260918103812 → 3.18.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 (75) hide show
  1. package/dist/boot/compose.d.ts +12 -0
  2. package/dist/boot/compose.d.ts.map +1 -1
  3. package/dist/boot/compose.js +4 -2
  4. package/dist/boot/compose.js.map +1 -1
  5. package/dist/domain/agentexecution/lifecycle.js +1 -1
  6. package/dist/domain/agentexecution/lifecycle.js.map +1 -1
  7. package/dist/domain/iampolicy/constants.d.ts +3 -3
  8. package/dist/domain/iampolicy/constants.js +3 -3
  9. package/dist/domain/oauthapp/refresolution/refresolution.js +1 -1
  10. package/dist/domain/oauthapp/refresolution.js +1 -1
  11. package/dist/domain/platform/controller.d.ts +8 -1
  12. package/dist/domain/platform/controller.d.ts.map +1 -1
  13. package/dist/domain/platform/controller.js +2 -3
  14. package/dist/domain/platform/controller.js.map +1 -1
  15. package/dist/domain/plugin/constants.d.ts +7 -1
  16. package/dist/domain/plugin/constants.d.ts.map +1 -1
  17. package/dist/domain/plugin/constants.js +7 -1
  18. package/dist/domain/plugin/constants.js.map +1 -1
  19. package/dist/domain/plugin/materialize/plan.d.ts.map +1 -1
  20. package/dist/domain/plugin/materialize/plan.js +16 -1
  21. package/dist/domain/plugin/materialize/plan.js.map +1 -1
  22. package/dist/domain/plugin/members.d.ts +46 -0
  23. package/dist/domain/plugin/members.d.ts.map +1 -1
  24. package/dist/domain/plugin/members.js +31 -8
  25. package/dist/domain/plugin/members.js.map +1 -1
  26. package/dist/domain/plugin/push.d.ts +5 -3
  27. package/dist/domain/plugin/push.d.ts.map +1 -1
  28. package/dist/domain/plugin/push.js +58 -14
  29. package/dist/domain/plugin/push.js.map +1 -1
  30. package/dist/domain/workflowexecution/lifecycle.js +1 -1
  31. package/dist/domain/workflowexecution/lifecycle.js.map +1 -1
  32. package/dist/pipeline/apiresource-labels.d.ts +20 -1
  33. package/dist/pipeline/apiresource-labels.d.ts.map +1 -1
  34. package/dist/pipeline/apiresource-labels.js +17 -0
  35. package/dist/pipeline/apiresource-labels.js.map +1 -1
  36. package/dist/sandbox/kubernetes.d.ts.map +1 -1
  37. package/dist/sandbox/kubernetes.js +1 -8
  38. package/dist/sandbox/kubernetes.js.map +1 -1
  39. package/dist/sandbox/provisioner.d.ts +5 -20
  40. package/dist/sandbox/provisioner.d.ts.map +1 -1
  41. package/dist/sandbox/provisioner.js.map +1 -1
  42. package/dist/sandbox/steps.d.ts +8 -22
  43. package/dist/sandbox/steps.d.ts.map +1 -1
  44. package/dist/sandbox/steps.js +12 -17
  45. package/dist/sandbox/steps.js.map +1 -1
  46. package/dist/store/interface.d.ts +6 -2
  47. package/dist/store/interface.d.ts.map +1 -1
  48. package/dist/store/interface.js.map +1 -1
  49. package/package.json +5 -5
  50. package/src/boot/compose.ts +16 -2
  51. package/src/domain/agentexecution/lifecycle.ts +1 -1
  52. package/src/domain/iampolicy/constants.ts +3 -3
  53. package/src/domain/oauthapp/__tests__/oauthapp.test.ts +2 -2
  54. package/src/domain/oauthapp/__tests__/refresolution.test.ts +2 -2
  55. package/src/domain/oauthapp/refresolution/refresolution.ts +1 -1
  56. package/src/domain/oauthapp/refresolution.ts +1 -1
  57. package/src/domain/platform/__tests__/platform.test.ts +47 -0
  58. package/src/domain/platform/controller.ts +10 -4
  59. package/src/domain/plugin/__tests__/materialize.test.ts +42 -47
  60. package/src/domain/plugin/__tests__/members.test.ts +149 -0
  61. package/src/domain/plugin/__tests__/plugin.test.ts +219 -8
  62. package/src/domain/plugin/constants.ts +7 -1
  63. package/src/domain/plugin/materialize/plan.ts +20 -1
  64. package/src/domain/plugin/members.ts +76 -7
  65. package/src/domain/plugin/push.ts +80 -20
  66. package/src/domain/workflowexecution/lifecycle.ts +1 -1
  67. package/src/pipeline/apiresource-labels.ts +26 -1
  68. package/src/sandbox/__tests__/docker.integration.test.ts +0 -2
  69. package/src/sandbox/__tests__/kubernetes.test.ts +2 -10
  70. package/src/sandbox/__tests__/local-process.integration.test.ts +0 -3
  71. package/src/sandbox/__tests__/steps.test.ts +19 -72
  72. package/src/sandbox/kubernetes.ts +1 -8
  73. package/src/sandbox/provisioner.ts +5 -20
  74. package/src/sandbox/steps.ts +12 -29
  75. package/src/store/interface.ts +6 -2
@@ -11,10 +11,7 @@
11
11
  * - the terminal observer deprovisions exactly on transitions INTO a
12
12
  * terminal phase, fire-and-forget, and swallows (logs) teardown
13
13
  * failures;
14
- * - a disabled mint lane launches token-less rather than failing;
15
- * - the caller splits two ways on both lanes: the identity id reaches
16
- * the credential mint, the caller class reaches the driver's
17
- * environment unchanged (a composed lane such as `guest` included).
14
+ * - a disabled mint lane launches token-less rather than failing.
18
15
  */
19
16
  import { mkdtempSync, rmSync } from "node:fs";
20
17
  import { tmpdir } from "node:os";
@@ -56,25 +53,14 @@ import {
56
53
  ensureWorkflowSandboxForExecution,
57
54
  newWorkflowSandboxTerminalObserver,
58
55
  SANDBOX_PROVISIONING_FAILED_PREFIX,
59
- type SandboxCaller,
60
56
  } from "../steps.js";
61
57
 
62
58
  /**
63
- * The caller the ensure bodies split two ways: the identity id into the
64
- * credential mint (C4 — the OSS execution-scoped mint ignores it, so the
65
- * token assertions stay binding-shaped) and the class onto the driver's
66
- * environment. `user` is the plain lane; the class-propagation cases hand
67
- * in a composed lane's word to prove the body copies, never normalises.
59
+ * The caller identity the ensure bodies thread into the credential mint
60
+ * (C4): the OSS execution-scoped mint ignores it, so these tests pass a
61
+ * fixed value and the token assertions stay binding-shaped.
68
62
  */
69
63
  const TEST_CALLER_IDENTITY_ID = "ida_test_caller";
70
- const TEST_CALLER: SandboxCaller = {
71
- identityId: TEST_CALLER_IDENTITY_ID,
72
- callerClass: "user",
73
- };
74
- const GUEST_CALLER: SandboxCaller = {
75
- identityId: "ida_guest_caller",
76
- callerClass: "guest",
77
- };
78
64
 
79
65
  const silentLogger = createLogger({
80
66
  level: "error",
@@ -249,7 +235,7 @@ describe("the session lane (ensureSessionSandboxForExecution)", () => {
249
235
  temporalConfig: sessionRoutingCloudDefault,
250
236
  },
251
237
  execution,
252
- TEST_CALLER,
238
+ TEST_CALLER_IDENTITY_ID,
253
239
  );
254
240
  expect(provisioner.ensured).toEqual([
255
241
  {
@@ -258,32 +244,11 @@ describe("the session lane (ensureSessionSandboxForExecution)", () => {
258
244
  env: {
259
245
  taskQueue: `session:${sessionId}`,
260
246
  stigmerToken: `tok-${execution.metadata?.id ?? ""}`,
261
- callerClass: "user",
262
247
  },
263
248
  },
264
249
  ]);
265
250
  });
266
251
 
267
- it("hands the caller's class to the driver unchanged and the caller's id to the mint", async () => {
268
- const provisioner = fakeProvisioner();
269
- const credentials = capabilityCredentials();
270
- const { execution } = await seed(ExecutionTarget.CLOUD);
271
- await ensureSessionSandboxForExecution(
272
- {
273
- store,
274
- logger: silentLogger,
275
- lane: lane(provisioner, credentials),
276
- temporalConfig: sessionRoutingCloudDefault,
277
- },
278
- execution,
279
- GUEST_CALLER,
280
- );
281
- expect(provisioner.ensured[0]?.env.callerClass).toBe("guest");
282
- expect(credentials.minted[0]?.callerIdentityId).toBe(
283
- GUEST_CALLER.identityId,
284
- );
285
- });
286
-
287
252
  it("delegates the mint to the capability provider with the full provisioning context (C4)", async () => {
288
253
  const provisioner = fakeProvisioner();
289
254
  const credentials = capabilityCredentials();
@@ -312,7 +277,7 @@ describe("the session lane (ensureSessionSandboxForExecution)", () => {
312
277
  temporalConfig: sessionRoutingCloudDefault,
313
278
  },
314
279
  execution,
315
- TEST_CALLER,
280
+ TEST_CALLER_IDENTITY_ID,
316
281
  );
317
282
 
318
283
  expect(credentials.minted).toEqual([
@@ -338,7 +303,7 @@ describe("the session lane (ensureSessionSandboxForExecution)", () => {
338
303
  temporalConfig: sessionRoutingCloudDefault,
339
304
  },
340
305
  execution,
341
- TEST_CALLER,
306
+ TEST_CALLER_IDENTITY_ID,
342
307
  );
343
308
  expect(provisioner.ensured).toEqual([]);
344
309
  });
@@ -362,7 +327,7 @@ describe("the session lane (ensureSessionSandboxForExecution)", () => {
362
327
  temporalConfig: sessionRoutingCloudDefault,
363
328
  },
364
329
  execution,
365
- TEST_CALLER,
330
+ TEST_CALLER_IDENTITY_ID,
366
331
  );
367
332
  });
368
333
 
@@ -380,7 +345,7 @@ describe("the session lane (ensureSessionSandboxForExecution)", () => {
380
345
  temporalConfig: sessionRoutingCloudDefault,
381
346
  },
382
347
  execution,
383
- TEST_CALLER,
348
+ TEST_CALLER_IDENTITY_ID,
384
349
  );
385
350
  expect(provisioner.ensured).toEqual([]);
386
351
  });
@@ -401,7 +366,7 @@ describe("the session lane (ensureSessionSandboxForExecution)", () => {
401
366
  ),
402
367
  },
403
368
  execution,
404
- TEST_CALLER,
369
+ TEST_CALLER_IDENTITY_ID,
405
370
  );
406
371
  expect(provisioner.ensured).toEqual([]);
407
372
  });
@@ -417,7 +382,7 @@ describe("the session lane (ensureSessionSandboxForExecution)", () => {
417
382
  temporalConfig: sessionRoutingCloudDefault,
418
383
  },
419
384
  execution,
420
- TEST_CALLER,
385
+ TEST_CALLER_IDENTITY_ID,
421
386
  );
422
387
  expect(provisioner.ensured[0]?.env.stigmerToken).toBe("");
423
388
  });
@@ -436,7 +401,7 @@ describe("the session lane (ensureSessionSandboxForExecution)", () => {
436
401
  temporalConfig: sessionRoutingCloudDefault,
437
402
  },
438
403
  execution,
439
- TEST_CALLER,
404
+ TEST_CALLER_IDENTITY_ID,
440
405
  );
441
406
  const stamped = await store.getResource(
442
407
  ApiResourceKind.agent_execution,
@@ -474,7 +439,7 @@ describe("the session lane (ensureSessionSandboxForExecution)", () => {
474
439
  temporalConfig: sessionRoutingCloudDefault,
475
440
  },
476
441
  execution,
477
- TEST_CALLER,
442
+ TEST_CALLER_IDENTITY_ID,
478
443
  );
479
444
  const after = await store.getResource(
480
445
  ApiResourceKind.agent_execution,
@@ -502,35 +467,17 @@ describe("the workflow lane (ensureWorkflowSandboxForExecution)", () => {
502
467
  temporalConfig: executionRoutingConfig,
503
468
  },
504
469
  workflowExecution(ExecutionTarget.CLOUD),
505
- TEST_CALLER,
470
+ TEST_CALLER_IDENTITY_ID,
506
471
  );
507
472
  expect(provisioner.ensured).toEqual([
508
473
  {
509
474
  scope: "workflow",
510
475
  id: "wfx_sbx_1",
511
- env: {
512
- taskQueue: "wfexec:wfx_sbx_1",
513
- stigmerToken: "tok-wfx_sbx_1",
514
- callerClass: "user",
515
- },
476
+ env: { taskQueue: "wfexec:wfx_sbx_1", stigmerToken: "tok-wfx_sbx_1" },
516
477
  },
517
478
  ]);
518
479
  });
519
480
 
520
- it("hands the caller's class to the driver unchanged on the workflow lane", async () => {
521
- const provisioner = fakeProvisioner();
522
- await ensureWorkflowSandboxForExecution(
523
- {
524
- logger: silentLogger,
525
- lane: lane(provisioner),
526
- temporalConfig: executionRoutingConfig,
527
- },
528
- workflowExecution(ExecutionTarget.CLOUD),
529
- GUEST_CALLER,
530
- );
531
- expect(provisioner.ensured[0]?.env.callerClass).toBe("guest");
532
- });
533
-
534
481
  it("delegates the mint to the capability provider on the workflow scope (C4)", async () => {
535
482
  const provisioner = fakeProvisioner();
536
483
  const credentials = capabilityCredentials();
@@ -544,7 +491,7 @@ describe("the workflow lane (ensureWorkflowSandboxForExecution)", () => {
544
491
  metadata: { id: "wfx_sbx_cap", name: "wfx_sbx_cap", org: "org-test" },
545
492
  spec: { executionTarget: ExecutionTarget.CLOUD },
546
493
  }),
547
- TEST_CALLER,
494
+ TEST_CALLER_IDENTITY_ID,
548
495
  );
549
496
  expect(credentials.minted).toEqual([
550
497
  {
@@ -567,7 +514,7 @@ describe("the workflow lane (ensureWorkflowSandboxForExecution)", () => {
567
514
  temporalConfig: executionRoutingConfig,
568
515
  },
569
516
  workflowExecution(ExecutionTarget.LOCAL),
570
- TEST_CALLER,
517
+ TEST_CALLER_IDENTITY_ID,
571
518
  );
572
519
  await ensureWorkflowSandboxForExecution(
573
520
  {
@@ -581,7 +528,7 @@ describe("the workflow lane (ensureWorkflowSandboxForExecution)", () => {
581
528
  ),
582
529
  },
583
530
  workflowExecution(ExecutionTarget.CLOUD),
584
- TEST_CALLER,
531
+ TEST_CALLER_IDENTITY_ID,
585
532
  );
586
533
  expect(provisioner.ensured).toEqual([]);
587
534
  });
@@ -598,7 +545,7 @@ describe("the workflow lane (ensureWorkflowSandboxForExecution)", () => {
598
545
  temporalConfig: executionRoutingConfig,
599
546
  },
600
547
  workflowExecution(ExecutionTarget.CLOUD),
601
- TEST_CALLER,
548
+ TEST_CALLER_IDENTITY_ID,
602
549
  );
603
550
  expect.unreachable("the workflow lane must throw on failure");
604
551
  } catch (error) {
@@ -85,14 +85,7 @@ const RUNNER_RESOURCES = {
85
85
  limits: { cpu: "2", memory: "2Gi" },
86
86
  } as const;
87
87
 
88
- /**
89
- * The persistent-workspace scopes (SandboxScope.persistentWorkspace).
90
- * Durability here is decided by SCOPE alone: this driver reads neither the
91
- * environment's caller class nor any per-session policy, so every session
92
- * keeps its PVC whoever asked. A driver that gives some caller classes a
93
- * workspace that dies with the conversation is a composition's choice
94
- * built on SandboxEnvironment.callerClass, not a built-in behaviour.
95
- */
88
+ /** The persistent-workspace scopes (SandboxScope.persistentWorkspace). */
96
89
  const PERSISTENT_SCOPES: ReadonlySet<SandboxScope> = new Set([
97
90
  "session",
98
91
  "workflow",
@@ -39,16 +39,13 @@
39
39
  * runner process polls the queues.
40
40
  */
41
41
  import type { Logger } from "../boot/logger.js";
42
- import type { CallerClass } from "../extensions/identity.js";
43
42
 
44
43
  /**
45
- * What is TRUE about one provisioning request, handed to a driver: which
46
- * queue the sandboxed runner must poll, the credential it authenticates
47
- * with, and the class of the caller whose request is being served. Facts
48
- * only — what a driver DOES with them (the workspace's durability, the
49
- * pod's shape, whether a warm pool is consulted) is driver policy and
50
- * never travels here. Endpoints, images and resource shapes are driver
51
- * configuration, not per-sandbox state.
44
+ * The runtime handed to a provisioner for one sandbox: which queue the
45
+ * sandboxed runner must poll and the credential it authenticates with.
46
+ * Deliberately minimal (the Java SandboxEnvironment carries the same two
47
+ * load-bearing fields plus cloud-only accounting) — endpoints, images,
48
+ * and resource shapes are DRIVER configuration, not per-sandbox state.
52
49
  */
53
50
  export interface SandboxEnvironment {
54
51
  /** The Temporal task queue the sandboxed runner polls (session:{id} / wfexec:{id}). */
@@ -59,18 +56,6 @@ export interface SandboxEnvironment {
59
56
  * and EC decrypt falls back to redaction, the oss#535 posture.
60
57
  */
61
58
  readonly stigmerToken: string;
62
- /**
63
- * The class of the caller whose request provisioned this sandbox — the
64
- * identity interceptor's word for it (`user`, `internal`, a composed
65
- * verifier's own lane such as a guest or a scheduled fire). A driver
66
- * that gives some session classes a workspace that does not outlive the
67
- * conversation reads it here; the built-in drivers (`local-process`,
68
- * `docker`, `kubernetes`) ignore it and keep every session persistent.
69
- * Required rather than optional so a construction site that forgets it
70
- * fails to compile instead of silently reading as a persistent user
71
- * session to every driver.
72
- */
73
- readonly callerClass: CallerClass;
74
59
  }
75
60
 
76
61
  /** One sandbox's observed live state (the Q5 probe result). */
@@ -50,7 +50,6 @@ import { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apiresource/
50
50
 
51
51
  import type { Logger } from "../boot/logger.js";
52
52
  import type { AgentExecutionTemporalConfig } from "../domain/agentexecution/temporal/config.js";
53
- import type { CallerIdentity } from "../extensions/identity.js";
54
53
  import {
55
54
  WORKFLOW_ROUTING_EXECUTION,
56
55
  type WorkflowExecutionTemporalConfig,
@@ -73,17 +72,6 @@ import { mintSandboxToken, type SandboxLane } from "./lane.js";
73
72
  export const SANDBOX_PROVISIONING_FAILED_PREFIX =
74
73
  "Sandbox provisioning failed: ";
75
74
 
76
- /**
77
- * The two facts about the requesting caller a sandbox ensure carries, cut
78
- * from the chain's CallerIdentity (the domain/identityaccount/actor.ts
79
- * shape): the id rides into the credential mint, so the session token is
80
- * minted FOR the caller; the class rides onto the driver's environment,
81
- * so a driver can decide the workspace's durability by who asked. A step
82
- * hands `ctx.callerIdentity` in whole; the pick keeps a test's fixture to
83
- * the two fields the body reads.
84
- */
85
- export type SandboxCaller = Pick<CallerIdentity, "identityId" | "callerClass">;
86
-
87
75
  type AgentExecutionCreateDesc = typeof AgentExecutionSchema;
88
76
 
89
77
  export interface EnsureSessionSandboxDeps {
@@ -113,7 +101,7 @@ export function newEnsureSessionSandboxStep(
113
101
  await ensureSessionSandboxForExecution(
114
102
  deps,
115
103
  ctx.newState,
116
- ctx.callerIdentity,
104
+ ctx.callerIdentity.identityId,
117
105
  );
118
106
  },
119
107
  };
@@ -126,18 +114,15 @@ export function newEnsureSessionSandboxStep(
126
114
  * chains' differing context shapes (newState vs loaded execution) meet
127
115
  * at this seam instead.
128
116
  *
129
- * The caller splits two ways (SandboxCaller): `identityId` rides into the
130
- * credential mint (lane.ts) — the Java ensure step mints session tokens
131
- * FOR the requesting caller, so the capability mint needs the identity
132
- * the OSS execution-scoped mint never did — and `callerClass` rides onto
133
- * the driver's environment as the one request fact a driver may decide
134
- * durability by. The chain always has a caller: the in-process transport
135
- * mints `internal` for the server's own calls.
117
+ * `callerIdentityId` rides into the credential mint (lane.ts): the Java
118
+ * ensure step mints session tokens FOR the requesting caller, so the
119
+ * capability mint needs the identity the OSS execution-scoped mint never
120
+ * did. Empty when the invoking site has no caller.
136
121
  */
137
122
  export async function ensureSessionSandboxForExecution(
138
123
  deps: EnsureSessionSandboxDeps,
139
124
  execution: AgentExecution,
140
- caller: SandboxCaller,
125
+ callerIdentityId: string,
141
126
  ): Promise<void> {
142
127
  if (!deps.lane.enabled) {
143
128
  return;
@@ -182,11 +167,10 @@ export async function ensureSessionSandboxForExecution(
182
167
  sessionId,
183
168
  executionId,
184
169
  org: execution.metadata?.org ?? "",
185
- callerIdentityId: caller.identityId,
170
+ callerIdentityId,
186
171
  },
187
172
  deps.logger,
188
173
  ),
189
- callerClass: caller.callerClass,
190
174
  });
191
175
  } catch (error) {
192
176
  // Non-critical: never fail the launch — but never silent either
@@ -263,7 +247,7 @@ export function newEnsureWorkflowSandboxStep(
263
247
  await ensureWorkflowSandboxForExecution(
264
248
  deps,
265
249
  ctx.newState,
266
- ctx.callerIdentity,
250
+ ctx.callerIdentity.identityId,
267
251
  );
268
252
  },
269
253
  };
@@ -274,13 +258,13 @@ export function newEnsureWorkflowSandboxStep(
274
258
  * re-provision (lifecycle.ts — the previous sandbox was deprovisioned at
275
259
  * the terminal FAILED, so a recovered execution needs a fresh one before
276
260
  * its fresh workflow starts). Throws Unavailable on provisioning failure
277
- * — the critical posture in both chains. The caller splits exactly as on
278
- * the session body: id to the mint, class to the environment.
261
+ * — the critical posture in both chains. `callerIdentityId` rides into
262
+ * the credential mint exactly as on the session body.
279
263
  */
280
264
  export async function ensureWorkflowSandboxForExecution(
281
265
  deps: EnsureWorkflowSandboxDeps,
282
266
  execution: WorkflowExecution,
283
- caller: SandboxCaller,
267
+ callerIdentityId: string,
284
268
  ): Promise<void> {
285
269
  if (!deps.lane.enabled) {
286
270
  return;
@@ -312,11 +296,10 @@ export async function ensureWorkflowSandboxForExecution(
312
296
  sessionId: "",
313
297
  executionId,
314
298
  org: execution.metadata?.org ?? "",
315
- callerIdentityId: caller.identityId,
299
+ callerIdentityId,
316
300
  },
317
301
  deps.logger,
318
302
  ),
319
- callerClass: caller.callerClass,
320
303
  });
321
304
  } catch (error) {
322
305
  deps.logger.error(
@@ -217,8 +217,12 @@ export interface SearchIndexQueryResult {
217
217
  // =============================================================================
218
218
 
219
219
  /**
220
- * Key-value state for idempotent seedpack bootstrap. Common keys:
221
- * "seedpack_version", "bootstrap_status", "skill:<name>", "agent:<name>".
220
+ * Key-value state for one-shot boot work that must run once per database.
221
+ * The one writer today is the membership rules' reconciliation
222
+ * (`iampolicy/constants.ts` ROLES_RECONCILED_KEY). A database migrated
223
+ * from the Go server carries that server's bootstrap keys too; the
224
+ * migration preserves them (see sqlite/__tests__/migrations.test.ts) and
225
+ * nothing reads them.
222
226
  */
223
227
  export interface BootstrapStateStore {
224
228
  /** Returns "" (not an error) when the key does not exist — Go's contract. */