@telorun/runner-core 0.6.0 → 0.7.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.
package/dist/backend.d.ts CHANGED
@@ -34,6 +34,11 @@ export interface BackendStartSpec {
34
34
  env: Record<string, string>;
35
35
  ports: PortMapping[];
36
36
  config: SessionConfig;
37
+ /** True for an operator-predefined app session (`StartSessionRequest.app`):
38
+ * `config.image` is self-contained (app + controllers baked in), so the
39
+ * backend runs the image's own entrypoint and stages no bundle — `bundle`
40
+ * is an empty placeholder. */
41
+ selfContained: boolean;
37
42
  /** When true, launch the workload with `--inspect` and relay its kernel debug
38
43
  * stream via `onDebug`. The inspect endpoint stays reachable only by the
39
44
  * runner — never published outward. */
@@ -1 +1 @@
1
- {"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../src/backend.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEtD,OAAO,KAAK,EACV,kBAAkB,EAClB,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,SAAS,EACT,QAAQ,EACR,SAAS,EACT,aAAa,EACd,MAAM,eAAe,CAAC;AAEvB;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,aAAa;IAC5B;wEACoE;IACpE,KAAK,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAExD;;8DAE0D;IAC1D,KAAK,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAEvD;;qEAEiE;IACjE,WAAW,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,SAAS,CAAC;IAClB,wEAAwE;IACxE,iBAAiB,EAAE,MAAM,CAAC;IAC1B,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,MAAM,EAAE,aAAa,CAAC;IACtB;;4CAEwC;IACxC,OAAO,EAAE,OAAO,CAAC;IAEjB;kDAC8C;IAC9C,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAAC;IAClC;;gEAE4D;IAC5D,UAAU,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IACnE,8DAA8D;IAC9D,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B;mFAC+E;IAC/E,OAAO,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;IACjC;;gFAE4E;IAC5E,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAC7D;6DACyD;IACzD,aAAa,IAAI,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,cAAc;IAC7B;0DACsD;IACtD,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;IAEpC,iCAAiC;IACjC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAEzC;;2BAEuB;IACvB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAE7B;wEACoE;IACpE,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB"}
1
+ {"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../src/backend.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEtD,OAAO,KAAK,EACV,kBAAkB,EAClB,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,SAAS,EACT,QAAQ,EACR,SAAS,EACT,aAAa,EACd,MAAM,eAAe,CAAC;AAEvB;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,aAAa;IAC5B;wEACoE;IACpE,KAAK,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAExD;;8DAE0D;IAC1D,KAAK,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAEvD;;qEAEiE;IACjE,WAAW,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,SAAS,CAAC;IAClB,wEAAwE;IACxE,iBAAiB,EAAE,MAAM,CAAC;IAC1B,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,MAAM,EAAE,aAAa,CAAC;IACtB;;;mCAG+B;IAC/B,aAAa,EAAE,OAAO,CAAC;IACvB;;4CAEwC;IACxC,OAAO,EAAE,OAAO,CAAC;IAEjB;kDAC8C;IAC9C,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAAC;IAClC;;gEAE4D;IAC5D,UAAU,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IACnE,8DAA8D;IAC9D,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B;mFAC+E;IAC/E,OAAO,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;IACjC;;gFAE4E;IAC5E,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAC7D;6DACyD;IACzD,aAAa,IAAI,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,cAAc;IAC7B;0DACsD;IACtD,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;IAEpC,iCAAiC;IACjC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAEzC;;2BAEuB;IACvB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAE7B;wEACoE;IACpE,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB"}
package/dist/config.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { RunnerTerms } from "./contract.js";
1
+ import type { PullPolicy, RunnerTerms } from "./contract.js";
2
2
  /**
3
3
  * Backend-neutral runner configuration. Concrete runners (docker, k8s) extend
4
4
  * `RunnerCoreConfig` with their own fields and reuse these parse helpers so
@@ -30,6 +30,48 @@ export declare function parsePort(raw: string | undefined, fallback: number): nu
30
30
  * silent "no terms", so a misconfiguration can't quietly drop the gate.
31
31
  */
32
32
  export declare function loadTermsFromEnv(env: NodeJS.ProcessEnv): RunnerTerms | undefined;
33
+ /**
34
+ * An operator-predefined application entry in `RUNNER_APPS`. The catalog is the
35
+ * whole gate: a client launches an app by name and can neither pick the image
36
+ * nor read the injected env, so no allowlist beyond the catalog is needed.
37
+ *
38
+ * The catalog may embed secrets (`env` values), so treat the whole `RUNNER_APPS`
39
+ * value as secret material (docker: a `.env.local` file; k8s: source it from a
40
+ * Secret). Only `name`/`title`/`description` are ever advertised outward —
41
+ * `image` and `env` never leave the runner.
42
+ */
43
+ export interface RunnerAppConfig {
44
+ image: string;
45
+ /** Env injected verbatim into the app's workload (operator secrets included).
46
+ * A client-supplied value for any key defined here is dropped — operator
47
+ * values always win. */
48
+ env?: Record<string, string>;
49
+ /** Workload image pull policy (default `missing`); `always` keeps a moving
50
+ * tag like `latest-slim` fresh. */
51
+ pullPolicy?: PullPolicy;
52
+ title?: string;
53
+ description?: string;
54
+ }
55
+ /** A validated catalog entry with defaults applied, keyed back by its name. */
56
+ export interface ResolvedRunnerApp {
57
+ name: string;
58
+ image: string;
59
+ env: Record<string, string>;
60
+ pullPolicy: PullPolicy;
61
+ title?: string;
62
+ description?: string;
63
+ }
64
+ /**
65
+ * Parse the `RUNNER_APPS` JSON catalog ({ "<name>": RunnerAppConfig }).
66
+ * Returns `undefined` when unset (no apps offered). Malformed JSON or entries
67
+ * are a hard `RunnerConfigError` — a broken catalog must not silently drop
68
+ * the apps.
69
+ */
70
+ export declare function loadAppsFromEnv(env: NodeJS.ProcessEnv): Record<string, RunnerAppConfig> | undefined;
71
+ /** The catalog runners pass to `buildServer`: `RUNNER_APPS` validated with
72
+ * defaults applied; empty when unset. The catalog is pure operator
73
+ * configuration — runner-core knows nothing about any specific app. */
74
+ export declare function loadResolvedApps(env: NodeJS.ProcessEnv): Record<string, ResolvedRunnerApp>;
33
75
  export declare function parseCorsOrigins(raw: string | undefined): string[] | "*";
34
76
  export declare function loadCoreConfig(env: NodeJS.ProcessEnv, defaults?: {
35
77
  port?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,WAAW,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC;CAC7B;AAED,qBAAa,iBAAkB,SAAQ,KAAK;CAAG;AAE/C,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,MAAM,GAAG,SAAS,EACvB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,GACZ,MAAM,CAOR;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAM5F;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAO3E;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,WAAW,GAAG,SAAS,CAQhF;AAsBD,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,EAAE,GAAG,GAAG,CAMxE;AAED,wBAAgB,cAAc,CAC5B,GAAG,EAAE,MAAM,CAAC,UAAU,EACtB,QAAQ,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/B,gBAAgB,CAiBlB"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE7D;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,WAAW,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC;CAC7B;AAED,qBAAa,iBAAkB,SAAQ,KAAK;CAAG;AAE/C,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,MAAM,GAAG,SAAS,EACvB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,GACZ,MAAM,CAOR;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAM5F;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAO3E;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,WAAW,GAAG,SAAS,CAQhF;AAsBD;;;;;;;;;GASG;AACH,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd;;6BAEyB;IACzB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B;wCACoC;IACpC,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,+EAA+E;AAC/E,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,UAAU,EAAE,UAAU,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAID;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,MAAM,CAAC,UAAU,GACrB,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,SAAS,CAmB7C;AAkCD;;wEAEwE;AACxE,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAc1F;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,EAAE,GAAG,GAAG,CAMxE;AAED,wBAAgB,cAAc,CAC5B,GAAG,EAAE,MAAM,CAAC,UAAU,EACtB,QAAQ,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/B,gBAAgB,CAiBlB"}
package/dist/config.js CHANGED
@@ -68,6 +68,83 @@ function resolveTermsBody(env) {
68
68
  function hashTermsVersion(body) {
69
69
  return createHash("sha256").update(body).digest("hex").slice(0, 12);
70
70
  }
71
+ const PULL_POLICIES = ["missing", "always", "never"];
72
+ /**
73
+ * Parse the `RUNNER_APPS` JSON catalog ({ "<name>": RunnerAppConfig }).
74
+ * Returns `undefined` when unset (no apps offered). Malformed JSON or entries
75
+ * are a hard `RunnerConfigError` — a broken catalog must not silently drop
76
+ * the apps.
77
+ */
78
+ export function loadAppsFromEnv(env) {
79
+ const raw = env.RUNNER_APPS?.trim();
80
+ if (!raw)
81
+ return undefined;
82
+ let parsed;
83
+ try {
84
+ parsed = JSON.parse(raw);
85
+ }
86
+ catch (err) {
87
+ throw new RunnerConfigError(`RUNNER_APPS is not valid JSON: ${err.message}`);
88
+ }
89
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
90
+ throw new RunnerConfigError("RUNNER_APPS must be a JSON object mapping app name → app config.");
91
+ }
92
+ // Null-prototype map so an app literally named `__proto__` is stored as a
93
+ // plain key rather than mutating the object's prototype.
94
+ const catalog = Object.create(null);
95
+ for (const [name, value] of Object.entries(parsed)) {
96
+ catalog[name] = validateAppEntry(name, value);
97
+ }
98
+ return catalog;
99
+ }
100
+ function validateAppEntry(name, value) {
101
+ const fail = (detail) => {
102
+ throw new RunnerConfigError(`RUNNER_APPS entry '${name}' ${detail}`);
103
+ };
104
+ if (name.trim() === "")
105
+ fail("has an empty name.");
106
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
107
+ fail("must be an object.");
108
+ }
109
+ const entry = value;
110
+ if (typeof entry.image !== "string" || entry.image.trim() === "") {
111
+ fail("needs a non-empty string 'image'.");
112
+ }
113
+ if (entry.env !== undefined &&
114
+ (entry.env === null ||
115
+ typeof entry.env !== "object" ||
116
+ Array.isArray(entry.env) ||
117
+ Object.values(entry.env).some((v) => typeof v !== "string"))) {
118
+ fail("has an invalid 'env' — expected an object of string values.");
119
+ }
120
+ if (entry.pullPolicy !== undefined && !PULL_POLICIES.includes(entry.pullPolicy)) {
121
+ fail(`has an invalid 'pullPolicy' — expected one of ${PULL_POLICIES.join(", ")}.`);
122
+ }
123
+ for (const key of ["title", "description"]) {
124
+ if (entry[key] !== undefined && typeof entry[key] !== "string") {
125
+ fail(`has an invalid '${key}' — expected a string.`);
126
+ }
127
+ }
128
+ return entry;
129
+ }
130
+ /** The catalog runners pass to `buildServer`: `RUNNER_APPS` validated with
131
+ * defaults applied; empty when unset. The catalog is pure operator
132
+ * configuration — runner-core knows nothing about any specific app. */
133
+ export function loadResolvedApps(env) {
134
+ const catalog = loadAppsFromEnv(env) ?? {};
135
+ const resolved = Object.create(null);
136
+ for (const [name, entry] of Object.entries(catalog)) {
137
+ resolved[name] = {
138
+ name,
139
+ image: entry.image,
140
+ env: entry.env ?? {},
141
+ pullPolicy: entry.pullPolicy ?? "missing",
142
+ title: entry.title,
143
+ description: entry.description,
144
+ };
145
+ }
146
+ return resolved;
147
+ }
71
148
  export function parseCorsOrigins(raw) {
72
149
  if (raw === undefined || raw.trim() === "" || raw.trim() === "*")
73
150
  return "*";
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -28,6 +28,10 @@ export interface RunnerCapabilities {
28
28
  * with `428 terms_required` unless the client sends `x-telo-accepted-terms`
29
29
  * matching `terms.version`. The editor surfaces it and records acceptance. */
30
30
  terms?: RunnerTerms;
31
+ /** Operator-predefined applications this runner can launch by name
32
+ * (`StartSessionRequest.app`). Absent/empty when none are offered — clients
33
+ * hide the corresponding entry points. */
34
+ apps?: RunnerAppDescriptor[];
31
35
  }
32
36
  /** An operator-defined agreement. `version` is opaque and operator-controlled;
33
37
  * bumping it re-prompts every client. `body` is plain text / markdown. */
@@ -44,6 +48,17 @@ export interface RunnerFeatures {
44
48
  /** Runner can publish workload ports back to the client. */
45
49
  ports: boolean;
46
50
  }
51
+ /** An operator-predefined application the runner can launch by name. Only the
52
+ * identity is advertised — the image and the operator env injected into it
53
+ * stay server-side, so a client can never pick the image or reach the
54
+ * secrets. Which apps exist is pure operator configuration (`RUNNER_APPS`);
55
+ * the runner has no built-in knowledge of any specific app. */
56
+ export interface RunnerAppDescriptor {
57
+ /** Wire id requested via `StartSessionRequest.app`. */
58
+ name: string;
59
+ title?: string;
60
+ description?: string;
61
+ }
47
62
  /** A JSON Schema document, kept structurally open so runner-core need not depend
48
63
  * on a JSON-Schema type package. The editor treats it as `JSONSchema7`. */
49
64
  export type JsonSchema = Record<string, unknown>;
@@ -98,10 +113,17 @@ export interface RunnerEndpoint {
98
113
  url?: string;
99
114
  }
100
115
  export interface StartSessionRequest {
101
- bundle: RunBundle;
116
+ /** Launch an operator-predefined application by name (see
117
+ * {@link RunnerAppDescriptor}) instead of a client bundle. The runner
118
+ * resolves the image and injects the app's operator env server-side;
119
+ * `bundle` and `config.image` are ignored. */
120
+ app?: string;
121
+ /** Required unless `app` is set. */
122
+ bundle?: RunBundle;
102
123
  env: Record<string, string>;
103
124
  ports?: PortMapping[];
104
- config: SessionConfig;
125
+ /** Required unless `app` is set. */
126
+ config?: SessionConfig;
105
127
  /** Request the kernel debug stream. When true the runner launches the
106
128
  * workload with `--inspect`, subscribes to the in-workload inspect endpoint
107
129
  * (reachable only by the runner — never published outward), and relays each
@@ -1 +1 @@
1
- {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAoCH,8EAA8E;AAC9E,MAAM,CAAC,MAAM,qBAAqB,GAAG,uBAAuB,CAAC;AA2G7D,MAAM,UAAU,UAAU,CAAC,MAAiB;IAC1C,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,CAAC;AAC3F,CAAC;AAeD,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IAExB;IACA;IAEA;IAJlB,YACkB,IAAoC,EACpC,KAAwB,EACxC,OAAe,EACC,aAAsB;QAEtC,KAAK,CAAC,OAAO,CAAC,CAAC;QALC,SAAI,GAAJ,IAAI,CAAgC;QACpC,UAAK,GAAL,KAAK,CAAmB;QAExB,kBAAa,GAAb,aAAa,CAAS;QAGtC,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IAClC,CAAC;CACF"}
1
+ {"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAwCH,8EAA8E;AAC9E,MAAM,CAAC,MAAM,qBAAqB,GAAG,uBAAuB,CAAC;AA8H7D,MAAM,UAAU,UAAU,CAAC,MAAiB;IAC1C,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,CAAC;AAC3F,CAAC;AAeD,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IAExB;IACA;IAEA;IAJlB,YACkB,IAAoC,EACpC,KAAwB,EACxC,OAAe,EACC,aAAsB;QAEtC,KAAK,CAAC,OAAO,CAAC,CAAC;QALC,SAAI,GAAJ,IAAI,CAAgC;QACpC,UAAK,GAAL,KAAK,CAAmB;QAExB,kBAAa,GAAb,aAAa,CAAS;QAGtC,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IAClC,CAAC;CACF"}
@@ -1,6 +1,7 @@
1
1
  import type { FastifyPluginAsync } from "fastify";
2
2
  import type { RunnerBackend } from "../backend.js";
3
3
  import { type RunnerTerms, type SessionConfig } from "../contract.js";
4
+ import type { ResolvedRunnerApp } from "../config.js";
4
5
  import { type SessionRegistry } from "../session/registry.js";
5
6
  export interface SessionsRouteDeps {
6
7
  backend: RunnerBackend;
@@ -12,6 +13,10 @@ export interface SessionsRouteDeps {
12
13
  /** When set, a session may only start if the client acknowledges this exact
13
14
  * terms version via the `x-telo-accepted-terms` header. */
14
15
  terms?: RunnerTerms;
16
+ /** Operator-predefined applications launchable by name
17
+ * (`StartSessionRequest.app`), with their operator env already resolved.
18
+ * The catalog is the whole gate — an unknown name is rejected. */
19
+ apps?: Record<string, ResolvedRunnerApp>;
15
20
  /** Backend-supplied config gate. Returns an error message to reject the
16
21
  * request with `400 invalid_config`, or `undefined` to accept. The runner is
17
22
  * the source of truth, so this re-checks what `/v1/capabilities` advertises
@@ -1 +1 @@
1
- {"version":3,"file":"sessions.d.ts","sourceRoot":"","sources":["../../src/routes/sessions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAmB,kBAAkB,EAAgB,MAAM,SAAS,CAAC;AAGjF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,aAAa,EAEnB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAAqB,KAAK,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGjF,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,aAAa,CAAC;IACvB,QAAQ,EAAE,eAAe,CAAC;IAC1B,WAAW,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC;IAC5B;kEAC8D;IAC9D,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;gEAC4D;IAC5D,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB;;;gFAG4E;IAC5E,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,MAAM,GAAG,SAAS,CAAC;CAChE;AAoDD,wBAAgB,aAAa,CAAC,IAAI,EAAE,iBAAiB,GAAG,kBAAkB,CAkEzE"}
1
+ {"version":3,"file":"sessions.d.ts","sourceRoot":"","sources":["../../src/routes/sessions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAmB,kBAAkB,EAAgB,MAAM,SAAS,CAAC;AAGjF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAIL,KAAK,WAAW,EAChB,KAAK,aAAa,EAEnB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAGtD,OAAO,EAAqB,KAAK,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGjF,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,aAAa,CAAC;IACvB,QAAQ,EAAE,eAAe,CAAC;IAC1B,WAAW,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC;IAC5B;kEAC8D;IAC9D,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;gEAC4D;IAC5D,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB;;uEAEmE;IACnE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IACzC;;;gFAG4E;IAC5E,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,MAAM,GAAG,SAAS,CAAC;CAChE;AAuDD,wBAAgB,aAAa,CAAC,IAAI,EAAE,iBAAiB,GAAG,kBAAkB,CAkEzE"}
@@ -4,10 +4,13 @@ import { BundlePathError, normalizeBundlePath } from "../session/bundle-path.js"
4
4
  import { generateSessionId } from "../session/session-id.js";
5
5
  import { SessionLimitError } from "../session/registry.js";
6
6
  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.
7
9
  const startBodySchema = {
8
10
  type: "object",
9
- required: ["bundle", "env", "config"],
11
+ required: ["env"],
10
12
  properties: {
13
+ app: { type: "string", minLength: 1 },
11
14
  bundle: {
12
15
  type: "object",
13
16
  required: ["entryRelativePath", "files"],
@@ -112,30 +115,68 @@ export function sessionsRoute(deps) {
112
115
  }
113
116
  async function startSession(app, deps, body, reply) {
114
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;
115
143
  let entryRelative;
116
- try {
117
- // Traversal guard for the entry path and every bundle file — a `../foo`
118
- // would let the workload read or execute paths outside its session dir.
119
- // Validated here (backend-neutral) so a bad path is a 400, not a backend
120
- // 500, regardless of how the backend ultimately delivers the bundle.
121
- entryRelative = normalizeBundlePath(body.bundle.entryRelativePath);
122
- for (const file of body.bundle.files)
123
- normalizeBundlePath(file.relativePath);
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 };
124
151
  }
125
- catch (err) {
126
- if (err instanceof BundlePathError) {
127
- reply.code(400).send({ error: "invalid_bundle", message: err.message });
128
- return;
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);
129
163
  }
130
- throw err;
131
- }
132
- // Backend config gate (e.g. an image allowlist). The advertised capabilities
133
- // constrain the editor; this enforces the same against any client.
134
- if (deps.validateConfig) {
135
- const message = deps.validateConfig(body.config);
136
- if (message) {
137
- reply.code(400).send({ error: "invalid_config", message });
138
- return;
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
+ }
139
180
  }
140
181
  }
141
182
  let entry;
@@ -149,15 +190,24 @@ async function startSession(app, deps, body, reply) {
149
190
  }
150
191
  throw err;
151
192
  }
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,
200
+ }
201
+ : body.env;
152
202
  // Surface a TELO_REGISTRY_URL to the workload so the telo CLI inside picks
153
- // it up. Precedence: body.env explicit value > body.config.registryUrl
154
- // (per-request override) > runner's own default. Trim client-supplied URLs
155
- // so stray whitespace from an editor input doesn't flow into the workload.
156
- const configRegistryUrl = body.config.registryUrl?.trim() || undefined;
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;
157
207
  const registryUrl = configRegistryUrl ?? deps.defaultRegistryUrl;
158
- const sessionEnv = registryUrl && !("TELO_REGISTRY_URL" in body.env)
159
- ? { ...body.env, TELO_REGISTRY_URL: registryUrl }
160
- : body.env;
208
+ const sessionEnv = registryUrl && !("TELO_REGISTRY_URL" in clientEnv)
209
+ ? { ...clientEnv, TELO_REGISTRY_URL: registryUrl }
210
+ : clientEnv;
161
211
  // Respond as soon as the session is registered — BEFORE the backend starts.
162
212
  // `backend.start()` now spans the on-cluster image build and pod bring-up,
163
213
  // which can take seconds-to-minutes; awaiting it here would hide the event
@@ -173,11 +223,12 @@ async function startSession(app, deps, body, reply) {
173
223
  deps.backend
174
224
  .start({
175
225
  sessionId,
176
- bundle: body.bundle,
226
+ bundle,
177
227
  entryRelativePath: entryRelative,
178
228
  env: sessionEnv,
179
229
  ports: body.ports ?? [],
180
- config: body.config,
230
+ config,
231
+ selfContained: appEntry !== undefined,
181
232
  inspect: body.inspect ?? false,
182
233
  onStatus: (status) => deps.registry.emit(sessionId, { type: "status", status }),
183
234
  onProgress: (phase, message, done) => deps.registry.emit(sessionId, { type: "progress", phase, message, done }),
@@ -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
@@ -1,6 +1,6 @@
1
1
  import { type FastifyBaseLogger, type FastifyInstance } from "fastify";
2
2
  import type { RunnerBackend } from "./backend.js";
3
- import type { RunnerCoreConfig } from "./config.js";
3
+ import type { ResolvedRunnerApp, RunnerCoreConfig } from "./config.js";
4
4
  import type { RunnerCapabilities, SessionConfig } from "./contract.js";
5
5
  import { SessionRegistry } from "./session/registry.js";
6
6
  export interface ServerDeps {
@@ -16,8 +16,13 @@ export interface ServerDeps {
16
16
  /** Runner's default registry URL, passed to workloads as TELO_REGISTRY_URL. */
17
17
  defaultRegistryUrl?: string;
18
18
  /** Backend config gate, enforced on `POST /v1/sessions` before the workload
19
- * starts (e.g. an `image` allowlist). Rejects with `400 invalid_config`. */
19
+ * starts (e.g. an `image` allowlist). Rejects with `400 invalid_config`.
20
+ * Not consulted for app sessions — their image comes from `apps`. */
20
21
  validateConfig?: (config: SessionConfig) => string | undefined;
22
+ /** Operator-predefined applications launchable by name (usually
23
+ * `loadResolvedApps(process.env)`). Advertised on /v1/capabilities as
24
+ * `apps` descriptors; the session route resolves and gates against it. */
25
+ apps?: Record<string, ResolvedRunnerApp>;
21
26
  registry?: SessionRegistry;
22
27
  }
23
28
  export interface ServerHandle {
@@ -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,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAMvE,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;iFAC6E;IAC7E,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,MAAM,GAAG,SAAS,CAAC;IAC/D,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,CA8CzE;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;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"}
package/dist/server.js CHANGED
@@ -25,11 +25,19 @@ export async function buildServer(deps) {
25
25
  exitTtlMs: deps.config.exitTtlMs,
26
26
  replayBufferBytes: deps.config.replayBufferBytes,
27
27
  });
28
+ // The app catalog is injected into the served capabilities document here, so
29
+ // what /v1/capabilities advertises and what the session route accepts can
30
+ // never drift — both come from `deps.apps`.
31
+ const appDescriptors = Object.values(deps.apps ?? {}).map(({ name, title, description }) => ({ name, title, description }));
32
+ const withApps = (caps) => appDescriptors.length > 0 ? { ...caps, apps: appDescriptors } : caps;
33
+ const capabilitiesGetter = typeof deps.capabilities === "function"
34
+ ? () => withApps(deps.capabilities())
35
+ : withApps(deps.capabilities);
28
36
  // Terms are stable across the process — resolve the capabilities once for them
29
37
  // even when `capabilities` is a getter (the route still re-resolves per request).
30
- const capabilitiesValue = typeof deps.capabilities === "function" ? deps.capabilities() : deps.capabilities;
38
+ const capabilitiesValue = typeof capabilitiesGetter === "function" ? capabilitiesGetter() : capabilitiesGetter;
31
39
  await app.register(healthRoute(deps.version));
32
- await app.register(capabilitiesRoute(deps.capabilities));
40
+ await app.register(capabilitiesRoute(capabilitiesGetter));
33
41
  await app.register(probeRoute({ backend: deps.backend }));
34
42
  await app.register(sessionsRoute({
35
43
  backend: deps.backend,
@@ -40,6 +48,7 @@ export async function buildServer(deps) {
40
48
  // The capabilities document is the single source of the runner's terms;
41
49
  // the session route enforces what /v1/capabilities advertises.
42
50
  terms: capabilitiesValue.terms,
51
+ apps: deps.apps,
43
52
  }));
44
53
  await app.register(ioRoute({ registry, corsOrigins: deps.config.corsOrigins }));
45
54
  return { app, registry };
@@ -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.6.0",
3
+ "version": "0.7.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",
@@ -0,0 +1,54 @@
1
+ import { describe, expect, it } from "vitest";
2
+
3
+ import { loadAppsFromEnv, loadResolvedApps, RunnerConfigError } from "./config.js";
4
+
5
+ describe("loadAppsFromEnv", () => {
6
+ it("returns undefined when RUNNER_APPS is unset (no apps offered)", () => {
7
+ expect(loadAppsFromEnv({})).toBeUndefined();
8
+ });
9
+
10
+ it("parses a valid catalog", () => {
11
+ const catalog = loadAppsFromEnv({
12
+ RUNNER_APPS: JSON.stringify({
13
+ tool: {
14
+ image: "acme/tool:1.2.0",
15
+ env: { SERVICE_TOKEN: "tok-op" },
16
+ pullPolicy: "never",
17
+ },
18
+ }),
19
+ })!;
20
+ expect(catalog.tool.image).toBe("acme/tool:1.2.0");
21
+ expect(catalog.tool.env).toEqual({ SERVICE_TOKEN: "tok-op" });
22
+ });
23
+
24
+ it("rejects malformed JSON and invalid entries loudly", () => {
25
+ expect(() => loadAppsFromEnv({ RUNNER_APPS: "{nope" })).toThrow(RunnerConfigError);
26
+ expect(() => loadAppsFromEnv({ RUNNER_APPS: '{"x":{}}' })).toThrow(/needs a non-empty string 'image'/);
27
+ expect(() => loadAppsFromEnv({ RUNNER_APPS: '{"x":{"image":"i","env":["nope"]}}' })).toThrow(
28
+ /invalid 'env'/,
29
+ );
30
+ expect(() =>
31
+ loadAppsFromEnv({ RUNNER_APPS: '{"x":{"image":"i","pullPolicy":"sometimes"}}' }),
32
+ ).toThrow(/pullPolicy/);
33
+ });
34
+ });
35
+
36
+ describe("loadResolvedApps", () => {
37
+ it("is empty when RUNNER_APPS is unset", () => {
38
+ expect(loadResolvedApps({})).toEqual({});
39
+ });
40
+
41
+ it("applies defaults to the configured catalog", () => {
42
+ const resolved = loadResolvedApps({
43
+ RUNNER_APPS: '{"tool":{"image":"acme/tool:1"}}',
44
+ });
45
+ expect(resolved.tool).toEqual({
46
+ name: "tool",
47
+ image: "acme/tool:1",
48
+ env: {},
49
+ pullPolicy: "missing",
50
+ title: undefined,
51
+ description: undefined,
52
+ });
53
+ });
54
+ });
package/src/backend.ts CHANGED
@@ -48,6 +48,11 @@ 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`):
52
+ * `config.image` is self-contained (app + controllers baked in), so the
53
+ * backend runs the image's own entrypoint and stages no bundle — `bundle`
54
+ * is an empty placeholder. */
55
+ selfContained: boolean;
51
56
  /** When true, launch the workload with `--inspect` and relay its kernel debug
52
57
  * stream via `onDebug`. The inspect endpoint stays reachable only by the
53
58
  * runner — never published outward. */
package/src/config.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { readFileSync } from "node:fs";
3
3
 
4
- import type { RunnerTerms } from "./contract.js";
4
+ import type { PullPolicy, RunnerTerms } from "./contract.js";
5
5
 
6
6
  /**
7
7
  * Backend-neutral runner configuration. Concrete runners (docker, k8s) extend
@@ -91,6 +91,121 @@ function hashTermsVersion(body: string): string {
91
91
  return createHash("sha256").update(body).digest("hex").slice(0, 12);
92
92
  }
93
93
 
94
+ /**
95
+ * An operator-predefined application entry in `RUNNER_APPS`. The catalog is the
96
+ * whole gate: a client launches an app by name and can neither pick the image
97
+ * nor read the injected env, so no allowlist beyond the catalog is needed.
98
+ *
99
+ * The catalog may embed secrets (`env` values), so treat the whole `RUNNER_APPS`
100
+ * value as secret material (docker: a `.env.local` file; k8s: source it from a
101
+ * Secret). Only `name`/`title`/`description` are ever advertised outward —
102
+ * `image` and `env` never leave the runner.
103
+ */
104
+ export interface RunnerAppConfig {
105
+ image: string;
106
+ /** Env injected verbatim into the app's workload (operator secrets included).
107
+ * A client-supplied value for any key defined here is dropped — operator
108
+ * values always win. */
109
+ env?: Record<string, string>;
110
+ /** Workload image pull policy (default `missing`); `always` keeps a moving
111
+ * tag like `latest-slim` fresh. */
112
+ pullPolicy?: PullPolicy;
113
+ title?: string;
114
+ description?: string;
115
+ }
116
+
117
+ /** A validated catalog entry with defaults applied, keyed back by its name. */
118
+ export interface ResolvedRunnerApp {
119
+ name: string;
120
+ image: string;
121
+ env: Record<string, string>;
122
+ pullPolicy: PullPolicy;
123
+ title?: string;
124
+ description?: string;
125
+ }
126
+
127
+ const PULL_POLICIES: readonly string[] = ["missing", "always", "never"];
128
+
129
+ /**
130
+ * Parse the `RUNNER_APPS` JSON catalog ({ "<name>": RunnerAppConfig }).
131
+ * Returns `undefined` when unset (no apps offered). Malformed JSON or entries
132
+ * are a hard `RunnerConfigError` — a broken catalog must not silently drop
133
+ * the apps.
134
+ */
135
+ export function loadAppsFromEnv(
136
+ env: NodeJS.ProcessEnv,
137
+ ): Record<string, RunnerAppConfig> | undefined {
138
+ const raw = env.RUNNER_APPS?.trim();
139
+ if (!raw) return undefined;
140
+ let parsed: unknown;
141
+ try {
142
+ parsed = JSON.parse(raw);
143
+ } catch (err) {
144
+ throw new RunnerConfigError(`RUNNER_APPS is not valid JSON: ${(err as Error).message}`);
145
+ }
146
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
147
+ throw new RunnerConfigError("RUNNER_APPS must be a JSON object mapping app name → app config.");
148
+ }
149
+ // Null-prototype map so an app literally named `__proto__` is stored as a
150
+ // plain key rather than mutating the object's prototype.
151
+ const catalog: Record<string, RunnerAppConfig> = Object.create(null);
152
+ for (const [name, value] of Object.entries(parsed)) {
153
+ catalog[name] = validateAppEntry(name, value);
154
+ }
155
+ return catalog;
156
+ }
157
+
158
+ function validateAppEntry(name: string, value: unknown): RunnerAppConfig {
159
+ const fail = (detail: string): never => {
160
+ throw new RunnerConfigError(`RUNNER_APPS entry '${name}' ${detail}`);
161
+ };
162
+ if (name.trim() === "") fail("has an empty name.");
163
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
164
+ fail("must be an object.");
165
+ }
166
+ const entry = value as Record<string, unknown>;
167
+ if (typeof entry.image !== "string" || entry.image.trim() === "") {
168
+ fail("needs a non-empty string 'image'.");
169
+ }
170
+ if (
171
+ entry.env !== undefined &&
172
+ (entry.env === null ||
173
+ typeof entry.env !== "object" ||
174
+ Array.isArray(entry.env) ||
175
+ Object.values(entry.env).some((v) => typeof v !== "string"))
176
+ ) {
177
+ fail("has an invalid 'env' — expected an object of string values.");
178
+ }
179
+ if (entry.pullPolicy !== undefined && !PULL_POLICIES.includes(entry.pullPolicy as string)) {
180
+ fail(`has an invalid 'pullPolicy' — expected one of ${PULL_POLICIES.join(", ")}.`);
181
+ }
182
+ for (const key of ["title", "description"] as const) {
183
+ if (entry[key] !== undefined && typeof entry[key] !== "string") {
184
+ fail(`has an invalid '${key}' — expected a string.`);
185
+ }
186
+ }
187
+ return entry as unknown as RunnerAppConfig;
188
+ }
189
+
190
+ /** The catalog runners pass to `buildServer`: `RUNNER_APPS` validated with
191
+ * defaults applied; empty when unset. The catalog is pure operator
192
+ * configuration — runner-core knows nothing about any specific app. */
193
+ export function loadResolvedApps(env: NodeJS.ProcessEnv): Record<string, ResolvedRunnerApp> {
194
+ const catalog = loadAppsFromEnv(env) ?? {};
195
+ const resolved: Record<string, ResolvedRunnerApp> = Object.create(null);
196
+ for (const [name, entry] of Object.entries(catalog)) {
197
+ resolved[name] = {
198
+ name,
199
+ image: entry.image,
200
+ env: entry.env ?? {},
201
+ pullPolicy: entry.pullPolicy ?? "missing",
202
+ title: entry.title,
203
+ description: entry.description,
204
+ };
205
+ }
206
+ return resolved;
207
+ }
208
+
94
209
  export function parseCorsOrigins(raw: string | undefined): string[] | "*" {
95
210
  if (raw === undefined || raw.trim() === "" || raw.trim() === "*") return "*";
96
211
  return raw
package/src/contract.ts CHANGED
@@ -29,6 +29,10 @@ export interface RunnerCapabilities {
29
29
  * with `428 terms_required` unless the client sends `x-telo-accepted-terms`
30
30
  * matching `terms.version`. The editor surfaces it and records acceptance. */
31
31
  terms?: RunnerTerms;
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. */
35
+ apps?: RunnerAppDescriptor[];
32
36
  }
33
37
 
34
38
  /** An operator-defined agreement. `version` is opaque and operator-controlled;
@@ -49,6 +53,18 @@ export interface RunnerFeatures {
49
53
  ports: boolean;
50
54
  }
51
55
 
56
+ /** An operator-predefined application the runner can launch by name. Only the
57
+ * identity is advertised — the image and the operator env injected into it
58
+ * stay server-side, so a client can never pick the image or reach the
59
+ * secrets. Which apps exist is pure operator configuration (`RUNNER_APPS`);
60
+ * the runner has no built-in knowledge of any specific app. */
61
+ export interface RunnerAppDescriptor {
62
+ /** Wire id requested via `StartSessionRequest.app`. */
63
+ name: string;
64
+ title?: string;
65
+ description?: string;
66
+ }
67
+
52
68
  /** A JSON Schema document, kept structurally open so runner-core need not depend
53
69
  * on a JSON-Schema type package. The editor treats it as `JSONSchema7`. */
54
70
  export type JsonSchema = Record<string, unknown>;
@@ -103,10 +119,17 @@ export interface RunnerEndpoint {
103
119
  }
104
120
 
105
121
  export interface StartSessionRequest {
106
- bundle: RunBundle;
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;
107
129
  env: Record<string, string>;
108
130
  ports?: PortMapping[];
109
- config: SessionConfig;
131
+ /** Required unless `app` is set. */
132
+ config?: SessionConfig;
110
133
  /** Request the kernel debug stream. When true the runner launches the
111
134
  * workload with `--inspect`, subscribes to the in-workload inspect endpoint
112
135
  * (reachable only by the runner — never published outward), and relays each
@@ -5,10 +5,12 @@ import type { RunnerBackend } from "../backend.js";
5
5
  import {
6
6
  ACCEPTED_TERMS_HEADER,
7
7
  SessionStartError,
8
+ type RunBundle,
8
9
  type RunnerTerms,
9
10
  type SessionConfig,
10
11
  type StartSessionRequest,
11
12
  } from "../contract.js";
13
+ import type { ResolvedRunnerApp } from "../config.js";
12
14
  import { BundlePathError, normalizeBundlePath } from "../session/bundle-path.js";
13
15
  import { generateSessionId } from "../session/session-id.js";
14
16
  import { SessionLimitError, type SessionRegistry } from "../session/registry.js";
@@ -24,6 +26,10 @@ export interface SessionsRouteDeps {
24
26
  /** When set, a session may only start if the client acknowledges this exact
25
27
  * terms version via the `x-telo-accepted-terms` header. */
26
28
  terms?: RunnerTerms;
29
+ /** Operator-predefined applications launchable by name
30
+ * (`StartSessionRequest.app`), with their operator env already resolved.
31
+ * The catalog is the whole gate — an unknown name is rejected. */
32
+ apps?: Record<string, ResolvedRunnerApp>;
27
33
  /** Backend-supplied config gate. Returns an error message to reject the
28
34
  * request with `400 invalid_config`, or `undefined` to accept. The runner is
29
35
  * the source of truth, so this re-checks what `/v1/capabilities` advertises
@@ -31,10 +37,13 @@ export interface SessionsRouteDeps {
31
37
  validateConfig?: (config: SessionConfig) => string | undefined;
32
38
  }
33
39
 
40
+ // `bundle`/`config` are schema-optional because an `app` session needs neither;
41
+ // the route enforces their presence for regular bundle sessions.
34
42
  const startBodySchema = {
35
43
  type: "object",
36
- required: ["bundle", "env", "config"],
44
+ required: ["env"],
37
45
  properties: {
46
+ app: { type: "string", minLength: 1 },
38
47
  bundle: {
39
48
  type: "object",
40
49
  required: ["entryRelativePath", "files"],
@@ -157,29 +166,68 @@ async function startSession(
157
166
  ): Promise<void> {
158
167
  const sessionId = generateSessionId();
159
168
 
169
+ // App sessions launch an operator-predefined image by name: the catalog
170
+ // resolves the image and operator env server-side, so the client can neither
171
+ // pick the image nor reach the secrets — the catalog IS the gate, and an
172
+ // unknown name is rejected here.
173
+ const appEntry = body.app === undefined ? undefined : deps.apps?.[body.app];
174
+ if (body.app !== undefined && !appEntry) {
175
+ const offered = Object.keys(deps.apps ?? {});
176
+ reply.code(400).send({
177
+ error: "unknown_app",
178
+ message:
179
+ `app '${body.app}' is not offered by this runner` +
180
+ (offered.length > 0
181
+ ? ` — offered apps: ${offered.join(", ")}`
182
+ : " — it offers no predefined applications") +
183
+ " (see /v1/capabilities).",
184
+ });
185
+ return;
186
+ }
187
+ if (!appEntry && (!body.bundle || !body.config)) {
188
+ reply.code(400).send({
189
+ error: "invalid_request",
190
+ message: "'bundle' and 'config' are required unless launching a predefined app via 'app'.",
191
+ });
192
+ return;
193
+ }
194
+
195
+ let bundle: RunBundle;
160
196
  let entryRelative: string;
161
- try {
162
- // Traversal guard for the entry path and every bundle file — a `../foo`
163
- // would let the workload read or execute paths outside its session dir.
164
- // Validated here (backend-neutral) so a bad path is a 400, not a backend
165
- // 500, regardless of how the backend ultimately delivers the bundle.
166
- entryRelative = normalizeBundlePath(body.bundle.entryRelativePath);
167
- for (const file of body.bundle.files) normalizeBundlePath(file.relativePath);
168
- } catch (err) {
169
- if (err instanceof BundlePathError) {
170
- reply.code(400).send({ error: "invalid_bundle", message: err.message });
171
- return;
197
+ let config: SessionConfig;
198
+ if (appEntry) {
199
+ // Self-contained image no bundle to deliver; the entry path is an unused
200
+ // placeholder so the backend spec stays total.
201
+ bundle = { entryRelativePath: "telo.yaml", files: [] };
202
+ entryRelative = bundle.entryRelativePath;
203
+ config = { image: appEntry.image, pullPolicy: appEntry.pullPolicy };
204
+ } else {
205
+ bundle = body.bundle!;
206
+ config = body.config!;
207
+ try {
208
+ // Traversal guard for the entry path and every bundle file — a `../foo`
209
+ // would let the workload read or execute paths outside its session dir.
210
+ // Validated here (backend-neutral) so a bad path is a 400, not a backend
211
+ // 500, regardless of how the backend ultimately delivers the bundle.
212
+ entryRelative = normalizeBundlePath(bundle.entryRelativePath);
213
+ for (const file of bundle.files) normalizeBundlePath(file.relativePath);
214
+ } catch (err) {
215
+ if (err instanceof BundlePathError) {
216
+ reply.code(400).send({ error: "invalid_bundle", message: err.message });
217
+ return;
218
+ }
219
+ throw err;
172
220
  }
173
- throw err;
174
- }
175
221
 
176
- // Backend config gate (e.g. an image allowlist). The advertised capabilities
177
- // constrain the editor; this enforces the same against any client.
178
- if (deps.validateConfig) {
179
- const message = deps.validateConfig(body.config);
180
- if (message) {
181
- reply.code(400).send({ error: "invalid_config", message });
182
- return;
222
+ // Backend config gate (e.g. an image allowlist). The advertised capabilities
223
+ // constrain the editor; this enforces the same against any client. App
224
+ // sessions skip it — their image comes from the catalog, not the client.
225
+ if (deps.validateConfig) {
226
+ const message = deps.validateConfig(config);
227
+ if (message) {
228
+ reply.code(400).send({ error: "invalid_config", message });
229
+ return;
230
+ }
183
231
  }
184
232
  }
185
233
 
@@ -194,16 +242,28 @@ async function startSession(
194
242
  throw err;
195
243
  }
196
244
 
245
+ // For an app session, drop client-supplied values for any env key the
246
+ // catalog defines (a client must never override operator-held values, which
247
+ // include secrets), then inject the operator's values.
248
+ const clientEnv = appEntry
249
+ ? {
250
+ ...Object.fromEntries(
251
+ Object.entries(body.env).filter(([key]) => !(key in appEntry.env)),
252
+ ),
253
+ ...appEntry.env,
254
+ }
255
+ : body.env;
256
+
197
257
  // Surface a TELO_REGISTRY_URL to the workload so the telo CLI inside picks
198
- // it up. Precedence: body.env explicit value > body.config.registryUrl
199
- // (per-request override) > runner's own default. Trim client-supplied URLs
200
- // so stray whitespace from an editor input doesn't flow into the workload.
201
- const configRegistryUrl = body.config.registryUrl?.trim() || undefined;
258
+ // it up. Precedence: explicit env value > config.registryUrl (per-request
259
+ // override) > runner's own default. Trim client-supplied URLs so stray
260
+ // whitespace from an editor input doesn't flow into the workload.
261
+ const configRegistryUrl = config.registryUrl?.trim() || undefined;
202
262
  const registryUrl = configRegistryUrl ?? deps.defaultRegistryUrl;
203
263
  const sessionEnv =
204
- registryUrl && !("TELO_REGISTRY_URL" in body.env)
205
- ? { ...body.env, TELO_REGISTRY_URL: registryUrl }
206
- : body.env;
264
+ registryUrl && !("TELO_REGISTRY_URL" in clientEnv)
265
+ ? { ...clientEnv, TELO_REGISTRY_URL: registryUrl }
266
+ : clientEnv;
207
267
 
208
268
  // Respond as soon as the session is registered — BEFORE the backend starts.
209
269
  // `backend.start()` now spans the on-cluster image build and pod bring-up,
@@ -221,11 +281,12 @@ async function startSession(
221
281
  deps.backend
222
282
  .start({
223
283
  sessionId,
224
- bundle: body.bundle,
284
+ bundle,
225
285
  entryRelativePath: entryRelative,
226
286
  env: sessionEnv,
227
287
  ports: body.ports ?? [],
228
- config: body.config,
288
+ config,
289
+ selfContained: appEntry !== undefined,
229
290
  inspect: body.inspect ?? false,
230
291
  onStatus: (status) => deps.registry.emit(sessionId, { type: "status", status }),
231
292
  onProgress: (phase, message, done) =>
package/src/server.ts CHANGED
@@ -3,8 +3,8 @@ import cors from "@fastify/cors";
3
3
  import websocket from "@fastify/websocket";
4
4
 
5
5
  import type { RunnerBackend } from "./backend.js";
6
- import type { RunnerCoreConfig } from "./config.js";
7
- import type { RunnerCapabilities, SessionConfig } from "./contract.js";
6
+ import type { ResolvedRunnerApp, RunnerCoreConfig } from "./config.js";
7
+ import type { RunnerAppDescriptor, RunnerCapabilities, SessionConfig } from "./contract.js";
8
8
  import { capabilitiesRoute } from "./routes/capabilities.js";
9
9
  import { healthRoute } from "./routes/health.js";
10
10
  import { ioRoute } from "./routes/io.js";
@@ -25,8 +25,13 @@ export interface ServerDeps {
25
25
  /** Runner's default registry URL, passed to workloads as TELO_REGISTRY_URL. */
26
26
  defaultRegistryUrl?: string;
27
27
  /** Backend config gate, enforced on `POST /v1/sessions` before the workload
28
- * starts (e.g. an `image` allowlist). Rejects with `400 invalid_config`. */
28
+ * starts (e.g. an `image` allowlist). Rejects with `400 invalid_config`.
29
+ * Not consulted for app sessions — their image comes from `apps`. */
29
30
  validateConfig?: (config: SessionConfig) => string | undefined;
31
+ /** Operator-predefined applications launchable by name (usually
32
+ * `loadResolvedApps(process.env)`). Advertised on /v1/capabilities as
33
+ * `apps` descriptors; the session route resolves and gates against it. */
34
+ apps?: Record<string, ResolvedRunnerApp>;
30
35
  registry?: SessionRegistry;
31
36
  }
32
37
 
@@ -58,13 +63,26 @@ export async function buildServer(deps: ServerDeps): Promise<ServerHandle> {
58
63
  replayBufferBytes: deps.config.replayBufferBytes,
59
64
  });
60
65
 
66
+ // The app catalog is injected into the served capabilities document here, so
67
+ // what /v1/capabilities advertises and what the session route accepts can
68
+ // never drift — both come from `deps.apps`.
69
+ const appDescriptors: RunnerAppDescriptor[] = Object.values(deps.apps ?? {}).map(
70
+ ({ name, title, description }) => ({ name, title, description }),
71
+ );
72
+ const withApps = (caps: RunnerCapabilities): RunnerCapabilities =>
73
+ appDescriptors.length > 0 ? { ...caps, apps: appDescriptors } : caps;
74
+ const capabilitiesGetter =
75
+ typeof deps.capabilities === "function"
76
+ ? () => withApps((deps.capabilities as () => RunnerCapabilities)())
77
+ : withApps(deps.capabilities);
78
+
61
79
  // Terms are stable across the process — resolve the capabilities once for them
62
80
  // even when `capabilities` is a getter (the route still re-resolves per request).
63
81
  const capabilitiesValue =
64
- typeof deps.capabilities === "function" ? deps.capabilities() : deps.capabilities;
82
+ typeof capabilitiesGetter === "function" ? capabilitiesGetter() : capabilitiesGetter;
65
83
 
66
84
  await app.register(healthRoute(deps.version));
67
- await app.register(capabilitiesRoute(deps.capabilities));
85
+ await app.register(capabilitiesRoute(capabilitiesGetter));
68
86
  await app.register(probeRoute({ backend: deps.backend }));
69
87
  await app.register(
70
88
  sessionsRoute({
@@ -76,6 +94,7 @@ export async function buildServer(deps: ServerDeps): Promise<ServerHandle> {
76
94
  // The capabilities document is the single source of the runner's terms;
77
95
  // the session route enforces what /v1/capabilities advertises.
78
96
  terms: capabilitiesValue.terms,
97
+ apps: deps.apps,
79
98
  }),
80
99
  );
81
100
  await app.register(ioRoute({ registry, corsOrigins: deps.config.corsOrigins }));