perf(test): use prebuilt hook install fixtures

This commit is contained in:
Peter Steinberger
2026-02-15 12:56:31 +00:00
parent 37aaca0d4e
commit fa472623f6
8 changed files with 10 additions and 166 deletions

View File

@@ -1,50 +1,27 @@
import JSZip from "jszip";
import { randomUUID } from "node:crypto";
import fs from "node:fs";
import fsPromises from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import * as tar from "tar";
import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { afterAll, beforeEach, describe, expect, it, vi } from "vitest";
const fixtureRoot = path.join(os.tmpdir(), `openclaw-hook-install-${randomUUID()}`);
let tempDirIndex = 0;
let zipHooksBuffer: Buffer;
let zipTraversalBuffer: Buffer;
let tarHooksBuffer: Buffer;
let tarTraversalBuffer: Buffer;
let tarEvilIdBuffer: Buffer;
let tarReservedIdBuffer: Buffer;
let npmPackHooksBuffer: Buffer;
const fixturesDir = path.resolve(process.cwd(), "test", "fixtures", "hooks-install");
const zipHooksBuffer = fs.readFileSync(path.join(fixturesDir, "zip-hooks.zip"));
const zipTraversalBuffer = fs.readFileSync(path.join(fixturesDir, "zip-traversal.zip"));
const tarHooksBuffer = fs.readFileSync(path.join(fixturesDir, "tar-hooks.tar"));
const tarTraversalBuffer = fs.readFileSync(path.join(fixturesDir, "tar-traversal.tar"));
const tarEvilIdBuffer = fs.readFileSync(path.join(fixturesDir, "tar-evil-id.tar"));
const tarReservedIdBuffer = fs.readFileSync(path.join(fixturesDir, "tar-reserved-id.tar"));
const npmPackHooksBuffer = fs.readFileSync(path.join(fixturesDir, "npm-pack-hooks.tgz"));
vi.mock("../process/exec.js", () => ({
runCommandWithTimeout: vi.fn(),
}));
async function packToArchive({
pkgDir,
outDir,
outName,
}: {
pkgDir: string;
outDir: string;
outName: string;
}) {
const dest = path.join(outDir, outName);
fs.rmSync(dest, { force: true });
await tar.c(
{
gzip: true,
file: dest,
cwd: path.dirname(pkgDir),
},
[path.basename(pkgDir)],
);
return dest;
}
function makeTempDir() {
fs.mkdirSync(fixtureRoot, { recursive: true });
const dir = path.join(fixtureRoot, `case-${tempDirIndex++}`);
fs.mkdirSync(dir, { recursive: true });
return dir;
@@ -54,139 +31,6 @@ const { runCommandWithTimeout } = await import("../process/exec.js");
const { installHooksFromArchive, installHooksFromNpmSpec, installHooksFromPath } =
await import("./install.js");
beforeAll(async () => {
fs.mkdirSync(fixtureRoot, { recursive: true });
const zipHooks = new JSZip();
zipHooks.file(
"package/package.json",
JSON.stringify({
name: "@openclaw/zip-hooks",
version: "0.0.1",
openclaw: { hooks: ["./hooks/zip-hook"] },
}),
);
zipHooks.file(
"package/hooks/zip-hook/HOOK.md",
[
"---",
"name: zip-hook",
"description: Zip hook",
'metadata: {"openclaw":{"events":["command:new"]}}',
"---",
"",
"# Zip Hook",
].join("\n"),
);
zipHooks.file("package/hooks/zip-hook/handler.ts", "export default async () => {};\n");
zipHooksBuffer = await zipHooks.generateAsync({ type: "nodebuffer" });
const zipTraversal = new JSZip();
zipTraversal.file("../pwned.txt", "nope\n");
zipTraversalBuffer = await zipTraversal.generateAsync({ type: "nodebuffer" });
const makeTarWithPackage = async (params: {
packageName: string;
hookName: string;
}): Promise<Buffer> => {
const workDir = makeTempDir();
const archivePath = path.join(workDir, "hooks.tar");
const pkgDir = path.join(workDir, "package");
fs.mkdirSync(path.join(pkgDir, "hooks", params.hookName), { recursive: true });
fs.writeFileSync(
path.join(pkgDir, "package.json"),
JSON.stringify({
name: params.packageName,
version: "0.0.1",
openclaw: { hooks: [`./hooks/${params.hookName}`] },
}),
"utf-8",
);
fs.writeFileSync(
path.join(pkgDir, "hooks", params.hookName, "HOOK.md"),
[
"---",
`name: ${params.hookName}`,
`description: ${params.hookName}`,
'metadata: {"openclaw":{"events":["command:new"]}}',
"---",
"",
"# Hook",
].join("\n"),
"utf-8",
);
fs.writeFileSync(
path.join(pkgDir, "hooks", params.hookName, "handler.ts"),
"export default async () => {};\n",
"utf-8",
);
await tar.c({ cwd: workDir, file: archivePath }, ["package"]);
return await fsPromises.readFile(archivePath);
};
tarHooksBuffer = await makeTarWithPackage({
packageName: "@openclaw/tar-hooks",
hookName: "tar-hook",
});
tarEvilIdBuffer = await makeTarWithPackage({ packageName: "@evil/..", hookName: "evil-hook" });
tarReservedIdBuffer = await makeTarWithPackage({
packageName: "@evil/.",
hookName: "reserved-hook",
});
const makeTraversalTar = async (): Promise<Buffer> => {
const workDir = makeTempDir();
const insideDir = path.join(workDir, "inside");
fs.mkdirSync(insideDir, { recursive: true });
fs.writeFileSync(path.join(workDir, "outside.txt"), "nope\n", "utf-8");
const archivePath = path.join(workDir, "traversal.tar");
await tar.c({ cwd: insideDir, file: archivePath }, ["../outside.txt"]);
return await fsPromises.readFile(archivePath);
};
tarTraversalBuffer = await makeTraversalTar();
const makeNpmPackTgz = async (): Promise<Buffer> => {
const workDir = makeTempDir();
const packedName = "test-hooks-0.0.1.tgz";
const pkgDir = path.join(workDir, "package");
fs.mkdirSync(path.join(pkgDir, "hooks", "one-hook"), { recursive: true });
fs.writeFileSync(
path.join(pkgDir, "package.json"),
JSON.stringify({
name: "@openclaw/test-hooks",
version: "0.0.1",
openclaw: { hooks: ["./hooks/one-hook"] },
}),
"utf-8",
);
fs.writeFileSync(
path.join(pkgDir, "hooks", "one-hook", "HOOK.md"),
[
"---",
"name: one-hook",
"description: One hook",
'metadata: {"openclaw":{"events":["command:new"]}}',
"---",
"",
"# One Hook",
].join("\n"),
"utf-8",
);
fs.writeFileSync(
path.join(pkgDir, "hooks", "one-hook", "handler.ts"),
"export default async () => {};\n",
"utf-8",
);
const packTmpDir = makeTempDir();
const archivePath = await packToArchive({ pkgDir, outDir: packTmpDir, outName: packedName });
return await fsPromises.readFile(archivePath);
};
npmPackHooksBuffer = await makeNpmPackTgz();
});
afterAll(() => {
try {
fs.rmSync(fixtureRoot, { recursive: true, force: true });

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.