fix(core): conditionally expose additional_permissions in shell tool (#23729)

Co-authored-by: Sandy Tao <sandytao520@icloud.com>
This commit is contained in:
Gal Zahavi
2026-03-24 18:46:15 -07:00
committed by GitHub
parent 578d656de9
commit a6c7affedb
9 changed files with 64 additions and 42 deletions
@@ -702,15 +702,6 @@ export class PolicyEngine {
} }
} }
// Sandbox Expansion requests MUST always be confirmed by the user,
// even if the base command is otherwise ALLOWED by the policy engine.
if (
decision === PolicyDecision.ALLOW &&
toolCall.args?.['additional_permissions']
) {
decision = PolicyDecision.ASK_USER;
}
return { return {
decision: this.applyNonInteractiveMode(decision), decision: this.applyNonInteractiveMode(decision),
rule: matchedRule, rule: matchedRule,
@@ -233,13 +233,19 @@ export {
export function getShellDefinition( export function getShellDefinition(
enableInteractiveShell: boolean, enableInteractiveShell: boolean,
enableEfficiency: boolean, enableEfficiency: boolean,
enableToolSandboxing: boolean = false,
): ToolDefinition { ): ToolDefinition {
return { return {
base: getShellDeclaration(enableInteractiveShell, enableEfficiency), base: getShellDeclaration(
enableInteractiveShell,
enableEfficiency,
enableToolSandboxing,
),
overrides: (modelId) => overrides: (modelId) =>
getToolSet(modelId).run_shell_command( getToolSet(modelId).run_shell_command(
enableInteractiveShell, enableInteractiveShell,
enableEfficiency, enableEfficiency,
enableToolSandboxing,
), ),
}; };
} }
@@ -69,7 +69,7 @@ describe('coreTools snapshots for specific models', () => {
{ name: 'list_directory', definition: LS_DEFINITION }, { name: 'list_directory', definition: LS_DEFINITION },
{ {
name: 'run_shell_command', name: 'run_shell_command',
definition: getShellDefinition(true, true), definition: getShellDefinition(true, true, true),
}, },
{ name: 'replace', definition: EDIT_DEFINITION }, { name: 'replace', definition: EDIT_DEFINITION },
{ name: 'google_web_search', definition: WEB_SEARCH_DEFINITION }, { name: 'google_web_search', definition: WEB_SEARCH_DEFINITION },
@@ -81,6 +81,7 @@ export function getCommandDescription(): string {
export function getShellDeclaration( export function getShellDeclaration(
enableInteractiveShell: boolean, enableInteractiveShell: boolean,
enableEfficiency: boolean, enableEfficiency: boolean,
enableToolSandboxing: boolean = false,
): FunctionDeclaration { ): FunctionDeclaration {
return { return {
name: SHELL_TOOL_NAME, name: SHELL_TOOL_NAME,
@@ -110,6 +111,8 @@ export function getShellDeclaration(
description: description:
'Set to true if this command should be run in the background (e.g. for long-running servers or watchers). The command will be started, allowed to run for a brief moment to check for immediate errors, and then moved to the background.', 'Set to true if this command should be run in the background (e.g. for long-running servers or watchers). The command will be started, allowed to run for a brief moment to check for immediate errors, and then moved to the background.',
}, },
...(enableToolSandboxing
? {
[PARAM_ADDITIONAL_PERMISSIONS]: { [PARAM_ADDITIONAL_PERMISSIONS]: {
type: 'object', type: 'object',
description: description:
@@ -139,6 +142,8 @@ export function getShellDeclaration(
}, },
}, },
}, },
}
: {}),
}, },
required: [SHELL_PARAM_COMMAND], required: [SHELL_PARAM_COMMAND],
}, },
@@ -332,8 +332,16 @@ export const DEFAULT_LEGACY_SET: CoreToolSet = {
}, },
}, },
run_shell_command: (enableInteractiveShell, enableEfficiency) => run_shell_command: (
getShellDeclaration(enableInteractiveShell, enableEfficiency), enableInteractiveShell,
enableEfficiency,
enableToolSandboxing,
) =>
getShellDeclaration(
enableInteractiveShell,
enableEfficiency,
enableToolSandboxing,
),
replace: { replace: {
name: EDIT_TOOL_NAME, name: EDIT_TOOL_NAME,
@@ -338,8 +338,16 @@ export const GEMINI_3_SET: CoreToolSet = {
}, },
}, },
run_shell_command: (enableInteractiveShell, enableEfficiency) => run_shell_command: (
getShellDeclaration(enableInteractiveShell, enableEfficiency), enableInteractiveShell,
enableEfficiency,
enableToolSandboxing,
) =>
getShellDeclaration(
enableInteractiveShell,
enableEfficiency,
enableToolSandboxing,
),
replace: { replace: {
name: EDIT_TOOL_NAME, name: EDIT_TOOL_NAME,
@@ -37,6 +37,7 @@ export interface CoreToolSet {
run_shell_command: ( run_shell_command: (
enableInteractiveShell: boolean, enableInteractiveShell: boolean,
enableEfficiency: boolean, enableEfficiency: boolean,
enableToolSandboxing: boolean,
) => FunctionDeclaration; ) => FunctionDeclaration;
replace: FunctionDeclaration; replace: FunctionDeclaration;
google_web_search: FunctionDeclaration; google_web_search: FunctionDeclaration;
+1
View File
@@ -137,6 +137,7 @@ describe('ShellTool', () => {
getShellToolInactivityTimeout: vi.fn().mockReturnValue(1000), getShellToolInactivityTimeout: vi.fn().mockReturnValue(1000),
getEnableInteractiveShell: vi.fn().mockReturnValue(false), getEnableInteractiveShell: vi.fn().mockReturnValue(false),
getEnableShellOutputEfficiency: vi.fn().mockReturnValue(true), getEnableShellOutputEfficiency: vi.fn().mockReturnValue(true),
getSandboxEnabled: vi.fn().mockReturnValue(false),
sanitizationConfig: {}, sanitizationConfig: {},
sandboxManager: new NoopSandboxManager(), sandboxManager: new NoopSandboxManager(),
} as unknown as Config; } as unknown as Config;
+2
View File
@@ -696,6 +696,7 @@ export class ShellTool extends BaseDeclarativeTool<
const definition = getShellDefinition( const definition = getShellDefinition(
context.config.getEnableInteractiveShell(), context.config.getEnableInteractiveShell(),
context.config.getEnableShellOutputEfficiency(), context.config.getEnableShellOutputEfficiency(),
context.config.getSandboxEnabled(),
); );
super( super(
ShellTool.Name, ShellTool.Name,
@@ -745,6 +746,7 @@ export class ShellTool extends BaseDeclarativeTool<
const definition = getShellDefinition( const definition = getShellDefinition(
this.context.config.getEnableInteractiveShell(), this.context.config.getEnableInteractiveShell(),
this.context.config.getEnableShellOutputEfficiency(), this.context.config.getEnableShellOutputEfficiency(),
this.context.config.getSandboxEnabled(),
); );
return resolveToolDeclaration(definition, modelId); return resolveToolDeclaration(definition, modelId);
} }