Skip to content

Commit 7db5fca

Browse files
committed
feat(supervisor): make the runner seccomp profile path configurable
1 parent 74db5a3 commit 7db5fca

4 files changed

Lines changed: 27 additions & 36 deletions

File tree

apps/supervisor/src/env.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ export const Env = z
210210

211211
KUBERNETES_MEMORY_OVERHEAD_GB: z.coerce.number().min(0).optional(), // Optional memory overhead to add to the limit in GB
212212
KUBERNETES_SCHEDULER_NAME: z.string().optional(), // Custom scheduler name for pods
213+
KUBERNETES_RUNNER_SECCOMP_PROFILE_PATH: z.string().default("profiles/block-io-uring.json"),
213214

214215
// Pod DNS config — override the cluster default ndots to `KUBERNETES_POD_DNS_NDOTS`.
215216
// Default k8s ndots is 5: any name with fewer than 5 dots (e.g. `api.example.com`, 2 dots) is first walked

apps/supervisor/src/workloadManager/kubernetes.test.ts

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import { describe, expect, it } from "vitest";
22
import {
3-
BLOCK_IO_URING_SECCOMP_PROFILE,
43
nodetypeNodeSelector,
54
runPodTolerations,
6-
withBlockIoUringSeccompProfile,
5+
withRunnerSeccompProfile,
76
withNodeSelector,
87
} from "./kubernetesPodSpec.js";
98

@@ -100,27 +99,25 @@ describe("withNodeSelector", () => {
10099
});
101100
});
102101

103-
describe("withBlockIoUringSeccompProfile", () => {
104-
it("adds the Localhost io_uring profile for node-24 and above, preserving pod security defaults", () => {
105-
for (const runtime of ["node-24", "node-26", "node-30", "experimental-node-24"]) {
106-
const podSpec = withBlockIoUringSeccompProfile(basePodSpec, runtime);
107-
108-
expect(podSpec).toMatchObject({
109-
...basePodSpec,
110-
securityContext: {
111-
...basePodSpec.securityContext,
112-
seccompProfile: {
113-
type: "Localhost",
114-
localhostProfile: BLOCK_IO_URING_SECCOMP_PROFILE,
115-
},
102+
describe("withRunnerSeccompProfile", () => {
103+
it("applies the profile for every runtime, preserving pod security defaults", () => {
104+
const podSpec = withRunnerSeccompProfile(basePodSpec, "profiles/example.json");
105+
106+
expect(podSpec).toMatchObject({
107+
...basePodSpec,
108+
securityContext: {
109+
...basePodSpec.securityContext,
110+
seccompProfile: {
111+
type: "Localhost",
112+
localhostProfile: "profiles/example.json",
116113
},
117-
});
118-
}
114+
},
115+
});
119116
});
120117

121-
it("leaves the pod spec unchanged for runtimes that do not create io_uring fds", () => {
122-
for (const runtime of ["node", "node-22", "bun", undefined, null, ""]) {
123-
expect(withBlockIoUringSeccompProfile(basePodSpec, runtime)).toEqual(basePodSpec);
118+
it("leaves the pod spec untouched when no profile is configured", () => {
119+
for (const profilePath of [undefined, ""]) {
120+
expect(withRunnerSeccompProfile(basePodSpec, profilePath)).toBe(basePodSpec);
124121
}
125122
});
126123
});

apps/supervisor/src/workloadManager/kubernetes.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import { getRunnerId } from "../util.js";
1717
import {
1818
nodetypeNodeSelector,
1919
runPodTolerations,
20-
withBlockIoUringSeccompProfile,
20+
withRunnerSeccompProfile,
2121
withNodeSelector,
2222
} from "./kubernetesPodSpec.js";
2323

@@ -136,7 +136,7 @@ export class KubernetesWorkloadManager implements WorkloadManager {
136136
}
137137
}
138138
const podSpec = this.opts.checkpointsEnabled
139-
? withBlockIoUringSeccompProfile(basePodSpec, opts.runtime)
139+
? withRunnerSeccompProfile(basePodSpec, env.KUBERNETES_RUNNER_SECCOMP_PROFILE_PATH)
140140
: basePodSpec;
141141

142142
await this.k8s.core.createNamespacedPod({

apps/supervisor/src/workloadManager/kubernetesPodSpec.ts

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

3-
/**
4-
* Relative path (kubelet seccomp root) of the profile blocking only io_uring
5-
* syscalls. Must match the profile deployed to worker nodes.
6-
*/
7-
export const BLOCK_IO_URING_SECCOMP_PROFILE = "profiles/block-io-uring.json";
8-
93
/**
104
* An empty label is the documented off-switch, leaving the pod unpinned. The Helm
115
* chart ships an empty value, so don't collapse this into a fallback default -
@@ -61,16 +55,15 @@ export function withNodeSelector(
6155
}
6256

6357
/**
64-
* Node >= 24 always creates io_uring fds, which can't be checkpointed. Blocking
65-
* io_uring_setup makes libuv fall back to epoll. Other runtimes don't need this,
66-
* so the profile is only applied for node-24+. Tolerates an "experimental-" prefix.
58+
* Applies the runner seccomp profile. The profile is a node-local file installed
59+
* outside this repo, so an empty path leaves the pod on the runtime default -
60+
* pointing at a profile the nodes don't have fails pod creation.
6761
*/
68-
export function withBlockIoUringSeccompProfile(
62+
export function withRunnerSeccompProfile(
6963
podSpec: Omit<k8s.V1PodSpec, "containers">,
70-
runtime: string | null | undefined
64+
profilePath: string | undefined
7165
): Omit<k8s.V1PodSpec, "containers"> {
72-
const match = runtime ? /^(?:experimental-)?node-(\d+)$/.exec(runtime) : null;
73-
if (!match || Number(match[1]) < 24) {
66+
if (!profilePath) {
7467
return podSpec;
7568
}
7669

@@ -80,7 +73,7 @@ export function withBlockIoUringSeccompProfile(
8073
...podSpec.securityContext,
8174
seccompProfile: {
8275
type: "Localhost",
83-
localhostProfile: BLOCK_IO_URING_SECCOMP_PROFILE,
76+
localhostProfile: profilePath,
8477
},
8578
},
8679
};

0 commit comments

Comments
 (0)