Skip to content

Commit 0ea5f74

Browse files
committed
feat: scope RuntimeDefault seccomp profile to node-24+ run pods
Only node-24+ runtimes create io_uring file descriptors (libuv >= ~1.52) that block CRIU checkpointing; node/node-22/bun do not. Apply the RuntimeDefault seccomp profile only to those cold pods instead of all run pods, so existing runtimes keep their current syscall surface. Plumbs the canonical runtime identifier through the dequeue message (backgroundWorker.runtime) to the Kubernetes workload manager.
1 parent bc38c3c commit 0ea5f74

6 files changed

Lines changed: 36 additions & 4 deletions

File tree

apps/supervisor/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,7 @@ class ManagedSupervisor {
615615
projectId: message.project.id,
616616
deploymentFriendlyId: message.deployment.friendlyId,
617617
deploymentVersion: message.backgroundWorker.version,
618+
runtime: message.backgroundWorker.runtime,
618619
runId: message.run.id,
619620
runFriendlyId: message.run.friendlyId,
620621
version: message.version,

apps/supervisor/src/workloadManager/kubernetes.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@ import { PlacementTagProcessor } from "@trigger.dev/core/v3/serverOnly";
1414
import { env } from "../env.js";
1515
import { type K8sApi, createK8sApi, type k8s } from "../clients/kubernetes.js";
1616
import { getRunnerId } from "../util.js";
17-
import { withRuntimeDefaultSeccompProfile } from "./kubernetesPodSpec.js";
17+
import {
18+
runtimeRequiresSeccompProfile,
19+
withRuntimeDefaultSeccompProfile,
20+
} from "./kubernetesPodSpec.js";
1821

1922
type ResourceQuantities = {
2023
[K in "cpu" | "memory" | "ephemeral-storage"]?: string;
@@ -106,6 +109,11 @@ export class KubernetesWorkloadManager implements WorkloadManager {
106109
const runnerId = getRunnerId(opts.runFriendlyId, opts.nextAttemptNumber);
107110

108111
try {
112+
const basePodSpec = this.addPlacementTags(this.#defaultPodSpec, opts.placementTags);
113+
const podSpec = runtimeRequiresSeccompProfile(opts.runtime)
114+
? withRuntimeDefaultSeccompProfile(basePodSpec)
115+
: basePodSpec;
116+
109117
await this.k8s.core.createNamespacedPod({
110118
namespace: this.namespace,
111119
body: {
@@ -120,7 +128,7 @@ export class KubernetesWorkloadManager implements WorkloadManager {
120128
},
121129
},
122130
spec: {
123-
...this.addPlacementTags(this.#defaultPodSpec, opts.placementTags),
131+
...podSpec,
124132
affinity: this.#getAffinity(opts),
125133
tolerations: this.#getScheduleTolerations(this.#isScheduledRun(opts)),
126134
terminationGracePeriodSeconds: 60 * 60,
@@ -310,7 +318,7 @@ export class KubernetesWorkloadManager implements WorkloadManager {
310318
}
311319

312320
get #defaultPodSpec(): Omit<k8s.V1PodSpec, "containers"> {
313-
return withRuntimeDefaultSeccompProfile({
321+
return {
314322
restartPolicy: "Never",
315323
automountServiceAccountToken: false,
316324
imagePullSecrets: this.getImagePullSecrets(),
@@ -333,7 +341,7 @@ export class KubernetesWorkloadManager implements WorkloadManager {
333341
},
334342
}
335343
: {}),
336-
});
344+
};
337345
}
338346

339347
get #defaultResourceRequests(): ResourceQuantities {

apps/supervisor/src/workloadManager/kubernetesPodSpec.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,21 @@
11
import type { k8s } from "../clients/kubernetes.js";
22

3+
/**
4+
* Node >= 24 (libuv >= ~1.52) unconditionally creates io_uring file descriptors,
5+
* which cannot be checkpointed. Launching those pods under the RuntimeDefault
6+
* seccomp profile makes io_uring_setup fail so libuv falls back to epoll, keeping
7+
* the pod checkpointable. "node" (21.x), "node-22" (UV_USE_IO_URING=0 still works)
8+
* and "bun" do not create these descriptors, so the profile is scoped to node-24+
9+
* to avoid changing the syscall surface of existing runtimes.
10+
*
11+
* Tolerant of an "experimental-" prefix in case a non-normalized value reaches here.
12+
*/
13+
export function runtimeRequiresSeccompProfile(runtime: string | null | undefined): boolean {
14+
if (!runtime) return false;
15+
const match = /^(?:experimental-)?node-(\d+)$/.exec(runtime);
16+
return match ? Number(match[1]) >= 24 : false;
17+
}
18+
319
export function withRuntimeDefaultSeccompProfile(
420
podSpec: Omit<k8s.V1PodSpec, "containers">
521
): Omit<k8s.V1PodSpec, "containers"> {

apps/supervisor/src/workloadManager/types.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ export interface WorkloadManagerCreateOptions {
4040
projectId: string;
4141
deploymentFriendlyId: string;
4242
deploymentVersion: string;
43+
// Canonical runtime identifier (e.g. "node", "node-22", "node-24"). Used to
44+
// scope the RuntimeDefault seccomp profile to runtimes that require it.
45+
runtime?: string;
4346
runId: string;
4447
runFriendlyId: string;
4548
snapshotId: string;

internal-packages/run-engine/src/engine/systems/dequeueSystem.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,7 @@ export class DequeueSystem {
597597
id: result.worker.id,
598598
friendlyId: result.worker.friendlyId,
599599
version: result.worker.version,
600+
runtime: result.worker.runtime ?? undefined,
600601
},
601602
// TODO: use a discriminated union schema to differentiate between dequeued runs in dev and in deployed environments.
602603
// Would help make the typechecking stricter

packages/core/src/v3/schemas/runEngine.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,9 @@ export const DequeuedMessage = z.object({
272272
id: z.string(),
273273
friendlyId: z.string(),
274274
version: z.string(),
275+
// Canonical runtime identifier (e.g. "node", "node-22", "node-24", "bun").
276+
// Consumed by orchestrators to decide per-runtime pod settings.
277+
runtime: z.string().optional(),
275278
}),
276279
deployment: z.object({
277280
id: z.string().optional(),

0 commit comments

Comments
 (0)