Files
openclaw/extensions/mxc/test/config.test.ts
Paul Campbell 9f8d81bd1a improve(mxc): document sandbox config options and flag network access as dangerous (#110256)
Add configContracts.dangerousFlags for network="default", per-field uiHints,
and configSchema/Zod field descriptions to the MXC sandbox plugin manifest.
Only network is flagged dangerous; containment "process" and "processcontainer"
currently resolve to the same Windows ProcessContainer. Align the manifest
description with the plugin entry and update the config schema test for the new
timeout description.


Copilot-Session: c299e8bd-b71c-4bb4-94a9-9c248543102a

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
2026-07-21 08:59:51 +09:00

117 lines
4.2 KiB
TypeScript

import { MAX_TIMER_TIMEOUT_SECONDS } from "openclaw/plugin-sdk/number-runtime";
import { describe, expect, test } from "vitest";
import { createMxcPluginConfigSchema, resolveConfig } from "../src/config.js";
describe("resolveConfig", () => {
test("uses defaults only when config is omitted", () => {
expect(resolveConfig(undefined)).toEqual({
mxcBinaryPath: undefined,
containment: "process",
network: "none",
timeoutSeconds: 120,
debug: false,
});
const config = resolveConfig({});
expect(config).toEqual({
mxcBinaryPath: undefined,
containment: "process",
network: "none",
timeoutSeconds: 120,
debug: false,
mxcPolicyPaths: undefined,
});
expect(config).not.toHaveProperty("timeoutSecondsConfigured");
});
test("applies valid overrides and preserves explicit timeout configuration", () => {
const config = resolveConfig({
mxcBinaryPath: " C:\\custom\\wxc-exec.exe ",
containment: "processcontainer",
network: "default",
timeoutSeconds: 60,
debug: true,
mxcPolicyPaths: [
" C:\\ProgramData\\openclaw\\mxc-machine-policy.json ",
" /opt/openclaw/mxc-user-policy.json ",
],
});
expect(config).toEqual({
mxcBinaryPath: "C:\\custom\\wxc-exec.exe",
containment: "processcontainer",
network: "default",
timeoutSeconds: 60,
timeoutSecondsConfigured: true,
debug: true,
mxcPolicyPaths: [
"C:\\ProgramData\\openclaw\\mxc-machine-policy.json",
"/opt/openclaw/mxc-user-policy.json",
],
});
});
test("rejects invalid root values and unknown keys", () => {
expect(() => resolveConfig(null)).toThrow(/Invalid mxc plugin config/u);
expect(() => resolveConfig("bad")).toThrow(/Invalid mxc plugin config/u);
expect(() => resolveConfig({ sandboxBaseline: {} })).toThrow(/sandboxBaseline/u);
});
test("rejects removed and malformed containment values", () => {
for (const containment of [
"windows_sandbox",
"wslc",
"microvm",
"seatbelt",
"isolation_session",
"lxc",
"invalid",
]) {
expect(() => resolveConfig({ containment })).toThrow(/containment/u);
}
});
test("rejects malformed enums and types instead of silently falling back", () => {
expect(() => resolveConfig({ network: "allow-all" })).toThrow(/network/u);
expect(() => resolveConfig({ debug: "true" })).toThrow(/debug/u);
expect(() => resolveConfig({ mxcBinaryPath: " " })).toThrow(/mxcBinaryPath/u);
});
test("enforces timeout bounds and only marks configured timeouts when supplied", () => {
expect(() => resolveConfig({ timeoutSeconds: 0 })).toThrow(/>= 1/u);
expect(() => resolveConfig({ timeoutSeconds: -5 })).toThrow(/>= 1/u);
expect(() => resolveConfig({ timeoutSeconds: "fast" })).toThrow(/timeoutSeconds/u);
expect(() => resolveConfig({ timeoutSeconds: MAX_TIMER_TIMEOUT_SECONDS + 1 })).toThrow(
new RegExp(`${MAX_TIMER_TIMEOUT_SECONDS}`, "u"),
);
const config = resolveConfig({ timeoutSeconds: MAX_TIMER_TIMEOUT_SECONDS });
expect(config.timeoutSeconds).toBe(MAX_TIMER_TIMEOUT_SECONDS);
expect(config.timeoutSecondsConfigured).toBe(true);
});
test("trims and validates mxcPolicyPaths as absolute paths", () => {
expect(() => resolveConfig({ mxcPolicyPaths: "C:\\policy.json" })).toThrow(/mxcPolicyPaths/u);
expect(() => resolveConfig({ mxcPolicyPaths: ["relative-policy.json"] })).toThrow(
/mxcPolicyPaths\[0\]/u,
);
expect(() => resolveConfig({ mxcPolicyPaths: [" "] })).toThrow(/mxcPolicyPaths/u);
expect(() => resolveConfig({ mxcPolicyPaths: [42] })).toThrow(/mxcPolicyPaths/u);
});
});
describe("createMxcPluginConfigSchema", () => {
test("publishes the same timeout cap in the plugin schema", () => {
const jsonSchema = createMxcPluginConfigSchema().jsonSchema as {
properties?: { timeoutSeconds?: unknown };
};
expect(jsonSchema.properties?.timeoutSeconds).toEqual({
type: "number",
minimum: 1,
maximum: MAX_TIMER_TIMEOUT_SECONDS,
description:
"Per-command execution timeout in seconds. Capped to the sandbox policy baseline timeout when both are set.",
});
});
});