Files
moltbot/src/daemon/schtasks.install.test.ts
2026-03-07 21:15:01 +00:00

155 lines
4.9 KiB
TypeScript

import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { PassThrough } from "node:stream";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { installScheduledTask, readScheduledTaskCommand } from "./schtasks.js";
const schtasksCalls: string[][] = [];
vi.mock("./schtasks-exec.js", () => ({
execSchtasks: async (argv: string[]) => {
schtasksCalls.push(argv);
return { code: 0, stdout: "", stderr: "" };
},
}));
beforeEach(() => {
schtasksCalls.length = 0;
});
describe("installScheduledTask", () => {
async function withUserProfileDir(
run: (tmpDir: string, env: Record<string, string>) => Promise<void>,
) {
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-schtasks-install-"));
const env = {
USERPROFILE: tmpDir,
OPENCLAW_PROFILE: "default",
};
try {
await run(tmpDir, env);
} finally {
await fs.rm(tmpDir, { recursive: true, force: true });
}
}
it("writes quoted set assignments and escapes metacharacters", async () => {
await withUserProfileDir(async (_tmpDir, env) => {
const { scriptPath } = await installScheduledTask({
env,
stdout: new PassThrough(),
programArguments: [
"node",
"gateway.js",
"--display-name",
"safe&whoami",
"--percent",
"%TEMP%",
"--bang",
"!token!",
],
workingDirectory: "C:\\temp\\poc&calc",
environment: {
OC_INJECT: "safe & whoami | calc",
OC_CARET: "a^b",
OC_PERCENT: "%TEMP%",
OC_BANG: "!token!",
OC_QUOTE: 'he said "hi"',
OC_EMPTY: "",
},
});
const script = await fs.readFile(scriptPath, "utf8");
expect(script).toContain('cd /d "C:\\temp\\poc&calc"');
expect(script).toContain(
'node gateway.js --display-name "safe&whoami" --percent "%%TEMP%%" --bang "^!token^!"',
);
expect(script).toContain('set "OC_INJECT=safe & whoami | calc"');
expect(script).toContain('set "OC_CARET=a^^b"');
expect(script).toContain('set "OC_PERCENT=%%TEMP%%"');
expect(script).toContain('set "OC_BANG=^!token^!"');
expect(script).toContain('set "OC_QUOTE=he said ^"hi^""');
expect(script).not.toContain('set "OC_EMPTY=');
expect(script).not.toContain("set OC_INJECT=");
const parsed = await readScheduledTaskCommand(env);
expect(parsed).toMatchObject({
programArguments: [
"node",
"gateway.js",
"--display-name",
"safe&whoami",
"--percent",
"%TEMP%",
"--bang",
"!token!",
],
workingDirectory: "C:\\temp\\poc&calc",
});
expect(parsed?.environment).toMatchObject({
OC_INJECT: "safe & whoami | calc",
OC_CARET: "a^b",
OC_PERCENT: "%TEMP%",
OC_BANG: "!token!",
OC_QUOTE: 'he said "hi"',
});
expect(parsed?.environment).not.toHaveProperty("OC_EMPTY");
expect(schtasksCalls[0]).toEqual(["/Query"]);
expect(schtasksCalls[1]?.[0]).toBe("/Create");
expect(schtasksCalls[2]).toEqual(["/Run", "/TN", "OpenClaw Gateway"]);
});
});
it("rejects line breaks in command arguments, env vars, and descriptions", async () => {
await withUserProfileDir(async (_tmpDir, env) => {
await expect(
installScheduledTask({
env,
stdout: new PassThrough(),
programArguments: ["node", "gateway.js", "bad\narg"],
environment: {},
}),
).rejects.toThrow(/Command argument cannot contain CR or LF/);
await expect(
installScheduledTask({
env,
stdout: new PassThrough(),
programArguments: ["node", "gateway.js"],
environment: { BAD: "line1\r\nline2" },
}),
).rejects.toThrow(/Environment variable value cannot contain CR or LF/);
await expect(
installScheduledTask({
env,
stdout: new PassThrough(),
description: "bad\ndescription",
programArguments: ["node", "gateway.js"],
environment: {},
}),
).rejects.toThrow(/Task description cannot contain CR or LF/);
});
});
it("does not persist a frozen PATH snapshot into the generated task script", async () => {
await withUserProfileDir(async (_tmpDir, env) => {
const { scriptPath } = await installScheduledTask({
env,
stdout: new PassThrough(),
programArguments: ["node", "gateway.js"],
environment: {
PATH: "C:\\Windows\\System32;C:\\Program Files\\Docker\\Docker\\resources\\bin",
OPENCLAW_GATEWAY_PORT: "18789",
},
});
const script = await fs.readFile(scriptPath, "utf8");
expect(script).not.toContain('set "PATH=');
expect(script).toContain('set "OPENCLAW_GATEWAY_PORT=18789"');
});
});
});