File size: 1,856 Bytes
d197cf3 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | import { randomUUID } from "node:crypto";
import { existsSync } from "node:fs";
import fs from "node:fs/promises";
import path from "node:path";
import { afterEach, describe, expect, it } from "vitest";
import { useAutoCleanupTempDirTracker } from "../../test/helpers/temp-dir.js";
import { prepareHostedStopExecutor } from "./hosted-stop-executor.js";
// Requires an isolated systemd VM with permission to create transient scopes.
describe.runIf(
process.platform === "linux" && process.getuid?.() === 0 && existsSync("/run/systemd/system"),
)("hosted stop executor native systemd scope", () => {
const dirs = useAutoCleanupTempDirTracker(afterEach);
it("retains literal shell arguments across scope placement and exec", async () => {
const output = path.join(dirs.make("hosted-stop-scope-"), "argv");
const unit = `openclaw-stop-test-${randomUUID()}.scope`;
const args = ["$@", "$$", "$HOME", "two words", "'\"; echo bad"];
const executor = await prepareHostedStopExecutor({
command: [
process.execPath,
"-e",
"require('node:fs').writeFileSync(process.argv[1], JSON.stringify(process.argv.slice(2)))",
output,
...args,
],
scopeArgs: [
"--system",
"--scope",
"--quiet",
"--collect",
"--no-ask-password",
`--unit=${unit}`,
],
env: process.env,
signal: new AbortController().signal,
assertCurrent: () => {},
verifyPlacement: async (pid) => {
expect(await fs.readFile(`/proc/${pid}/cgroup`, "utf8")).toContain(`/${unit}\n`);
},
});
try {
await expect(executor.execute(() => {})).resolves.toMatchObject({ disposition: "accepted" });
expect(JSON.parse(await fs.readFile(output, "utf8"))).toEqual(args);
} finally {
await executor.dispose();
}
});
});
|