6.6 KiB
6.6 KiB
tags, create time
| tags | create time | ||||||
|---|---|---|---|---|---|---|---|
|
2026-06-09 22:30 |
TREE_SITTER_BASH — Bash AST 解析
概述
TREE_SITTER_BASH 启用一个完整的 Bash AST 解析器,用于安全验证 Bash 命令。它用完整的树遍历安全分析器取代了旧的基于正则表达式的 shell-quote 解析器。关键属性是 fail-closed:任何无法识别的内容都被归类为 too-complex 并需要用户批准。
[!info] Feature Flag:
FEATURE_TREE_SITTER_BASH=1实现状态:完整可用(纯 TypeScript 实现,~7000+ 行)
正文
关联 Feature
| Feature | 说明 |
|---|---|
TREE_SITTER_BASH |
激活用于权限检查的 AST 解析器 |
TREE_SITTER_BASH_SHADOW |
Shadow/观测模式:运行解析器但丢弃结果,仅记录遥测 |
安全架构
Fail-Closed 设计
核心设计使用 allowlist 遍历模式:
walkArgument()只处理已知安全的节点类型(word、number、raw_string、string、concatenation、arithmetic_expansion、simple_expansion)- 任何未知节点类型 ->
tooComplex()-> 需要用户批准 - 解析器加载但失败(超时/节点预算/panic)-> 返回
PARSE_ABORTED符号(区别于"模块未加载")
解析结果
parseForSecurity(cmd) 返回:
{ kind: 'simple', commands: SimpleCommand[] } // 可静态分析
{ kind: 'too-complex', reason, nodeType } // 需要用户批准
{ kind: 'parse-unavailable' } // 解析器未加载
安全检查层次
flowchart TD
A["parseForSecurity(cmd)"] --> B["parseCommandRaw(cmd) -> AST root node"]
B --> C["预检查: 控制字符、Unicode 空白、反斜杠+空白、zsh 语法"]
C --> D["walkProgram(root) -> collectCommands(root, commands, varScope)"]
D --> E{"节点类型"}
E -->|"command"| F["walkCommand()"]
E -->|"pipeline/list"| G["结构性,递归子节点"]
E -->|"for_statement"| H["跟踪循环变量为 VAR_PLACEHOLDER"]
E -->|"if/while"| I["作用域隔离的分支"]
E -->|"subshell"| J["作用域复制"]
E -->|"variable_assignment"| K["walkVariableAssignment()"]
E -->|"declaration_command"| L["验证 declare/export flags"]
E -->|"test_command"| M["walk test expressions"]
E -->|"其他"| N["tooComplex()"]
D --> O["checkSemantics(commands)"]
O --> P["EVAL_LIKE_BUILTINS eval/source/exec/trap..."]
O --> Q["ZSH_DANGEROUS_BUILTINS zmodload/emulate..."]
O --> R["SUBSCRIPT_EVAL_FLAGS test -v/printf -v/read -a"]
O --> S["Shell keywords as argv0 误解析检测"]
O --> T["/proc/*/environ 访问"]
O --> U["jq system() 和危险 flags"]
O --> V["包装器剥离 time/nohup/timeout/nice/env/stdbuf"]
实现架构
核心模块
| 模块 | 文件 | 行数 | 职责 |
|---|---|---|---|
| 门控入口 | src/utils/bash/parser.ts |
~110 | parseCommand()、parseCommandRaw()、ensureInitialized() |
| Bash 解析器 | src/utils/bash/bashParser.ts |
4437 | 纯 TS 词法分析 + 递归下降解析器 |
| 安全分析器 | src/utils/bash/ast.ts |
2680 | 树遍历安全分析 + parseForSecurity() |
| AST 分析辅助 | src/utils/bash/treeSitterAnalysis.ts |
507 | 引号上下文、复合结构、危险模式提取 |
| 权限检查入口 | src/tools/BashTool/bashPermissions.ts |
— | 集成 AST 结果到权限决策 |
Bash 解析器
文件:src/utils/bash/bashParser.ts(4437 行)
- 纯 TypeScript 实现(无原生依赖)
- 生成与 tree-sitter-bash 兼容的 AST
- 关键类型:
TsNode(type、text、startIndex、endIndex、children) - 安全限制:
PARSE_TIMEOUT_MS = 50、MAX_NODES = 50_000— 防止对抗性输入导致 OOM
安全分析器
文件: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() |
递归收集所有命令 |
AST 分析辅助
文件:src/utils/bash/treeSitterAnalysis.ts(507 行)
| 函数 | 职责 |
|---|---|
extractQuoteContext() |
识别单引号、双引号、ANSI-C 字符串、heredoc |
extractCompoundStructure() |
检测管道、子 shell、命令组 |
hasActualOperatorNodes() |
区分真实 ;/&&/` |
extractDangerousPatterns() |
检测命令替换、参数展开、heredocs |
analyzeCommand() |
单次遍历提取 |
Shadow 模式
TREE_SITTER_BASH_SHADOW 运行解析器但从不影响权限决策:
// Shadow 模式:记录遥测,然后强制使用旧版路径
astResult = { kind: 'parse-unavailable' }
astRoot = null
// 记录: available, astTooComplex, astSemanticFail, subsDiffer, ...
记录 tengu_tree_sitter_shadow 事件,包含与旧版 splitCommand() 的对比数据。用于在不影响行为的情况下收集遥测。
关键设计决策
- Allowlist 遍历:只处理已知安全的节点类型,未知类型直接
tooComplex() - PARSE_ABORTED 符号:区分"解析器未加载"和"解析器加载但失败"。后者阻止回退旧版(旧版缺少
EVAL_LIKE_BUILTINS检查) - 变量作用域跟踪:
VAR=value && cmd $VAR模式。静态值解析为真实字符串,$()输出使用VAR_PLACEHOLDER - PS4/IFS Allowlist:PS4 赋值使用严格字符白名单
[A-Za-z0-9 _+:.\/=\[\]-],只允许${VAR}引用 - 包装器剥离:从 argv 前面剥离
time/nohup/timeout/nice/env/stdbuf,未知标志 -> fail-closed - 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.ts |
4437 | 纯 TS bash 解析器 |
src/utils/bash/ast.ts |
2680 | 安全分析器(核心) |
src/utils/bash/treeSitterAnalysis.ts |
507 | AST 分析辅助 |
packages/builtin-tools/src/tools/BashTool/bashPermissions.ts |
~140 | 权限集成 + Shadow 遥测 |