test(sandbox): table-drive dangerous docker config rejection cases

This commit is contained in:
Peter Steinberger
2026-02-21 23:47:28 +00:00
parent a353dae14f
commit 012654c7c5

View File

@@ -2,6 +2,40 @@ import { describe, expect, it } from "vitest";
import { buildSandboxCreateArgs, type SandboxDockerConfig } from "./sandbox.js"; import { buildSandboxCreateArgs, type SandboxDockerConfig } from "./sandbox.js";
describe("buildSandboxCreateArgs", () => { describe("buildSandboxCreateArgs", () => {
function createSandboxConfig(
overrides: Partial<SandboxDockerConfig> = {},
binds?: string[],
): SandboxDockerConfig {
return {
image: "openclaw-sandbox:bookworm-slim",
containerPrefix: "openclaw-sbx-",
workdir: "/workspace",
readOnlyRoot: false,
tmpfs: [],
network: "none",
capDrop: [],
...(binds ? { binds } : {}),
...overrides,
};
}
function expectBuildToThrow(
name: string,
cfg: SandboxDockerConfig,
expectedMessage: RegExp,
): void {
expect(
() =>
buildSandboxCreateArgs({
name,
cfg,
scopeKey: "main",
createdAtMs: 1700000000000,
}),
name,
).toThrow(expectedMessage);
}
it("includes hardening and resource flags", () => { it("includes hardening and resource flags", () => {
const cfg: SandboxDockerConfig = { const cfg: SandboxDockerConfig = {
image: "openclaw-sandbox:bookworm-slim", image: "openclaw-sandbox:bookworm-slim",
@@ -127,113 +161,39 @@ describe("buildSandboxCreateArgs", () => {
expect(vFlags).toContain("/var/data/myapp:/data:ro"); expect(vFlags).toContain("/var/data/myapp:/data:ro");
}); });
it("throws on dangerous bind mounts (Docker socket)", () => { it.each([
const cfg: SandboxDockerConfig = { {
image: "openclaw-sandbox:bookworm-slim", name: "dangerous Docker socket bind mounts",
containerPrefix: "openclaw-sbx-", containerName: "openclaw-sbx-dangerous",
workdir: "/workspace", cfg: createSandboxConfig({}, ["/var/run/docker.sock:/var/run/docker.sock"]),
readOnlyRoot: false, expected: /blocked path/,
tmpfs: [], },
network: "none", {
capDrop: [], name: "dangerous parent bind mounts",
binds: ["/var/run/docker.sock:/var/run/docker.sock"], containerName: "openclaw-sbx-dangerous-parent",
}; cfg: createSandboxConfig({}, ["/run:/run"]),
expected: /blocked path/,
expect(() => },
buildSandboxCreateArgs({ {
name: "openclaw-sbx-dangerous", name: "network host mode",
cfg, containerName: "openclaw-sbx-host",
scopeKey: "main", cfg: createSandboxConfig({ network: "host" }),
createdAtMs: 1700000000000, expected: /network mode "host" is blocked/,
}), },
).toThrow(/blocked path/); {
}); name: "seccomp unconfined",
containerName: "openclaw-sbx-seccomp",
it("throws on dangerous bind mounts (parent path)", () => { cfg: createSandboxConfig({ seccompProfile: "unconfined" }),
const cfg: SandboxDockerConfig = { expected: /seccomp profile "unconfined" is blocked/,
image: "openclaw-sandbox:bookworm-slim", },
containerPrefix: "openclaw-sbx-", {
workdir: "/workspace", name: "apparmor unconfined",
readOnlyRoot: false, containerName: "openclaw-sbx-apparmor",
tmpfs: [], cfg: createSandboxConfig({ apparmorProfile: "unconfined" }),
network: "none", expected: /apparmor profile "unconfined" is blocked/,
capDrop: [], },
binds: ["/run:/run"], ])("throws on $name", ({ containerName, cfg, expected }) => {
}; expectBuildToThrow(containerName, cfg, expected);
expect(() =>
buildSandboxCreateArgs({
name: "openclaw-sbx-dangerous-parent",
cfg,
scopeKey: "main",
createdAtMs: 1700000000000,
}),
).toThrow(/blocked path/);
});
it("throws on network host mode", () => {
const cfg: SandboxDockerConfig = {
image: "openclaw-sandbox:bookworm-slim",
containerPrefix: "openclaw-sbx-",
workdir: "/workspace",
readOnlyRoot: false,
tmpfs: [],
network: "host",
capDrop: [],
};
expect(() =>
buildSandboxCreateArgs({
name: "openclaw-sbx-host",
cfg,
scopeKey: "main",
createdAtMs: 1700000000000,
}),
).toThrow(/network mode "host" is blocked/);
});
it("throws on seccomp unconfined", () => {
const cfg: SandboxDockerConfig = {
image: "openclaw-sandbox:bookworm-slim",
containerPrefix: "openclaw-sbx-",
workdir: "/workspace",
readOnlyRoot: false,
tmpfs: [],
network: "none",
capDrop: [],
seccompProfile: "unconfined",
};
expect(() =>
buildSandboxCreateArgs({
name: "openclaw-sbx-seccomp",
cfg,
scopeKey: "main",
createdAtMs: 1700000000000,
}),
).toThrow(/seccomp profile "unconfined" is blocked/);
});
it("throws on apparmor unconfined", () => {
const cfg: SandboxDockerConfig = {
image: "openclaw-sandbox:bookworm-slim",
containerPrefix: "openclaw-sbx-",
workdir: "/workspace",
readOnlyRoot: false,
tmpfs: [],
network: "none",
capDrop: [],
apparmorProfile: "unconfined",
};
expect(() =>
buildSandboxCreateArgs({
name: "openclaw-sbx-apparmor",
cfg,
scopeKey: "main",
createdAtMs: 1700000000000,
}),
).toThrow(/apparmor profile "unconfined" is blocked/);
}); });
it("omits -v flags when binds is empty or undefined", () => { it("omits -v flags when binds is empty or undefined", () => {