@telorun/k8s-runner 0.13.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/README.md +72 -92
  2. package/dist/bundle-store.d.ts +6 -13
  3. package/dist/bundle-store.d.ts.map +1 -1
  4. package/dist/bundle-store.js +6 -18
  5. package/dist/bundle-store.js.map +1 -1
  6. package/dist/capabilities.d.ts +3 -3
  7. package/dist/capabilities.js +4 -4
  8. package/dist/capabilities.js.map +1 -1
  9. package/dist/config.d.ts +7 -32
  10. package/dist/config.d.ts.map +1 -1
  11. package/dist/config.js +13 -21
  12. package/dist/config.js.map +1 -1
  13. package/dist/k8s/api-error.d.ts +34 -0
  14. package/dist/k8s/api-error.d.ts.map +1 -0
  15. package/dist/k8s/api-error.js +118 -0
  16. package/dist/k8s/api-error.js.map +1 -0
  17. package/dist/k8s/backend.d.ts.map +1 -1
  18. package/dist/k8s/backend.js +23 -35
  19. package/dist/k8s/backend.js.map +1 -1
  20. package/dist/k8s/client.d.ts +1 -2
  21. package/dist/k8s/client.d.ts.map +1 -1
  22. package/dist/k8s/client.js +1 -2
  23. package/dist/k8s/client.js.map +1 -1
  24. package/dist/k8s/pod-spec.d.ts +8 -9
  25. package/dist/k8s/pod-spec.d.ts.map +1 -1
  26. package/dist/k8s/pod-spec.js +19 -29
  27. package/dist/k8s/pod-spec.js.map +1 -1
  28. package/dist/k8s/pod-status.d.ts.map +1 -1
  29. package/dist/k8s/pod-status.js +2 -2
  30. package/dist/k8s/pod-status.js.map +1 -1
  31. package/dist/k8s/watch-session.d.ts +4 -5
  32. package/dist/k8s/watch-session.d.ts.map +1 -1
  33. package/dist/k8s/watch-session.js +8 -8
  34. package/dist/k8s/watch-session.js.map +1 -1
  35. package/dist/server.js +3 -3
  36. package/dist/server.js.map +1 -1
  37. package/package.json +2 -2
  38. package/src/bundle-store.ts +6 -19
  39. package/src/capabilities.ts +4 -4
  40. package/src/config.ts +20 -61
  41. package/src/k8s/api-error.test.ts +89 -0
  42. package/src/k8s/api-error.ts +128 -0
  43. package/src/k8s/backend.ts +34 -39
  44. package/src/k8s/client.ts +1 -10
  45. package/src/k8s/pod-spec.test.ts +57 -2
  46. package/src/k8s/pod-spec.ts +25 -36
  47. package/src/k8s/pod-status.ts +2 -2
  48. package/src/k8s/watch-pod-spec.test.ts +0 -1
  49. package/src/k8s/watch-session.ts +8 -13
  50. package/src/server.ts +3 -3
  51. package/dist/k8s/image-build.d.ts +0 -103
  52. package/dist/k8s/image-build.d.ts.map +0 -1
  53. package/dist/k8s/image-build.js +0 -427
  54. package/dist/k8s/image-build.js.map +0 -1
  55. package/src/k8s/image-build.test.ts +0 -238
  56. package/src/k8s/image-build.ts +0 -540
package/README.md CHANGED
@@ -31,40 +31,40 @@ for status, attaches a PTY over the Pod `attach` subresource for the interactive
31
31
  per-session Service + Ingress (`<sessionId>.<base-domain>`) garbage-collected via
32
32
  an ownerReference to the Pod.
33
33
 
34
- **Every session runs a prebuilt per-app image** there is no in-pod install
35
- path. On a session-create the runner stages the bundle plus a generated
36
- `Dockerfile` (`FROM <base>`, `ENV TELO_CACHE_DIR=/telo-cache`, `RUN telo install`),
37
- runs a trusted **Kaniko** Job in the `telo-builds` namespace that bakes every
38
- controller and module manifest into `/telo-cache/{manifests,npm}` and pushes the
39
- result, then runs the session pod from that image — so the session never installs
40
- anything on the start path and a slow/unreachable package registry can't stall it.
41
-
42
- **The image is keyed on the dependency closure, not the whole bundle** — the
43
- `imports:` set plus any controllers declared by inline `Telo.Definition` docs
44
- (see `extractDependencyKey`). A body-only edit (resource config, CEL) reuses the
45
- existing image; only an import or controller change rebuilds. The per-session
46
- **body is delivered at boot**, not baked: a body-fetch initContainer untars the
47
- staged bundle into a writable `/app` emptyDir, and the session runs `telo run
48
- /app/<entry> --no-cache-write` — reading the baked deps from the read-only
49
- `/telo-cache` and validating in-memory, so `readOnlyRootFilesystem` stays on with
50
- nothing written to the cache. Builds are existence-checked before building and
51
- single-flighted; a build failure surfaces as an actionable error carrying the
52
- build pod's log tail. `RUNNER_IMAGE_REPOSITORY` is therefore **required** — the
53
- runner refuses to start without a registry to build into.
34
+ **Every session runs the plain kernel image.** A body-fetch initContainer untars
35
+ the staged bundle into a writable `/app` emptyDir and the session container runs
36
+ `telo run /app/<entry>`, resolving its own module closure into a `/telo-cache`
37
+ emptyDir on the way up. `readOnlyRootFilesystem` stays on every write lands on
38
+ a mounted emptyDir. The runner needs **no image registry of its own**: it builds
39
+ nothing, pushes nothing, and creates no Jobs.
40
+
41
+ The runner used to prebuild a self-contained per-app image with an on-cluster
42
+ Kaniko Job, so that a slow package registry could not stall the start path. That
43
+ is gone, and the cost is where it now shows: **a run session downloads its
44
+ closure on every start**, since the cache lives and dies with the pod. A watch
45
+ session pays it once and keeps the cache for the pod's life, which is the shape
46
+ to reach for when start latency matters.
54
47
 
55
48
  **Coming-up progress** is reported over the `/v1` SSE stream as `progress` events
