mirror of
https://github.com/moltbot/moltbot.git
synced 2026-04-24 07:01:49 +00:00
ACP: fail closed on conflicting tool identity hints (#46817)
* ACP: fail closed on conflicting tool identity hints * ACP: restore rawInput fallback for safe tool resolution * ACP tests: cover rawInput-only safe tool approval
This commit is contained in:
@@ -44,6 +44,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Docs/Mintlify: fix MDX marker syntax on Perplexity, Model Providers, Moonshot, and exec approvals pages so local docs preview no longer breaks rendering or leaves stale pages unpublished. (#46695) Thanks @velvet-shark.
|
||||
- Email/webhook wrapping: sanitize sender and subject metadata before external-content wrapping so metadata fields cannot break the wrapper structure. Thanks @vincentkoc.
|
||||
- Node/startup: remove leftover debug `console.log("node host PATH: ...")` that printed the resolved PATH on every `openclaw node run` invocation. (#46411)
|
||||
- ACP/approvals: use canonical tool identity for prompting decisions and fail closed when conflicting tool identity hints are present. Thanks @vincentkoc.
|
||||
- Telegram/message send: forward `--force-document` through the `sendPayload` path as well as `sendMedia`, so Telegram payload sends with `channelData` keep uploading images as documents instead of silently falling back to compressed photo sends. (#47119) Thanks @thepagent.
|
||||
- Telegram/message chunking: preserve spaces, paragraph separators, and word boundaries when HTML overflow rechunking splits formatted replies. (#47274)
|
||||
|
||||
|
||||
@@ -366,6 +366,47 @@ describe("resolvePermissionRequest", () => {
|
||||
expect(prompt).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("auto-approves safe tools when rawInput is the only identity hint", async () => {
|
||||
const prompt = vi.fn(async () => true);
|
||||
const res = await resolvePermissionRequest(
|
||||
makePermissionRequest({
|
||||
toolCall: {
|
||||
toolCallId: "tool-raw-only",
|
||||
title: "Searching files",
|
||||
status: "pending",
|
||||
rawInput: {
|
||||
name: "search",
|
||||
query: "foo",
|
||||
},
|
||||
},
|
||||
}),
|
||||
{ prompt, log: () => {} },
|
||||
);
|
||||
expect(res).toEqual({ outcome: { outcome: "selected", optionId: "allow" } });
|
||||
expect(prompt).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("prompts when raw input spoofs a safe tool name for a dangerous title", async () => {
|
||||
const prompt = vi.fn(async () => false);
|
||||
const res = await resolvePermissionRequest(
|
||||
makePermissionRequest({
|
||||
toolCall: {
|
||||
toolCallId: "tool-exec-spoof",
|
||||
title: "exec: cat /etc/passwd",
|
||||
status: "pending",
|
||||
rawInput: {
|
||||
command: "cat /etc/passwd",
|
||||
name: "search",
|
||||
},
|
||||
},
|
||||
}),
|
||||
{ prompt, log: () => {} },
|
||||
);
|
||||
expect(prompt).toHaveBeenCalledTimes(1);
|
||||
expect(prompt).toHaveBeenCalledWith(undefined, "exec: cat /etc/passwd");
|
||||
expect(res).toEqual({ outcome: { outcome: "selected", optionId: "reject" } });
|
||||
});
|
||||
|
||||
it("prompts for read outside cwd scope", async () => {
|
||||
const prompt = vi.fn(async () => false);
|
||||
const res = await resolvePermissionRequest(
|
||||
|
||||
@@ -104,7 +104,22 @@ function resolveToolNameForPermission(params: RequestPermissionRequest): string
|
||||
const fromMeta = readFirstStringValue(toolMeta, ["toolName", "tool_name", "name"]);
|
||||
const fromRawInput = readFirstStringValue(rawInput, ["tool", "toolName", "tool_name", "name"]);
|
||||
const fromTitle = parseToolNameFromTitle(toolCall?.title);
|
||||
return normalizeToolName(fromMeta ?? fromRawInput ?? fromTitle ?? "");
|
||||
const metaName = fromMeta ? normalizeToolName(fromMeta) : undefined;
|
||||
const rawInputName = fromRawInput ? normalizeToolName(fromRawInput) : undefined;
|
||||
const titleName = fromTitle;
|
||||
if ((fromMeta && !metaName) || (fromRawInput && !rawInputName)) {
|
||||
return undefined;
|
||||
}
|
||||
if (metaName && titleName && metaName !== titleName) {
|
||||
return undefined;
|
||||
}
|
||||
if (rawInputName && metaName && rawInputName !== metaName) {
|
||||
return undefined;
|
||||
}
|
||||
if (rawInputName && titleName && rawInputName !== titleName) {
|
||||
return undefined;
|
||||
}
|
||||
return metaName ?? titleName ?? rawInputName;
|
||||
}
|
||||
|
||||
function extractPathFromToolTitle(
|
||||
|
||||
Reference in New Issue
Block a user