@stigmer/server 3.15.0 → 3.15.2-dev.20260913223433

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 (69) hide show
  1. package/dist/boot/compose.d.ts.map +1 -1
  2. package/dist/boot/compose.js +23 -2
  3. package/dist/boot/compose.js.map +1 -1
  4. package/dist/boot/config.d.ts +14 -0
  5. package/dist/boot/config.d.ts.map +1 -1
  6. package/dist/boot/config.js +1 -0
  7. package/dist/boot/config.js.map +1 -1
  8. package/dist/domain/agentchannel/controller.js +15 -26
  9. package/dist/domain/agentchannel/controller.js.map +1 -1
  10. package/dist/domain/agentexecution/controller.d.ts.map +1 -1
  11. package/dist/domain/agentexecution/controller.js +3 -2
  12. package/dist/domain/agentexecution/controller.js.map +1 -1
  13. package/dist/domain/agentexecution/steps.d.ts +20 -8
  14. package/dist/domain/agentexecution/steps.d.ts.map +1 -1
  15. package/dist/domain/agentexecution/steps.js +32 -12
  16. package/dist/domain/agentexecution/steps.js.map +1 -1
  17. package/dist/domain/agentinstance/steps.d.ts.map +1 -1
  18. package/dist/domain/agentinstance/steps.js +9 -22
  19. package/dist/domain/agentinstance/steps.js.map +1 -1
  20. package/dist/domain/agentshare/controller.js +15 -26
  21. package/dist/domain/agentshare/controller.js.map +1 -1
  22. package/dist/domain/environment/controller.js +8 -10
  23. package/dist/domain/environment/controller.js.map +1 -1
  24. package/dist/domain/memory/steps.d.ts.map +1 -1
  25. package/dist/domain/memory/steps.js +5 -10
  26. package/dist/domain/memory/steps.js.map +1 -1
  27. package/dist/domain/schedule/controller.js +15 -24
  28. package/dist/domain/schedule/controller.js.map +1 -1
  29. package/dist/domain/session/steps.d.ts.map +1 -1
  30. package/dist/domain/session/steps.js +8 -4
  31. package/dist/domain/session/steps.js.map +1 -1
  32. package/dist/domain/workflowexecution/controller.d.ts.map +1 -1
  33. package/dist/domain/workflowexecution/controller.js +12 -6
  34. package/dist/domain/workflowexecution/controller.js.map +1 -1
  35. package/dist/domain/workflowexecution/list-pending-approvals.d.ts.map +1 -1
  36. package/dist/domain/workflowexecution/list-pending-approvals.js +19 -8
  37. package/dist/domain/workflowexecution/list-pending-approvals.js.map +1 -1
  38. package/dist/domain/workflowinstance/controller.js +6 -13
  39. package/dist/domain/workflowinstance/controller.js.map +1 -1
  40. package/dist/extensions/list-read-scope.d.ts +31 -4
  41. package/dist/extensions/list-read-scope.d.ts.map +1 -1
  42. package/dist/extensions/list-read-scope.js +12 -10
  43. package/dist/extensions/list-read-scope.js.map +1 -1
  44. package/dist/transport/console/handler.d.ts +22 -5
  45. package/dist/transport/console/handler.d.ts.map +1 -1
  46. package/dist/transport/console/handler.js +53 -24
  47. package/dist/transport/console/handler.js.map +1 -1
  48. package/package.json +4 -4
  49. package/src/boot/__tests__/auth-enabled-composition.test.ts +49 -3
  50. package/src/boot/__tests__/config.test.ts +41 -3
  51. package/src/boot/compose.ts +30 -2
  52. package/src/boot/config.ts +15 -0
  53. package/src/domain/agentchannel/controller.ts +23 -31
  54. package/src/domain/agentexecution/controller.ts +11 -5
  55. package/src/domain/agentexecution/steps.ts +47 -22
  56. package/src/domain/agentinstance/steps.ts +17 -26
  57. package/src/domain/agentshare/controller.ts +23 -31
  58. package/src/domain/environment/controller.ts +12 -12
  59. package/src/domain/memory/steps.ts +6 -12
  60. package/src/domain/schedule/controller.ts +25 -33
  61. package/src/domain/session/steps.ts +24 -11
  62. package/src/domain/workflowexecution/controller.ts +32 -26
  63. package/src/domain/workflowexecution/list-pending-approvals.ts +37 -16
  64. package/src/domain/workflowinstance/controller.ts +11 -18
  65. package/src/extensions/__tests__/list-read-scope.test.ts +29 -7
  66. package/src/extensions/list-read-scope.ts +37 -12
  67. package/src/transport/console/__tests__/handler.test.ts +93 -23
  68. package/src/transport/console/__tests__/resolver.test.ts +6 -0
  69. package/src/transport/console/handler.ts +84 -30
