mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-24 15:41:40 +00:00
173 lines
5.4 KiB
TypeScript
173 lines
5.4 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import {
|
|
resolveSandboxBrowserConfig,
|
|
resolveSandboxConfigForAgent,
|
|
resolveSandboxDockerConfig,
|
|
resolveSandboxPruneConfig,
|
|
resolveSandboxScope,
|
|
resolveSandboxSshConfig,
|
|
} from "./sandbox/config.js";
|
|
|
|
describe("sandbox config merges", () => {
|
|
it("resolves sandbox scope deterministically", () => {
|
|
expect(resolveSandboxScope({})).toBe("agent");
|
|
expect(resolveSandboxScope({ perSession: true })).toBe("session");
|
|
expect(resolveSandboxScope({ perSession: false })).toBe("shared");
|
|
expect(resolveSandboxScope({ perSession: true, scope: "agent" })).toBe("agent");
|
|
});
|
|
|
|
it("merges sandbox docker env and ulimits (agent wins)", () => {
|
|
const resolved = resolveSandboxDockerConfig({
|
|
scope: "agent",
|
|
globalDocker: {
|
|
env: { LANG: "C.UTF-8", FOO: "1" },
|
|
ulimits: { nofile: { soft: 10, hard: 20 } },
|
|
},
|
|
agentDocker: {
|
|
env: { FOO: "2", BAR: "3" },
|
|
ulimits: { nproc: 256 },
|
|
},
|
|
});
|
|
|
|
expect(resolved.env).toEqual({ LANG: "C.UTF-8", FOO: "2", BAR: "3" });
|
|
expect(resolved.ulimits).toEqual({
|
|
nofile: { soft: 10, hard: 20 },
|
|
nproc: 256,
|
|
});
|
|
});
|
|
|
|
it("resolves docker binds and shared-scope override behavior", () => {
|
|
for (const scenario of [
|
|
{
|
|
name: "merges sandbox docker binds (global + agent combined)",
|
|
input: {
|
|
scope: "agent" as const,
|
|
globalDocker: {
|
|
binds: ["/var/run/docker.sock:/var/run/docker.sock"],
|
|
},
|
|
agentDocker: {
|
|
binds: ["/home/user/source:/source:rw"],
|
|
},
|
|
},
|
|
assert: (resolved: ReturnType<typeof resolveSandboxDockerConfig>) => {
|
|
expect(resolved.binds).toEqual([
|
|
"/var/run/docker.sock:/var/run/docker.sock",
|
|
"/home/user/source:/source:rw",
|
|
]);
|
|
},
|
|
},
|
|
{
|
|
name: "returns undefined binds when neither global nor agent has binds",
|
|
input: {
|
|
scope: "agent" as const,
|
|
globalDocker: {},
|
|
agentDocker: {},
|
|
},
|
|
assert: (resolved: ReturnType<typeof resolveSandboxDockerConfig>) => {
|
|
expect(resolved.binds).toBeUndefined();
|
|
},
|
|
},
|
|
{
|
|
name: "ignores agent binds under shared scope",
|
|
input: {
|
|
scope: "shared" as const,
|
|
globalDocker: {
|
|
binds: ["/var/run/docker.sock:/var/run/docker.sock"],
|
|
},
|
|
agentDocker: {
|
|
binds: ["/home/user/source:/source:rw"],
|
|
},
|
|
},
|
|
assert: (resolved: ReturnType<typeof resolveSandboxDockerConfig>) => {
|
|
expect(resolved.binds).toEqual(["/var/run/docker.sock:/var/run/docker.sock"]);
|
|
},
|
|
},
|
|
{
|
|
name: "ignores agent docker overrides under shared scope",
|
|
input: {
|
|
scope: "shared" as const,
|
|
globalDocker: { image: "global" },
|
|
agentDocker: { image: "agent" },
|
|
},
|
|
assert: (resolved: ReturnType<typeof resolveSandboxDockerConfig>) => {
|
|
expect(resolved.image).toBe("global");
|
|
},
|
|
},
|
|
]) {
|
|
const resolved = resolveSandboxDockerConfig(scenario.input);
|
|
scenario.assert(resolved);
|
|
}
|
|
});
|
|
|
|
it("applies per-agent browser and prune overrides (ignored under shared scope)", () => {
|
|
const browser = resolveSandboxBrowserConfig({
|
|
scope: "agent",
|
|
globalBrowser: { enabled: false, headless: false, enableNoVnc: true },
|
|
agentBrowser: { enabled: true, headless: true, enableNoVnc: false },
|
|
});
|
|
expect(browser.enabled).toBe(true);
|
|
expect(browser.headless).toBe(true);
|
|
expect(browser.enableNoVnc).toBe(false);
|
|
|
|
const prune = resolveSandboxPruneConfig({
|
|
scope: "agent",
|
|
globalPrune: { idleHours: 24, maxAgeDays: 7 },
|
|
agentPrune: { idleHours: 0, maxAgeDays: 1 },
|
|
});
|
|
expect(prune).toEqual({ idleHours: 0, maxAgeDays: 1 });
|
|
|
|
const browserShared = resolveSandboxBrowserConfig({
|
|
scope: "shared",
|
|
globalBrowser: { enabled: false },
|
|
agentBrowser: { enabled: true },
|
|
});
|
|
expect(browserShared.enabled).toBe(false);
|
|
|
|
const pruneShared = resolveSandboxPruneConfig({
|
|
scope: "shared",
|
|
globalPrune: { idleHours: 24, maxAgeDays: 7 },
|
|
agentPrune: { idleHours: 0, maxAgeDays: 1 },
|
|
});
|
|
expect(pruneShared).toEqual({ idleHours: 24, maxAgeDays: 7 });
|
|
});
|
|
|
|
it("merges sandbox ssh settings and ignores agent overrides under shared scope", () => {
|
|
const ssh = resolveSandboxSshConfig({
|
|
scope: "agent",
|
|
globalSsh: {
|
|
target: "global@example.com:22",
|
|
command: "ssh",
|
|
identityFile: "~/.ssh/global",
|
|
strictHostKeyChecking: true,
|
|
},
|
|
agentSsh: {
|
|
target: "agent@example.com:2222",
|
|
certificateFile: "~/.ssh/agent-cert.pub",
|
|
strictHostKeyChecking: false,
|
|
},
|
|
});
|
|
expect(ssh).toMatchObject({
|
|
target: "agent@example.com:2222",
|
|
command: "ssh",
|
|
identityFile: "~/.ssh/global",
|
|
certificateFile: "~/.ssh/agent-cert.pub",
|
|
strictHostKeyChecking: false,
|
|
});
|
|
|
|
const sshShared = resolveSandboxSshConfig({
|
|
scope: "shared",
|
|
globalSsh: {
|
|
target: "global@example.com:22",
|
|
},
|
|
agentSsh: {
|
|
target: "agent@example.com:2222",
|
|
},
|
|
});
|
|
expect(sshShared.target).toBe("global@example.com:22");
|
|
});
|
|
|
|
it("defaults sandbox backend to docker", () => {
|
|
expect(resolveSandboxConfigForAgent().backend).toBe("docker");
|
|
});
|
|
});
|