56
- (`build` → `provision`) while the session is still `starting`. The session is
57
- created with a fast `201` carrying the `streamUrl` **before** the build runs, so
58
- the client connects immediately and sees build + provision progress live; the
59
- backend then runs in the background and a start failure surfaces as a terminal
60
- `failed` status on the stream. The session flips to `running` when the Pod reaches
61
- `Running`.
49
+ (`provision` → `boot`) while the session is still `starting`. The session is
50
+ created with a fast `201` carrying the `streamUrl` **before** the pod is created,
51
+ so the client connects immediately and sees provisioning live; the backend then
52
+ runs in the background and a start failure surfaces as a terminal `failed` status
53
+ on the stream. The session flips to `running` when the Pod reaches `Running`.
62
54
 
63
55
  Sandbox hardening is always on (non-root, read-only rootfs, drop-all caps, no
64
56
  service-account token, seccomp `RuntimeDefault`); a sandbox RuntimeClass
65
- (gVisor/Kata) is layered on when configured. In the prebuilt path the per-app
66
- image is single-tenant, so install scripts run normally inside the trusted build
67
- (native/postinstall controllers work) with no cross-tenant cache to poison.
57
+ (gVisor/Kata) is layered on when configured. A controller whose install needs to
58
+ run scripts or build native code runs them **inside the session pod** under that
59
+ hardening there is no trusted build step to run them in.
60
+
61
+ **A Kubernetes API rejection reaches the client as its status and `reason`, never
62
+ as the exception.** The API's error carries the full HTTP dump — the raw `Status`
63
+ body naming the runner's ServiceAccount, the audit id, every response header —
64
+ and a start failure's message travels verbatim to the client as the session's
65
+ terminal status. So the client is told the operation, the HTTP code and the
66
+ one-word reason (`Forbidden`, `NotFound`), plus who can fix a `403`; the raw
67
+ exception rides along as the error's `cause` and lands in the runner's log.
68
68
 
69
69
  ## Watch sessions
70
70
 
@@ -74,7 +74,7 @@ different — a **workspace that runs continuously**. One pod holds a shared
74
74
  `/workspace` volume, a `workspace` container serving the editor's file routes, one
75
75
  `app-<name>` container per application running `telo run --watch`, and optionally
76
76
  a co-resident `agent` drawn from the `RUNNER_APPS` catalog. An edit then costs a
77
- kernel reload instead of a pod: no schedule, no pull, no build.
77
+ kernel reload instead of a pod: no schedule, no pull, no module re-resolve.
78
78
 
79
79
  Off unless `RUNNER_WATCH_SESSIONS` is set. Run sessions are entirely unaffected.
80
80
 
@@ -128,10 +128,10 @@ runner reconciles into a content-addressed ConfigMap — there is no third image
128
128
  build, and a runner upgrade that changes the manifest leaves running sessions
129
129
  mounting the one they booted with.
130
130
 
131
- **Watch sessions never build an image.** The build path exists to put a dependency
132
- closure on disk before boot; a watch session resolves its own into the workspace
133
- volume, which lives as long as the pod, so the download happens once per session
134
- and every later reload resolves from local disk.
131
+ **A watch session resolves its closure once.** It lands in the workspace volume,
132
+ which lives as long as the pod, so the download happens once per session and
133
+ every later reload resolves from local disk where a run session, whose cache
134
+ dies with its pod, pays for it on every start.
135
135
 
136
136
  **One cache for the whole session.** The runner seeds `telo-workspace.yaml` at
137
137
  the workspace root when the session starts, and the kernel anchors its `.telo`
@@ -144,13 +144,11 @@ manifest lives outside the workspace and the walk-up would never reach the
144
144
  marker. A workspace that brings its own marker keeps it — overwriting one with a
145
145
  real `modules:` list would change what `telo release` discovers.
146
146
 
147
- **Egress moves into the session namespace.** Module fetches used to be scoped to
148
- the build namespace; a watch session resolves them itself, so the session
149
- namespace's NetworkPolicy has to reach module registries as well as the model
150
- provider. Core NetworkPolicy is CIDR-only and registries sit behind rotating-IP
151
- CDNs, so a locked-down operator needs a CNI with FQDN policy or an egress proxy
152
- here — the same stated dependency the build namespace already carries, one
153
- namespace over.
147
+ **Egress lives in the session namespace.** Every session resolves its own module
148
+ closure, so the session namespace's NetworkPolicy has to reach the module
149
+ registries as well as the model provider. Core NetworkPolicy is CIDR-only and
150
+ registries sit behind rotating-IP CDNs, so a locked-down operator needs a CNI
151
+ with FQDN policy or an egress proxy here.
154
152
 
155
153
  ### Two nouns on one stream
156
154
 
@@ -288,14 +286,15 @@ outcome than a URL that silently reaches the wrong app.
288
286
  | `PORT` | `8062` | HTTP listen port |