@@ -7,13 +7,30 @@ import type { ConsoleAssets } from "./assets.js";
7
7
  * of RPC path shapes belongs to this module.
8
8
  */
9
9
  export declare function consoleLaneEligible(request: LaneRequest): boolean;
10
+ /**
11
+ * How the console this lane serves signs in — the server's authentication
12
+ * posture as the console needs to hear it (20260913.02 sp.console-login).
13
+ * A modeled state, never a nullable: "no issuer configured" and "forgot to
14
+ * wire the posture" must stay distinguishable at the call site.
15
+ *
16
+ * Under `oidc`, `consoleClientId` is the PUBLIC client the operator
17
+ * registered for the browser's PKCE flow, or "" when they have not
18
+ * (Q-CL-1): the lane publishes that truth as-is and the console refuses
19
+ * with copy that names the knob (Q-CL-2), while the composition root has
20
+ * already WARNed at wiring time. Emitting `disabled` instead would send
21
+ * the console into every RPC tokenless, to fail with a worse message.
22
+ */
23
+ export type ConsoleSignInPosture = {
24
+ readonly posture: "trusted-local";
25
+ } | {
26
+ readonly posture: "oidc";
27
+ readonly issuer: string;
28
+ readonly audience: string;
29
+ readonly consoleClientId: string;
30
+ };
10
31
  export interface ConsoleLaneOptions {
11
32
  readonly assets: ConsoleAssets;
12
- /**
13
- * Fallback port for the synthesized apiUrl when a request carries no
14
- * Host/:authority (technically possible on HTTP/1.0-style clients).
15
- */
16
- readonly grpcPort: number;
33
+ readonly signIn: ConsoleSignInPosture;
17
34
  readonly logger: Logger;
18
35
  }
19
36
  export declare function createConsoleLane(options: ConsoleLaneOptions): LaneHandler;
@@ -1 +1 @@
1
- {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/transport/console/handler.ts"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAgB,MAAM,aAAa,CAAC;AAC1E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAkBjD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAYjE;AAQD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B;;;OAGG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,GAAG,WAAW,CA8C1E"}
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../../src/transport/console/handler.ts"],"names":[],"mappings":"AAsCA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAgB,MAAM,aAAa,CAAC;AAC1E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAkBjD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAYjE;AAQD;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,oBAAoB,GAC5B;IAAE,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAA;CAAE,GACrC;IACE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;CAClC,CAAC;AAEN,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B,QAAQ,CAAC,MAAM,EAAE,oBAAoB,CAAC;IACtC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,GAAG,WAAW,CAiD1E"}
@@ -6,6 +6,13 @@
6
6
  * nginx-equivalence-gated); this module owns the HTTP half: the lane
7
7
  * guard, header policy, config synthesis, and file streaming.
8
8
  *
