diff --git a/.changeset/auto-unanalyzable-command-allow.md b/.changeset/auto-unanalyzable-command-allow.md new file mode 100644 index 0000000000..32b3d15684 --- /dev/null +++ b/.changeset/auto-unanalyzable-command-allow.md @@ -0,0 +1,5 @@ +--- +"@moonshot-ai/kimi-code": patch +--- + +Stop blocking dangerous commands and commands that cannot be statically analyzed in auto permission mode. diff --git a/docs/en/configuration/config-files.md b/docs/en/configuration/config-files.md index 15119726b2..abbb4f4655 100644 --- a/docs/en/configuration/config-files.md +++ b/docs/en/configuration/config-files.md @@ -479,7 +479,7 @@ api_key = "sk-xxx" `permission` sets permission rules that are automatically loaded when a session starts, controlling whether the Agent needs user confirmation before calling a tool. Rules are written as a `[[permission.rules]]` array of tables, matched in order; the first matching rule takes effect. -You can also set `dangerous_command_guard = false` under `[permission]` to turn off the built-in dangerous-command policy entirely (no dangerous-command ask or auto-mode deny); the default is `true`. An environment variable `KIMI_CODE_DANGEROUS_COMMAND_GUARD=false` overrides the file setting and restores the behavior before the policy was introduced. Use this switch only for environments that already gate commands outside the agent. +You can also set `dangerous_command_guard = false` under `[permission]` to turn off the built-in dangerous-command policy entirely (no dangerous-command confirmation in Always Ask and Ask When Needed mode; the policy is never active in Never Ask mode); the default is `true`. An environment variable `KIMI_CODE_DANGEROUS_COMMAND_GUARD=false` overrides the file setting and restores the behavior before the policy was introduced. Use this switch only for environments that already gate commands outside the agent. | Field | Type | Required | Description | | --- | --- | --- | --- | diff --git a/docs/en/guides/interaction.md b/docs/en/guides/interaction.md index 71329bc1bf..1f6bf581b9 100644 --- a/docs/en/guides/interaction.md +++ b/docs/en/guides/interaction.md @@ -66,7 +66,7 @@ Approvals are not triggered for regular tool calls in Ask When Needed mode, nor **Ask When Needed mode** (formerly YOLO), toggled with `/ask-when-needed`, auto-approves regular tool calls, making it suitable for batch tasks you know are safe. It still asks before sensitive actions — accessing sensitive files such as `.env` or SSH keys, running dangerous commands such as `shutdown` or `rm -rf`, or exiting Plan mode — and the agent can still ask you questions. -**Never Ask mode** (formerly Auto), toggled with `/never-ask`, is the fully unattended mode: every tool approval is handled automatically, including sensitive files and plan exits, and the agent never asks you questions — it decides everything on its own. The only exception is the built-in dangerous-command guard: commands such as `shutdown`, `reboot`, or `rm -rf` are always blocked in Never Ask mode, and always require your confirmation in Always Ask and Ask When Needed mode. +**Never Ask mode** (formerly Auto), toggled with `/never-ask`, is the fully unattended mode: every tool approval is handled automatically, including sensitive files and plan exits, and the agent never asks you questions — it decides everything on its own. The built-in dangerous-command guard asks for your confirmation before commands such as `shutdown`, `reboot`, or `rm -rf` in Always Ask and Ask When Needed mode; in Never Ask mode these commands run without interruption. ## Mode switching diff --git a/docs/zh/configuration/config-files.md b/docs/zh/configuration/config-files.md index bc880e6112..2f066b0517 100644 --- a/docs/zh/configuration/config-files.md +++ b/docs/zh/configuration/config-files.md @@ -478,7 +478,7 @@ api_key = "sk-xxx" `permission` 设置会话启动时自动加载的权限规则,控制 Agent 调用工具时是否需要用户确认。规则用 `[[permission.rules]]` 数组表写出,按顺序匹配,第一条命中即生效。 -也可以在 `[permission]` 下设置 `dangerous_command_guard = false` 完全关闭内置危险命令策略(不再触发危险命令审批或 auto 模式拒绝),默认 `true`。环境变量 `KIMI_CODE_DANGEROUS_COMMAND_GUARD=false` 会覆盖文件设置并恢复策略引入前的行为。此开关只适用于已经在 Agent 之外统一命令限权的环境。 +也可以在 `[permission]` 下设置 `dangerous_command_guard = false` 完全关闭内置危险命令策略("Always Ask" 和 "Ask When Needed" 模式下不再触发危险命令审批;"Never Ask" 模式本就不启用该策略),默认 `true`。环境变量 `KIMI_CODE_DANGEROUS_COMMAND_GUARD=false` 会覆盖文件设置并恢复策略引入前的行为。此开关只适用于已经在 Agent 之外统一命令限权的环境。 | 字段 | 类型 | 必填 | 说明 | | --- | --- | --- | --- | diff --git a/docs/zh/guides/interaction.md b/docs/zh/guides/interaction.md index ceae4be598..4d577d9c54 100644 --- a/docs/zh/guides/interaction.md +++ b/docs/zh/guides/interaction.md @@ -66,7 +66,7 @@ Agent 调用会产生副作用的工具(修改文件、执行命令等)时 **"Ask When Needed"**(必要时询问,原 YOLO)用 `/ask-when-needed` 切换,自动批准普通工具调用,适合已知安全的批处理任务。敏感操作仍会询问——例如访问 `.env`、SSH 私钥等敏感文件、执行 `shutdown`、`rm -rf` 这类危险命令,或退出 Plan 模式——Agent 也仍可能向你提问。 -**"Never Ask"**(完全自动,原 Auto)用 `/never-ask` 切换,是完全无人值守模式:所有工具审批自动处理,包括敏感文件和计划退出,且 Agent 不会向你提问,完全由它自己做决定。唯一的例外是内置的危险命令拦截:`shutdown`、`reboot`、`rm -rf` 这类命令在 "Never Ask" 模式下会被直接拒绝,在 "Always Ask" 和 "Ask When Needed" 模式下必须经你确认。 +**"Never Ask"**(完全自动,原 Auto)用 `/never-ask` 切换,是完全无人值守模式:所有工具审批自动处理,包括敏感文件和计划退出,且 Agent 不会向你提问,完全由它自己做决定。内置的危险命令拦截会在 "Always Ask" 和 "Ask When Needed" 模式下要求你确认 `shutdown`、`reboot`、`rm -rf` 这类命令;在 "Never Ask" 模式下这些命令直接执行,不再拦截。 ## 模式切换 diff --git a/packages/agent-core-v2/src/agent/permissionPolicy/policies/dangerous-command-ask.ts b/packages/agent-core-v2/src/agent/permissionPolicy/policies/dangerous-command-ask.ts index f7c2a561ef..6bf4cd2af9 100644 --- a/packages/agent-core-v2/src/agent/permissionPolicy/policies/dangerous-command-ask.ts +++ b/packages/agent-core-v2/src/agent/permissionPolicy/policies/dangerous-command-ask.ts @@ -119,6 +119,7 @@ export class DangerousCommandAskPermissionPolicyService implements PermissionPol evaluate(context: ResolvedToolExecutionHookContext): PermissionPolicyResult | undefined { if (!isDangerousCommandGuardEnabled(this.config)) return undefined; + if (this.modeService.mode === 'auto') return undefined; if (context.toolCall.name !== 'Bash') return undefined; const command = bashCommandText(context.args); const verdict = @@ -128,25 +129,9 @@ export class DangerousCommandAskPermissionPolicyService implements PermissionPol this.bashParser.parse(source, PARSE_OPTIONS), ); if (verdict === undefined) return undefined; - const auto = this.modeService.mode === 'auto'; if (verdict.kind === 'dangerous') { - if (auto) { - return { - kind: 'deny', - reason: { dangerous_command: verdict.command }, - message: `Bash command '${verdict.command}' is blocked in auto permission mode because it is considered dangerous. Ask the user to switch permission mode or run it themselves.`, - }; - } return { kind: 'ask', reason: { dangerous_command: verdict.command } }; } - if (auto) { - return { - kind: 'deny', - reason: { unanalyzable_command: true }, - message: - 'This Bash command could not be analyzed and is blocked in auto permission mode. Rewrite it with a literal command name and arguments, or ask the user to run it themselves.', - }; - } return { kind: 'ask', reason: { unanalyzable_command: true } }; } } diff --git a/packages/agent-core-v2/test/agent/permissionPolicy/permissionPolicyService.test.ts b/packages/agent-core-v2/test/agent/permissionPolicy/permissionPolicyService.test.ts index 056b46eda8..1db90dcc59 100644 --- a/packages/agent-core-v2/test/agent/permissionPolicy/permissionPolicyService.test.ts +++ b/packages/agent-core-v2/test/agent/permissionPolicy/permissionPolicyService.test.ts @@ -236,19 +236,19 @@ describe('AgentPermissionPolicyService chain', () => { ); it.each([ - ['shutdown -h now', 'shutdown'], - ['reboot', 'reboot'], - ['rm -rf /tmp/build', 'rm -rf'], - ['dd if=/dev/zero of=/dev/sda bs=1M', 'dd'], - ] as const)('denies `%s` in auto mode', async (command, matched) => { + 'shutdown -h now', + 'reboot', + 'rm -rf /tmp/build', + 'dd if=/dev/zero of=/dev/sda bs=1M', + ])('approves `%s` in auto mode', async (command) => { mode = 'auto'; await expect(evaluate({ toolName: 'Bash', args: { command, timeout: 60 }, })).resolves.toMatchObject({ - policyName: 'dangerous-command-ask', - result: { kind: 'deny', reason: { dangerous_command: matched } }, + policyName: 'auto-mode-approve', + result: { kind: 'approve' }, }); }); @@ -370,7 +370,7 @@ describe('AgentPermissionPolicyService chain', () => { }); it.each(['$CMD --force', 'bash -c "echo $HOME"', 'env $FLAGS'])( - 'denies unanalyzable command `%s` in auto mode', + 'approves unanalyzable command `%s` in auto mode', async (command) => { mode = 'auto'; @@ -378,8 +378,8 @@ describe('AgentPermissionPolicyService chain', () => { toolName: 'Bash', args: { command, timeout: 60 }, })).resolves.toMatchObject({ - policyName: 'dangerous-command-ask', - result: { kind: 'deny', reason: { unanalyzable_command: true } }, + policyName: 'auto-mode-approve', + result: { kind: 'approve' }, }); }, );