diff --git a/src/agents/tool-policy-match.ts b/src/agents/tool-policy-match.ts index 01108246b4e..d0b91c817a9 100644 --- a/src/agents/tool-policy-match.ts +++ b/src/agents/tool-policy-match.ts @@ -16,9 +16,6 @@ function makeToolPolicyMatcher(policy: SandboxToolPolicy) { if (matchesAnyGlobPattern(normalized, deny)) { return false; } - if (normalized === "apply_patch" && matchesAnyGlobPattern("write", deny)) { - return false; - } if (allow.length === 0) { return true; } diff --git a/src/agents/tool-policy.test.ts b/src/agents/tool-policy.test.ts index 98b1d756e87..912bad8829b 100644 --- a/src/agents/tool-policy.test.ts +++ b/src/agents/tool-policy.test.ts @@ -3,6 +3,7 @@ import type { OpenClawConfig } from "../config/config.js"; import { DEFAULT_GATEWAY_HTTP_TOOL_DENY } from "../security/dangerous-tools.js"; import { isToolAllowed, resolveSandboxToolPolicyForAgent } from "./sandbox/tool-policy.js"; import type { SandboxToolPolicy } from "./sandbox/types.js"; +import { isToolAllowedByPolicyName } from "./tool-policy-match.js"; import { TOOL_POLICY_CONFORMANCE } from "./tool-policy.conformance.js"; import { applyOwnerOnlyToolPolicy, @@ -264,3 +265,23 @@ describe("resolveSandboxToolPolicyForAgent", () => { expect(resolved.deny).toEqual(["image"]); }); }); + +describe("isToolAllowedByPolicyName — apply_patch / write deny decoupling (#76749)", () => { + it("does not deny apply_patch when write is denied", () => { + expect(isToolAllowedByPolicyName("apply_patch", { deny: ["write"] })).toBe(true); + }); + + it("still denies apply_patch when apply_patch is explicitly denied", () => { + expect(isToolAllowedByPolicyName("apply_patch", { deny: ["apply_patch"] })).toBe(false); + }); + + it("still allows apply_patch via write in the allow list", () => { + expect(isToolAllowedByPolicyName("apply_patch", { allow: ["write"], deny: [] })).toBe(true); + }); + + it("denies apply_patch when both write and apply_patch are denied", () => { + expect(isToolAllowedByPolicyName("apply_patch", { deny: ["write", "apply_patch"] })).toBe( + false, + ); + }); +});