Skip to content

Commit 0db1c31

Browse files
committed
test: tighten install mode and allowlist coverage
1 parent 1bf56e7 commit 0db1c31

File tree

2 files changed

+101
-38
lines changed

2 files changed

+101
-38
lines changed

src/infra/exec-allowlist-pattern.test.ts

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,47 @@ import { describe, expect, it } from "vitest";
22
import { matchesExecAllowlistPattern } from "./exec-allowlist-pattern.js";
33

44
describe("matchesExecAllowlistPattern", () => {
5+
it.each([
6+
{ pattern: "", target: "/tmp/tool", expected: false },
7+
{ pattern: " ", target: "/tmp/tool", expected: false },
8+
{ pattern: "/tmp/tool", target: "/tmp/tool", expected: true },
9+
])("handles literal patterns for %j", ({ pattern, target, expected }) => {
10+
expect(matchesExecAllowlistPattern(pattern, target)).toBe(expected);
11+
});
12+
513
it("does not let ? cross path separators", () => {
614
expect(matchesExecAllowlistPattern("/tmp/a?b", "/tmp/a/b")).toBe(false);
715
expect(matchesExecAllowlistPattern("/tmp/a?b", "/tmp/acb")).toBe(true);
816
});
917

10-
it("keeps ** matching across path separators", () => {
11-
expect(matchesExecAllowlistPattern("/tmp/**/tool", "/tmp/a/b/tool")).toBe(true);
18+
it.each([
19+
{ pattern: "/tmp/*/tool", target: "/tmp/a/tool", expected: true },
20+
{ pattern: "/tmp/*/tool", target: "/tmp/a/b/tool", expected: false },
21+
{ pattern: "/tmp/**/tool", target: "/tmp/a/b/tool", expected: true },
22+
])("handles star patterns for %j", ({ pattern, target, expected }) => {
23+
expect(matchesExecAllowlistPattern(pattern, target)).toBe(expected);
24+
});
25+
26+
it("expands home-prefix patterns", () => {
27+
const prevOpenClawHome = process.env.OPENCLAW_HOME;
28+
const prevHome = process.env.HOME;
29+
process.env.OPENCLAW_HOME = "/srv/openclaw-home";
30+
process.env.HOME = "/home/other";
31+
try {
32+
expect(matchesExecAllowlistPattern("~/bin/tool", "/srv/openclaw-home/bin/tool")).toBe(true);
33+
expect(matchesExecAllowlistPattern("~/bin/tool", "/home/other/bin/tool")).toBe(false);
34+
} finally {
35+
if (prevOpenClawHome === undefined) {
36+
delete process.env.OPENCLAW_HOME;
37+
} else {
38+
process.env.OPENCLAW_HOME = prevOpenClawHome;
39+
}
40+
if (prevHome === undefined) {
41+
delete process.env.HOME;
42+
} else {
43+
process.env.HOME = prevHome;
44+
}
45+
}
1246
});
1347

1448
it.runIf(process.platform !== "win32")("preserves case sensitivity on POSIX", () => {

src/infra/install-mode-options.test.ts

Lines changed: 65 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -5,47 +5,76 @@ import {
55
} from "./install-mode-options.js";
66

77
describe("install mode option helpers", () => {
8-
it("applies logger, mode, and dryRun defaults", () => {
9-
const logger = { warn: (_message: string) => {} };
10-
const result = resolveInstallModeOptions({}, logger);
8+
it.each([
9+
{
10+
name: "applies logger, mode, and dryRun defaults",
11+
params: {},
12+
expected: { loggerKey: "default", mode: "install", dryRun: false },
13+
},
14+
{
15+
name: "preserves explicit mode and dryRun values",
16+
params: { loggerKey: "explicit", mode: "update" as const, dryRun: true },
17+
expected: { loggerKey: "explicit", mode: "update", dryRun: true },
18+
},
19+
{
20+
name: "preserves explicit false dryRun values",
21+
params: { mode: "update" as const, dryRun: false },
22+
expected: { loggerKey: "default", mode: "update", dryRun: false },
23+
},
24+
])("$name", ({ params, expected }) => {
25+
const loggers = {
26+
default: { warn: (_message: string) => {} },
27+
explicit: { warn: (_message: string) => {} },
28+
};
1129

12-
expect(result).toEqual({
13-
logger,
14-
mode: "install",
15-
dryRun: false,
30+
expect(
31+
resolveInstallModeOptions(
32+
{
33+
logger: params.loggerKey ? loggers[params.loggerKey] : undefined,
34+
mode: params.mode,
35+
dryRun: params.dryRun,
36+
},
37+
loggers.default,
38+
),
39+
).toEqual({
40+
logger: loggers[expected.loggerKey],
41+
mode: expected.mode,
42+
dryRun: expected.dryRun,
1643
});
1744
});
1845

19-
it("preserves explicit mode and dryRun values", () => {
46+
it.each([
47+
{
48+
name: "uses default timeout when not provided",
49+
params: {},
50+
defaultTimeoutMs: undefined,
51+
expectedTimeoutMs: 120_000,
52+
expectedMode: "install",
53+
expectedDryRun: false,
54+
},
55+
{
56+
name: "honors custom timeout default override",
57+
params: {},
58+
defaultTimeoutMs: 5000,
59+
expectedTimeoutMs: 5000,
60+
expectedMode: "install",
61+
expectedDryRun: false,
62+
},
63+
{
64+
name: "preserves explicit timeout values",
65+
params: { timeoutMs: 0, mode: "update" as const, dryRun: true },
66+
defaultTimeoutMs: 5000,
67+
expectedTimeoutMs: 0,
68+
expectedMode: "update",
69+
expectedDryRun: true,
70+
},
71+
])("$name", ({ params, defaultTimeoutMs, expectedTimeoutMs, expectedMode, expectedDryRun }) => {
2072
const logger = { warn: (_message: string) => {} };
21-
const result = resolveInstallModeOptions(
22-
{
23-
logger,
24-
mode: "update",
25-
dryRun: true,
26-
},
27-
{ warn: () => {} },
28-
);
29-
30-
expect(result).toEqual({
31-
logger,
32-
mode: "update",
33-
dryRun: true,
34-
});
35-
});
36-
37-
it("uses default timeout when not provided", () => {
38-
const logger = { warn: (_message: string) => {} };
39-
const result = resolveTimedInstallModeOptions({}, logger);
40-
41-
expect(result.timeoutMs).toBe(120_000);
42-
expect(result.mode).toBe("install");
43-
expect(result.dryRun).toBe(false);
44-
});
45-
46-
it("honors custom timeout default override", () => {
47-
const result = resolveTimedInstallModeOptions({}, { warn: () => {} }, 5000);
73+
const result = resolveTimedInstallModeOptions(params, logger, defaultTimeoutMs);
4874

49-
expect(result.timeoutMs).toBe(5000);
75+
expect(result.timeoutMs).toBe(expectedTimeoutMs);
76+
expect(result.mode).toBe(expectedMode);
77+
expect(result.dryRun).toBe(expectedDryRun);
78+
expect(result.logger).toBe(logger);
5079
});
5180
});

0 commit comments

Comments
 (0)