Files
openclaw/extensions/openshell/src/config.test.ts
Peter Steinberger 3d0df74b0f fix(openshell): sandbox cleanup, workspace sync, and gateway setup failures (#129641)
* fix(openshell): harden sandbox lifecycle and workspace sync

* fix(openshell): preserve shipped workspace root layouts

* test(gateway): reset shared agent harness state between cases

* test(qa): measure channel health startup grace directly

* chore(release): leave changelog updates to release automation
2026-08-25 18:08:55 -07:00

134 lines
4.1 KiB
TypeScript

// Openshell tests cover config plugin behavior.
import fsSync from "node:fs";
import { describe, expect, it } from "vitest";
import { createOpenShellPluginConfigSchema, resolveOpenShellPluginConfig } from "./config.js";
describe("openshell plugin config", () => {
it("applies defaults", () => {
expect(resolveOpenShellPluginConfig(undefined)).toEqual({
mode: "mirror",
command: "openshell",
gateway: undefined,
gatewayEndpoint: undefined,
workspace: undefined,
from: "openclaw",
policy: undefined,
providers: [],
gpu: false,
autoProviders: true,
remoteWorkspaceDir: "/sandbox",
remoteAgentWorkspaceDir: "/agent",
timeoutMs: 120_000,
});
});
it("accepts remote mode", () => {
expect(resolveOpenShellPluginConfig({ mode: "remote" }).mode).toBe("remote");
});
it("rejects relative remote paths", () => {
expect(
createOpenShellPluginConfigSchema().safeParse?.({
remoteWorkspaceDir: "sandbox",
}).success,
).toBe(false);
expect(() =>
resolveOpenShellPluginConfig({
remoteWorkspaceDir: "sandbox",
}),
).toThrow("OpenShell remoteWorkspaceDir must be absolute");
});
it("rejects remote paths outside managed sandbox roots", () => {
expect(
createOpenShellPluginConfigSchema().safeParse?.({
remoteWorkspaceDir: "/tmp/victim",
}).success,
).toBe(false);
expect(() =>
resolveOpenShellPluginConfig({
remoteWorkspaceDir: "/tmp/victim",
}),
).toThrow("OpenShell remoteWorkspaceDir must stay under /sandbox or /agent");
});
it("rejects normalized paths that escape managed sandbox roots during config validation", () => {
expect(
createOpenShellPluginConfigSchema().safeParse?.({
remoteAgentWorkspaceDir: "/agent/../../etc",
}).success,
).toBe(false);
});
it.each([
["/sandbox/project", "/sandbox/project"],
["/sandbox/project", "/sandbox/project/agent"],
["/agent/worker/project", "/agent/worker"],
])(
"preserves shipped overlapping workspace roots %s and %s",
(remoteWorkspaceDir, remoteAgentWorkspaceDir) => {
const config = { remoteWorkspaceDir, remoteAgentWorkspaceDir };
expect(createOpenShellPluginConfigSchema().safeParse?.(config).success).toBe(true);
expect(resolveOpenShellPluginConfig(config)).toMatchObject(config);
},
);
it("normalizes managed sandbox subpaths", () => {
expect(
resolveOpenShellPluginConfig({
remoteWorkspaceDir: "/sandbox/../sandbox/project",
remoteAgentWorkspaceDir: "/agent/./session",
}),
).toEqual({
mode: "mirror",
command: "openshell",
gateway: undefined,
gatewayEndpoint: undefined,
workspace: undefined,
from: "openclaw",
policy: undefined,
providers: [],
gpu: false,
autoProviders: true,
remoteWorkspaceDir: "/sandbox/project",
remoteAgentWorkspaceDir: "/agent/session",
timeoutMs: 120_000,
});
});
it("rejects unknown mode", () => {
expect(() =>
resolveOpenShellPluginConfig({
mode: "bogus",
}),
).toThrow("mode must be one of mirror, remote");
});
it("accepts an OpenShell workspace name", () => {
expect(resolveOpenShellPluginConfig({ workspace: "team-1" }).workspace).toBe("team-1");
});
it.each(["Team", "-team", "team-", "team--one", "abcdefghijklmnopqrst"])(
"rejects invalid OpenShell workspace name %s",
(workspace) => {
expect(() => resolveOpenShellPluginConfig({ workspace })).toThrow(/workspace must/);
},
);
it("rejects timeouts beyond Node's safe timer range", () => {
expect(() =>
resolveOpenShellPluginConfig({
timeoutSeconds: 2_147_001,
}),
).toThrow("timeoutSeconds must be a number <= 2147000");
});
it("keeps the runtime json schema in sync with the manifest config schema", () => {
const manifest = JSON.parse(
fsSync.readFileSync(new URL("../openclaw.plugin.json", import.meta.url), "utf8"),
) as { configSchema?: unknown };
expect(createOpenShellPluginConfigSchema().jsonSchema).toEqual(manifest.configSchema);
});
});