@telorun/k8s-runner 0.6.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 (63) hide show
  1. package/LICENSE +17 -0
  2. package/README.md +206 -0
  3. package/dist/bundle-store.d.ts +32 -0
  4. package/dist/bundle-store.d.ts.map +1 -0
  5. package/dist/bundle-store.js +86 -0
  6. package/dist/bundle-store.js.map +1 -0
  7. package/dist/capabilities.d.ts +15 -0
  8. package/dist/capabilities.d.ts.map +1 -0
  9. package/dist/capabilities.js +30 -0
  10. package/dist/capabilities.js.map +1 -0
  11. package/dist/config.d.ts +95 -0
  12. package/dist/config.d.ts.map +1 -0
  13. package/dist/config.js +76 -0
  14. package/dist/config.js.map +1 -0
  15. package/dist/k8s/backend.d.ts +19 -0
  16. package/dist/k8s/backend.d.ts.map +1 -0
  17. package/dist/k8s/backend.js +488 -0
  18. package/dist/k8s/backend.js.map +1 -0
  19. package/dist/k8s/client.d.ts +16 -0
  20. package/dist/k8s/client.d.ts.map +1 -0
  21. package/dist/k8s/client.js +24 -0
  22. package/dist/k8s/client.js.map +1 -0
  23. package/dist/k8s/image-build.d.ts +105 -0
  24. package/dist/k8s/image-build.d.ts.map +1 -0
  25. package/dist/k8s/image-build.js +432 -0
  26. package/dist/k8s/image-build.js.map +1 -0
  27. package/dist/k8s/ingress.d.ts +15 -0
  28. package/dist/k8s/ingress.d.ts.map +1 -0
  29. package/dist/k8s/ingress.js +102 -0
  30. package/dist/k8s/ingress.js.map +1 -0
  31. package/dist/k8s/pod-spec.d.ts +41 -0
  32. package/dist/k8s/pod-spec.d.ts.map +1 -0
  33. package/dist/k8s/pod-spec.js +146 -0
  34. package/dist/k8s/pod-spec.js.map +1 -0
  35. package/dist/limits.d.ts +25 -0
  36. package/dist/limits.d.ts.map +1 -0
  37. package/dist/limits.js +58 -0
  38. package/dist/limits.js.map +1 -0
  39. package/dist/server.d.ts +13 -0
  40. package/dist/server.d.ts.map +1 -0
  41. package/dist/server.js +93 -0
  42. package/dist/server.js.map +1 -0
  43. package/dist/tar.d.ts +10 -0
  44. package/dist/tar.d.ts.map +1 -0
  45. package/dist/tar.js +63 -0
  46. package/dist/tar.js.map +1 -0
  47. package/package.json +41 -0
  48. package/src/bundle-store.ts +101 -0
  49. package/src/capabilities.ts +40 -0
  50. package/src/config.ts +201 -0
  51. package/src/k8s/backend-failure.test.ts +148 -0
  52. package/src/k8s/backend.ts +535 -0
  53. package/src/k8s/client.ts +39 -0
  54. package/src/k8s/image-build.test.ts +244 -0
  55. package/src/k8s/image-build.ts +547 -0
  56. package/src/k8s/ingress.test.ts +146 -0
  57. package/src/k8s/ingress.ts +127 -0
  58. package/src/k8s/pod-spec.ts +180 -0
  59. package/src/limits.test.ts +59 -0
  60. package/src/limits.ts +90 -0
  61. package/src/server.ts +124 -0
  62. package/src/tar.test.ts +55 -0
  63. package/src/tar.ts +68 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-build.d.ts","sourceRoot":"","sources":["../../src/k8s/image-build.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAGlE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAO9C,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,SAAS,CAAC;IAClB,kDAAkD;IAClD,SAAS,EAAE,MAAM,CAAC;IAClB;;8EAE0E;IAC1E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,8EAA8E;IAC9E,eAAe,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAmB9D;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,gBAAgB,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAEtE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,iBAAiB,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAW9F;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,gBAAgB,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,4FAA4F;IAC5F,UAAU,EAAE,MAAM,CAAC;IACnB,+CAA+C;IAC/C,WAAW,EAAE,MAAM,CAAC;IACpB,oEAAoE;IACpE,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,aAAa,GAAG,KAAK,CA8EzD;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,UAAU,CAAC;IACjB,KAAK,EAAE,gBAAgB,CAAC;IACxB,WAAW,EAAE,WAAW,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,SAAS,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB;;qFAEiF;IACjF,UAAU,EAAE,UAAU,CAAC;IACvB,gDAAgD;IAChD,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;CACxD;AAQD;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,eAAe,EACrB,IAAI,EAAE,eAAe,GACpB,OAAO,CAAC,MAAM,CAAC,CAoCjB;AAuGD,2EAA2E;AAC3E,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AA6FD,sFAAsF;AACtF,wBAAgB,qBAAqB,CACnC,gBAAgB,EAAE,MAAM,EACxB,UAAU,EAAE,MAAM,GACjB,YAAY,GAAG,SAAS,CAoB1B;AAED,kFAAkF;AAClF,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,mFAAmF;AACnF,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAMzE"}
