MCPcopy
hub / github.com/codeaashu/claude-code / bashToolHasPermission

Function bashToolHasPermission

src/tools/BashTool/bashPermissions.ts:1663–2557  ·  view source on GitHub ↗
(
  input: z.infer<typeof BashTool.inputSchema>,
  context: ToolUseContext,
  getCommandSubcommandPrefixFn = getCommandSubcommandPrefix,
)

Source from the content-addressed store, hash-verified

1661 * The main implementation to check if we need to ask for user permission to call BashTool with a given input
1662 */
1663export async function bashToolHasPermission(
1664 input: z.infer<typeof BashTool.inputSchema>,
1665 context: ToolUseContext,
1666 getCommandSubcommandPrefixFn = getCommandSubcommandPrefix,
1667): Promise<PermissionResult> {
1668 let appState = context.getAppState()
1669
1670 // 0. AST-based security parse. This replaces both tryParseShellCommand
1671 // (the shell-quote pre-check) and the bashCommandIsSafe misparsing gate.
1672 // tree-sitter produces either a clean SimpleCommand[] (quotes resolved,
1673 // no hidden substitutions) or 'too-complex' — which is exactly the signal
1674 // we need to decide whether splitCommand's output can be trusted.
1675 //
1676 // When tree-sitter WASM is unavailable OR the injection check is disabled
1677 // via env var, we fall back to the old path (legacy gate at ~1370 runs).
1678 const injectionCheckDisabled = isEnvTruthy(
1679 process.env.CLAUDE_CODE_DISABLE_COMMAND_INJECTION_CHECK,
1680 )
1681 // GrowthBook killswitch for shadow mode — when off, skip the native parse
1682 // entirely. Computed once; feature() must stay inline in the ternary below.
1683 const shadowEnabled = feature('TREE_SITTER_BASH_SHADOW')
1684 ? getFeatureValue_CACHED_MAY_BE_STALE('tengu_birch_trellis', true)
1685 : false
1686 // Parse once here; the resulting AST feeds both parseForSecurityFromAst
1687 // and bashToolCheckCommandOperatorPermissions.
1688 let astRoot = injectionCheckDisabled
1689 ? null
1690 : feature('TREE_SITTER_BASH_SHADOW') && !shadowEnabled
1691 ? null
1692 : await parseCommandRaw(input.command)
1693 let astResult: ParseForSecurityResult = astRoot
1694 ? parseForSecurityFromAst(input.command, astRoot)
1695 : { kind: 'parse-unavailable' }
1696 let astSubcommands: string[] | null = null
1697 let astRedirects: Redirect[] | undefined
1698 let astCommands: SimpleCommand[] | undefined
1699 let shadowLegacySubs: string[] | undefined
1700
1701 // Shadow-test tree-sitter: record its verdict, then force parse-unavailable
1702 // so the legacy path stays authoritative. parseCommand stays gated on
1703 // TREE_SITTER_BASH (not SHADOW) so legacy internals remain pure regex.
1704 // One event per bash call captures both divergence AND unavailability
1705 // reasons; module-load failures are separately covered by the
1706 // session-scoped tengu_tree_sitter_load event.
1707 if (feature('TREE_SITTER_BASH_SHADOW')) {
1708 const available = astResult.kind !== 'parse-unavailable'
1709 let tooComplex = false
1710 let semanticFail = false
1711 let subsDiffer = false
1712 if (available) {
1713 tooComplex = astResult.kind === 'too-complex'
1714 semanticFail =
1715 astResult.kind === 'simple' && !checkSemantics(astResult.commands).ok
1716 const tsSubs =
1717 astResult.kind === 'simple'
1718 ? astResult.commands.map(c => c.text)
1719 : undefined
1720 const legacySubs = splitCommand(input.command)

Callers 1

checkPermissionsFunction · 0.85

Calls 15

isEnvTruthyFunction · 0.85
featureFunction · 0.85
parseCommandRawFunction · 0.85
parseForSecurityFromAstFunction · 0.85
checkSemanticsFunction · 0.85
logEventFunction · 0.85
checkEarlyExitDenyFunction · 0.85
nodeTypeIdFunction · 0.85
checkSemanticsDenyFunction · 0.85
logForDebuggingFunction · 0.85

Tested by

no test coverage detected