Skip to main content

TREE_SITTER_BASH — Bash AST 解析

Feature Flag: FEATURE_TREE_SITTER_BASH=1 实现状态:完整可用(纯 TypeScript 实现,~7000+ 行) 引用数:3

一、功能概述

TREE_SITTER_BASH 启用一个完整的 Bash AST 解析器,用于安全验证 Bash 命令。它用完整的树遍历安全分析器取代了旧的基于正则表达式的 shell-quote 解析器。关键属性是 fail-closed:任何无法识别的内容都被归类为 too-complex 并需要用户批准。

关联 Feature

Feature说明
TREE_SITTER_BASH激活用于权限检查的 AST 解析器
TREE_SITTER_BASH_SHADOWShadow/观测模式:运行解析器但丢弃结果,仅记录遥测

二、安全架构

2.1 Fail-Closed 设计

核心设计使用 allowlist 遍历模式:
  • walkArgument() 只处理已知安全的节点类型(wordnumberraw_stringstringconcatenationarithmetic_expansionsimple_expansion
  • 任何未知节点类型 → tooComplex() → 需要用户批准
  • 解析器加载但失败(超时/节点预算/panic)→ 返回 PARSE_ABORTED 符号(区别于”模块未加载”)

2.2 解析结果

parseForSecurity(cmd) 返回
  { kind: 'simple', commands: SimpleCommand[] }     // 可静态分析
  { kind: 'too-complex', reason, nodeType }          // 需要用户批准
  { kind: 'parse-unavailable' }                      // 解析器未加载

2.3 安全检查层次

parseForSecurity(cmd)


parseCommandRaw(cmd) → AST root node


预检查:控制字符、Unicode 空白、反斜杠+空白、
        zsh ~[ ] 语法、zsh =cmd 展开、大括号+引号混淆


walkProgram(root) → collectCommands(root, commands, varScope)

      ├── 'command'         → walkCommand()
      ├── 'pipeline'/'list' → 结构性,递归子节点
      ├── 'for_statement'   → 跟踪循环变量为 VAR_PLACEHOLDER
      ├── 'if/while'        → 作用域隔离的分支
      ├── 'subshell'        → 作用域复制
      ├── 'variable_assignment' → walkVariableAssignment()
      ├── 'declaration_command' → 验证 declare/export flags
      ├── 'test_command'    → walk test expressions
      └── 其他              → tooComplex()


checkSemantics(commands)
  ├── EVAL_LIKE_BUILTINS(eval, source, exec, trap...)
  ├── ZSH_DANGEROUS_BUILTINS(zmodload, emulate...)
  ├── SUBSCRIPT_EVAL_FLAGS(test -v, printf -v, read -a)
  ├── Shell keywords as argv[0](误解析检测)
  ├── /proc/*/environ 访问
  ├── jq system() 和危险 flags
  └── 包装器剥离(time, nohup, timeout, nice, env, stdbuf)

三、实现架构

3.1 核心模块

模块文件行数职责
门控入口src/utils/bash/parser.ts~110parseCommand()parseCommandRaw()ensureInitialized()
Bash 解析器src/utils/bash/bashParser.ts4437纯 TS 词法分析 + 递归下降解析器
安全分析器src/utils/bash/ast.ts2680树遍历安全分析 + parseForSecurity()
AST 分析辅助src/utils/bash/treeSitterAnalysis.ts507引号上下文、复合结构、危险模式提取
权限检查入口src/tools/BashTool/bashPermissions.ts集成 AST 结果到权限决策

3.2 Bash 解析器

文件:src/utils/bash/bashParser.ts(4437 行)
  • 纯 TypeScript 实现(无原生依赖)
  • 生成与 tree-sitter-bash 兼容的 AST
  • 关键类型:TsNode(type、text、startIndex、endIndex、children)
  • 安全限制:PARSE_TIMEOUT_MS = 50MAX_NODES = 50_000 — 防止对抗性输入导致 OOM

3.3 安全分析器

文件:src/utils/bash/ast.ts(2680 行) 核心函数:
函数职责
parseForSecurity(cmd)顶层入口,返回 simple/too-complex/parse-unavailable
parseForSecurityFromAst(cmd, root)接受预解析 AST
checkSemantics(commands)后解析语义检查
walkCommand()提取 argv、envVars、redirects
walkArgument()Allowlist 参数遍历
collectCommands()递归收集所有命令

3.4 AST 分析辅助

文件:src/utils/bash/treeSitterAnalysis.ts(507 行)
函数职责
extractQuoteContext()识别单引号、双引号、ANSI-C 字符串、heredoc
extractCompoundStructure()检测管道、子 shell、命令组
hasActualOperatorNodes()区分真实 ;/&&/`` 与转义形式
extractDangerousPatterns()检测命令替换、参数展开、heredocs
analyzeCommand()单次遍历提取

3.5 Shadow 模式

TREE_SITTER_BASH_SHADOW 运行解析器但从不影响权限决策
// Shadow 模式:记录遥测,然后强制使用旧版路径
astResult = { kind: 'parse-unavailable' }
astRoot = null
// 记录: available, astTooComplex, astSemanticFail, subsDiffer, ...
记录 tengu_tree_sitter_shadow 事件,包含与旧版 splitCommand() 的对比数据。用于在不影响行为的情况下收集遥测。

四、关键设计决策

  1. Allowlist 遍历:只处理已知安全的节点类型,未知类型直接 tooComplex()
  2. PARSE_ABORTED 符号:区分”解析器未加载”和”解析器加载但失败”。后者阻止回退旧版(旧版缺少 EVAL_LIKE_BUILTINS 检查)
  3. 变量作用域跟踪VAR=value && cmd $VAR 模式。静态值解析为真实字符串,$() 输出使用 VAR_PLACEHOLDER
  4. PS4/IFS Allowlist:PS4 赋值使用严格字符白名单 [A-Za-z0-9 _+:.\/=\[\]-],只允许 ${VAR} 引用
  5. 包装器剥离:从 argv 前面剥离 time/nohup/timeout/nice/env/stdbuf,未知标志 → fail-closed
  6. Shadow 安全性:Shadow 模式总是强制 astResult = { kind: 'parse-unavailable' },绝不影响权限

五、使用方式

# 激活 AST 解析用于权限检查
FEATURE_TREE_SITTER_BASH=1 bun run dev

# Shadow 模式(仅遥测,不影响行为)
FEATURE_TREE_SITTER_BASH_SHADOW=1 bun run dev

六、文件索引

文件行数职责
src/utils/bash/parser.ts~110门控入口点
src/utils/bash/bashParser.ts4437纯 TS bash 解析器
src/utils/bash/ast.ts2680安全分析器(核心)
src/utils/bash/treeSitterAnalysis.ts507AST 分析辅助
src/tools/BashTool/bashPermissions.ts:1670-1810~140权限集成 + Shadow 遥测