@@ -0,0 +1,432 @@
1
+ import { createHash } from "node:crypto";
2
+ import { SessionStartError, extractDependencyKey, resolveTagDigest } from "@telorun/runner-core";
3
+ const CONTEXT_DIR = "/workspace";
4
+ const POLL_INTERVAL_MS = 2_000;
5
+ /** Grace beyond the Job's own activeDeadlineSeconds before the runner gives up. */
6
+ const WAIT_GRACE_MS = 30_000;
7
+ /**
8
+ * Content-address the per-app image on its DEPENDENCY closure — the only thing
9
+ * `telo install` bakes into `.telo/{manifests,npm}`: the `imports:` set plus any
10
+ * controllers declared by inline `Telo.Definition` docs (`extractDependencyKey`).
11
+ * A body-only edit (resource config, CEL) keeps the tag stable so the image is
12
+ * reused and the new body is delivered to the pod at runtime; an import or
13
+ * controller change produces a fresh tag and rebuilds. The entry path is
14
+ * deliberately excluded — it's supplied to `telo run` at runtime, and the same
15
+ * imports resolve the same closure regardless of the entry filename.
16
+ *
17
+ * `local_path` controllers (or an unparseable file) set `fullContentFallback`,
18
+ * which folds the whole bundle into the digest — keying degrades to today's
19
+ * content-address, which is correct (those depend on body bytes) if less optimal.
20
+ */
21
+ export function computeImageTag(inputs) {
22
+ const key = extractDependencyKey(inputs.bundle);
23
+ const h = createHash("sha256");
24
+ h.update("base\0" + inputs.baseImage + "\0");
25
+ if (inputs.baseDigest)
26
+ h.update("base-digest\0" + inputs.baseDigest + "\0");
27
+ h.update("telo-registry\0" + inputs.teloRegistryUrl + "\0");
28
+ for (const source of key.importSources)
29
+ h.update("import\0" + source + "\0");
30
+ for (const locator of key.controllerLocators)
31
+ h.update("controller\0" + locator + "\0");
32
+ if (key.fullContentFallback) {
33
+ const files = [...inputs.bundle.files].sort((a, b) => a.relativePath < b.relativePath ? -1 : a.relativePath > b.relativePath ? 1 : 0);
34
+ for (const f of files) {
35
+ h.update("file\0" + f.relativePath + "\0");
36
+ h.update(f.contents);
37
+ h.update("\0");
38
+ }
39
+ }
40
+ return h.digest("hex").slice(0, 32);
41
+ }
42
+ export function imageRef(config, tag) {
43
+ return `${config.repository}:${tag}`;
44
+ }
45
+ /**
46
+ * Dockerfile for a self-contained per-app image: `telo install` populates
47
+ * `/telo-cache/{manifests,npm}` so the runtime `telo run` resolves every
48
+ * controller and module from disk with no network and no install. The telo
49
+ * registry arrives as a build-arg so the build (not the running session)
50
+ * carries the registry dependency.
51
+ *
52
+ * `TELO_CACHE_DIR=/telo-cache` relocates the baked `.telo` OFF `/app`, so at
53
+ * runtime the pod mounts the freshly-delivered body at `/app` without shadowing
54
+ * the deps. The deps depend only on the imports/controllers closure (see
55
+ * `computeImageTag`); the body COPYed here is whichever session first built this
56
+ * tag — disposable, replaced at boot.
57
+ */
58
+ export function buildDockerfile(opts) {
59
+ return [
60
+ `FROM ${opts.baseImage}`,
61
+ `WORKDIR /app`,
62
+ `COPY . /app`,
63
+ `ARG TELO_REGISTRY_URL`,
64
+ `ENV TELO_REGISTRY_URL=$TELO_REGISTRY_URL`,
65
+ `ENV TELO_CACHE_DIR=/telo-cache`,
66
+ `RUN telo install /app/${opts.entryRelativePath}`,
67
+ ``,
68
+ ].join("\n");
69
+ }
70
+ /**
71
+ * Builds the Kaniko Job. An initContainer fetches the tokenized context tarball
72
+ * into a shared emptyDir; Kaniko builds it and pushes to the registry. The Job
73
+ * is single-attempt (`backoffLimit: 0`), deadline-bounded, and self-cleaning
74
+ * (`ttlSecondsAfterFinished`). Kaniko needs a writable rootfs, so this runs in
75
+ * the trusted `telo-builds` namespace at baseline PodSecurity — never alongside
76
+ * untrusted session pods.
77
+ */
78
+ export function buildKanikoJob(args) {
79
+ const { config } = args;
80
+ const kanikoArgs = [
81
+ `--context=dir://${CONTEXT_DIR}`,
82
+ `--dockerfile=${CONTEXT_DIR}/Dockerfile`,
83
+ `--destination=${args.destination}`,
84
+ `--build-arg=TELO_REGISTRY_URL=${config.teloRegistryUrl}`,
85
+ ];
86
+ if (config.insecureRegistry) {
87
+ kanikoArgs.push("--insecure", "--skip-tls-verify", "--insecure-pull", "--skip-tls-verify-pull");
88
+ }
89
+ const labels = {
90
+ "app.kubernetes.io/managed-by": args.managedByLabel,
91
+ "telo.run/build": "true",
92
+ };
93
+ const usesPushSecret = Boolean(config.pushSecretName);
94
+ return {
95
+ apiVersion: "batch/v1",
96
+ kind: "Job",
97
+ metadata: { name: args.jobName, namespace: config.namespace, labels },
98
+ spec: {
99
+ backoffLimit: 0,
100
+ activeDeadlineSeconds: config.timeoutSeconds,
101
+ ttlSecondsAfterFinished: 300,
102
+ template: {
103
+ metadata: { labels },
104
+ spec: {
105
+ restartPolicy: "Never",
106
+ automountServiceAccountToken: false,
107
+ initContainers: [
108
+ {
109
+ name: "context-fetch",
110
+ image: args.initImage,
111
+ command: ["sh", "-c"],
112
+ args: [
113
+ `set -e; wget -qO /tmp/context.tgz "${args.contextUrl}"; ` +
114
+ `tar xzf /tmp/context.tgz -C ${CONTEXT_DIR}`,
115
+ ],
116
+ volumeMounts: [
117
+ { name: "context", mountPath: CONTEXT_DIR },
118
+ { name: "tmp", mountPath: "/tmp" },
119
+ ],
120
+ },
121
+ ],
122
+ containers: [
123
+ {
124
+ name: "kaniko",
125
+ image: config.builderImage,
126
+ args: kanikoArgs,
127
+ volumeMounts: [
128
+ { name: "context", mountPath: CONTEXT_DIR },
129
+ ...(usesPushSecret
130
+ ? [{ name: "docker-config", mountPath: "/kaniko/.docker" }]
131
+ : []),
132
+ ],
133
+ },
134
+ ],
135
+ volumes: [
136
+ { name: "context", emptyDir: {} },
137
+ { name: "tmp", emptyDir: {} },
138
+ ...(usesPushSecret
139
+ ? [
140
+ {
141
+ name: "docker-config",
142
+ secret: {
143
+ secretName: config.pushSecretName,
144
+ items: [{ key: ".dockerconfigjson", path: "config.json" }],
145
+ },
146
+ },
147
+ ]
148
+ : []),
149
+ ],
150
+ },
151
+ },
152
+ },
153
+ };
154
+ }
155
+ /**
156
+ * Process-local single-flight: concurrent session-creates for byte-identical
157
+ * bundles share one build instead of each racing to create the same Job.
158
+ */
159
+ const inFlight = new Map();
160
+ /**
161
+ * Resolve the per-app image, building it on-cluster if absent. Returns the image
162
+ * ref to run; throws `SessionStartError` (stage `create`) with the build pod's
163
+ * log tail on failure so the cause reaches the editor instead of an opaque hang.
164
+ */
165
+ export async function ensureSessionImage(deps, args) {
166
+ // Under the `always` pull policy, pin the per-app image to the base image's
167
+ // CURRENT digest: a moved moving-tag (latest-slim) then yields a fresh tag and
168
+ // rebuilds. Movement detection is Docker-Hub-only — if the digest can't be
169
+ // resolved (a non-Hub base, or a transient Hub failure) the build can't tell
170
+ // the base moved and reuses the cached image, so `always` degrades to
171
+ // `missing` for that base. We deliberately do NOT force a rebuild on an
172
+ // unresolved digest: the per-app tag would be unchanged, so the rebuild would
173
+ // overwrite the same `repo:tag` — which nodes pulling `IfNotPresent` never
174
+ // re-pull, and a peer build for that tag would be reused via 409 anyway. So a
175
+ // tagless rebuild buys no freshness; only a changed digest does.
176
+ let baseDigest;
177
+ if (args.pullPolicy === "always") {
178
+ baseDigest = await resolveTagDigest(args.baseImage, {
179
+ onError: (err) => args.onProgress?.(`Base image freshness check failed (${msg(err)}); using cached image`),
180
+ });
181
+ }
182
+ const tag = computeImageTag({
183
+ bundle: args.bundle,
184
+ baseImage: args.baseImage,
185
+ baseDigest,
186
+ teloRegistryUrl: deps.build.teloRegistryUrl,
187
+ });
188
+ const ref = imageRef(deps.build, tag);
189
+ const existing = inFlight.get(ref);
190
+ if (existing) {
191
+ args.onProgress?.("Waiting for in-progress build…");
192
+ return existing;
193
+ }
194
+ const work = buildOnce(deps, args, tag, ref).finally(() => inFlight.delete(ref));
195
+ inFlight.set(ref, work);
196
+ return work;
197
+ }
198
+ async function buildOnce(deps, args, tag, ref) {
199
+ if (await imageExists(deps.kube, deps.build, tag)) {
200
+ args.onProgress?.("Using cached image", true);
201
+ return ref;
202
+ }
203
+ args.onProgress?.("Building image…");
204
+ const dockerfile = buildDockerfile({
205
+ baseImage: args.baseImage,
206
+ entryRelativePath: args.entryRelativePath,
207
+ });
208
+ const buildId = `build-${tag}`;
209
+ const contextUrl = await deps.bundleStore.stageBuildContext(buildId, args.bundle, dockerfile);
210
+ const jobName = `telo-build-${tag}`;
211
+ const job = buildKanikoJob({
212
+ config: deps.build,
213
+ jobName,
214
+ contextUrl,
215
+ destination: ref,
216
+ initImage: deps.initImage,
217
+ managedByLabel: deps.managedByLabel,
218
+ });
219
+ try {
220
+ await deps.kube.batch.createNamespacedJob({ namespace: deps.build.namespace, body: job });
221
+ }
222
+ catch (err) {
223
+ if (!isConflict(err)) {
224
+ deps.bundleStore.drop(buildId);
225
+ throw new SessionStartError("start_failed", "create", `failed to create image build job: ${msg(err)}`, msg(err));
226
+ }
227
+ // 409: a build for this exact tag is already running (peer/prior attempt) —
228
+ // fall through and wait for it rather than starting a duplicate.
229
+ }
230
+ try {
231
+ await waitForJob(deps.kube, deps.build, jobName);
232
+ }
233
+ finally {
234
+ deps.bundleStore.drop(buildId);
235
+ }
236
+ args.onProgress?.("Image built", true);
237
+ return ref;
238
+ }
239
+ async function waitForJob(kube, build, jobName) {
240
+ const deadline = Date.now() + build.timeoutSeconds * 1000 + WAIT_GRACE_MS;
241
+ while (Date.now() < deadline) {
242
+ let status;
243
+ try {
244
+ const job = await kube.batch.readNamespacedJob({ name: jobName, namespace: build.namespace });
245
+ status = job.status;
246
+ }
247
+ catch (err) {
248
+ if (is404(err)) {
249
+ throw new SessionStartError("start_failed", "create", `image build job '${jobName}' disappeared before completing`);
250
+ }
251
+ await sleep(POLL_INTERVAL_MS);
252
+ continue;
253
+ }
254
+ if ((status?.succeeded ?? 0) >= 1)
255
+ return;
256
+ if ((status?.failed ?? 0) >= 1) {
257
+ const logs = await buildLogTail(kube, build.namespace, jobName);
258
+ throw new SessionStartError("start_failed", "create", `image build failed${logs ? `: ${logs}` : ""}`, logs || undefined);
259
+ }
260
+ await sleep(POLL_INTERVAL_MS);
261
+ }
262
+ throw new SessionStartError("start_failed", "create", `image build did not finish within ${build.timeoutSeconds}s`);
263
+ }
264
+ const MANIFEST_ACCEPT = [
265
+ "application/vnd.oci.image.manifest.v1+json",
266
+ "application/vnd.oci.image.index.v1+json",
267
+ "application/vnd.docker.distribution.manifest.v2+json",
268
+ "application/vnd.docker.distribution.manifest.list.v2+json",
269
+ ].join(", ");
270
+ /**
271
+ * Best-effort registry manifest HEAD; a hit lets the runner skip the build.
272
+ * Reuses the push Secret's dockerconfig so the check authenticates against a
273
+ * private registry — without credentials a private registry answers 401 and the
274
+ * runner would rebuild every time. Fails safe to `false` (build) on any error.
275
+ */
276
+ async function imageExists(kube, build, tag) {
277
+ if (!build.registryApiUrl)
278
+ return false;
279
+ const repoPath = repoPathOf(build.repository);
280
+ if (!repoPath)
281
+ return false;
282
+ try {
283
+ const base = build.registryApiUrl.replace(/\/+$/, "");
284
+ const url = `${base}/v2/${repoPath}/manifests/${tag}`;
285
+ const auth = await resolveRegistryAuth(kube, build);
286
+ const res = await manifestHead(url, repoPath, auth);
287
+ return res.ok;
288
+ }
289
+ catch {
290
+ return false;
291
+ }
292
+ }
293
+ /**
294
+ * HEAD the manifest, handling both auth schemes a registry may demand: Basic
295
+ * (sent upfront when credentials exist) and Bearer token (acquired from the
296
+ * realm advertised in a 401 `WWW-Authenticate` challenge, then retried).
297
+ */
298
+ async function manifestHead(url, repoPath, auth) {
299
+ const headers = { Accept: MANIFEST_ACCEPT };
300
+ if (auth)
301
+ headers.Authorization = `Basic ${basicCredential(auth)}`;
302
+ const res = await fetch(url, { method: "HEAD", headers });
303
+ if (res.status !== 401 || !auth)
304
+ return res;
305
+ const token = await acquireBearerToken(res.headers.get("www-authenticate"), repoPath, auth);
306
+ if (!token)
307
+ return res;
308
+ return fetch(url, {
309
+ method: "HEAD",
310
+ headers: { Accept: MANIFEST_ACCEPT, Authorization: `Bearer ${token}` },
311
+ });
312
+ }
313
+ /** Exchange Basic credentials for a pull token at the challenge's `realm`. */
314
+ async function acquireBearerToken(challenge, repoPath, auth) {
315
+ if (!challenge)
316
+ return undefined;
317
+ const m = /^Bearer\s+(.*)$/i.exec(challenge.trim());
318
+ if (!m)
319
+ return undefined;
320
+ const params = parseAuthParams(m[1]);
321
+ if (!params.realm)
322
+ return undefined;
323
+ const tokenUrl = new URL(params.realm);
324
+ if (params.service)
325
+ tokenUrl.searchParams.set("service", params.service);
326
+ tokenUrl.searchParams.set("scope", params.scope || `repository:${repoPath}:pull`);
327
+ const res = await fetch(tokenUrl.toString(), {
328
+ headers: { Authorization: `Basic ${basicCredential(auth)}` },
329
+ });
330
+ if (!res.ok)
331
+ return undefined;
332
+ const body = (await res.json());
333
+ return body.token ?? body.access_token;
334
+ }
335
+ /** Read + decode the push Secret's dockerconfig into credentials for the repo's host. */
336
+ async function resolveRegistryAuth(kube, build) {
337
+ if (!build.pushSecretName)
338
+ return undefined;
339
+ try {
340
+ const secret = await kube.core.readNamespacedSecret({
341
+ name: build.pushSecretName,
342
+ namespace: build.namespace,
343
+ });
344
+ const raw = secret.data?.[".dockerconfigjson"];
345
+ if (!raw)
346
+ return undefined;
347
+ const json = Buffer.from(raw, "base64").toString("utf8");
348
+ return parseDockerConfigAuth(json, build.repository);
349
+ }
350
+ catch {
351
+ return undefined;
352
+ }
353
+ }
354
+ /** Extract credentials for `repository`'s host from a `.dockerconfigjson` payload. */
355
+ export function parseDockerConfigAuth(dockerconfigjson, repository) {
356
+ let cfg;
357
+ try {
358
+ cfg = JSON.parse(dockerconfigjson);
359
+ }
360
+ catch {
361
+ return undefined;
362
+ }
363
+ const auths = cfg.auths ?? {};
364
+ const host = registryHost(repository);
365
+ const entry = auths[host] ?? Object.entries(auths).find(([k]) => registryHost(k) === host)?.[1];
366
+ if (!entry)
367
+ return undefined;
368
+ if (entry.username && entry.password) {
369
+ return { username: entry.username, password: entry.password };
370
+ }
371
+ if (entry.auth) {
372
+ const decoded = Buffer.from(entry.auth, "base64").toString("utf8");
373
+ const sep = decoded.indexOf(":");
374
+ if (sep >= 0)
375
+ return { username: decoded.slice(0, sep), password: decoded.slice(sep + 1) };
376
+ }
377
+ return undefined;
378
+ }
379
+ /** Host portion of a registry ref / dockerconfig key (scheme + path stripped). */
380
+ export function registryHost(ref) {
381
+ return ref.replace(/^https?:\/\//, "").split("/")[0];
382
+ }
383
+ /** Parse `key="value"` pairs out of a `WWW-Authenticate: Bearer ...` challenge. */
384
+ export function parseAuthParams(challenge) {
385
+ const params = {};
386
+ const re = /(\w+)="([^"]*)"/g;
387
+ let m;
388
+ while ((m = re.exec(challenge)) !== null)
389
+ params[m[1]] = m[2];
390
+ return params;
391
+ }
392
+ function basicCredential(auth) {
393
+ return Buffer.from(`${auth.username}:${auth.password}`).toString("base64");
394
+ }
395
+ /** Last log lines of the build pod, for an actionable failure message. */
396
+ async function buildLogTail(kube, namespace, jobName) {
397
+ try {
398
+ const pods = await kube.core.listNamespacedPod({
399
+ namespace,
400
+ labelSelector: `job-name=${jobName}`,
401
+ });
402
+ const podName = pods.items?.[0]?.metadata?.name;
403
+ if (!podName)
404
+ return "";
405
+ const log = await kube.core.readNamespacedPodLog({ name: podName, namespace, tailLines: 20 });
406
+ return typeof log === "string" ? log.trim() : "";
407
+ }
408
+ catch {
409
+ return "";
410
+ }
411
+ }
412
+ function repoPathOf(repository) {
413
+ const slash = repository.indexOf("/");
414
+ return slash >= 0 ? repository.slice(slash + 1) : null;
415
+ }
416
+ function statusCode(err) {
417
+ const e = err;
418
+ return e?.statusCode ?? e?.code ?? e?.response?.statusCode;
419
+ }
420
+ function is404(err) {
421
+ return statusCode(err) === 404;
422
+ }
423
+ function isConflict(err) {
424
+ return statusCode(err) === 409;
425
+ }
426
+ function msg(err) {
427
+ return err instanceof Error ? err.message : String(err);
428
+ }
429
+ function sleep(ms) {
430
+ return new Promise((resolve) => setTimeout(resolve, ms));
431
+ }
432
+ //# sourceMappingURL=image-build.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-build.js","sourceRoot":"","sources":["../../src/k8s/image-build.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAIzC,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAMjG,MAAM,WAAW,GAAG,YAAY,CAAC;AACjC,MAAM,gBAAgB,GAAG,KAAK,CAAC;AAC/B,mFAAmF;AACnF,MAAM,aAAa,GAAG,MAAM,CAAC;AAc7B;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,eAAe,CAAC,MAAsB;IACpD,MAAM,GAAG,GAAG,oBAAoB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAChD,MAAM,CAAC,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;IAC/B,CAAC,CAAC,MAAM,CAAC,QAAQ,GAAG,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;IAC7C,IAAI,MAAM,CAAC,UAAU;QAAE,CAAC,CAAC,MAAM,CAAC,eAAe,GAAG,MAAM,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;IAC5E,CAAC,CAAC,MAAM,CAAC,iBAAiB,GAAG,MAAM,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC;IAC5D,KAAK,MAAM,MAAM,IAAI,GAAG,CAAC,aAAa;QAAE,CAAC,CAAC,MAAM,CAAC,UAAU,GAAG,MAAM,GAAG,IAAI,CAAC,CAAC;IAC7E,KAAK,MAAM,OAAO,IAAI,GAAG,CAAC,kBAAkB;QAAE,CAAC,CAAC,MAAM,CAAC,cAAc,GAAG,OAAO,GAAG,IAAI,CAAC,CAAC;IACxF,IAAI,GAAG,CAAC,mBAAmB,EAAE,CAAC;QAC5B,MAAM,KAAK,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACnD,CAAC,CAAC,YAAY,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAC/E,CAAC;QACF,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;YACtB,CAAC,CAAC,MAAM,CAAC,QAAQ,GAAG,CAAC,CAAC,YAAY,GAAG,IAAI,CAAC,CAAC;YAC3C,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;YACrB,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACjB,CAAC;IACH,CAAC;IACD,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,MAAwB,EAAE,GAAW;IAC5D,OAAO,GAAG,MAAM,CAAC,UAAU,IAAI,GAAG,EAAE,CAAC;AACvC,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,eAAe,CAAC,IAAsD;IACpF,OAAO;QACL,QAAQ,IAAI,CAAC,SAAS,EAAE;QACxB,cAAc;QACd,aAAa;QACb,uBAAuB;QACvB,0CAA0C;QAC1C,gCAAgC;QAChC,yBAAyB,IAAI,CAAC,iBAAiB,EAAE;QACjD,EAAE;KACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAcD;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAAC,IAAmB;IAChD,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IACxB,MAAM,UAAU,GAAG;QACjB,mBAAmB,WAAW,EAAE;QAChC,gBAAgB,WAAW,aAAa;QACxC,iBAAiB,IAAI,CAAC,WAAW,EAAE;QACnC,iCAAiC,MAAM,CAAC,eAAe,EAAE;KAC1D,CAAC;IACF,IAAI,MAAM,CAAC,gBAAgB,EAAE,CAAC;QAC5B,UAAU,CAAC,IAAI,CAAC,YAAY,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,wBAAwB,CAAC,CAAC;IAClG,CAAC;IAED,MAAM,MAAM,GAAG;QACb,8BAA8B,EAAE,IAAI,CAAC,cAAc;QACnD,gBAAgB,EAAE,MAAM;KACzB,CAAC;IACF,MAAM,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;IAEtD,OAAO;QACL,UAAU,EAAE,UAAU;QACtB,IAAI,EAAE,KAAK;QACX,QAAQ,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE;QACrE,IAAI,EAAE;YACJ,YAAY,EAAE,CAAC;YACf,qBAAqB,EAAE,MAAM,CAAC,cAAc;YAC5C,uBAAuB,EAAE,GAAG;YAC5B,QAAQ,EAAE;gBACR,QAAQ,EAAE,EAAE,MAAM,EAAE;gBACpB,IAAI,EAAE;oBACJ,aAAa,EAAE,OAAO;oBACtB,4BAA4B,EAAE,KAAK;oBACnC,cAAc,EAAE;wBACd;4BACE,IAAI,EAAE,eAAe;4BACrB,KAAK,EAAE,IAAI,CAAC,SAAS;4BACrB,OAAO,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC;4BACrB,IAAI,EAAE;gCACJ,sCAAsC,IAAI,CAAC,UAAU,KAAK;oCACxD,+BAA+B,WAAW,EAAE;6BAC/C;4BACD,YAAY,EAAE;gCACZ,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE;gCAC3C,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE;6BACnC;yBACF;qBACF;oBACD,UAAU,EAAE;wBACV;4BACE,IAAI,EAAE,QAAQ;4BACd,KAAK,EAAE,MAAM,CAAC,YAAY;4BAC1B,IAAI,EAAE,UAAU;4BAChB,YAAY,EAAE;gCACZ,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE;gCAC3C,GAAG,CAAC,cAAc;oCAChB,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,SAAS,EAAE,iBAAiB,EAAE,CAAC;oCAC3D,CAAC,CAAC,EAAE,CAAC;6BACR;yBACF;qBACF;oBACD,OAAO,EAAE;wBACP,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,EAAE;wBACjC,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,EAAE;wBAC7B,GAAG,CAAC,cAAc;4BAChB,CAAC,CAAC;gCACE;oCACE,IAAI,EAAE,eAAe;oCACrB,MAAM,EAAE;wCACN,UAAU,EAAE,MAAM,CAAC,cAAc;wCACjC,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,mBAAmB,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC;qCAC3D;iCACF;6BACF;4BACH,CAAC,CAAC,EAAE,CAAC;qBACR;iBACF;aACF;SACF;KACF,CAAC;AACJ,CAAC;AAsBD;;;GAGG;AACH,MAAM,QAAQ,GAAG,IAAI,GAAG,EAA2B,CAAC;AAEpD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,IAAqB,EACrB,IAAqB;IAErB,4EAA4E;IAC5E,+EAA+E;IAC/E,2EAA2E;IAC3E,6EAA6E;IAC7E,sEAAsE;IACtE,wEAAwE;IACxE,8EAA8E;IAC9E,2EAA2E;IAC3E,8EAA8E;IAC9E,iEAAiE;IACjE,IAAI,UAA8B,CAAC;IACnC,IAAI,IAAI,CAAC,UAAU,KAAK,QAAQ,EAAE,CAAC;QACjC,UAAU,GAAG,MAAM,gBAAgB,CAAC,IAAI,CAAC,SAAS,EAAE;YAClD,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE,CACf,IAAI,CAAC,UAAU,EAAE,CAAC,sCAAsC,GAAG,CAAC,GAAG,CAAC,uBAAuB,CAAC;SAC3F,CAAC,CAAC;IACL,CAAC;IAED,MAAM,GAAG,GAAG,eAAe,CAAC;QAC1B,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,UAAU;QACV,eAAe,EAAE,IAAI,CAAC,KAAK,CAAC,eAAe;KAC5C,CAAC,CAAC;IACH,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAEtC,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACnC,IAAI,QAAQ,EAAE,CAAC;QACb,IAAI,CAAC,UAAU,EAAE,CAAC,gCAAgC,CAAC,CAAC;QACpD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IACjF,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACxB,OAAO,IAAI,CAAC;AACd,CAAC;AAED,KAAK,UAAU,SAAS,CACtB,IAAqB,EACrB,IAAqB,EACrB,GAAW,EACX,GAAW;IAEX,IAAI,MAAM,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,CAAC;QAClD,IAAI,CAAC,UAAU,EAAE,CAAC,oBAAoB,EAAE,IAAI,CAAC,CAAC;QAC9C,OAAO,GAAG,CAAC;IACb,CAAC;IACD,IAAI,CAAC,UAAU,EAAE,CAAC,iBAAiB,CAAC,CAAC;IAErC,MAAM,UAAU,GAAG,eAAe,CAAC;QACjC,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;KAC1C,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,SAAS,GAAG,EAAE,CAAC;IAC/B,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,iBAAiB,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC9F,MAAM,OAAO,GAAG,cAAc,GAAG,EAAE,CAAC;IACpC,MAAM,GAAG,GAAG,cAAc,CAAC;QACzB,MAAM,EAAE,IAAI,CAAC,KAAK;QAClB,OAAO;QACP,UAAU;QACV,WAAW,EAAE,GAAG;QAChB,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,cAAc,EAAE,IAAI,CAAC,cAAc;KACpC,CAAC,CAAC;IAEH,IAAI,CAAC;QACH,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,mBAAmB,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;IAC5F,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACrB,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC/B,MAAM,IAAI,iBAAiB,CACzB,cAAc,EACd,QAAQ,EACR,qCAAqC,GAAG,CAAC,GAAG,CAAC,EAAE,EAC/C,GAAG,CAAC,GAAG,CAAC,CACT,CAAC;QACJ,CAAC;QACD,4EAA4E;QAC5E,iEAAiE;IACnE,CAAC;IAED,IAAI,CAAC;QACH,MAAM,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IACnD,CAAC;YAAS,CAAC;QACT,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACjC,CAAC;IACD,IAAI,CAAC,UAAU,EAAE,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;IACvC,OAAO,GAAG,CAAC;AACb,CAAC;AAED,KAAK,UAAU,UAAU,CACvB,IAAgB,EAChB,KAAuB,EACvB,OAAe;IAEf,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,cAAc,GAAG,IAAI,GAAG,aAAa,CAAC;IAC1E,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;QAC7B,IAAI,MAAuB,CAAC;QAC5B,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,iBAAiB,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC;YAC9F,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;QACtB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;gBACf,MAAM,IAAI,iBAAiB,CACzB,cAAc,EACd,QAAQ,EACR,oBAAoB,OAAO,iCAAiC,CAC7D,CAAC;YACJ,CAAC;YACD,MAAM,KAAK,CAAC,gBAAgB,CAAC,CAAC;YAC9B,SAAS;QACX,CAAC;QACD,IAAI,CAAC,MAAM,EAAE,SAAS,IAAI,CAAC,CAAC,IAAI,CAAC;YAAE,OAAO;QAC1C,IAAI,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;YAC/B,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,IAAI,EAAE,KAAK,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;YAChE,MAAM,IAAI,iBAAiB,CACzB,cAAc,EACd,QAAQ,EACR,qBAAqB,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAC9C,IAAI,IAAI,SAAS,CAClB,CAAC;QACJ,CAAC;QACD,MAAM,KAAK,CAAC,gBAAgB,CAAC,CAAC;IAChC,CAAC;IACD,MAAM,IAAI,iBAAiB,CACzB,cAAc,EACd,QAAQ,EACR,qCAAqC,KAAK,CAAC,cAAc,GAAG,CAC7D,CAAC;AACJ,CAAC;AAED,MAAM,eAAe,GAAG;IACtB,4CAA4C;IAC5C,yCAAyC;IACzC,sDAAsD;IACtD,2DAA2D;CAC5D,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAQb;;;;;GAKG;AACH,KAAK,UAAU,WAAW,CACxB,IAAgB,EAChB,KAAuB,EACvB,GAAW;IAEX,IAAI,CAAC,KAAK,CAAC,cAAc;QAAE,OAAO,KAAK,CAAC;IACxC,MAAM,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAC9C,IAAI,CAAC,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5B,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACtD,MAAM,GAAG,GAAG,GAAG,IAAI,OAAO,QAAQ,cAAc,GAAG,EAAE,CAAC;QACtD,MAAM,IAAI,GAAG,MAAM,mBAAmB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QACpD,MAAM,GAAG,GAAG,MAAM,YAAY,CAAC,GAAG,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;QACpD,OAAO,GAAG,CAAC,EAAE,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,YAAY,CACzB,GAAW,EACX,QAAgB,EAChB,IAA8B;IAE9B,MAAM,OAAO,GAA2B,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC;IACpE,IAAI,IAAI;QAAE,OAAO,CAAC,aAAa,GAAG,SAAS,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC;IACnE,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;IAC1D,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI;QAAE,OAAO,GAAG,CAAC;IAE5C,MAAM,KAAK,GAAG,MAAM,kBAAkB,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;IAC5F,IAAI,CAAC,KAAK;QAAE,OAAO,GAAG,CAAC;IACvB,OAAO,KAAK,CAAC,GAAG,EAAE;QAChB,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,MAAM,EAAE,eAAe,EAAE,aAAa,EAAE,UAAU,KAAK,EAAE,EAAE;KACvE,CAAC,CAAC;AACL,CAAC;AAED,8EAA8E;AAC9E,KAAK,UAAU,kBAAkB,CAC/B,SAAwB,EACxB,QAAgB,EAChB,IAAkB;IAElB,IAAI,CAAC,SAAS;QAAE,OAAO,SAAS,CAAC;IACjC,MAAM,CAAC,GAAG,kBAAkB,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC;IACpD,IAAI,CAAC,CAAC;QAAE,OAAO,SAAS,CAAC;IACzB,MAAM,MAAM,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACrC,IAAI,CAAC,MAAM,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAEpC,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACvC,IAAI,MAAM,CAAC,OAAO;QAAE,QAAQ,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IACzE,QAAQ,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,KAAK,IAAI,cAAc,QAAQ,OAAO,CAAC,CAAC;IAClF,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,QAAQ,CAAC,QAAQ,EAAE,EAAE;QAC3C,OAAO,EAAE,EAAE,aAAa,EAAE,SAAS,eAAe,CAAC,IAAI,CAAC,EAAE,EAAE;KAC7D,CAAC,CAAC;IACH,IAAI,CAAC,GAAG,CAAC,EAAE;QAAE,OAAO,SAAS,CAAC;IAC9B,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAA8C,CAAC;IAC7E,OAAO,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,YAAY,CAAC;AACzC,CAAC;AAED,yFAAyF;AACzF,KAAK,UAAU,mBAAmB,CAChC,IAAgB,EAChB,KAAuB;IAEvB,IAAI,CAAC,KAAK,CAAC,cAAc;QAAE,OAAO,SAAS,CAAC;IAC5C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,oBAAoB,CAAC;YAClD,IAAI,EAAE,KAAK,CAAC,cAAc;YAC1B,SAAS,EAAE,KAAK,CAAC,SAAS;SAC3B,CAAC,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,mBAAmB,CAAC,CAAC;QAC/C,IAAI,CAAC,GAAG;YAAE,OAAO,SAAS,CAAC;QAC3B,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACzD,OAAO,qBAAqB,CAAC,IAAI,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;IACvD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,sFAAsF;AACtF,MAAM,UAAU,qBAAqB,CACnC,gBAAwB,EACxB,UAAkB;IAElB,IAAI,GAAwF,CAAC;IAC7F,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC;IAC9B,MAAM,IAAI,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC;IACtC,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAChG,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAC7B,IAAI,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;QACrC,OAAO,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC;IAChE,CAAC;IACD,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QACnE,MAAM,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACjC,IAAI,GAAG,IAAI,CAAC;YAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,EAAE,CAAC;IAC7F,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,YAAY,CAAC,GAAW;IACtC,OAAO,GAAG,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AACvD,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,eAAe,CAAC,SAAiB;IAC/C,MAAM,MAAM,GAA2B,EAAE,CAAC;IAC1C,MAAM,EAAE,GAAG,kBAAkB,CAAC;IAC9B,IAAI,CAAyB,CAAC;IAC9B,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,KAAK,IAAI;QAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9D,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,eAAe,CAAC,IAAkB;IACzC,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AAC7E,CAAC;AAED,0EAA0E;AAC1E,KAAK,UAAU,YAAY,CAAC,IAAgB,EAAE,SAAiB,EAAE,OAAe;IAC9E,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC;YAC7C,SAAS;YACT,aAAa,EAAE,YAAY,OAAO,EAAE;SACrC,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC;QAChD,IAAI,CAAC,OAAO;YAAE,OAAO,EAAE,CAAC;QACxB,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,oBAAoB,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAAC;QAC9F,OAAO,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACnD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,SAAS,UAAU,CAAC,UAAkB;IACpC,MAAM,KAAK,GAAG,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACtC,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACzD,CAAC;AAED,SAAS,UAAU,CAAC,GAAY;IAC9B,MAAM,CAAC,GAAG,GAAiF,CAAC;IAC5F,OAAO,CAAC,EAAE,UAAU,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,EAAE,QAAQ,EAAE,UAAU,CAAC;AAC7D,CAAC;AAED,SAAS,KAAK,CAAC,GAAY;IACzB,OAAO,UAAU,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC;AACjC,CAAC;AAED,SAAS,UAAU,CAAC,GAAY;IAC9B,OAAO,UAAU,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC;AACjC,CAAC;AAED,SAAS,GAAG,CAAC,GAAY;IACvB,OAAO,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AAC1D,CAAC;AAED,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAC3D,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { V1Ingress, V1Service } from "@kubernetes/client-node";
2
+ import type { K8sRunnerConfig } from "../config.js";
3
+ import type { PortMapping, RunnerEndpoint } from "@telorun/runner-core";
4
+ export declare function buildSessionService(config: K8sRunnerConfig, sessionId: string, podName: string, podUid: string, ports: PortMapping[]): V1Service;
5
+ export declare function buildSessionIngress(config: K8sRunnerConfig, sessionId: string, serviceName: string, podName: string, podUid: string, ports: PortMapping[]): {
6
+ ingress: V1Ingress;
7
+ hosts: string[];
8
+ };
9
+ /** Endpoints announced on the `running` status. Every tcp port is fronted by its
10
+ * own per-session Ingress host (`<port>-<sessionId>.<domain>`, served on 443) and
11
+ * carries an external `url`. udp ports aren't HTTP-routable, so they keep the
12
+ * host-less form. Without an ingress base domain, host is left blank for the
13
+ * client adapter to fill (parity with docker). */
14
+ export declare function endpointsFor(config: K8sRunnerConfig, sessionId: string, ports: PortMapping[]): RunnerEndpoint[];
15
+ //# sourceMappingURL=ingress.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ingress.d.ts","sourceRoot":"","sources":["../../src/k8s/ingress.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAoB,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAEtF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAgBxE,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,eAAe,EACvB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,WAAW,EAAE,GACnB,SAAS,CAoBX;AAUD,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,eAAe,EACvB,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,WAAW,EAAE,GACnB;IAAE,OAAO,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,CA0CzC;AAED;;;;mDAImD;AACnD,wBAAgB,YAAY,CAC1B,MAAM,EAAE,eAAe,EACvB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,WAAW,EAAE,GACnB,cAAc,EAAE,CAWlB"}
@@ -0,0 +1,102 @@
1
+ /** OwnerReference to the session Pod so the Service + Ingress are garbage
2
+ * collected automatically when the Pod dies — essential for sub-minute
3
+ * sessions that would otherwise leak ingress objects. */
4
+ function podOwnerRef(podName, podUid) {
5
+ return {
6
+ apiVersion: "v1",
7
+ kind: "Pod",
8
+ name: podName,
9
+ uid: podUid,
10
+ controller: true,
11
+ blockOwnerDeletion: true,
12
+ };
13
+ }
14
+ export function buildSessionService(config, sessionId, podName, podUid, ports) {
15
+ return {
16
+ apiVersion: "v1",
17
+ kind: "Service",
18
+ metadata: {
19
+ name: `telo-run-${sessionId}`,
20
+ namespace: config.sessionNamespace,
21
+ labels: { "app.kubernetes.io/managed-by": config.managedByLabel },
22
+ ownerReferences: [podOwnerRef(podName, podUid)],
23
+ },
24
+ spec: {
25
+ selector: { "telo.run/session-id": sessionId },
26
+ ports: ports.map((p) => ({
27
+ name: `p${p.port}`,
28
+ port: p.port,
29
+ targetPort: p.port,
30
+ protocol: p.protocol.toUpperCase(),
31
+ })),
32
+ },
33
+ };
34
+ }
35
+ /** Host fronting a single tcp port: `<port>-<sessionId>.<domain>`. The port
36
+ * rides as a leading label (no dots), so it stays a single label under the base
37
+ * domain — matching the docker runner's proxy scheme and compatible with a
38
+ * single-label wildcard cert (`*.<domain>`). */
39
+ function hostForPort(config, sessionId, port) {
40
+ return `${port}-${sessionId}.${config.sessionIngressBaseDomain}`;
41
+ }
42
+ export function buildSessionIngress(config, sessionId, serviceName, podName, podUid, ports) {
43
+ // Only tcp ports are HTTP-routable; one host rule per port to the matching
44
+ // service port, mirroring the docker runner's per-port URLs.
45
+ const rules = ports
46
+ .filter((p) => p.protocol === "tcp")
47
+ .map((p) => ({
48
+ host: hostForPort(config, sessionId, p.port),
49
+ http: {
50
+ paths: [
51
+ {
52
+ path: "/",
53
+ pathType: "Prefix",
54
+ backend: { service: { name: serviceName, port: { number: p.port } } },
55
+ },
56
+ ],
57
+ },
58
+ }));
59
+ const ingress = {
60
+ apiVersion: "networking.k8s.io/v1",
61
+ kind: "Ingress",
62
+ metadata: {
63
+ name: `telo-run-${sessionId}`,
64
+ namespace: config.sessionNamespace,
65
+ labels: { "app.kubernetes.io/managed-by": config.managedByLabel },
66
+ ownerReferences: [podOwnerRef(podName, podUid)],
67
+ },
68
+ spec: {
69
+ ...(config.sessionIngressClassName
70
+ ? { ingressClassName: config.sessionIngressClassName }
71
+ : {}),
72
+ // Present the predefined cert (e.g. a Cloudflare Origin cert) so an upstream
73
+ // in Full (Strict) mode can validate the origin. Only meaningful with routable
74
+ // hosts; a single wildcard `*.<domain>` Secret covers every session host.
75
+ ...(config.sessionIngressTlsSecretName && rules.length > 0
76
+ ? {
77
+ tls: [{ hosts: rules.map((r) => r.host), secretName: config.sessionIngressTlsSecretName }],
78
+ }
79
+ : {}),
80
+ rules,
81
+ },
82
+ };
83
+ return { ingress, hosts: rules.map((r) => r.host) };
84
+ }
85
+ /** Endpoints announced on the `running` status. Every tcp port is fronted by its
86
+ * own per-session Ingress host (`<port>-<sessionId>.<domain>`, served on 443) and
87
+ * carries an external `url`. udp ports aren't HTTP-routable, so they keep the
88
+ * host-less form. Without an ingress base domain, host is left blank for the
89
+ * client adapter to fill (parity with docker). */
90
+ export function endpointsFor(config, sessionId, ports) {
91
+ if (!config.sessionIngressBaseDomain || ports.length === 0) {
92
+ return ports.map((p) => ({ host: "", port: p.port, protocol: p.protocol }));
93
+ }
94
+ return ports.map((p) => {
95
+ if (p.protocol !== "tcp") {
96
+ return { host: "", port: p.port, protocol: p.protocol };
97
+ }
98
+ const host = hostForPort(config, sessionId, p.port);
99
+ return { host, port: p.port, protocol: p.protocol, url: `https://${host}` };
100
+ });
101
+ }
102
+ //# sourceMappingURL=ingress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ingress.js","sourceRoot":"","sources":["../../src/k8s/ingress.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ import type { V1Pod } from "@kubernetes/client-node";
2
+ import type { K8sRunnerConfig } from "../config.js";
3
+ import type { ResolvedLimits } from "../limits.js";
4
+ import type { PortMapping } from "@telorun/runner-core";
5
+ export interface BuildPodArgs {
6
+ config: K8sRunnerConfig;
7
+ sessionId: string;
8
+ podName: string;
9
+ entryRelativePath: string;
10
+ env: Record<string, string>;
11
+ ports: PortMapping[];
12
+ limits: ResolvedLimits;
13
+ /** Prebuilt per-app image to run. Controllers + module manifests are baked
14
+ * into `/telo-cache/{manifests,npm}` (read-only) by the on-cluster build;
15
+ * the image is keyed only on the dependency closure, so the per-session body
16
+ * is NOT baked — it's delivered to `/app` at boot via the initContainer. */
17
+ image: string;
18
+ /** Tokenized, single-use URL the body-delivery initContainer fetches the
19
+ * session bundle tarball from (`BundleStore.stageSessionBundle`). */
20
+ bundleUrl: string;
21
+ /** When true, run the workload with `--inspect` so the runner can relay its
22
+ * kernel debug stream. Binds `0.0.0.0:<INSPECT_PORT>` (reachable only by the
23
+ * runner over the cluster pod network — never exposed via Service/Ingress). */
24
+ inspect: boolean;
25
+ }
26
+ /** Port the workload's `--inspect` server binds inside the session container.
27
+ * Reached by the runner over the cluster pod network (`http://<podIP>:<port>`);
28
+ * never declared as a Service port — only the runner relays the stream out. */
29
+ export declare const INSPECT_PORT = 9230;
30
+ /**
31
+ * Builds the session Pod. Hardening that needs no RuntimeClass is always on
32
+ * (non-root, read-only rootfs, drop-all caps, no service-account token,
33
+ * seccomp RuntimeDefault); a sandbox RuntimeClass is layered on when configured.
34
+ *
35
+ * The body-delivery initContainer fetches the session bundle into the writable
36
+ * `/app` emptyDir; the session container runs `telo run /app/<entry>
37
+ * --no-cache-write` reading its deps from the baked, read-only `/telo-cache`.
38
+ * `readOnlyRootFilesystem` stays on — every write lands on a mounted emptyDir.
39
+ */
40
+ export declare function buildSessionPod(args: BuildPodArgs): V1Pod;
41
+ //# sourceMappingURL=pod-spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pod-spec.d.ts","sourceRoot":"","sources":["../../src/k8s/pod-spec.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAErD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAExD,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,eAAe,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,MAAM,EAAE,cAAc,CAAC;IACvB;;;iFAG6E;IAC7E,KAAK,EAAE,MAAM,CAAC;IACd;0EACsE;IACtE,SAAS,EAAE,MAAM,CAAC;IAClB;;oFAEgF;IAChF,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;gFAEgF;AAChF,eAAO,MAAM,YAAY,OAAO,CAAC;AAajC;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,YAAY,GAAG,KAAK,CAoHzD"}