fix(security): harden npm plugin and hook install integrity flow

This commit is contained in:
Peter Steinberger
2026-02-19 15:10:57 +01:00
parent 2777d8ad93
commit 5dc50b8a3f
23 changed files with 1047 additions and 183 deletions

View File

@@ -253,7 +253,16 @@ describe("installHooksFromNpmSpec", () => {
fs.writeFileSync(path.join(packTmpDir, packedName), npmPackHooksBuffer);
return {
code: 0,
stdout: `${packedName}\n`,
stdout: JSON.stringify([
{
id: "@openclaw/test-hooks@0.0.1",
name: "@openclaw/test-hooks",
version: "0.0.1",
filename: packedName,
integrity: "sha512-hook-test",
shasum: "hookshasum",
},
]),
stderr: "",
signal: null,
killed: false,
@@ -274,6 +283,8 @@ describe("installHooksFromNpmSpec", () => {
return;
}
expect(result.hookPackId).toBe("test-hooks");
expect(result.npmResolution?.resolvedSpec).toBe("@openclaw/test-hooks@0.0.1");
expect(result.npmResolution?.integrity).toBe("sha512-hook-test");
expect(fs.existsSync(path.join(result.targetDir, "hooks", "one-hook", "HOOK.md"))).toBe(true);
expectSingleNpmPackIgnoreScriptsCall({
@@ -293,6 +304,46 @@ describe("installHooksFromNpmSpec", () => {
}
expect(result.error).toContain("unsupported npm spec");
});
it("aborts when integrity drift callback rejects the fetched artifact", async () => {
const run = vi.mocked(runCommandWithTimeout);
run.mockResolvedValue({
code: 0,
stdout: JSON.stringify([
{
id: "@openclaw/test-hooks@0.0.1",
name: "@openclaw/test-hooks",
version: "0.0.1",
filename: "test-hooks-0.0.1.tgz",
integrity: "sha512-new",
shasum: "newshasum",
},
]),
stderr: "",
signal: null,
killed: false,
termination: "exit",
});
const onIntegrityDrift = vi.fn(async () => false);
const result = await installHooksFromNpmSpec({
spec: "@openclaw/test-hooks@0.0.1",
expectedIntegrity: "sha512-old",
onIntegrityDrift,
});
expect(onIntegrityDrift).toHaveBeenCalledWith(
expect.objectContaining({
expectedIntegrity: "sha512-old",
actualIntegrity: "sha512-new",
}),
);
expect(result.ok).toBe(false);
if (result.ok) {
return;
}
expect(result.error).toContain("integrity drift");
});
});
describe("gmail watcher", () => {