9
+ * /config.json is also how the served console learns to sign in
10
+ * (20260913.02 sp.console-login; stigmer#924): the composition root hands
11
+ * the lane the server's authentication posture (ConsoleSignInPosture) and
12
+ * the lane publishes it in the console's own vocabulary — the OIDC
13
+ * issuer, audience and the console's PKCE client id under the posture,
14
+ * `disabled` under trusted local.
15
+ *
9
16
  * Lane guard (consoleLaneEligible): the lane claims GET/HEAD only — RPC
10
17
  * traffic is POST on service-qualified paths, and OPTIONS preflights keep
11
18
  * flowing to the RPC lane's CORS handling — and it never claims:
@@ -63,14 +70,17 @@ function isServiceShapedPath(pathname) {
63
70
  return segments.length === 2 && (segments[0] ?? "").includes(".");
64
71
  }
65
72
  export function createConsoleLane(options) {
66
- const { assets, grpcPort, logger } = options;
73
+ const { assets, signIn, logger } = options;
74
+ // The console's runtime config is a pure function of the posture: one
75
+ // body, built once, served on every request.
76
+ const configJsonBody = JSON.stringify(consoleRuntimeConfig(signIn));
67
77
  return (request, response) => {
68
78
  const url = request.url ?? "";
69
79
  const queryStart = url.indexOf("?");
70
80
  const rawPath = queryStart === -1 ? url : url.slice(0, queryStart);
71
81
  const query = queryStart === -1 ? "" : url.slice(queryStart);
72
82
  if (rawPath === CONFIG_JSON_PATH) {
73
- serveConfigJson(request, response, grpcPort);
83
+ serveConfigJson(request, response, configJsonBody);
74
84
  return;
75
85
  }
76
86
  let pathname;
@@ -108,29 +118,48 @@ export function createConsoleLane(options) {
108
118
  }
109
119
  /**
110
120
  * The runtime config the cloud container's entrypoint.sh generates from
111
- * env — synthesized here from the server's own knowledge instead (DD-012:
112
- * the nginx entrypoint script is not ported). apiUrl derives from the
113
- * request's own Host so the answer is correct wherever the browser
114
- * reached us from (localhost, a LAN address, a self-host name) — the
115
- * console cannot express "same origin" itself (its config loader maps
116
- * empty fields to a localhost default). TLS-terminating proxies
117
- * (x-forwarded-proto) are out of scope until a tier serves TLS.
121
+ * env, synthesized here from the server's own knowledge instead (DD-012:
122
+ * the nginx entrypoint script is not ported). The field names are the
123
+ * console's loader's (client-apps/web/src/config/runtime-config.ts).
124
+ *
125
+ * `apiUrl` is the empty string, which the console reads as "my own
126
+ * origin" — the rule its `appUrl` already follows (20260913.02 Q-CL-3).
127
+ * This lane and the RPC lane share one port, so the console can never
128
+ * need a different origin, and it makes the answer right behind a
129
+ * TLS-terminating proxy without trusting x-forwarded-proto: the earlier
130
+ * Host-derived `http://<host>` sent an https-loaded console to an http
131
+ * API and died on mixed content.
132
+ *
133
+ * Every value here is public metadata: an OIDC issuer URL, an audience
134
+ * string and a PKCE client id are what a browser is handed by design.
118
135
  */
119
- function serveConfigJson(request, response, grpcPort) {
120
- // HTTP/1.1 carries Host; Node maps HTTP/2's :authority into the same
121
- // headers view (and Http2ServerRequest.authority falls back to it).
122
- const host = request.headers.host ?? request.headers[":authority"];
123
- const apiUrl = typeof host === "string" && host !== ""
124
- ? `http://${host}`
125
- : `http://localhost:${grpcPort}`;
126
- const body = JSON.stringify({
127
- apiUrl,
128
- appUrl: "",
129
- authMode: "disabled",
130
- oidcIssuer: "",
131
- oidcClientId: "",
132
- oidcAudience: "",
133
- });
136
+ function consoleRuntimeConfig(signIn) {
137
+ switch (signIn.posture) {
138
+ case "trusted-local":
139
+ return {
140
+ apiUrl: "",
141
+ appUrl: "",
142
+ authMode: "disabled",
143
+ oidcIssuer: "",
144
+ oidcClientId: "",
145
+ oidcAudience: "",
146
+ };
147
+ case "oidc":
148
+ return {
149
+ apiUrl: "",
150
+ appUrl: "",
151
+ authMode: "oidc",
152
+ oidcIssuer: signIn.issuer,
153
+ oidcClientId: signIn.consoleClientId,
154
+ oidcAudience: signIn.audience,
155
+ };
156
+ default: {
157
+ const exhaustive = signIn;
158
+ throw new Error(`unhandled sign-in posture ${String(exhaustive)}`);
159
+ }
160
+ }
161
+ }
162
+ function serveConfigJson(request, response, body) {
134
163
  response.statusCode = 200;
135
164
  response.setHeader("Content-Type", "application/json");
136
165
  response.setHeader("Cache-Control", CONFIG_JSON_CACHE_CONTROL);
@@ -1 +1 @@
1
- {"version":3,"file":"handler.js","sourceRoot":"","sources":["../../../src/transport/console/handler.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"handler.js","sourceRoot":"","sources":["../../../src/transport/console/handler.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stigmer/server",
3
- "version": "3.15.0",
3
+ "version": "3.15.2-dev.20260913223433",
4
4
  "description": "The Stigmer OSS control plane as a composable library: composeServer, the extension registry and the driver seams a composition builds on. The self-contained deployable of the same server is @stigmer/server-slim.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -62,9 +62,9 @@
62
62
  "@connectrpc/connect-node": "^2.0.0",
63
63
  "@kubernetes/client-node": "2.0.0",
64
64
  "@opentelemetry/api": "^1.9.0",
65
- "@stigmer/protos": "3.15.0",
66
- "@stigmer/temporal-codecs": "3.15.0",
67
- "@stigmer/zip-structure": "3.15.0",
65
+ "@stigmer/protos": "3.15.2-dev.20260913223433",
66
+ "@stigmer/temporal-codecs": "3.15.2-dev.20260913223433",
67
+ "@stigmer/zip-structure": "3.15.2-dev.20260913223433",
68
68
  "@temporalio/activity": "1.16.2",
69
69
  "@temporalio/client": "1.16.2",
70
70
  "@temporalio/common": "1.16.2",
@@ -21,9 +21,17 @@
21
21
  * the issuer's userinfo profile; from then on the verifier resolves
22
22
  * the subject to the account id and API keys minted before OR after
23
23
  * provisioning answer whoAmI with the owner's account; no operator
24
- * account exists under the posture.
24
+ * account exists under the posture;
25
+ * 7. (20260913.02, sp.console-login) the console the server serves is
26
+ * told the posture through /config.json — the issuer and audience
27
+ * this composition runs under, with the console client id the
28
+ * operator did NOT register here left empty — and the composition
29
+ * root WARNs at wiring time that the served console cannot sign in
30
+ * (Q-CL-2), the STIGMER_OAUTH_REDIRECT_URI precedent. Proven through
31
+ * compose.ts with STIGMER_CONSOLE_DIR at a fixture export, not
32
+ * through the lane alone (handler.test.ts covers that).
25
33
  */
26
- import { mkdtempSync, rmSync } from "node:fs";
34
+ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
27
35
  import { tmpdir } from "node:os";
28
36
  import path from "node:path";
29
37
  import { createServer } from "node:http";
@@ -75,6 +83,9 @@ let port: number;
75
83
  // the raw sub. The identity-account arms prove that stamp resolves to the
76
84
  // owner's account once one exists (20260911.11 A1's derived id).
77
85
  let keyMintedBeforeProvisioning: string;
86
+ // Every WARN the composition root logged while wiring — the console
87
+ // sign-in arm (7) reads it.
88
+ const warnings: string[] = [];
78
89
 
79
90
  function bearer(token: string): Interceptor {
80
91
  return (next) => (request) => {
@@ -177,6 +188,10 @@ beforeAll(async () => {
177
188
  issuer = `http://127.0.0.1:${address.port}`;
178
189
 
179
190
  dir = mkdtempSync(path.join(tmpdir(), "auth-enabled-test-"));
191
+ // The smallest export the console lane discovers: the app shell alone.
192
+ const consoleDir = path.join(dir, "console");
193
+ mkdirSync(consoleDir, { recursive: true });
194
+ writeFileSync(path.join(consoleDir, "index.html"), "<html>app shell</html>");
180
195
  server = await composeServer({
181
196
  config: loadConfig({
182
197
  STIGMER_MODEL_REGISTRY_REFRESH: "off",
@@ -186,8 +201,18 @@ beforeAll(async () => {
186
201
  ARTIFACT_LOCAL_BASE_PATH: path.join(dir, "artifacts"),
187
202
  STIGMER_OIDC_ISSUER: issuer,
188
203
  STIGMER_OIDC_AUDIENCE: AUDIENCE,
204
+ STIGMER_CONSOLE_DIR: consoleDir,
205
+ }),
206
+ logger: createLogger({
207
+ level: "warn",
208
+ pretty: false,
209
+ write: (line) => {
210
+ const entry = JSON.parse(line) as { level?: string; message?: string };
211
+ if (entry.level === "warn" && entry.message !== undefined) {
212
+ warnings.push(entry.message);
213
+ }
214
+ },
189
215
  }),
190
- logger: createLogger({ level: "error", pretty: false, write: () => {} }),
191
216
  portOverride: 0,
192
217
  host: "127.0.0.1",
193
218
  });
@@ -236,6 +261,27 @@ describe("the require-authentication posture on the wire", () => {
236
261
  });
237
262
  });
238
263
 
264
+ describe("the console the server serves is told the posture (20260913.02, sp.console-login)", () => {
265
+ it("/config.json carries the issuer and audience this composition verifies against, with the unregistered console client id empty", async () => {
266
+ const response = await fetch(`http://127.0.0.1:${port}/config.json`);
267
+ expect(response.status).toBe(200);
268
+ expect(await response.json()).toEqual({
269
+ apiUrl: "",
270
+ appUrl: "",
271
+ authMode: "oidc",
272
+ oidcIssuer: issuer,
273
+ oidcClientId: "",
274
+ oidcAudience: AUDIENCE,
275
+ });
276
+ });
277
+
278
+ it("the composition root WARNs at wiring time that the served console cannot sign in without STIGMER_OIDC_CONSOLE_CLIENT_ID (Q-CL-2)", () => {
279
+ expect(warnings).toContainEqual(
280
+ expect.stringContaining("STIGMER_OIDC_CONSOLE_CLIENT_ID"),
281
+ );
282
+ });
283
+ });
284
+
239
285
  describe("the full credential loop (OIDC login → API key → revocation)", () => {
240
286
  let apiKeyPlaintext: string;
241
287
  let apiKeyId: string;
@@ -59,15 +59,53 @@ describe("loadConfig", () => {
59
59
  });
60
60
 
61
61
  it("reads an explicit ARTIFACT_HTTP_HOST (the container override)", () => {
62
- expect(
63
- loadConfig({ ARTIFACT_HTTP_HOST: "0.0.0.0" }).artifactHttpHost,
64
- ).toBe("0.0.0.0");
62
+ expect(loadConfig({ ARTIFACT_HTTP_HOST: "0.0.0.0" }).artifactHttpHost).toBe(
63
+ "0.0.0.0",
64
+ );
65
65
  // Empty string is absent, per the Go getEnvString leniency.
66
66
  expect(loadConfig({ ARTIFACT_HTTP_HOST: "" }).artifactHttpHost).toBe(
67
67
  "127.0.0.1",
68
68
  );
69
69
  });
70
70
 
71
+ // 20260913.02 (sp.console-login, Q-CL-1): the console's public PKCE client
72
+ // id is lenient on purpose — a CLI-only self-host that set the issuer
73
+ // before this knob existed must keep booting on upgrade, and the served
74
+ // console reports the gap itself (Q-CL-2).
75
+ describe("STIGMER_OIDC_CONSOLE_CLIENT_ID (the console's sign-in client)", () => {
76
+ const OIDC = {
77
+ STIGMER_OIDC_ISSUER: "https://auth.example.com/realms/main",
78
+ STIGMER_OIDC_AUDIENCE: "https://stigmer.example.com/",
79
+ };
80
+
81
+ it("is empty when absent, and the issuer alone still boots", () => {
82
+ expect(loadConfig(OIDC).oidcConsoleClientId).toBe("");
83
+ });
84
+
85
+ it("reads the explicit value", () => {
86
+ expect(
87
+ loadConfig({
88
+ ...OIDC,
89
+ STIGMER_OIDC_CONSOLE_CLIENT_ID: "stigmer-console",
90
+ }).oidcConsoleClientId,
91
+ ).toBe("stigmer-console");
92
+ });
93
+
94
+ it("treats an empty string as absent (Go's getEnvString)", () => {
95
+ expect(
96
+ loadConfig({ ...OIDC, STIGMER_OIDC_CONSOLE_CLIENT_ID: "" })
97
+ .oidcConsoleClientId,
98
+ ).toBe("");
99
+ });
100
+
101
+ it("is carried even without an issuer — the posture, not this knob, decides whether it is used", () => {
102
+ expect(
103
+ loadConfig({ STIGMER_OIDC_CONSOLE_CLIENT_ID: "stigmer-console" })
104
+ .oidcConsoleClientId,
105
+ ).toBe("stigmer-console");
106
+ });
107
+ });
108
+
71
109
  it("disables the model-registry refresh only for the literal 'off'", () => {
72
110
  expect(
73
111
  loadConfig({ STIGMER_MODEL_REGISTRY_REFRESH: "off" })
@@ -161,7 +161,10 @@ import { newWorkflowExecutionEngineStateProvider } from "../temporal/workflowexe
161
161
  import { newWorkflowExecutionWorkerFactory } from "../temporal/workflowexecution/worker.js";
162
162
  import { HealthState, registerHealthService } from "../transport/health.js";
163
163
  import { resolveConsoleAssets } from "../transport/console/assets.js";
164
- import { createConsoleLane } from "../transport/console/handler.js";
164
+ import {
165
+ createConsoleLane,
166
+ type ConsoleSignInPosture,
167
+ } from "../transport/console/handler.js";
165
168
  import { createRegistryLanes } from "../transport/registry/lanes.js";
166
169
  import { createUnifiedPortServer } from "../transport/server.js";
167
170
  import type { ServerConfig } from "./config.js";
@@ -762,11 +765,36 @@ export async function composeServer(
762
765
  } else {
763
766
  logger.debug("no web console export bundled; console lane disabled");
764
767
  }
768
+ // The console is told how to sign in (20260913.02 sp.console-login): the
769
+ // OSS issuer arm of the posture, in the console's vocabulary. A composed
770
+ // unit's own `requireAuthentication` is NOT expressed here — a
771
+ // composition whose verifiers resolve its users serves its console its
772
+ // own way (the cloud's container does); the Enterprise console story is
773
+ // P4's. Issuer set but no console client registered is WARN-degrade, the
774
+ // STIGMER_OAUTH_REDIRECT_URI posture: the CLI and SDKs keep working with
775
+ // API keys, and the served console refuses with copy naming the knob.
776
+ const consoleSignIn: ConsoleSignInPosture = authEnabled
777
+ ? {
778
+ posture: "oidc",
779
+ issuer: config.oidcIssuer,
780
+ audience: config.oidcAudience,
781
+ consoleClientId: config.oidcConsoleClientId,
782
+ }
783
+ : { posture: "trusted-local" };
784
+ if (
785
+ consoleAssets !== undefined &&
786
+ consoleSignIn.posture === "oidc" &&
787
+ consoleSignIn.consoleClientId === ""
788
+ ) {
789
+ logger.warn(
790
+ "STIGMER_OIDC_ISSUER is set but STIGMER_OIDC_CONSOLE_CLIENT_ID is not — the web console this server serves cannot sign in; register a public PKCE client for the console at the issuer and set it",
791
+ );
792
+ }
765
793
  const consoleLane =
766
794
  consoleAssets !== undefined
767
795
  ? createConsoleLane({
768
796
  assets: consoleAssets,
769
- grpcPort: options.portOverride ?? config.grpcPort,
797
+ signIn: consoleSignIn,
770
798
  logger,
771
799
  })
772
800
  : undefined;
@@ -170,6 +170,20 @@ export interface ServerConfig {
170
170
  * OIDC is boot-fatal, the R2/operator-identity loud-fail precedent.
171
171
  */
172
172
  readonly oidcAudience: string;
173
+ /**
174
+ * The OAuth client the served web console signs in with
175
+ * (STIGMER_OIDC_CONSOLE_CLIENT_ID; 20260913.02 sp.console-login, Q-CL-1):
176
+ * a PUBLIC client the operator registers at the issuer for the browser's
177
+ * Authorization Code + PKCE flow — a public identifier, never a secret.
178
+ * Deliberately lenient beside the two boot-fatal OIDC fields: a
179
+ * self-host that set the issuer before this knob existed, and uses the
180
+ * CLI and SDKs with API keys, must keep booting on upgrade. Empty means
181
+ * the console cannot sign in; the composition root WARNs and the served
182
+ * console says so itself (Q-CL-2). Named for the console on purpose — a
183
+ * future CLI or desktop sign-in against a self-host is a different
184
+ * client type (loopback/native) and should not be tempted to reuse it.
185
+ */
186
+ readonly oidcConsoleClientId: string;
173
187
  /**
174
188
  * Sandbox provisioner driver (SANDBOX_PROVISIONER_TYPE; §6d, O6). ""
175
189
  * — the default — is the external-runner posture: no provisioner is
@@ -329,6 +343,7 @@ export function loadConfig(env: NodeJS.ProcessEnv = process.env): ServerConfig {
329
343
  oauthRedirectUri: envString(env, "STIGMER_OAUTH_REDIRECT_URI", ""),
330
344
  consoleDir: envString(env, "STIGMER_CONSOLE_DIR", ""),
331
345
  ...loadOidcConfig(env),
346
+ oidcConsoleClientId: envString(env, "STIGMER_OIDC_CONSOLE_CLIENT_ID", ""),
332
347
  sandboxProvisionerType: envString(env, "SANDBOX_PROVISIONER_TYPE", ""),
333
348
  sandboxBackendEndpoint: envString(
334
349
  env,
@@ -599,28 +599,25 @@ function newLoadChannelsByAgentStep(
599
599
  continue;
600
600
  }
601
601
  }
602
- // 20260830.01 census lane 19: the scope narrows the decoded scan;
603
- // the org/agent filters below are contract parity in both editions.
604
- const visible = await restrictListByReadScope(
602
+ // 20260830.01 census lane 19: the org/agent filters are contract
603
+ // parity in both editions and run FIRST; the scope narrows the
604
+ // agent's channels last (the scope is the last per-row predicate,
605
+ // stigmer-cloud 20260913.04 T02).
606
+ const channels = await restrictListByReadScope(
605
607
  listReadScope,
606
608
  ctx.callerIdentity,
607
609
  ApiResourceKind.agent_channel,
608
- decoded,
610
+ decoded.filter((channel) => {
611
+ const ref = channel.spec?.agentRef;
612
+ return (
613
+ (ref?.org ?? "") === agentOrg &&
614
+ (ref?.slug ?? "") === agentSlug &&
615
+ (req.org === "" || (channel.metadata?.org ?? "") === req.org)
616
+ );
617
+ }),
609
618
  "",
610
619
  );
611
620
 
612
- const channels: AgentChannel[] = [];
613
- for (const channel of visible) {
614
- const ref = channel.spec?.agentRef;
615
- if ((ref?.org ?? "") !== agentOrg || (ref?.slug ?? "") !== agentSlug) {
616
- continue;
617
- }
618
- if (req.org !== "" && (channel.metadata?.org ?? "") !== req.org) {
619
- continue;
620
- }
621
- channels.push(channel);
622
- }
623
-
624
621
  ctx.set(
625
622
  CHANNEL_LIST_KEY,
626
623
  create(AgentChannelListSchema, {
@@ -702,27 +699,22 @@ function newListByOrgAndLabelsStep(
702
699
  continue;
703
700
  }
704
701
  }
705
- // 20260830.01 census lane 18: the scope narrows the decoded scan;
706
- // the org equality below already serves the Java handler's org arm.
707
- const visible = await restrictListByReadScope(
702
+ // 20260830.01 census lane 18: the org and label filters serve the
703
+ // Java handler's arms in both editions and run FIRST; the scope
704
+ // narrows the org's rows last (the scope is the last per-row
705
+ // predicate, stigmer-cloud 20260913.04 T02).
706
+ const channels = await restrictListByReadScope(
708
707
  listReadScope,
709
708
  ctx.callerIdentity,
710
709
  ApiResourceKind.agent_channel,
711
- decoded,
710
+ decoded.filter(
711
+ (channel) =>
712
+ (channel.metadata?.org ?? "") === org &&
713
+ matchesAllLabels(channel.metadata?.labels ?? {}, filterLabels),
714
+ ),
712
715
  "",
713
716
  );
714
717
 
715
- const channels: AgentChannel[] = [];
716
- for (const channel of visible) {
717
- if ((channel.metadata?.org ?? "") !== org) {
718
- continue;
719
- }
720
- if (!matchesAllLabels(channel.metadata?.labels ?? {}, filterLabels)) {
721
- continue;
722
- }
723
- channels.push(channel);
724
- }
725
-
726
718
  channels.sort((a, b) =>
727
719
  compareCreatedAtDesc(
728
720
  a.status?.audit?.specAudit?.createdAt,
@@ -130,6 +130,7 @@ import {
130
130
  newApplyPhaseFilterStep,
131
131
  newBuildExecutionListResponseStep,
132
132
  newQueryAllExecutionsStep,
133
+ newRestrictByReadScopeStep,
133
134
  newQueryExecutionsBySessionStep,
134
135
  newValidateListBySessionRequestStep,
135
136
  newValidateListRequestStep,
@@ -320,7 +321,9 @@ async function createExecution(
320
321
  .addStep(newValidateThinkingModeStep(deps.modelRegistry))
321
322
  .addStep(newResolveDefaultAgentStep(deps.store, deps.logger))
322
323
  .addStep(newEnsureSessionOrAgentResolvedStep(deps.logger))
323
- .addStep(newAuthorizeRunTargetStep(deps.authorizer, agentExecutionRunTarget))
324
+ .addStep(
325
+ newAuthorizeRunTargetStep(deps.authorizer, agentExecutionRunTarget),
326
+ )
324
327
  .addStep(newResolveSlugStep())
325
328
  .addStep(newBuildNewStateStep())
326
329
  // Vouches the runner-stamped workflow lineage labels (or refuses a
@@ -549,10 +552,9 @@ async function list(
549
552
  ),
550
553
  )
551
554
  .addStep(newValidateListRequestStep())
552
- .addStep(
553
- newQueryAllExecutionsStep(deps.store, deps.logger, deps.listReadScope),
554
- )
555
+ .addStep(newQueryAllExecutionsStep(deps.store, deps.logger))
555
556
  .addStep(newApplyPhaseFilterStep(deps.logger))
557
+ .addStep(newRestrictByReadScopeStep(deps.listReadScope))
556
558
  .addStep(newBuildExecutionListResponseStep())
557
559
  .build()
558
560
  .execute(reqCtx);
@@ -582,7 +584,11 @@ async function listBySession(
582
584
  )
583
585
  .addStep(newValidateListBySessionRequestStep())
584
586
  .addStep(
585
- newQueryExecutionsBySessionStep(deps.store, deps.logger, deps.listReadScope),
587
+ newQueryExecutionsBySessionStep(
588
+ deps.store,
589
+ deps.logger,
590
+ deps.listReadScope,
591
+ ),
586
592
  )
587
593
  .addStep(newBuildExecutionListResponseStep())
588
594
  .build()