ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

解构 Destructive Command Guard 的模式库设计:分层检测架构、稳定规则 ID 与 rm 解析器一致性规范

解构 Destructive Command Guard 的模式库设计:分层检测架构、稳定规则 ID 与 rm 解析器一致性规范 解构 Destructive Command Guard 的模式库设计分层检测架构、稳定规则 ID 与 rm 解析器一致性规范【免费下载链接】destructive_command_guardThe Destructive Command Guard (dcg) is for blocking dangerous git and shell commands from being executed by agents.项目地址: https://gitcode.com/GitHub_Trending/de/destructive_command_guard本文基于 Destructive Command Guarddcg仓库中的设计文档 pattern-library-design.md完整解析该项目为heredoc / 内联脚本构建破坏性命令模式库Pattern Library的整套设计混合式Rust 硬编码 TOML 扩展的选型决策、HeredocPattern元数据模式、稳定规则 ID 的命名与稳定性规则、与 pack 系统的三层集成流程、初始模式清单、上下文复合匹配策略、模式作者检查清单以及面向未来的 rm 解析器一致性规范Parity Spec。读完本文你能掌握该模式库的完整数据模型与严重级别Severity到默认动作的映射关系并能对照仓库源码src/heredoc.rs、src/ast_matcher.rs、src/packs/core/filesystem.rs验证每一项设计决策的实际落地情况甚至按同一套规范为项目贡献新模式。1. 选型决策Rust 硬编码 TOML 用户扩展的混合方案设计文档开篇即给出了核心决策核心模式以 Rust 硬编码实现性能与类型安全优先用户可选扩展通过 TOML 提供灵活性。这一决策的权衡逻辑是模式库运行在每次 hook 调用的关键路径上命令执行前拦截正则与 AST 匹配必须零运行时加载开销——Rust 静态初始化LazyLock编译期注册天然满足这一点模式元数据rule ID、severity、reason、suggestion是类型安全的结构化数据硬编码可获得编译期检查但用户场景如我们 CI 需要这条规则放行又不可能要求改 Rust 代码因此把allowlist / 扩展配置下沉到 TOML见 docs/configuration.md 与config.schema.json。从源码结构看这一决策已完全落地模式注册与匹配逻辑集中在 src/ast_matcher.rsTier 3 AST 匹配与 src/heredoc.rsTier 1 触发 Tier 2 抽取而用户侧的 TOML 配置allowlist、severity 覆盖则由 src/allowlist.rs 与 src/config.rs 解析两者通过稳定规则 ID这一契约解耦。2. 模式元数据模式HeredocPattern结构体每个模式由如下 Rust 结构体描述字段命名与设计文档一致/// A destructive pattern for heredoc/inline script scanning. pub struct HeredocPattern { /// Stable rule ID: {pack_id}.{pattern_name} /// Example: heredoc.python.shutil_rmtree pub id: static str, /// Target language for this pattern. pub language: Language, /// Pattern matcher (regex or AST). pub matcher: PatternMatcher, /// Human-readable explanation. pub reason: static str, /// Suggestion for safe alternative. pub suggestion: Optionstatic str, /// Severity level (affects default mode). pub severity: Severity, /// False positive risk notes (for maintainers). pub fp_notes: Optionstatic str, } pub enum Language { Python, Bash, JavaScript, TypeScript, Ruby, Perl, Go, Php, Unknown, } pub enum PatternMatcher { /// Simple regex (Tier 1 compatible). Regex(Regex), /// AST pattern for ast-grep-core. Ast(String), /// Composite: regex trigger AST validation. Composite { trigger: Regex, validator: String }, } pub enum Severity { /// Always block (irreversible high confidence). Critical, /// Block by default, allowlistable. High, /// Warn by default, blockable via config. Medium, /// Log only (for history/learning). Low, }设计要点id使用static str规则 ID 是常量编译期内存、零分配且直接充当 hook 输出与 allowlist 的引用键详见第 4 节Language枚举与 Tier 2 的语言识别对齐src/heredoc.rs 在抽取 heredoc / 内联脚本正文后识别语言再分发到对应语言的 Tier 3 模式集PatternMatcher三种形态Regex用于 Tier 1 级别的简单触发Ast存 ast-grep-core 的结构化模式字符串Composite是正则触发 AST 验证的两段式复合匹配器第 5 节详述fp_notes面向维护者把已知误报场景固化到模式元数据中与测试夹具强制要求第 6 节共同构成误报False Positive治理机制。当前源码中的对应实现见 src/ast_matcher.rsSeverity枚举已带label()与blocks_by_default()方法Critical/High 默认阻断Medium/Low 不阻断匹配结果以PatternMatch结构体返回其中rule_id字段注释明确写着 Stable rule ID for allowlisting (e.g.,heredoc.python.subprocess_rm)与设计文档的ID allowlist 键规则一一对应。同时该模块为 AST 操作设定了 20ms 硬超时与 1 MiB 输入上限AST_TIMEOUT_MS/MAX_AST_INPUT_BYTES把设计文档中Tier 3 5ms 典型、有界降级的性能契约变成了可测试的常量。3. 稳定规则 ID命名规范与稳定性规则规则 ID 的格式为{category}.{language}.{operation}[.{variant}]文档给出的示例heredoc.python.shutil_rmtreeheredoc.python.subprocess_rm_rfheredoc.bash.rm_rf.recursivevariant 使用点分隔heredoc.javascript.fs_rmsync_recursiveheredoc.ruby.fileutils_rm_rf文档定义了四条ID 稳定性规则这是模式库能长期作为 hook 输出契约与 allowlist 键的基础永不重命名已有模式 ID需要下线时弃用而非删除追加.deprecated后缀新变体分配新 ID不修改已有 IDID 即 allowlist 键用户按 ID 引用规则。从源码结构看这套契约确实被当作跨模块的稳定接口使用src/ast_matcher.rs 的测试断言rule_id heredoc.python.shutil_rmtreesrc/evaluator.rs 的评估测试同样按该 ID 断言阻断结果src/suggestions.rs 则为每个规则 ID 维护建议文案。值得注意的是src/suggestions.rs 中也出现了heredoc.python:shutil_rmtree这种冒号变体src/cli.rs 附近的注释提及了heredoc.posix:eval-dynamic等变体可以推断当前代码库中规则 ID 存在点分隔与冒号分隔两种呈现形式的演进痕迹对外配置契约以仓库当前测试断言的形式为准。4. Pack 集成heredoc作为新类别heredoc是与现有 packcore、cloud、kubernetes 等见 src/packs/mod.rs并列的新 pack 类别按语言细分子类heredoc.python - Python heredoc patterns heredoc.bash - Bash heredoc patterns heredoc.javascript - JavaScript heredoc patterns heredoc.ruby - Ruby heredoc patterns heredoc.perl - Perl heredoc patterns heredoc.go - Go heredoc patterns heredoc.php - PHP heredoc patterns这些模式只有在三层检测链完整通过时才被评估这正是设计文档与 src/heredoc.rs 模块头注释共同定义的架构Command Input │ ▼ ┌─────────────────┐ │ Tier 1: Trigger │ ─── No match ──► ALLOW (fast path) │ (100μs) │ └────────┬────────┘ │ Match ▼ ┌─────────────────┐ │ Tier 2: Extract │ ─── Error/Timeout ──► ALLOW warn │ (1ms) │ └────────┬────────┘ │ Success ▼ ┌─────────────────┐ │ Tier 3: AST │ ─── No match ──► ALLOW │ (5ms) │ ─── Match ──► BLOCK └─────────────────┘三层各自承担的职责均有源码可查Tier 1 触发检测用RegexSet对输入做单遍并行匹配目标 100μs必须零漏报宁可多触发让 Tier 2 复核不可漏掉真实 heredoc。src/heredoc.rs 中的 21 条触发模式覆盖了、python -c、node -e、ruby -e、perl -e、php -r、lua -e、sh/bash/zsh/fish -c、PowerShell-Command/-EncodedCommandbase64 内嵌脚本、cmd /c以及bun/deno等内联解释器执行形态并处理了 Windows.exe后缀、组合短标志簇如bash -lc、$()/反引号替换等边界情况Tier 2 内容抽取在内存与时间双重预算内抽取 heredoc / 内联脚本正文并识别语言畸形输入走优雅降级ALLOW warnTier 3 语言级 AST 模式匹配由 src/ast_matcher.rs 基于 ast-grep-core 执行解析错误、超时、未知语言均作为非致命错误回传给 evaluator按配置的 bounded-fallback 或 strict-block 策略处理。这一分层让模式库只在真正需要时参与评估——普通命令走 Tier 1 快速放行只有含 heredoc / 内联脚本的命令才会进入语言级 AST 匹配兼顾延迟与检出率性能基线数据见 perf/baselines/ 与 docs/adr-001-heredoc-scanning.md。5. 初始模式清单Initial Pattern Inventory设计文档逐语言列出了首批模式这是模式库的种子目录完整继承如下5.1 Pythonheredoc.pythonIDPatternSeverityFP Riskshutil_rmtreeshutil.rmtree($PATH)CriticalLowos_removedirsos.removedirs($PATH)沿路径向上删除空目录CriticalLowsubprocess_rm_rfsubprocess.*([rm, -rf, ...])CriticalMediumos_system_rmos.system(rm ...)CriticalMedium5.2 Bashheredoc.bashIDPatternSeverityFP Riskrm_rfrm -rf $PATH非 temp 路径CriticalMediumgit_destructive破坏性 git 命令CriticalLowdestructive_pipe\| sh、\| bash、\| zshHighMedium5.3 JavaScriptheredoc.javascriptIDPatternSeverityFP Riskfs_rmsync_recursivefs.rmSync($, {recursive: true})CriticalLowexecsync_rmexecSync(rm ...)CriticalMediumspawn_rmspawn(rm, [...])CriticalMedium5.4 Rubyheredoc.rubyIDPatternSeverityFP Riskfileutils_rm_rfFileUtils.rm_rf($PATH)CriticalLowsystem_rmsystem(rm ...)CriticalMediumbacktick_rm反引号内含 rmCriticalMedium清单的设计取向值得注意凡是不可逆 高置信的文件删除 sinkshutil.rmtree、fs.rmSync、FileUtils.rm_rf一律 Critical / Low FP Risk而经子进程执行 rm一类subprocess_rm_rf、execsync_rm、spawn_rm、os_system_rm、system_rm、backtick_rm统一标为 Medium FP Risk——因为命令参数可能是动态拼接的静态匹配存在误报空间。该取向直接映射到第 8 节的严重级别默认动作。清单中的规则 ID 在测试中均可验证src/ast_matcher.rs 断言heredoc.python.shutil_rmtree命中src/evaluator.rs 中的python_shutil_rmtree_is_blocked测试则验证了匹配即阻断的端到端行为语料级回归还覆盖在 tests/corpus/ 的bypass_attempts/、false_positives/heredoc_data.toml等夹具中tests/heredoc_pack_gap.rs 专门守护 heredoc pack 的覆盖缺口。6. 上下文模式策略低信号模式的复合匹配问题低信号模式像subprocess.run(cmd)这样的调用单独出现时信号量太低——cmd可能是任意内容直接把它标为破坏性会产生海量误报。方案复合匹配器Composite matcher设计文档给出的解法是把判断拆成三段正则触发检测 subprocess / exec 类调用高召回、低成本AST 抽取取到命令参数表达式二次校验验证该命令参数是否真的含破坏性内容。对应的模式定义PatternMatcher::Composite { trigger: regex!(rsubprocess\.\w\(), validator: $EXPR.run($CMD).to_string(), } // The matcher first runs trigger regex. If it matches, // it extracts via the validator AST pattern, then checks // if $CMD contains destructive content.语义是先用trigger正则做廉价筛命中后进入validatorAST 模式做结构化抽取最后对$CMD捕获组做破坏性内容判定——把宽触发 严判定的漏斗固化为模式的一等公民。从当前 src/ast_matcher.rs 的实现看Tier 3 主要采用直接的 AST 模式匹配并对rm函数名等做了带命名捕获组的动态规则 ID 生成如 src/ast_matcher.rs 处的caps.name(fn)逻辑可以推断复合匹配器是设计文档规划中、随 Tier 3 能力扩展逐步引入的形态无论实现形态如何演化触发—抽取—校验三段式漏斗已被整个三层架构在宏观层面实现Tier 1 触发 → Tier 2 抽取 → Tier 3 校验。7. 模式作者检查清单与测试夹具格式设计文档要求每一个新模式必须满足以下清单这是误报治理的制度层唯一且符合命名规范的稳定 ID带论证的严重级别人类可读的 reason100 字符至少 1 个正例夹具应当命中至少 1 个反例夹具不应当命中记录已知误报场景的 FP notes可选的安全替代建议suggestion配套的测试夹具格式示例#[test] fn test_heredoc_python_shutil_rmtree() { let pattern patterns::get(heredoc.python.shutil_rmtree); // Positive fixtures (should match) assert!(pattern.matches(shutil.rmtree(/home/user))); assert!(pattern.matches(shutil.rmtree(path))); // Negative fixtures (should NOT match) assert!(!pattern.matches(# shutil.rmtree(/tmp))); // Comment assert!(!pattern.matches(shutil.rmtree(x))); // String literal assert!(!pattern.matches(shutil.copy(path))); // Different function }三类反例恰好覆盖了静态误报的三大来源注释、字符串字面量、相似函数名shutil.copyvsshutil.rmtree。仓库中这类纪律有直接对应物src/ast_matcher.rs 测试模块内的shutil_rmtree_blocks等用例验证正例tests/false_positive_corpus.rs 与 tests/corpus/false_positives/ 维护全局误报语料scripts/audit_patterns.py 与 tests/pattern_audit.rs 提供模式级审计工具链docs/canonical-corpus-invariants.md 则定义了 canonical 语料不变式tests/corpus/canonical.toml。8. 严重级别到默认模式的映射严重级别不仅影响展示还直接决定 hook 的默认动作与可覆盖方式SeverityDefault ModeUser OverrideCriticalBlockAllowlist onlyHighBlockAllowlist by IDMediumWarnBlock via configLowLogWarn/Block via config源码中该映射体现为 src/ast_matcher.rs 的blocks_by_default()仅Critical与High返回 true即默认阻断Medium/Low默认只记录/告警需用户通过配置升级为阻断。Critical与High的区分在于覆盖方式Critical 只能显式 allowlist不可逆 高置信High 可按 ID allowlist与第 2 节Severity枚举的注释Always block - no allowlist override without explicit config vs Block by default, can be allowlisted严格一致。配套的阻断策略文档见 docs/graduated-response.md。9. rm 解析器一致性规范core.filesystem Parity Spec设计文档第 8 节定义了未来 rm 解析器必须满足的语义规范新解析器与当前 src/packs/core/filesystem.rs 中的正则行为必须同构isomorphic——对同一命令给出相同的 allow/deny 结论与严重级别。这是先定契约、再换实现的经典做法完整规则如下9.1 命令识别仅匹配命令词rm剥离 wrapper 之后非rm命令忽略交由其他 pack 处理。9.2 标志语义必须与现有正则一致满足以下任一条件即判定为破坏性组合标志同一 token 中同时含r/R和f如-rf、-fr、-rfx、-xfr顺序不敏感分离标志-r/-R与-f以任意顺序出现中间允许夹杂其他短标志 token如-r -f、-f -r长标志--recursive与--force同时出现任意顺序。额外标志允许存在且不得改变判定——例如--no-preserve-root的存在不削弱破坏性检测。9.3 选项终止符--出现--后其后所有 token 一律视为路径--本身不削弱破坏性检测只是终止选项解析。9.4 路径分类规则安全白名单仅限 temp/tmp/.../var/tmp/...$TMPDIR/...${TMPDIR}...含${TMPDIR}/...$TMPDIR/...或${TMPDIR}...的双引号形式遍历守卫即使在 temp 目录也保持阻断任一路径中含..段/tmp/../etc、/var/tmp/foo/../bar等均必须阻断。Critical 阻断Severity: Critical根或家目录路径/、/etc、/home、~/以及任何~前缀路径。一般破坏性Severity: High任何带 recursive force 标志的rm只要不在temp 安全白名单内、也不命中Critical 根/家目录规则。9.5 多路径存在多个路径参数时所有路径必须同时满足安全白名单 遍历守卫才算安全任一路径不安全或命中 Critical整条命令必须阻断。9.6 引号路径双引号路径允许参与 temp 白名单匹配含..的引号路径仍必须阻断遍历守卫。9.7 与既有测试的映射解析器规则必须映射到 src/packs/core/filesystem.rs 中的现有测试用例新实现通过这些测试验证精确决策同构规则类别对应测试均已存在于 src/packs/core/filesystem.rsCritical 根/家目录test_rm_rf_root_criticalfilesystem.rs#L6319一般破坏性test_rm_rf_general_highfilesystem.rs#L6613标志顺序组合/分离/长标志test_rm_flags_orderingfilesystem.rs#L6669Temp 白名单无引号 引号test_safe_rm_tmpfilesystem.rs#L6686、test_safe_rm_variantsfilesystem.rs#L6706遍历守卫test_safe_rm_variants中含..的用例该规范与仓库既有的回归测试体系形成双重保险tests/false_positive_corpus.rs 中的rm_safe.tomltests/corpus/false_positives/rm_safe.toml守护 temp 路径等安全形态不被误杀tests/repro_rm_multi_arg.rs 专门回归多参数 rm 的判定逻辑。任何 rm 解析器的替换工作都必须同时通过单元测试与这两层语料验证。10. Allowlist 集成按稳定规则 ID 放行用户以稳定规则 ID 进行放行示例配置dcg.toml[allow] rules [ heredoc.python.subprocess_rm_rf, # We review these manually heredoc.bash.rm_rf, # Our CI needs this ]放行条目按以下维度限定作用域规则 ID必填可选文件模式、过期时间、理由。这一设计与第 3 节的ID 稳定性规则闭环正因为 ID 永不重命名、只弃用不删除用户写在配置里的放行条目才不会在版本升级后悄然失效。解析与生效逻辑见 src/allowlist.rsallow-once交互式短期放行机制的使用说明见 docs/allow-once-usage.md。11. 验收标准回顾设计文档以如下验收标准收尾也是评估该模式库设计完整性的清单清晰可执行的模式元数据模式第 2 节HeredocPattern用于 hook 输出 / allowlisting 的稳定规则 ID第 3 节四条稳定性规则与默认模式绑定的严重级别分类法第 8 节四档映射表通过测试夹具强制要求实现的误报控制第 7 节正例/反例双夹具与 pack 系统的集成方案第 4 节heredoc新类别 三层检测链通过复合匹配器实现的上下文模式第 6 节触发—抽取—校验三段式。从仓库现状看上述标准均有可验证的落地物证Tier 1/2/3 架构已在 src/heredoc.rs 与 src/ast_matcher.rs 实现rm 语义的判定同构由 src/packs/core/filesystem.rs 的既有测试守护allowlist 与 severity 策略在 src/allowlist.rs、src/config.rs 中生效而 docs/adr-001-heredoc-scanning.md 记录了该方案的架构决策背景。对模式库使用者而言这套设计的实际含义是拦截理由可以追溯到某一条稳定 ID该 ID 在 hook 输出、日志、allowlist 配置与测试断言中始终指代同一个模式——这正是破坏性命令防护工具在长期演进中不产生配置漂移的关键工程实践。【免费下载链接】destructive_command_guardThe Destructive Command Guard (dcg) is for blocking dangerous git and shell commands from being executed by agents.项目地址: https://gitcode.com/GitHub_Trending/de/destructive_command_guard创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进