diff --git a/packages/core/src/policy/config.ts b/packages/core/src/policy/config.ts index eb53196c92..c54e7f1667 100644 --- a/packages/core/src/policy/config.ts +++ b/packages/core/src/policy/config.ts @@ -30,7 +30,10 @@ import { type MessageBus } from '../confirmation-bus/message-bus.js'; import { coreEvents } from '../utils/events.js'; import { debugLogger } from '../utils/debugLogger.js'; import { SHELL_TOOL_NAMES } from '../utils/shell-utils.js'; -import { SHELL_TOOL_NAME, SENSITIVE_TOOLS } from '../tools/tool-names.js'; +import { + SHELL_TOOL_NAME, + TOOLS_REQUIRING_NARROWING, +} from '../tools/tool-names.js'; import { isNodeError } from '../utils/errors.js'; import { MCP_TOOL_PREFIX } from '../tools/mcp-tool.js'; @@ -560,7 +563,7 @@ export function createPolicyUpdater( : WORKSPACE_POLICY_TIER; const priority = tier + getAlwaysAllowPriorityFraction() / 1000; - if (SENSITIVE_TOOLS.has(toolName) && !message.commandPrefix) { + if (TOOLS_REQUIRING_NARROWING.has(toolName) && !message.commandPrefix) { debugLogger.warn( `Attempted to update policy for sensitive tool '${toolName}' without a commandPrefix. Skipping.`, ); @@ -600,7 +603,7 @@ export function createPolicyUpdater( : WORKSPACE_POLICY_TIER; const priority = tier + getAlwaysAllowPriorityFraction() / 1000; - if (SENSITIVE_TOOLS.has(toolName) && !message.argsPattern) { + if (TOOLS_REQUIRING_NARROWING.has(toolName) && !message.argsPattern) { debugLogger.warn( `Attempted to update policy for sensitive tool '${toolName}' without an argsPattern. Skipping.`, ); diff --git a/packages/core/src/policy/policies/write.toml b/packages/core/src/policy/policies/write.toml index c24f6dfee3..527ac6f059 100644 --- a/packages/core/src/policy/policies/write.toml +++ b/packages/core/src/policy/policies/write.toml @@ -74,6 +74,12 @@ type = "in-process" name = "allowed-path" required_context = ["environment"] +[[rule]] +toolName = "web_fetch" +decision = "allow" +priority = 15 +modes = ["autoEdit"] + [[rule]] toolName = "web_fetch" decision = "ask_user" diff --git a/packages/core/src/tools/tool-names.ts b/packages/core/src/tools/tool-names.ts index e818881662..801bd9430c 100644 --- a/packages/core/src/tools/tool-names.ts +++ b/packages/core/src/tools/tool-names.ts @@ -155,14 +155,13 @@ export const LS_TOOL_NAME_LEGACY = 'list_directory'; // Just to be safe if anyth export const EDIT_TOOL_NAMES = new Set([EDIT_TOOL_NAME, WRITE_FILE_TOOL_NAME]); /** - * Tools that can access local files or remote resources and should be - * treated with extra caution when updating policies. + * Tools that require mandatory argument narrowing (e.g., file paths, command prefixes) + * when granting persistent or session-wide approval. */ -export const SENSITIVE_TOOLS = new Set([ +export const TOOLS_REQUIRING_NARROWING = new Set([ GLOB_TOOL_NAME, GREP_TOOL_NAME, READ_MANY_FILES_TOOL_NAME, - WEB_FETCH_TOOL_NAME, READ_FILE_TOOL_NAME, LS_TOOL_NAME, WRITE_FILE_TOOL_NAME, diff --git a/packages/core/src/tools/web-fetch.test.ts b/packages/core/src/tools/web-fetch.test.ts index 2b65a24930..f52ff214f4 100644 --- a/packages/core/src/tools/web-fetch.test.ts +++ b/packages/core/src/tools/web-fetch.test.ts @@ -752,6 +752,24 @@ describe('WebFetchTool', () => { }); }); + describe('getPolicyUpdateOptions', () => { + it('should return empty object for any outcome to allow global approval', () => { + const tool = new WebFetchTool(mockConfig, bus); + const invocation = tool.build({ prompt: 'fetch https://example.com' }); + + expect( + invocation.getPolicyUpdateOptions!( + ToolConfirmationOutcome.ProceedAlways, + ), + ).toEqual({}); + expect( + invocation.getPolicyUpdateOptions!( + ToolConfirmationOutcome.ProceedAlwaysAndSave, + ), + ).toEqual({}); + }); + }); + describe('Message Bus Integration', () => { let policyEngine: PolicyEngine; let messageBus: MessageBus; diff --git a/packages/core/src/tools/web-fetch.ts b/packages/core/src/tools/web-fetch.ts index 5240da9451..0ec19c8182 100644 --- a/packages/core/src/tools/web-fetch.ts +++ b/packages/core/src/tools/web-fetch.ts @@ -5,16 +5,15 @@ */ import { + type ToolConfirmationOutcome, BaseDeclarativeTool, BaseToolInvocation, Kind, type ToolCallConfirmationDetails, type ToolInvocation, type ToolResult, - type ToolConfirmationOutcome, type PolicyUpdateOptions, } from './tools.js'; -import { buildParamArgsPattern } from '../policy/utils.js'; import type { MessageBus } from '../confirmation-bus/message-bus.js'; import { ToolErrorType } from './tool-error.js'; import { getErrorMessage } from '../utils/errors.js'; @@ -509,16 +508,7 @@ ${aggregatedContent} override getPolicyUpdateOptions( _outcome: ToolConfirmationOutcome, ): PolicyUpdateOptions | undefined { - if (this.params.url) { - return { - argsPattern: buildParamArgsPattern('url', this.params.url), - }; - } else if (this.params.prompt) { - return { - argsPattern: buildParamArgsPattern('prompt', this.params.prompt), - }; - } - return undefined; + return {}; } protected override async getConfirmationDetails(