mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-09 08:11:09 +00:00
125 lines
2.9 KiB
TypeScript
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,
|
|
});
|
|
});
|
|
});
|