@telorun/runner-core 0.7.0 → 0.8.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.
@@ -1,16 +1,10 @@
1
- import { isEventFrame } from "@telorun/debug-wire";
2
- import { ACCEPTED_TERMS_HEADER, SessionStartError, } from "../contract.js";
3
1
  import { BundlePathError, normalizeBundlePath } from "../session/bundle-path.js";
4
- import { generateSessionId } from "../session/session-id.js";
5
- import { SessionLimitError } from "../session/registry.js";
2
+ import { enforceTerms, portsSchema, startWorkloadSession } from "./session-start.js";
6
3
  import { streamSessionEvents } from "../sse/channel.js";
7
- // `bundle`/`config` are schema-optional because an `app` session needs neither;
8
- // the route enforces their presence for regular bundle sessions.
9
4
  const startBodySchema = {
10
5
  type: "object",
11
- required: ["env"],
6
+ required: ["bundle", "env", "config"],
12
7
  properties: {
13
- app: { type: "string", minLength: 1 },
14
8
  bundle: {
15
9
  type: "object",
16
10
  required: ["entryRelativePath", "files"],
@@ -33,17 +27,7 @@ const startBodySchema = {
33
27
  type: "object",
34
28
  additionalProperties: { type: "string" },
35
29
  },
36
- ports: {
37
- type: "array",
38
- items: {
39
- type: "object",
40
- required: ["port", "protocol"],
41
- properties: {
42
- port: { type: "integer", minimum: 1, maximum: 65535 },
43
- protocol: { type: "string", enum: ["tcp", "udp"] },
44
- },
45
- },
46
- },
30
+ ports: portsSchema,
47
31
  config: {
48
32
  type: "object",
49
33
  required: ["image", "pullPolicy"],
@@ -59,17 +43,8 @@ const startBodySchema = {
59
43
  export function sessionsRoute(deps) {
60
44
  return async (app) => {
61
45
  app.post("/v1/sessions", { schema: { body: startBodySchema } }, async (req, reply) => {
62
- // Terms enforcement — the server is the source of truth, so a client that
63
- // skips the editor gate still can't start a session without acknowledging
64
- // the current terms version.
65
- if (deps.terms) {
66
- const raw = req.headers[ACCEPTED_TERMS_HEADER];
67
- const accepted = Array.isArray(raw) ? raw[0] : raw;
68
- if (accepted !== deps.terms.version) {
69
- reply.code(428).send({ error: "terms_required", terms: deps.terms });
70
- return;
71
- }
72
- }
46
+ if (!enforceTerms(req, reply, deps.terms))
47
+ return;
73
48
  return startSession(app, deps, req.body, reply);
74
49
  });
75
50
  app.get("/v1/sessions/:id", async (req, reply) => {
@@ -114,162 +89,40 @@ export function sessionsRoute(deps) {
114
89
  };
115
90
  }
116
91
  async function startSession(app, deps, body, reply) {
117
- const sessionId = generateSessionId();
118
- // App sessions launch an operator-predefined image by name: the catalog
119
- // resolves the image and operator env server-side, so the client can neither
120
- // pick the image nor reach the secrets — the catalog IS the gate, and an
121
- // unknown name is rejected here.
122
- const appEntry = body.app === undefined ? undefined : deps.apps?.[body.app];
123
- if (body.app !== undefined && !appEntry) {
124
- const offered = Object.keys(deps.apps ?? {});
125
- reply.code(400).send({
126
- error: "unknown_app",
127
- message: `app '${body.app}' is not offered by this runner` +
128
- (offered.length > 0
129
- ? ` — offered apps: ${offered.join(", ")}`
130
- : " — it offers no predefined applications") +
131
- " (see /v1/capabilities).",
132
- });
133
- return;
134
- }
135
- if (!appEntry && (!body.bundle || !body.config)) {
136
- reply.code(400).send({
137
- error: "invalid_request",
138
- message: "'bundle' and 'config' are required unless launching a predefined app via 'app'.",
139
- });
140
- return;
141
- }
142
- let bundle;
143
92
  let entryRelative;
144
- let config;
145
- if (appEntry) {
146
- // Self-contained image — no bundle to deliver; the entry path is an unused
147
- // placeholder so the backend spec stays total.
148
- bundle = { entryRelativePath: "telo.yaml", files: [] };
149
- entryRelative = bundle.entryRelativePath;
150
- config = { image: appEntry.image, pullPolicy: appEntry.pullPolicy };
151
- }
152
- else {
153
- bundle = body.bundle;
154
- config = body.config;
155
- try {
156
- // Traversal guard for the entry path and every bundle file — a `../foo`
157
- // would let the workload read or execute paths outside its session dir.
158
- // Validated here (backend-neutral) so a bad path is a 400, not a backend
159
- // 500, regardless of how the backend ultimately delivers the bundle.
160
- entryRelative = normalizeBundlePath(bundle.entryRelativePath);
161
- for (const file of bundle.files)
162
- normalizeBundlePath(file.relativePath);
163
- }
164
- catch (err) {
165
- if (err instanceof BundlePathError) {
166
- reply.code(400).send({ error: "invalid_bundle", message: err.message });
167
- return;
168
- }
169
- throw err;
170
- }
171
- // Backend config gate (e.g. an image allowlist). The advertised capabilities
172
- // constrain the editor; this enforces the same against any client. App
173
- // sessions skip it — their image comes from the catalog, not the client.
174
- if (deps.validateConfig) {
175
- const message = deps.validateConfig(config);
176
- if (message) {
177
- reply.code(400).send({ error: "invalid_config", message });
178
- return;
179
- }
180
- }
181
- }
182
- let entry;
183
93
  try {
184
- entry = deps.registry.register({ sessionId });
94
+ // Traversal guard for the entry path and every bundle file — a `../foo`
95
+ // would let the workload read or execute paths outside its session dir.
96
+ // Validated here (backend-neutral) so a bad path is a 400, not a backend
97
+ // 500, regardless of how the backend ultimately delivers the bundle.
98
+ entryRelative = normalizeBundlePath(body.bundle.entryRelativePath);
99
+ for (const file of body.bundle.files)
100
+ normalizeBundlePath(file.relativePath);
185
101
  }
186
102
  catch (err) {
187
- if (err instanceof SessionLimitError) {
188
- reply.code(409).send({ error: "too_many_sessions", message: err.message });
103
+ if (err instanceof BundlePathError) {
104
+ reply.code(400).send({ error: "invalid_bundle", message: err.message });
189
105
  return;
190
106
  }
191
107
  throw err;
192
108
  }
193
- // For an app session, drop client-supplied values for any env key the
194
- // catalog defines (a client must never override operator-held values, which
195
- // include secrets), then inject the operator's values.
196
- const clientEnv = appEntry
197
- ? {
198
- ...Object.fromEntries(Object.entries(body.env).filter(([key]) => !(key in appEntry.env))),
199
- ...appEntry.env,
109
+ // Backend config gate (e.g. an image allowlist). The advertised capabilities
110
+ // constrain the editor; this enforces the same against any client.
111
+ if (deps.validateConfig) {
112
+ const message = deps.validateConfig(body.config);
113
+ if (message) {
114
+ reply.code(400).send({ error: "invalid_config", message });
115
+ return;
200
116
  }
201
- : body.env;
202
- // Surface a TELO_REGISTRY_URL to the workload so the telo CLI inside picks
203
- // it up. Precedence: explicit env value > config.registryUrl (per-request
204
- // override) > runner's own default. Trim client-supplied URLs so stray
205
- // whitespace from an editor input doesn't flow into the workload.
206
- const configRegistryUrl = config.registryUrl?.trim() || undefined;
207
- const registryUrl = configRegistryUrl ?? deps.defaultRegistryUrl;
208
- const sessionEnv = registryUrl && !("TELO_REGISTRY_URL" in clientEnv)
209
- ? { ...clientEnv, TELO_REGISTRY_URL: registryUrl }
210
- : clientEnv;
211
- // Respond as soon as the session is registered — BEFORE the backend starts.
212
- // `backend.start()` now spans the on-cluster image build and pod bring-up,
213
- // which can take seconds-to-minutes; awaiting it here would hide the event
214
- // stream until the workload is already up, so the client never sees build /
215
- // provision / boot progress live. Returning the streamUrl first lets the
216
- // client connect immediately; start runs in the background and its progress,
217
- // output, and terminal status flow over the stream.
218
- reply.code(201).send({
219
- sessionId,
220
- streamUrl: `/v1/sessions/${sessionId}/events`,
221
- createdAt: entry.createdAt.toISOString(),
222
- });
223
- deps.backend
224
- .start({
225
- sessionId,
226
- bundle,
117
+ }
118
+ return startWorkloadSession(app, deps, {
119
+ bundle: body.bundle,
227
120
  entryRelativePath: entryRelative,
228
- env: sessionEnv,
121
+ env: body.env,
229
122
  ports: body.ports ?? [],
230
- config,
231
- selfContained: appEntry !== undefined,
123
+ config: body.config,
124
+ selfContained: false,
232
125
  inspect: body.inspect ?? false,
233
- onStatus: (status) => deps.registry.emit(sessionId, { type: "status", status }),
234
- onProgress: (phase, message, done) => deps.registry.emit(sessionId, { type: "progress", phase, message, done }),
235
- onOutput: (chunk) => deps.registry.pushBytes(sessionId, chunk),
236
- // Relay only kernel *event* frames to the client. stdout/stderr already
237
- // arrive over the byte channel (onOutput), so forwarding log frames would
238
- // double the traffic and let log spam evict lifecycle events from the
239
- // byte-capped replay buffer. The editor discards relayed logs anyway.
240
- onDebug: (frame) => {
241
- if (isEventFrame(frame))
242
- deps.registry.emit(sessionId, { type: "debug", frame });
243
- },
244
- onReachability: (port, state) => deps.registry.emit(sessionId, { type: "reachability", port, state }),
245
- isUserStopped: () => entry.userStopped,
246
- })
247
- .then(async (session) => {
248
- entry.session = session;
249
- // Pre-start DELETE race: a DELETE received during backend.start (e.g.
250
- // while an image build was running) can't stop a workload that didn't
251
- // exist yet — it set userStopped and returned 204. Now that the workload
252
- // is live, honor the earlier DELETE.
253
- if (entry.userStopped) {
254
- try {
255
- await session.stop();
256
- }
257
- catch (err) {
258
- app.log.warn({ err, sessionId }, "failed to stop after race with pre-start DELETE");
259
- }
260
- }
261
- })
262
- .catch((err) => {
263
- // The 201 is already sent, so a start failure surfaces as a terminal
264
- // `failed` status on the stream (the registry schedules eviction on a
265
- // terminal status; the SSE channel delivers it, then closes).
266
- const message = err instanceof SessionStartError
267
- ? `${err.stage}: ${err.message}`
268
- : err instanceof Error
269
- ? err.message
270
- : String(err);
271
- app.log.error({ err, sessionId }, "session start failed");
272
- deps.registry.emit(sessionId, { type: "status", status: { kind: "failed", message } });
273
- });
126
+ }, reply);
274
127
  }
275
128
  //# sourceMappingURL=sessions.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"sessions.js","sourceRoot":"","sources":["../../src/routes/sessions.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sessions.js","sourceRoot":"","sources":["../../src/routes/sessions.ts"],"names":[],"mappings":"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"}
package/dist/server.d.ts CHANGED
@@ -21,7 +21,8 @@ export interface ServerDeps {
21
21
  validateConfig?: (config: SessionConfig) => string | undefined;
22
22
  /** Operator-predefined applications launchable by name (usually
23
23
  * `loadResolvedApps(process.env)`). Advertised on /v1/capabilities as
24
- * `apps` descriptors; the session route resolves and gates against it. */
24
+ * `apps` descriptors; sessions of them are created via
25
+ * `POST /v1/apps/:name/sessions`. */
25
26
  apps?: Record<string, ResolvedRunnerApp>;
26
27
  registry?: SessionRegistry;
27
28
  }
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAgB,EAAE,KAAK,iBAAiB,EAAE,KAAK,eAAe,EAAE,MAAM,SAAS,CAAC;AAIhF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACvE,OAAO,KAAK,EAAuB,kBAAkB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAM5F,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,aAAa,CAAC;IACvB,MAAM,EAAE,gBAAgB,CAAC;IACzB,qEAAqE;IACrE,OAAO,EAAE,MAAM,CAAC;IAChB;;;4EAGwE;IACxE,YAAY,EAAE,kBAAkB,GAAG,CAAC,MAAM,kBAAkB,CAAC,CAAC;IAC9D,+EAA+E;IAC/E,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;0EAEsE;IACtE,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,MAAM,GAAG,SAAS,CAAC;IAC/D;;+EAE2E;IAC3E,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IACzC,QAAQ,CAAC,EAAE,eAAe,CAAC;CAC5B;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,eAAe,CAAC;IACrB,QAAQ,EAAE,eAAe,CAAC;CAC3B;AAED,wBAAsB,WAAW,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,YAAY,CAAC,CA4DzE;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,eAAe,EACzB,GAAG,EAAE,IAAI,CAAC,iBAAiB,EAAE,MAAM,GAAG,MAAM,CAAC,GAC5C,OAAO,CAAC,IAAI,CAAC,CAcf"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAgB,EAAE,KAAK,iBAAiB,EAAE,KAAK,eAAe,EAAE,MAAM,SAAS,CAAC;AAIhF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACvE,OAAO,KAAK,EAAuB,kBAAkB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAO5F,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,aAAa,CAAC;IACvB,MAAM,EAAE,gBAAgB,CAAC;IACzB,qEAAqE;IACrE,OAAO,EAAE,MAAM,CAAC;IAChB;;;4EAGwE;IACxE,YAAY,EAAE,kBAAkB,GAAG,CAAC,MAAM,kBAAkB,CAAC,CAAC;IAC9D,+EAA+E;IAC/E,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;0EAEsE;IACtE,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,MAAM,GAAG,SAAS,CAAC;IAC/D;;;0CAGsC;IACtC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IACzC,QAAQ,CAAC,EAAE,eAAe,CAAC;CAC5B;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,eAAe,CAAC;IACrB,QAAQ,EAAE,eAAe,CAAC;CAC3B;AAED,wBAAsB,WAAW,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,YAAY,CAAC,CAoEzE;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,eAAe,EACzB,GAAG,EAAE,IAAI,CAAC,iBAAiB,EAAE,MAAM,GAAG,MAAM,CAAC,GAC5C,OAAO,CAAC,IAAI,CAAC,CAcf"}
package/dist/server.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import Fastify from "fastify";
2
2
  import cors from "@fastify/cors";
3
3
  import websocket from "@fastify/websocket";
4
+ import { appsRoute } from "./routes/apps.js";
4
5
  import { capabilitiesRoute } from "./routes/capabilities.js";
5
6
  import { healthRoute } from "./routes/health.js";
6
7
  import { ioRoute } from "./routes/io.js";
@@ -46,7 +47,13 @@ export async function buildServer(deps) {
46
47
  defaultRegistryUrl: deps.defaultRegistryUrl,
47
48
  validateConfig: deps.validateConfig,
48
49
  // The capabilities document is the single source of the runner's terms;
49
- // the session route enforces what /v1/capabilities advertises.
50
+ // every session-creating route enforces what /v1/capabilities advertises.
51
+ terms: capabilitiesValue.terms,
52
+ }));
53
+ await app.register(appsRoute({
54
+ backend: deps.backend,
55
+ registry,
56
+ defaultRegistryUrl: deps.defaultRegistryUrl,
50
57
  terms: capabilitiesValue.terms,
51
58
  apps: deps.apps,
52
59
  }));
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@telorun/runner-core",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "Backend-neutral core for Telo runners: the /v1 session contract, the RunnerBackend interface, the session registry, SSE/byte ring buffers, and bundle handling. Shared by docker-runner and k8s-runner.",
5
5
  "keywords": [
6
6
  "telo",
package/src/backend.ts CHANGED
@@ -48,7 +48,7 @@ export interface BackendStartSpec {
48
48
  env: Record<string, string>;
49
49
  ports: PortMapping[];
50
50
  config: SessionConfig;
51
- /** True for an operator-predefined app session (`StartSessionRequest.app`):
51
+ /** True for an operator-predefined app session (`POST /v1/apps/:name/sessions`):
52
52
  * `config.image` is self-contained (app + controllers baked in), so the
53
53
  * backend runs the image's own entrypoint and stages no bundle — `bundle`
54
54
  * is an empty placeholder. */
package/src/contract.ts CHANGED
@@ -30,8 +30,8 @@ export interface RunnerCapabilities {
30
30
  * matching `terms.version`. The editor surfaces it and records acceptance. */
31
31
  terms?: RunnerTerms;
32
32
  /** Operator-predefined applications this runner can launch by name
33
- * (`StartSessionRequest.app`). Absent/empty when none are offered — clients
34
- * hide the corresponding entry points. */
33
+ * (`POST /v1/apps/:name/sessions`). Absent/empty when none are offered —
34
+ * clients hide the corresponding entry points. */
35
35
  apps?: RunnerAppDescriptor[];
36
36
  }
37
37
 
@@ -59,7 +59,7 @@ export interface RunnerFeatures {
59
59
  * secrets. Which apps exist is pure operator configuration (`RUNNER_APPS`);
60
60
  * the runner has no built-in knowledge of any specific app. */
61
61
  export interface RunnerAppDescriptor {
62
- /** Wire id requested via `StartSessionRequest.app`. */
62
+ /** Wire id: an app session is created via `POST /v1/apps/<name>/sessions`. */
63
63
  name: string;
64
64
  title?: string;
65
65
  description?: string;
@@ -119,17 +119,10 @@ export interface RunnerEndpoint {
119
119
  }
120
120
 
121
121
  export interface StartSessionRequest {
122
- /** Launch an operator-predefined application by name (see
123
- * {@link RunnerAppDescriptor}) instead of a client bundle. The runner
124
- * resolves the image and injects the app's operator env server-side;
125
- * `bundle` and `config.image` are ignored. */
126
- app?: string;
127
- /** Required unless `app` is set. */
128
- bundle?: RunBundle;
122
+ bundle: RunBundle;
129
123
  env: Record<string, string>;
130
124
  ports?: PortMapping[];
131
- /** Required unless `app` is set. */
132
- config?: SessionConfig;
125
+ config: SessionConfig;
133
126
  /** Request the kernel debug stream. When true the runner launches the
134
127
  * workload with `--inspect`, subscribes to the in-workload inspect endpoint
135
128
  * (reachable only by the runner — never published outward), and relays each
package/src/index.ts CHANGED
@@ -28,6 +28,7 @@ export { healthRoute } from "./routes/health.js";
28
28
  export { capabilitiesRoute } from "./routes/capabilities.js";
29
29
  export { probeRoute, type ProbeRouteDeps } from "./routes/probe.js";
30
30
  export { sessionsRoute, type SessionsRouteDeps } from "./routes/sessions.js";
31
+ export { appsRoute, type AppsRouteDeps } from "./routes/apps.js";
31
32
  export { ioRoute, type IoRouteDeps } from "./routes/io.js";
32
33
  export { relayDebugStream, type DebugRelayOptions } from "./debug/relay.js";
33
34
  export {
@@ -0,0 +1,106 @@
1
+ import type { FastifyInstance, FastifyPluginAsync } from "fastify";
2
+
3
+ import type { RunnerBackend } from "../backend.js";
4
+ import type { ResolvedRunnerApp } from "../config.js";
5
+ import type { PortMapping, RunnerTerms } from "../contract.js";
6
+ import type { SessionRegistry } from "../session/registry.js";
7
+ import { enforceTerms, portsSchema, startWorkloadSession } from "./session-start.js";
8
+
9
+ export interface AppsRouteDeps {
10
+ backend: RunnerBackend;
11
+ registry: SessionRegistry;
12
+ /** The runner's own default registry URL, surfaced to the workload as
13
+ * TELO_REGISTRY_URL when the request doesn't override it. */
14
+ defaultRegistryUrl?: string;
15
+ /** Terms gate shared with `POST /v1/sessions` — app sessions execute on the
16
+ * operator's infrastructure just like runs, so they ride the same 428. */
17
+ terms?: RunnerTerms;
18
+ /** Operator-predefined applications launchable by name. The catalog is the
19
+ * whole gate: the client picks a name, never an image, and the operator env
20
+ * is injected server-side. */
21
+ apps?: Record<string, ResolvedRunnerApp>;
22
+ }
23
+
24
+ interface StartAppSessionBody {
25
+ env?: Record<string, string>;
26
+ ports?: PortMapping[];
27
+ inspect?: boolean;
28
+ }
29
+
30
+ const startAppBodySchema = {
31
+ type: "object",
32
+ properties: {
33
+ env: {
34
+ type: "object",
35
+ additionalProperties: { type: "string" },
36
+ },
37
+ ports: portsSchema,
38
+ inspect: { type: "boolean" },
39
+ },
40
+ } as const;
41
+
42
+ /**
43
+ * Creation door for operator-predefined app sessions. A client launches an app
44
+ * by name; the runner resolves the image and injects the app's operator env
45
+ * from the catalog (`RUNNER_APPS`). The created session lives in the SAME
46
+ * session collection as bundle sessions — the 201 carries the shared
47
+ * `/v1/sessions/:id/events` stream URL, and status/DELETE/io are served by the
48
+ * sessions routes.
49
+ */
50
+ export function appsRoute(deps: AppsRouteDeps): FastifyPluginAsync {
51
+ return async (app: FastifyInstance) => {
52
+ app.post<{ Params: { name: string }; Body: StartAppSessionBody }>(
53
+ "/v1/apps/:name/sessions",
54
+ { schema: { body: startAppBodySchema } },
55
+ async (req, reply) => {
56
+ // Resolve the app before the terms gate: an unknown name is a 404
57
+ // regardless of terms (there's no workload to gate), and the catalog is
58
+ // already public on /v1/capabilities, so this leaks nothing.
59
+ const appEntry = deps.apps?.[req.params.name];
60
+ if (!appEntry) {
61
+ const offered = Object.keys(deps.apps ?? {});
62
+ reply.code(404).send({
63
+ error: "unknown_app",
64
+ message:
65
+ `app '${req.params.name}' is not offered by this runner` +
66
+ (offered.length > 0
67
+ ? ` — offered apps: ${offered.join(", ")}`
68
+ : " — it offers no predefined applications") +
69
+ " (see /v1/capabilities).",
70
+ });
71
+ return;
72
+ }
73
+
74
+ if (!enforceTerms(req, reply, deps.terms)) return;
75
+
76
+ // Drop client-supplied values for any env key the catalog defines (a
77
+ // client must never override operator-held values, which include
78
+ // secrets), then inject the operator's values.
79
+ const clientEnv = req.body?.env ?? {};
80
+ const env = {
81
+ ...Object.fromEntries(
82
+ Object.entries(clientEnv).filter(([key]) => !(key in appEntry.env)),
83
+ ),
84
+ ...appEntry.env,
85
+ };
86
+
87
+ return startWorkloadSession(
88
+ app,
89
+ deps,
90
+ {
91
+ // Self-contained image — no bundle to deliver; the entry path is an
92
+ // unused placeholder so the backend spec stays total.
93
+ bundle: { entryRelativePath: "telo.yaml", files: [] },
94
+ entryRelativePath: "telo.yaml",
95
+ env,
96
+ ports: req.body?.ports ?? [],
97
+ config: { image: appEntry.image, pullPolicy: appEntry.pullPolicy },
98
+ selfContained: true,
99
+ inspect: req.body?.inspect ?? false,
100
+ },
101
+ reply,
102
+ );
103
+ },
104
+ );
105
+ };
106
+ }