289
287
  | `RUNNER_DISPLAY_NAME` | `Telo Runner` | Display name advertised on `/v1/capabilities` (the editor's runner label) |
290
288
  | `RUNNER_DESCRIPTION` | `Runs the Telo application in a cloud environment` | Description advertised on `/v1/capabilities` |
291
- | `RUNNER_APPS` | _(unset → no apps)_ | JSON map of operator-predefined apps launchable by name (chart: inline `apps.catalog`, or `apps.catalogSecret` referencing a Secret holding the JSON — use the Secret whenever entries embed secrets in `env`); see the docker-runner README for the entry shape, including the `port` an entry must declare to be usable as a session's co-resident `agent`. App sessions run the catalog image directly as a pod — no on-cluster build |
289
+ | `RUNNER_APPS` | _(unset → no apps)_ | JSON map of operator-predefined apps launchable by name (chart: inline `apps.catalog`, or `apps.catalogSecret` referencing a Secret holding the JSON — use the Secret whenever entries embed secrets in `env`); see the docker-runner README for the entry shape, including the `port` an entry must declare to be usable as a session's co-resident `agent`. App sessions run the catalog image directly as a pod |
292
290
  | `RUNNER_APP_MAX_CPU` | `500m` | CPU ceiling for predefined-app pods (separate from the anonymous-session ceiling) |
293
291
  | `RUNNER_APP_MAX_MEMORY` | `512Mi` | Memory ceiling for predefined-app pods |
294
292
  | `RUNNER_APP_MAX_TTL_SECONDS` | `21600` | Wall-clock TTL for predefined-app pods (agent sessions are long-lived) |
295
293
  | `RUNNER_APP_MAX_EPHEMERAL_STORAGE` | `1Gi` | Ephemeral-storage ceiling for predefined-app pods |
296
294
  | `RUNNER_SESSION_NAMESPACE` | `telo-sessions` | Namespace for session objects |
297
295
  | `RUNNER_IMAGE` | _(baked at build: the CLI version for a released runner, `telorun/node:latest-slim` for a dev build)_ | Default base image; always offered in the picker and the fallback when the catalog is unreachable. Leave the chart's `session.image` empty to keep the session kernel in lockstep with the runner |
298
- | `RUNNER_INIT_IMAGE` | `busybox:stable` | Build-context fetch initContainer image (wget + tar) |
296
+ | `RUNNER_INIT_IMAGE` | `busybox:stable` | Bundle-fetch initContainer image (wget + tar) |
297
+ | `RUNNER_IMAGE_PULL_SECRET` | _(unset)_ | dockerconfig Secret (in `telo-sessions`) the kubelet pulls session images with — needed only for a kernel or catalog image in a private registry |
299
298
  | `RUNNER_RUNTIME_CLASS` | _(unset → runc)_ | Sandbox RuntimeClass (gvisor/kata) |
300
299
  | `SESSION_INGRESS_BASE_DOMAIN` | _(unset → logs-only)_ | Wildcard base for per-session ingress |
301
300
  | `SESSION_INGRESS_TLS_SECRET` | _(unset → no TLS block)_ | `kubernetes.io/tls` Secret (in `telo-sessions`) the session Ingress presents; must cover `*.<base-domain>`. Set for Cloudflare Full (Strict) / any origin-cert upstream |
@@ -327,12 +326,9 @@ against the same list, so a client that skips the editor can't widen the set.
327
326
  unreachable. Disable the catalog to lock `image` to `RUNNER_IMAGE`.
328
327
 
329
328
  Pinned tags (e.g. `0.30.1-slim`) are immutable. A picked **moving** tag like
330
- `latest-slim` only refreshes when the session's `pullPolicy` is `always`: the
331
- build then pins the per-app image to the base's current digest, so a moved tag
332
- yields a new image and rebuilds (otherwise the cached build keyed on the tag
333
- string — is reused). Movement detection reads the digest from Docker Hub, so a
334
- base hosted elsewhere (GHCR, a private registry) can't be tracked — `always`
335
- degrades to reusing the cached build for it, same as `missing` / `never`.
329
+ `latest-slim` only refreshes when the session's `pullPolicy` is `always`, which
330
+ is the Pod's own `imagePullPolicy`: the kubelet re-pulls the tag on every
331
+ session. `missing` and `never` reuse whatever that node already cached.
336
332
 
337
333
  | Env | Default | Purpose |
338
334
  | --- | --- | --- |
@@ -346,53 +342,38 @@ degrades to reusing the cached build for it, same as `missing` / `never`.
346
342
  | `RUNNER_BASE_IMAGE_LIMIT` | `20` | Cap on advertised tags (newest first) |
347
343
  | `RUNNER_BASE_IMAGE_REFRESH_SECONDS` | `3600` | Catalog re-fetch cadence |
348
344
 
349
- ### Image build (required)
350
-
351
- | Env | Default | Purpose |
352
- | --- | --- | --- |
353
- | `RUNNER_IMAGE_REPOSITORY` | _(required)_ | Registry repo for per-app images; tag = bundle hash |
354
- | `RUNNER_BUILD_NAMESPACE` | `telo-builds` | Namespace the trusted Kaniko build Jobs run in |
355
- | `RUNNER_BUILDER_IMAGE` | `gcr.io/kaniko-project/executor:latest` | Image builder |
356
- | `RUNNER_BUILD_TIMEOUT_SECONDS` | `600` | Build Job deadline / wait budget |
357
- | `RUNNER_REGISTRY_INSECURE` | `false` | Push/pull over HTTP / self-signed |
358
- | `RUNNER_REGISTRY_API_URL` | _(unset → always build)_ | HTTP(S) base for the manifest existence check (authenticated via the push Secret) |
359
- | `RUNNER_REGISTRY_PUSH_SECRET` | _(unset)_ | dockerconfig Secret (in `telo-builds`) Kaniko pushes with; also authenticates the existence check |
360
- | `RUNNER_IMAGE_PULL_SECRET` | _(unset)_ | dockerconfig Secret (in `telo-sessions`) the kubelet pulls per-app images with |
361
-
362
345
  ## Deploy (Helm)
363
346
 
364
- The runner **requires a registry to build into** (there is no in-pod install
365
- fallback), so point it at one your cluster's kubelet can pull from:
347
+ The chart is published as an OCI artifact at
348
+ `oci://ghcr.io/telorun/charts/k8s-runner`:
366
349
 
367
350
  ```bash
368
- helm install telo-runner ./chart \
369
- --set build.repository=registry.example.com/telo-sessions \
370
- --set-file registry.dockerconfigjson=./dockerconfig.json \ # private-registry auth
351
+ helm install telo-runner oci://ghcr.io/telorun/charts/k8s-runner \
352
+ --set watch.enabled=true \
371
353
  --set session.runtimeClass=gvisor
372
354
  ```
373
355
 
374
- For a private registry, `registry.dockerconfigjson` creates the dockerconfig
375
- Secret in **both** namespaces (push in `telo-builds`, pull in `telo-sessions`) and
376
- wires `RUNNER_REGISTRY_PUSH_SECRET` + `RUNNER_IMAGE_PULL_SECRET` — the kubelet
377
- needs the pull copy because the per-app image is private. (Or manage the Secrets
378
- yourself and reference them via `build.pushSecretName` / `build.pullSecretName`.)
379
- The push Secret doubles as the credential for the manifest existence check, so
380
- the runner can see an already-built image in a private registry and skip the
381
- rebuild without it a private registry answers `401` and every run rebuilds.
382
- A no-auth registry needs none of this.
356
+ Helm resolves the newest release when no `--version` is given; pass one to pin.
357
+ From a checkout, `./chart` works the same way and is what you want when changing
358
+ the chart itself.
359
+
360
+ **The chart's version IS the runner's.** `version` and `appVersion` both carry
361
+ `@telorun/k8s-runner`'s package version, stamped in the release PR and checked on
362
+ every PR so chart `0.13.0` installs runner image `0.13.0`, with no lookup
363
+ table. That is also why `image.tag` defaults to empty and resolves to the chart's
364
+ own `appVersion` rather than to `latest`: `--version 0.13.0` has to mean one
365
+ thing, where a floating tag meant whatever it had moved to overnight.
383
366
 
384
367
  The chart provisions the static scaffolding: the runner Deployment (single
385
368
  replica — the registry is in-memory and the runner reaps orphaned pods on boot),
386
- Service, scoped RBAC, the `telo-runner` / restricted-PSS `telo-sessions` /
387
- baseline-PSS `telo-builds` namespaces, a `ResourceQuota`, and NetworkPolicies
388
- (session pod-to-pod isolation + the build namespace's registry egress). The
389
- runner creates per-session and per-build objects at runtime.
369
+ Service, scoped RBAC, the `telo-runner` and restricted-PSS `telo-sessions`
370
+ namespaces, a `ResourceQuota`, and the session pod-to-pod NetworkPolicy. The
371
+ runner creates per-session objects at runtime. Nothing else is required — no
372
+ image registry, no build namespace, no push credentials.
390
373
 
391
- The optional in-cluster registry (`--set registry.enabled=true --set
392
- build.insecureRegistry=true`) derives `build.repository` for you, but works only
393
- on clusters whose **nodes are configured to trust it** — otherwise an external/
394
- cloud registry is simpler. Installing with neither a `build.repository` nor
395
- `registry.enabled` is rejected at template time.
374
+ For a kernel image or an operator catalog image held in a **private registry**,
375
+ create the dockerconfigjson Secret in `telo-sessions` yourself and point
376
+ `session.imagePullSecret` at it; the kubelet pulls with it.
396
377
 
397
378
  ### Origin TLS (Cloudflare et al.)
398
379
 
@@ -416,18 +397,17 @@ Either wires `SESSION_INGRESS_TLS_SECRET`, and the runner stamps a `spec.tls`
416
397
  block on every session Ingress. Leave all three empty to skip TLS at the origin
417
398
  (terminated entirely upstream).
418
399
 
419
- > **Egress notes.** (1) The kubelet pulls session images directly and does **not**
420
- > use cluster DNS, so the in-cluster registry only works where nodes trust it
421
- > (e.g. containerd `registries.conf`). (2) Core NetworkPolicy is CIDR-only and
422
- > cannot express the package-registry FQDN allowlist the build namespace needs —
423
- > use a CNI with FQDN policy (Cilium) or an egress proxy to tighten it.
400
+ > **Egress note.** Core NetworkPolicy is CIDR-only and cannot express the
401
+ > package-registry FQDN allowlist the session namespace needs use a CNI with
402
+ > FQDN policy (Cilium) or an egress proxy to tighten it.
424
403
 
425
404
  ## Development
426
405
 
427
406
  ```bash
428
407
  pnpm --filter @telorun/k8s-runner build # tsc
429
- pnpm --filter @telorun/k8s-runner test # vitest (limits clamp, tar, bundle token)
408
+ pnpm --filter @telorun/k8s-runner test # vitest (pod specs, limits clamp, tar, API errors)
430
409
  ```
431
410
 
432
411
  The Kubernetes backend can't be exercised without a cluster; unit tests cover the
433
- backend-independent logic (limit clamping, the tar writer, bundle tokens).
412
+ backend-independent logic (the pod specs, limit clamping, the tar writer, and
413
+ what an API rejection is allowed to tell a client).
@@ -1,9 +1,9 @@
1
1
  import type { FastifyInstance } from "fastify";
2
2
  import type { RunBundle } from "@telorun/runner-core";
3
3
  /**
4
- * Holds image-build contexts in memory and serves them over a tokenized,
5
- * cluster-internal URL the build Job's initContainer fetches once. The
6
- * per-build unguessable token prevents cross-build disclosure; the entry is
4
+ * Holds session bundles in memory and serves them over a tokenized,
5
+ * cluster-internal URL the session pod's initContainer fetches once. The
6
+ * per-session unguessable token prevents cross-session disclosure; the entry is
7
7
  * dropped after first fetch (or explicitly on cleanup).
8
8
  */
9
9
  export declare class BundleStore {
@@ -11,16 +11,9 @@ export declare class BundleStore {
11
11
  private readonly bundles;
12
12
  constructor(selfUrl: string);
13
13
  /**
14
- * Stages an image-build context the bundle plus a generated `Dockerfile` at
15
- * the context root and returns the tokenized, single-use URL the build Job's
16
- * initContainer fetches. Keyed by `id` (a build id).
17
- */
18
- stageBuildContext(id: string, bundle: RunBundle, dockerfile: string): Promise<string>;
19
- /**
20
- * Stages the raw session bundle (no Dockerfile) and returns the tokenized,
21
- * single-use URL the session Pod's body-delivery initContainer fetches into
22
- * `/app`. Keyed by `sessionId`. The image is keyed only on the dependency
23
- * closure, so the per-session body is delivered here at boot rather than baked.
14
+ * Stages the session bundle and returns the tokenized, single-use URL the
15
+ * session Pod's body-delivery initContainer fetches into `/app`. Keyed by
16
+ * `sessionId`.
24
17
  */
25
18
  stageSessionBundle(sessionId: string, bundle: RunBundle): Promise<string>;
26
19
  private stage;
@@ -1 +1 @@
1
- {"version":3,"file":"bundle-store.d.ts","sourceRoot":"","sources":["../src/bundle-store.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AActD;;;;;GAKG;AACH,qBAAa,WAAW;IAGV,OAAO,CAAC,QAAQ,CAAC,OAAO;IAFpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAmC;gBAE9B,OAAO,EAAE,MAAM;IAE5C;;;;OAIG;IACG,iBAAiB,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAO3F;;;;;OAKG;IACG,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC;YAIjE,KAAK;IAUnB,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAM7B,OAAO,CAAC,IAAI;IASZ,yEAAyE;IACzE,aAAa,CAAC,GAAG,EAAE,eAAe,GAAG,IAAI;CAiB1C"}
1
+ {"version":3,"file":"bundle-store.d.ts","sourceRoot":"","sources":["../src/bundle-store.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AActD;;;;;GAKG;AACH,qBAAa,WAAW;IAGV,OAAO,CAAC,QAAQ,CAAC,OAAO;IAFpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAmC;gBAE9B,OAAO,EAAE,MAAM;IAE5C;;;;OAIG;IACG,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC;YAIjE,KAAK;IAUnB,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAM7B,OAAO,CAAC,IAAI;IASZ,yEAAyE;IACzE,aAAa,CAAC,GAAG,EAAE,eAAe,GAAG,IAAI;CAiB1C"}
@@ -4,9 +4,9 @@ import { makeBundleTarGz } from "./tar.js";
4
4
  * stuck/never-started Pod can't grow the store unbounded. */
5
5
  const STAGING_TTL_MS = 5 * 60 * 1000;
6
6
  /**
7
- * Holds image-build contexts in memory and serves them over a tokenized,
8
- * cluster-internal URL the build Job's initContainer fetches once. The
9
- * per-build unguessable token prevents cross-build disclosure; the entry is
7
+ * Holds session bundles in memory and serves them over a tokenized,
8
+ * cluster-internal URL the session pod's initContainer fetches once. The
9
+ * per-session unguessable token prevents cross-session disclosure; the entry is
10
10
  * dropped after first fetch (or explicitly on cleanup).
11
11
  */
12
12
  export class BundleStore {
@@ -16,21 +16,9 @@ export class BundleStore {
16
16
  this.selfUrl = selfUrl;
17
17
  }
18
18
  /**
19
- * Stages an image-build context the bundle plus a generated `Dockerfile` at
20
- * the context root and returns the tokenized, single-use URL the build Job's
21
- * initContainer fetches. Keyed by `id` (a build id).
22
- */
23
- async stageBuildContext(id, bundle, dockerfile) {
24
- return this.stage(id, {
25
- entryRelativePath: bundle.entryRelativePath,
26
- files: [...bundle.files, { relativePath: "Dockerfile", contents: dockerfile }],
27
- });
28
- }
29
- /**
30
- * Stages the raw session bundle (no Dockerfile) and returns the tokenized,
31
- * single-use URL the session Pod's body-delivery initContainer fetches into
32
- * `/app`. Keyed by `sessionId`. The image is keyed only on the dependency
33
- * closure, so the per-session body is delivered here at boot rather than baked.
19
+ * Stages the session bundle and returns the tokenized, single-use URL the
20
+ * session Pod's body-delivery initContainer fetches into `/app`. Keyed by
21
+ * `sessionId`.
34
22
  */
35
23
  async stageSessionBundle(sessionId, bundle) {
36
24
  return this.stage(sessionId, bundle);
@@ -1 +1 @@
1
- {"version":3,"file":"bundle-store.js","sourceRoot":"","sources":["../src/bundle-store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"bundle-store.js","sourceRoot":"","sources":["../src/bundle-store.ts"],"names":[],"mappings":"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"}
@@ -19,9 +19,9 @@ export interface KubernetesRunnerCapabilitiesOptions {
19
19
  * studio renders an editable dropdown constrained to that allowlist — which the
20
20
  * session route re-validates server-side. Without a catalog (disabled /
21
21
  * first-fetch failure) the list collapses to the single `defaultImage` (locked
22
- * via `enforced`). `pullPolicy` is client-editable: `always` re-pulls the base
23
- * image when its tag has moved upstream (rebuilding the per-app image), which
24
- * is how a picked moving tag like `latest-slim` stays current.
22
+ * via `enforced`). `pullPolicy` is client-editable and is the pod's own
23
+ * `imagePullPolicy`: `always` re-pulls the kernel image, which is how a picked
24
+ * moving tag like `latest-slim` stays current.
25
25
  *
26
26
  * `terms`, when set (operator-provided via RUNNER_TERMS_*), are enforced: a
27
27
  * session won't start until the client acknowledges the current version. */
@@ -5,9 +5,9 @@ import { sessionConfigSchema, } from "@telorun/runner-core";
5
5
  * studio renders an editable dropdown constrained to that allowlist — which the
6
6
  * session route re-validates server-side. Without a catalog (disabled /
7
7
  * first-fetch failure) the list collapses to the single `defaultImage` (locked
8
- * via `enforced`). `pullPolicy` is client-editable: `always` re-pulls the base
9
- * image when its tag has moved upstream (rebuilding the per-app image), which
10
- * is how a picked moving tag like `latest-slim` stays current.
8
+ * via `enforced`). `pullPolicy` is client-editable and is the pod's own
9
+ * `imagePullPolicy`: `always` re-pulls the kernel image, which is how a picked
10
+ * moving tag like `latest-slim` stays current.
11
11
  *
12
12
  * `terms`, when set (operator-provided via RUNNER_TERMS_*), are enforced: a
13
13
  * session won't start until the client acknowledges the current version. */
@@ -30,7 +30,7 @@ export function kubernetesRunnerCapabilities(opts) {
30
30
  imageDefault: defaultImage,
31
31
  enforced: true,
32
32
  imageEnum,
33
- pullPolicyDescription: "Base-image freshness. `always` rebuilds the session image when the base tag has moved upstream (Docker Hub only); `missing` and `never` reuse the cached build.",
33
+ pullPolicyDescription: "Kernel-image freshness, applied as the Pod's imagePullPolicy. `always` re-pulls on every session, so a moving tag like `latest-slim` picks up a new release. `missing` pulls only when the node has no copy. `never` never pulls at all — on a node that has not already cached the image the session fails to start (ErrImageNeverPull), so it suits a cluster that pre-loads its images and nothing else.",
34
34
  }),
35
35
  },
36
36
  terms,
@@ -1 +1 @@
1
- {"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../src/capabilities.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,GAGpB,MAAM,sBAAsB,CAAC;AAiB9B;;;;;;;;;;;6EAW6E;AAC7E,MAAM,UAAU,4BAA4B,CAC1C,IAAyC;IAEzC,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,IAAI,CAAC;IAC1E,OAAO;QACL,WAAW;QACX,WAAW;QACX,QAAQ,EAAE;YACR,qEAAqE;YACrE,0EAA0E;YAC1E,kCAAkC;YAClC,EAAE,EAAE,CAAC,KAAK,EAAE,SAAS,CAAC;YACtB,KAAK,EAAE,IAAI;YACX,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,GAAG,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC1E;QACD,MAAM,EAAE;YACN,MAAM,EAAE,mBAAmB,CAAC;gBAC1B,YAAY,EAAE,YAAY;gBAC1B,QAAQ,EAAE,IAAI;gBACd,SAAS;gBACT,qBAAqB,EACnB,iKAAiK;aACpK,CAAC;SACH;QACD,KAAK;KACN,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../src/capabilities.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,GAGpB,MAAM,sBAAsB,CAAC;AAiB9B;;;;;;;;;;;6EAW6E;AAC7E,MAAM,UAAU,4BAA4B,CAC1C,IAAyC;IAEzC,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,IAAI,CAAC;IAC1E,OAAO;QACL,WAAW;QACX,WAAW;QACX,QAAQ,EAAE;YACR,qEAAqE;YACrE,0EAA0E;YAC1E,kCAAkC;YAClC,EAAE,EAAE,CAAC,KAAK,EAAE,SAAS,CAAC;YACtB,KAAK,EAAE,IAAI;YACX,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,GAAG,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC1E;QACD,MAAM,EAAE;YACN,MAAM,EAAE,mBAAmB,CAAC;gBAC1B,YAAY,EAAE,YAAY;gBAC1B,QAAQ,EAAE,IAAI;gBACd,SAAS;gBACT,qBAAqB,EACnB,6YAA6Y;aAChZ,CAAC;SACH;QACD,KAAK;KACN,CAAC;AACJ,CAAC"}
package/dist/config.d.ts CHANGED
@@ -34,33 +34,6 @@ export interface LimitCeilings {
34
34
  /** Per-Pod ephemeral-storage limit, e.g. "512Mi". */
35
35
  ephemeralStorage: string;
36
36
  }
37
- /**
38
- * On-cluster image-build settings. The runner ALWAYS prebuilds a self-contained
39
- * per-app image (controllers + module manifests baked in via `telo install`) and
40
- * the session pod runs it directly — there is no in-pod install fallback, so a
41
- * registry repository (`RUNNER_IMAGE_REPOSITORY`) is required.
42
- */
43
- export interface ImageBuildConfig {
44
- /** Registry repository the per-app image is pushed to / pulled from; the tag
45
- * is the bundle content hash (e.g. `registry.telo-runner.svc:5000/telo-sessions`). */
46
- repository: string;
47
- /** Namespace the trusted Kaniko build Jobs run in (registry egress lives here). */
48
- namespace: string;
49
- /** Builder image — Kaniko (or a compatible `--context`/`--destination` executor). */
50
- builderImage: string;
51
- /** Build Job `activeDeadlineSeconds` and the runner's wait budget. */
52
- timeoutSeconds: number;
53
- /** Push/pull to an insecure (HTTP / self-signed) registry — the in-cluster default. */
54
- insecureRegistry: boolean;
55
- /** HTTP(S) base for a best-effort manifest existence check (skip build on hit);
56
- * undefined → always build. */
57
- registryApiUrl?: string;
58
- /** Optional dockerconfig Secret (in the build namespace) Kaniko pushes with. */
59
- pushSecretName?: string;
60
- /** Optional dockerconfig Secret (in the session namespace) the kubelet uses to
61
- * pull per-app images from a private registry. */
62
- imagePullSecret?: string;
63
- }
64
37
  export interface K8sRunnerConfig extends RunnerCoreConfig {
65
38
  /** Identity advertised on `/v1/capabilities` — studio labels the runner
66
39
  * with these. */
@@ -72,8 +45,12 @@ export interface K8sRunnerConfig extends RunnerCoreConfig {
72
45
  * image as `RUNNER_IMAGE` at build time (the kernel version the runner was
73
46
  * built against); the literal fallback below is for a source checkout only. */
74
47
  defaultImage: string;
75
- /** Small image for the bundle/build-context fetch initContainer (needs wget + tar). */
48
+ /** Small image for the bundle-fetch initContainer (needs wget + tar). */
76
49
  initImage: string;
50
+ /** Optional dockerconfig Secret (in the session namespace) the kubelet pulls
51
+ * session images with — the kernel image, and any operator catalog image
52
+ * (`RUNNER_APPS`) held in a private registry. */
53
+ imagePullSecret?: string;
77
54
  /** Optional sandbox RuntimeClass (gvisor/kata). Unset → cluster default (runc). */
78
55
  runtimeClass?: string;
79
56
  /** Wildcard base domain for per-session ingress; unset → logs-only. */
@@ -84,10 +61,8 @@ export interface K8sRunnerConfig extends RunnerCoreConfig {
84
61
  * Ingress presents so an upstream (e.g. Cloudflare Full (Strict)) can validate
85
62
  * the origin. Must cover the wildcard `*.<sessionIngressBaseDomain>`. Unset → no TLS block. */
86
63
  sessionIngressTlsSecretName?: string;
87
- /** On-cluster image build the only delivery path (always present). */
88
- build: ImageBuildConfig;
89
- /** Runner's own in-cluster base URL, used to build the bundle/build-context
90
- * fetch URL the initContainer curls (e.g. http://k8s-runner.telo-runner:8062). */
64
+ /** Runner's own in-cluster base URL, used to build the bundle fetch URL the
65
+ * initContainer curls (e.g. http://k8s-runner.telo-runner:8062). */
91
66
  selfUrl: string;
92
67
  /** Label applied to every session object, used for orphan reaping. */
93
68
  managedByLabel: string;
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,iBAAiB,EACjB,KAAK,gBAAgB,EACrB,KAAK,SAAS,EACf,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,iBAAiB,EAAE,CAAC;AAE7B;;;;;;;GAOG;AACH,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,OAAO,CAAC;IACjB,yEAAyE;IACzE,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,SAAS,CAAC;IAClB,6CAA6C;IAC7C,KAAK,EAAE,MAAM,CAAC;IACd,wCAAwC;IACxC,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,2CAA2C;IAC3C,GAAG,EAAE,MAAM,CAAC;IACZ,gDAAgD;IAChD,MAAM,EAAE,MAAM,CAAC;IACf,6DAA6D;IAC7D,UAAU,EAAE,MAAM,CAAC;IACnB,qDAAqD;IACrD,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B;2FACuF;IACvF,UAAU,EAAE,MAAM,CAAC;IACnB,mFAAmF;IACnF,SAAS,EAAE,MAAM,CAAC;IAClB,qFAAqF;IACrF,YAAY,EAAE,MAAM,CAAC;IACrB,sEAAsE;IACtE,cAAc,EAAE,MAAM,CAAC;IACvB,uFAAuF;IACvF,gBAAgB,EAAE,OAAO,CAAC;IAC1B;oCACgC;IAChC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gFAAgF;IAChF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;uDACmD;IACnD,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,eAAgB,SAAQ,gBAAgB;IACvD;sBACkB;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,mEAAmE;IACnE,gBAAgB,EAAE,MAAM,CAAC;IACzB;;oFAEgF;IAChF,YAAY,EAAE,MAAM,CAAC;IACrB,uFAAuF;IACvF,SAAS,EAAE,MAAM,CAAC;IAClB,mFAAmF;IACnF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,uEAAuE;IACvE,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,gEAAgE;IAChE,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC;;oGAEgG;IAChG,2BAA2B,CAAC,EAAE,MAAM,CAAC;IACrC,wEAAwE;IACxE,KAAK,EAAE,gBAAgB,CAAC;IACxB;uFACmF;IACnF,OAAO,EAAE,MAAM,CAAC;IAChB,sEAAsE;IACtE,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,aAAa,CAAC;IACtB;;;6BAGyB;IACzB,SAAS,EAAE,aAAa,CAAC;IACzB,+EAA+E;IAC/E,gBAAgB,EAAE,sBAAsB,CAAC;CAC1C;AA0CD,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,eAAe,CAkE3E"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,iBAAiB,EACjB,KAAK,gBAAgB,EACrB,KAAK,SAAS,EACf,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,iBAAiB,EAAE,CAAC;AAE7B;;;;;;;GAOG;AACH,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,OAAO,CAAC;IACjB,yEAAyE;IACzE,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,SAAS,CAAC;IAClB,6CAA6C;IAC7C,KAAK,EAAE,MAAM,CAAC;IACd,wCAAwC;IACxC,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,2CAA2C;IAC3C,GAAG,EAAE,MAAM,CAAC;IACZ,gDAAgD;IAChD,MAAM,EAAE,MAAM,CAAC;IACf,6DAA6D;IAC7D,UAAU,EAAE,MAAM,CAAC;IACnB,qDAAqD;IACrD,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,eAAgB,SAAQ,gBAAgB;IACvD;sBACkB;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,mEAAmE;IACnE,gBAAgB,EAAE,MAAM,CAAC;IACzB;;oFAEgF;IAChF,YAAY,EAAE,MAAM,CAAC;IACrB,yEAAyE;IACzE,SAAS,EAAE,MAAM,CAAC;IAClB;;sDAEkD;IAClD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,mFAAmF;IACnF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,uEAAuE;IACvE,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,gEAAgE;IAChE,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC;;oGAEgG;IAChG,2BAA2B,CAAC,EAAE,MAAM,CAAC;IACrC;yEACqE;IACrE,OAAO,EAAE,MAAM,CAAC;IAChB,sEAAsE;IACtE,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,aAAa,CAAC;IACtB;;;6BAGyB;IACzB,SAAS,EAAE,aAAa,CAAC;IACzB,+EAA+E;IAC/E,gBAAgB,EAAE,sBAAsB,CAAC;CAC1C;AA0CD,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,eAAe,CAmD3E"}
package/dist/config.js CHANGED
@@ -34,23 +34,6 @@ export function loadK8sRunnerConfig(env) {
34
34
  throw new RunnerConfigError("RUNNER_SELF_URL env var is required. Set it to the runner's in-cluster base URL " +
35
35
  "(e.g. http://k8s-runner.telo-runner.svc:8062) so session initContainers can fetch the bundle.");
36
36
  }
37
- const repository = env.RUNNER_IMAGE_REPOSITORY?.trim();
38
- if (!repository) {
39
- throw new RunnerConfigError("RUNNER_IMAGE_REPOSITORY env var is required. The runner prebuilds a per-app session image for " +
40
- "every run (there is no in-pod install fallback); set it to the registry repository the built " +
41
- "images are pushed to / pulled from (e.g. registry.example.com/telo-sessions). The tag is the " +
42
- "bundle content hash.");
43
- }
44
- const build = {
45
- repository: repository.replace(/\/+$/, ""),
46
- namespace: env.RUNNER_BUILD_NAMESPACE?.trim() || "telo-builds",
47
- builderImage: env.RUNNER_BUILDER_IMAGE?.trim() || "gcr.io/kaniko-project/executor:latest",
48
- timeoutSeconds: parsePositiveInt(env.RUNNER_BUILD_TIMEOUT_SECONDS, 600, "RUNNER_BUILD_TIMEOUT_SECONDS"),
49
- insecureRegistry: env.RUNNER_REGISTRY_INSECURE?.trim() === "true",
50
- registryApiUrl: env.RUNNER_REGISTRY_API_URL?.trim() || undefined,
51
- pushSecretName: env.RUNNER_REGISTRY_PUSH_SECRET?.trim() || undefined,
52
- imagePullSecret: env.RUNNER_IMAGE_PULL_SECRET?.trim() || undefined,
53
- };
54
37
  return {
55
38
  ...loadCoreConfig(env, { port: DEFAULT_PORT }),
56
39
  displayName: env.RUNNER_DISPLAY_NAME?.trim() || "Telo Runner",
@@ -58,18 +41,27 @@ export function loadK8sRunnerConfig(env) {
58
41
  sessionNamespace: env.RUNNER_SESSION_NAMESPACE?.trim() || "telo-sessions",
59
42
  defaultImage: env.RUNNER_IMAGE?.trim() || "telorun/node:latest-slim",
60
43
  initImage: env.RUNNER_INIT_IMAGE?.trim() || "busybox:stable",
44
+ imagePullSecret: env.RUNNER_IMAGE_PULL_SECRET?.trim() || undefined,
61
45
  runtimeClass: env.RUNNER_RUNTIME_CLASS?.trim() || undefined,
62
46
  sessionIngressBaseDomain: env.SESSION_INGRESS_BASE_DOMAIN?.trim() || undefined,
63
47
  sessionIngressClassName: env.SESSION_INGRESS_CLASS?.trim() || undefined,
64
48
  sessionIngressTlsSecretName: env.SESSION_INGRESS_TLS_SECRET?.trim() || undefined,
65
- build,
66
49
  selfUrl: selfUrl.replace(/\/+$/, ""),
67
50
  managedByLabel: env.RUNNER_MANAGED_BY?.trim() || "telo-k8s-runner",
51
+ // Sized for a pod that RESOLVES ITS OWN module closure. They used to be
52
+ // 50m / 100Mi / 512Mi, which described a different workload: the closure
53
+ // arrived in image layers, so the pod only ran it. It now downloads,
54
+ // unpacks and resolves it in-pod, into an emptyDir that counts against
55
+ // ephemeral-storage — so the old numbers meant an OOMKill on the memory
56
+ // ceiling and an eviction on the storage one, for the ordinary case. The
57
+ // watch path already ran this workload and already carried the roomier
58
+ // ceiling; these match it. `appLimits` stays separate: it still differs in
59
+ // TTL, and both remain the operator's policy to tighten.
68
60
  limits: {
69
- cpu: env.RUNNER_MAX_CPU?.trim() || "50m",
70
- memory: env.RUNNER_MAX_MEMORY?.trim() || "100Mi",
61
+ cpu: env.RUNNER_MAX_CPU?.trim() || "500m",
62
+ memory: env.RUNNER_MAX_MEMORY?.trim() || "512Mi",
71
63
  ttlSeconds: parsePositiveInt(env.RUNNER_MAX_TTL_SECONDS, 3600, "RUNNER_MAX_TTL_SECONDS"),
72
- ephemeralStorage: env.RUNNER_MAX_EPHEMERAL_STORAGE?.trim() || "512Mi",
64
+ ephemeralStorage: env.RUNNER_MAX_EPHEMERAL_STORAGE?.trim() || "1Gi",
73
65
  },
74
66
  appLimits: {
75
67
  cpu: env.RUNNER_APP_MAX_CPU?.trim() || "500m",
@@ -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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"}
@@ -0,0 +1,34 @@
1
+ import { SessionStartError, type StartFailureStage } from "@telorun/runner-core";
2
+ /**
3
+ * A Kubernetes API rejection, phrased for the person who clicked Run.
4
+ *
5
+ * `ApiException.message` is a full HTTP dump — status line, the raw `Status`
6
+ * body and every response header — and a start failure's message travels
7
+ * verbatim to the client as the session's terminal `failed` status. That put
8
+ * the runner's ServiceAccount name, the request's audit id and its flowschema
9
+ * UIDs on an end user's screen, none of which they can act on.
10
+ *
11
+ * So the client sees the operation, the HTTP status and the API's own one-word
12
+ * `reason` — enough for an operator to know what was refused — and never the
13
+ * body or the headers. The raw exception rides along as the error's `cause`,
14
+ * which the runner's log serializer records, so nothing is swallowed: the detail
15
+ * moves to the log, it does not disappear.
16
+ */
17
+ export declare function apiFailure(err: unknown, stage: StartFailureStage, action: string): SessionStartError;
18
+ /** Attach the original error as `cause` so a log serializer can reach it.
19
+ * Every wrap on a failure path goes through here — a rewrap that drops the
20
+ * cause silently undoes the whole point of summarizing the message. */
21
+ export declare function withCause<E extends Error>(error: E, cause: unknown): E;
22
+ /** The client-safe half of a Kubernetes API error: what was refused, and who
23
+ * can act on it — never the `Status` message, which names cluster identities. */
24
+ export declare function apiReason(err: unknown): string;
25
+ /**
26
+ * The HTTP status an error carries, or `undefined` when it carries none.
27
+ *
28
+ * The number check is the whole point: `code` is also where Node puts a system
29
+ * error's string code and where a `DOMException` puts its legacy numeric one, so
30
+ * an unreachable apiserver and an aborted request both arrive here looking like
31
+ * a status. Only a value in the HTTP range is one.
32
+ */
33
+ export declare function statusCode(err: unknown): number | undefined;
34
+ //# sourceMappingURL=api-error.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-error.d.ts","sourceRoot":"","sources":["../../src/k8s/api-error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,KAAK,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAEjF;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,UAAU,CACxB,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,iBAAiB,EACxB,MAAM,EAAE,MAAM,GACb,iBAAiB,CAKnB;AAED;;wEAEwE;AACxE,wBAAgB,SAAS,CAAC,CAAC,SAAS,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,OAAO,GAAG,CAAC,CAGtE;AAED;kFACkF;AAClF,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAoB9C;AAuDD;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAM3D"}