Files
openclaw/src/acp/approval-classifier.test.ts
2026-03-31 20:49:31 +09:00

125 lines
2.9 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { classifyAcpToolApproval } from "./approval-classifier.js";
function classify(params: {
title: string;
rawInput?: Record<string, unknown>;
meta?: Record<string, unknown>;
cwd?: string;
}) {
return classifyAcpToolApproval({
cwd: params.cwd ?? "/workspace",
toolCall: {
title: params.title,
rawInput: params.rawInput,
_meta: params.meta,
},
});
}
describe("classifyAcpToolApproval", () => {
it("auto-approves scoped readonly reads", () => {
expect(
classify({
title: "read: src/index.ts",
rawInput: { path: "src/index.ts" },
}),
).toEqual({
toolName: "read",
approvalClass: "readonly_scoped",
autoApprove: true,
});
});
it("does not auto-approve reads outside cwd", () => {
expect(
classify({
title: "read: ~/.ssh/id_rsa",
rawInput: { path: "~/.ssh/id_rsa" },
}),
).toEqual({
toolName: "read",
approvalClass: "other",
autoApprove: false,
});
});
it("auto-approves readonly search tools", () => {
expect(
classify({
title: "memory_search: vectors",
rawInput: { name: "memory_search", query: "vectors" },
}),
).toEqual({
toolName: "memory_search",
approvalClass: "readonly_search",
autoApprove: true,
});
});
it("classifies process as exec-capable even for readonly-like actions", () => {
expect(
classify({
title: "process: list",
rawInput: { name: "process", action: "list" },
}),
).toEqual({
toolName: "process",
approvalClass: "exec_capable",
autoApprove: false,
});
});
it("classifies nodes as exec-capable even for list actions", () => {
expect(
classify({
title: "nodes: list",
rawInput: { name: "nodes", action: "list" },
}),
).toEqual({
toolName: "nodes",
approvalClass: "exec_capable",
autoApprove: false,
});
});
it("classifies gateway as control-plane", () => {
expect(
classify({
title: "gateway: status",
rawInput: { name: "gateway", action: "status" },
}),
).toEqual({
toolName: "gateway",
approvalClass: "control_plane",
autoApprove: false,
});
});
it("classifies mutating messaging tools as mutating", () => {
expect(
classify({
title: "message: send",
rawInput: { name: "message", action: "send", message: "hi" },
}),
).toEqual({
toolName: "message",
approvalClass: "mutating",
autoApprove: false,
});
});
it("fails closed on spoofed metadata and title mismatches", () => {
expect(
classify({
title: "exec: uname -a",
rawInput: { name: "search", query: "uname -a" },
}),
).toEqual({
toolName: undefined,
approvalClass: "unknown",
autoApprove: false,
});
});
});