( input: z.infer<typeof BashTool.inputSchema>, toolPermissionContext: ToolPermissionContext, commandPrefixResult: CommandPrefixResult | null | undefined, compoundCommandHasCd?: boolean, astParseSucceeded?: boolean, )
| 1181 | * Processes an individual subcommand and applies prefix checks & suggestions |
| 1182 | */ |
| 1183 | export async function checkCommandAndSuggestRules( |
| 1184 | input: z.infer<typeof BashTool.inputSchema>, |
| 1185 | toolPermissionContext: ToolPermissionContext, |
| 1186 | commandPrefixResult: CommandPrefixResult | null | undefined, |
| 1187 | compoundCommandHasCd?: boolean, |
| 1188 | astParseSucceeded?: boolean, |
| 1189 | ): Promise<PermissionResult> { |
| 1190 | // 1. Check exact match first |
| 1191 | const exactMatchResult = bashToolCheckExactMatchPermission( |
| 1192 | input, |
| 1193 | toolPermissionContext, |
| 1194 | ) |
| 1195 | if (exactMatchResult.behavior !== 'passthrough') { |
| 1196 | return exactMatchResult |
| 1197 | } |
| 1198 | |
| 1199 | // 2. Check the command prefix |
| 1200 | const permissionResult = bashToolCheckPermission( |
| 1201 | input, |
| 1202 | toolPermissionContext, |
| 1203 | compoundCommandHasCd, |
| 1204 | ) |
| 1205 | // 2a. Deny/ask if command was explictly denied/asked |
| 1206 | if ( |
| 1207 | permissionResult.behavior === 'deny' || |
| 1208 | permissionResult.behavior === 'ask' |
| 1209 | ) { |
| 1210 | return permissionResult |
| 1211 | } |
| 1212 | |
| 1213 | // 3. Ask for permission if command injection is detected. Skip when the |
| 1214 | // AST parse already succeeded — tree-sitter has verified there are no |
| 1215 | // hidden substitutions or structural tricks, so the legacy regex-based |
| 1216 | // validators (backslash-escaped operators, etc.) would only add FPs. |
| 1217 | if ( |
| 1218 | !astParseSucceeded && |
| 1219 | !isEnvTruthy(process.env.CLAUDE_CODE_DISABLE_COMMAND_INJECTION_CHECK) |
| 1220 | ) { |
| 1221 | const safetyResult = await bashCommandIsSafeAsync(input.command) |
| 1222 | |
| 1223 | if (safetyResult.behavior !== 'passthrough') { |
| 1224 | const decisionReason: PermissionDecisionReason = { |
| 1225 | type: 'other' as const, |
| 1226 | reason: |
| 1227 | safetyResult.behavior === 'ask' && safetyResult.message |
| 1228 | ? safetyResult.message |
| 1229 | : 'This command contains patterns that could pose security risks and requires approval', |
| 1230 | } |
| 1231 | |
| 1232 | return { |
| 1233 | behavior: 'ask', |
| 1234 | message: createPermissionRequestMessage(BashTool.name, decisionReason), |
| 1235 | decisionReason, |
| 1236 | suggestions: [], // Don't suggest saving a potentially dangerous command |
| 1237 | } |
| 1238 | } |
| 1239 | } |
| 1240 |
no test coverage detected