fix(core): prevent YOLO mode from being downgraded (#25341)

This commit is contained in:
Gal Zahavi
2026-04-14 23:27:36 -07:00
committed by GitHub
parent 06e7621b26
commit 366f9e4766
3 changed files with 45 additions and 0 deletions

View File

@@ -1762,6 +1762,39 @@ describe('PolicyEngine', () => {
});
describe('shell command parsing failure', () => {
it('should return ALLOW in YOLO mode for dangerous commands due to heuristics override', async () => {
// Create an engine with YOLO mode and a sandbox manager that flags a command as dangerous
const rules: PolicyRule[] = [
{
toolName: '*',
decision: PolicyDecision.ALLOW,
priority: 999,
modes: [ApprovalMode.YOLO],
},
];
const mockSandboxManager = new NoopSandboxManager();
mockSandboxManager.isDangerousCommand = vi.fn().mockReturnValue(true);
mockSandboxManager.isKnownSafeCommand = vi.fn().mockReturnValue(false);
engine = new PolicyEngine({
rules,
approvalMode: ApprovalMode.YOLO,
sandboxManager: mockSandboxManager,
});
const result = await engine.check(
{
name: 'run_shell_command',
args: { command: 'powershell echo "dangerous"' },
},
undefined,
);
// Even though the command is flagged as dangerous, YOLO mode should preserve the ALLOW decision
expect(result.decision).toBe(PolicyDecision.ALLOW);
});
it('should return ALLOW in YOLO mode even if shell command parsing fails', async () => {
const { splitCommands } = await import('../utils/shell-utils.js');
const rules: PolicyRule[] = [

View File

@@ -312,6 +312,13 @@ export class PolicyEngine {
const parsedArgs = parsedObjArgs.map(extractStringFromParseEntry);
if (this.sandboxManager.isDangerousCommand(parsedArgs)) {
if (this.approvalMode === ApprovalMode.YOLO) {
debugLogger.debug(
`[PolicyEngine.check] Command evaluated as dangerous, but YOLO mode is active. Preserving decision: ${command}`,
);
return decision;
}
debugLogger.debug(
`[PolicyEngine.check] Command evaluated as dangerous, forcing ASK_USER: ${command}`,
);

View File

@@ -45,6 +45,7 @@ import {
} from '../utils/shell-utils.js';
import { SHELL_TOOL_NAME } from './tool-names.js';
import { PARAM_ADDITIONAL_PERMISSIONS } from './definitions/base-declarations.js';
import { ApprovalMode } from '../policy/types.js';
import type { MessageBus } from '../confirmation-bus/message-bus.js';
import { getShellDefinition } from './definitions/coreTools.js';
import { resolveToolDeclaration } from './definitions/resolver.js';
@@ -249,6 +250,10 @@ export class ShellToolInvocation extends BaseToolInvocation<
abortSignal: AbortSignal,
forcedDecision?: ForcedToolDecision,
): Promise<ToolCallConfirmationDetails | false> {
if (this.context.config.getApprovalMode() === ApprovalMode.YOLO) {
return super.shouldConfirmExecute(abortSignal, forcedDecision);
}
if (this.params[PARAM_ADDITIONAL_PERMISSIONS]) {
return this.getConfirmationDetails(abortSignal);
}