ARTICLE · INTELLIGENCE

战地情报 · 详情页

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

dcg scan 预提交集成实战指南:用 Destructive Command Guard 在 commit 之前拦截破坏性命令

dcg scan 预提交集成实战指南:用 Destructive Command Guard 在 commit 之前拦截破坏性命令 dcg scan 预提交集成实战指南用 Destructive Command Guard 在 commit 之前拦截破坏性命令【免费下载链接】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的dcg scan扫描模式系统讲解如何将其安全地集成进 pre-commit 工作流从一键安装、渐进式灰度上线Warn-First、发现解读与修复、allowlist 管理到 CI 强制与隐私保护并深入仓库源码src/scan.rs、src/cli.rs讲解其 extractor 式架构与底层实现原理。读完你可以独立完成本地 pre-commit 拦截 CI 差分扫描的完整防护落地。dcg scan 是什么以及不是什么它是什么dcg scan是一个面向已提交文件的破坏性命令扫描器。它不会逐字匹配全文而是先通过格式感知的 extractor从文件中抽取可执行上下文里的命令再交给与实时 hook 完全一致的评估管道evaluator pipeline做判定。扫描覆盖面包括GitHub Actions 工作流.github/workflows/*.ymlDockerfileRUN指令Shell 脚本*.sh、*.bashMakefilerecipe 行GitLab CI.gitlab-ci.ymlDocker Composecommand:字段Terraformlocal-execprovisioner从源码看扫描入口在 src/scan.rs 的scan_paths_with_progress函数中按文件类型分派到不同的 extractorextract_shell_script_from_str、extract_dockerfile_from_str、extract_github_actions_workflow_from_str、extract_gitlab_ci_from_str、extract_azure_pipelines_from_str、extract_circleci_from_str、extract_makefile_from_str、extract_package_json_from_str、extract_terraform_from_str、extract_docker_compose_from_str、extract_powershell_from_str、extract_batch_from_str等一应俱全文件路径识别函数is_shell_script_path、is_dockerfile_path、is_github_actions_workflow_path等在 src/scan.rs 处统一判定。它与实时 hook单独的dcg命令的核心差异模式保护对象生效时机Hookdcg交互式 Agent 命令命令执行时Scandcg scan已提交文件中的命令commit / CI 时两者互补而非替代hook 保护交互执行scan 保护仓库本身。它不是什么不是完整的静态分析引擎。它不理解你的 shell 逻辑、变量展开或条件分支不是朴素的 grep。它通过 extractor 理解文件格式只在可执行上下文内匹配命令不会命中注释、文档或字符串字面量不是 hook 的替代品。最佳实践是两者同时启用。这一点在源码模块文档中有明确注释Extractors MUST be conservative: if unsure whether something is executed, prefer returning no extraction rather than producing false positivessrc/scan.rs即 extractor 遵循宁可漏报、不可误报的保守契约。快速开始一键安装# 进入你的 git 仓库 cd /path/to/your/repo # 安装 pre-commit hook dcg scan install-pre-commit该命令会在.git/hooks/pre-commit写入一个由 dcg 管理的 hook在每次 commit 前运行dcg scan --staged。生成的 hook 脚本逻辑在 src/cli.rs 的build_scan_pre_commit_hook_script中值得了解的几个设计点脚本首行写入哨兵标记# dcg:scan-pre-commit常量DCG_SCAN_PRE_COMMIT_SENTINEL卸载命令据此识别这是 dcg 装的 hook避免误删其他 hook若dcg不在 PATH 中hook 会打印提示并以0 退出跳过扫描而非阻塞提交避免因环境问题导致团队无法提交扫描失败时hook 会给出修复提示包括 allowlist 建议命令和git commit --no-verify的一次性绕过方式明确标注 unsafe。手动集成如果你已有自己的 pre-commit hook 或使用 hook 管理器# 在你现有 hook 中加入这一行 dcg scan --staged针对 Husky、Lefthook、pre-commit.com 等 hook 管理器的具体配置见下文 Hook Manager 示例。卸载dcg scan uninstall-pre-commit卸载逻辑同样会先检查哨兵标记只有当 hook 确认为 dcg 安装时才会移除否则提示你把dcg scan --staged手动加入现有 hooksrc/cli.rs。推荐的渐进式上线计划Warn-FirstTL;DR:先保守再逐步扩大范围。不要第一天就开启警告即失败。Phase 1观察1-2 周启用扫描并使用默认配置——只有灾难级规则fail_on error会阻塞提交。# .dcg/hooks.toml [scan] fail_on error # 只在高置信度灾难级规则上阻塞 format pretty # 人类可读输出此阶段要做的事收集团队对误报的反馈用dcg explain command理解某条命令为何被标记针对合法场景逐步构建你的 allowlist。Phase 2扩大范围团队适应后增加扫描的文件类型[scan.paths] include [ .github/workflows/**, Dockerfile*, Makefile, scripts/**/*.sh, ]考虑对特定高风险模式启用警告即失败# 先在本地测试再考虑强制 dcg scan --staged --fail-on warningPhase 3在 CI 中强制本地 pre-commit 稳定后加入 CI 强制# .github/workflows/dcg-scan.yml name: DCG Scan on: [pull_request] jobs: scan: runs-on: ubuntu-latest steps: - uses: actions/checkoutv4 with: fetch-depth: 0 - run: | curl -fsSL https://raw.githubusercontent.com/Dicklesworthstone/destructive_command_guard/main/install.sh | bash - run: dcg scan --git-diff origin/${{ github.base_ref }}...HEAD --fail-on error说明上面示例中使用的安装脚本即是仓库根目录的 install.sh。--git-diff模式只扫描指定 commit 区间内变更的文件与--staged、--paths互斥参数定义见 src/cli.rs非常适合 PR 差分扫描场景。如何解读扫描发现输出格式[ERROR] .github/workflows/ci.yml:42 Rule: core.git:reset-hard Severity: critical Reason: git reset --hard destroys uncommitted changes → dcg allow core.git:reset-hard -r CI cleanup --user字段含义字段说明[ERROR]/[WARN]/[INFO]严重级别——默认只有 ERROR 会阻塞文件路径 行号命令被抽取出的位置Rule:稳定的规则 IDpack_id:pattern_name用于 allowlistSeverity:critical、high、medium、low——危险程度Reason:该命令被标记的原因→建议如何修复或加入 allowlist从源码看每条发现的底层结构是ScanFindingsrc/scan.rs包含file、line、col、extractor_id、extracted_command、decision、severity、rule_id、reason、suggestion字段。其中rule_id由resolve_severity_and_rule_id拼装为{pack_id}:{pattern_name}格式src/scan.rssuggestion则通过get_suggestion_by_kind从更安全替代方案SaferAlternative中取出。JSON 输出中的所有发现会经过sort_findings稳定排序文件、行、列、规则、严重级别保证 CI 输出确定性src/scan.rs。严重级别严重级别默认动作示例critical阻塞errorgit reset --hard、rm -rf /、DROP DATABASEhigh阻塞errorgit push --force、docker system prune -amedium警告上下文相关模式low提示建议性模式、低置信度严重级别到扫描严重度的映射逻辑在evaluate_extracted_command中pack 规则的Critical/High映射为扫描ErrorMedium映射为WarningLow映射为Infosrc/scan.rs。而fail_on阈值由ScanFailOn::blocks实现——Error阈值只阻塞Error级Warning阈值阻塞Warning与ErrorNone永不阻塞src/scan.rs。如何修复一条发现方案一修改代码推荐很多破坏性命令都有更安全的替代不要用改用git reset --hardgit stash或定向git checkoutgit push --forcegit push --force-with-leaserm -rf ./build使用构建工具的清理如cargo clean、make cleandocker system prune -afdocker image prune --filter until24h方案二用 explain 调查# 查看某条命令为什么被标记 dcg explain git reset --hard HEAD~1这会输出完整的决策链路哪个 pack 匹配、哪个 pattern 触发、是否命中 allowlist。方案三Allowlist如果是误报如果该命令在你的上下文中是安全的例如 CI 清理步骤可以加入 allowlistrepo_root$(git rev-parse --show-toplevel) # 按规则 ID 加白推荐——最稳定 dcg allow core.git:reset-hard -r Used for CI cleanup after tests \ --user --path $repo_root --path $repo_root/** # 或者按具体命令精确加白 dcg allowlist add-command git reset --hard HEAD -r CI cleanup \ --user --path $repo_root --path $repo_root/**重要的安全说明始终提供原因-r ...——记录为什么这是安全的对项目级例外使用 user 所有的路径作用域。仓库内检入的.dcg/allowlist.toml在用户明确审核并通过DCG_CONFIG选择仓库根的.dcg.toml之前是**不生效INACTIVE**的防止代码审查即白名单授权的漏洞临时覆盖使用过期时间dcg allow core.git:reset-hard -r Migration \ --expires 2026-02-01T00:00:00Z --user \ --path $repo_root --path $repo_root/**查看与管理 allowlist# 列出生效的 allowlist 条目 dcg allowlist list # 查看原始项目策略未显式信任前标记为 INACTIVE dcg allowlist list --project # 移除 user 所有的条目 dcg allowlist remove core.git:reset-hard --user # 校验 allowlist 文件 dcg allowlist validate隐私与机密保护命令脱敏redaction默认情况下scan 输出会展示完整命令。在 CI 中这可能泄露机密。# .dcg/hooks.toml [scan] redact quoted # 脱敏引号字符串rm -rf [REDACTED] # redact aggressive # 更激进的脱敏 # redact none # 显示完整命令默认适合本地三种模式在源码中对应ScanRedactMode::None / Quoted / Aggressivesrc/scan.rs其中Quoted只脱敏引号包裹的字符串Aggressive还会脱敏疑似敏感片段。实际输出经redact_and_truncate统一处理先按模式脱敏再按truncate做 UTF-8 安全截断0 表示不截断src/scan.rs。CI 最佳实践CI 中使用redact quoted避免机密出现在日志里限制输出量用truncate和max_findings[scan] truncate 100 # 截断过长的命令输出 max_findings 50 # 限制单次扫描的发现总数CI 中使用 JSON 格式便于机器解析[scan] format json--format json的输出遵循稳定的ScanReport结构schema 版本号SCAN_SCHEMA_VERSION 1包含summary统计扫描/跳过文件数、抽取命令数、allow/warn/deny 决策计数、各严重级别计数、max_findings_reached等与findings数组对应 JSON Schema 定义见 docs/json-schema/scan-results.json。此外格式枚举还支持markdownGitHub 风格用于 PR 评论使用details折叠块与sarif供代码扫描工具消费两种输出src/scan.rs。值得注意的一个细节扫描摘要会区分文件被跳过和顶层路径不存在两类情况——paths_skipped中的条目如path_not_found意味着 CI 调用路径配置错误此时即使没有任何发现也会按fail_on阈值失败should_fail逻辑src/scan.rs避免路径拼错却静默通过的 CI 假绿。配置参考.dcg/hooks.toml在仓库根目录创建该文件即可配置扫描行为[scan] # 输出格式pretty人类可读或 json format pretty # 何时失败error、warning 或 none fail_on error # 最大扫描文件大小字节——更大的文件会被跳过 max_file_size 1048576 # 1MB # 每次运行最大报告发现数 max_findings 100 # 命令脱敏none、quoted 或 aggressive redact none # 截断过长的命令输出0 不截断 truncate 200 [scan.paths] # 要包含的 glob 模式默认所有受支持的文件类型 include [ .github/workflows/**, Dockerfile*, **/Makefile, scripts/**/*.sh, ] # 要排除的 glob 模式 exclude [ vendor/**, node_modules/**, **/testdata/**, ]该 TOML 在源码中对应HooksToml/HooksTomlScan/HooksTomlScanPaths结构src/scan.rs解析函数parse_hooks_toml还会对未知键给出警告提示将被忽略对非法枚举值返回带说明的错误避免配置拼错后静默失效src/scan.rs。CLI 标志覆盖配置文件dcg scan --staged \ --format json \ --fail-on warning \ --max-file-size 2097152 \ --exclude tests/** \ --include *.shCLI 标志始终优先于.dcg/hooks.toml。完整的标志清单定义于 src/cli.rs还包括--paths PATH.../ 位置参数扫描显式路径目录递归展开dcg scan a.sh b.sh等价于dcg scan --paths a.sh b.sh--git-diff REV_RANGE扫描 git diff 区间变更的文件如HEAD~3..HEAD、main..feature--with-packs ID,...本次扫描额外启用的 pack逗号分隔--max-findings N达到上限即停止扫描--truncate N截断输出命令长度字符数0 为不截断--top Npretty 输出中展示的示例数量默认 10以上--staged、--paths、--git-diff三种文件选择模式互斥。Hook Manager 示例Huskynpmv8# .husky/pre-commit dcg scan --staged创建方式npx husky add .husky/pre-commit dcg scan --stagedLefthook# lefthook.yml pre-commit: commands: dcg-scan: run: dcg scan --stagedpre-commit.com# .pre-commit-config.yaml repos: - repo: local hooks: - id: dcg-scan name: dcg scan entry: dcg scan --staged language: system pass_filenames: false仓库提供了对应的端到端验证脚本 scripts/scan_precommit_e2e.sh它会创建临时 git 仓库、分别暂存可执行上下文中含破坏性命令的文件与纯数据提及不应触发的文件然后运行dcg scan --staged断言输出与退出码可用--binary PATH指定待测二进制cargo build --release后位于./target/release/dcg。故障排查dcg not found in PATHpre-commit hook 找不到dcg。解决方法全局安装cargo install destructive_command_guard在运行 git 命令前把 dcg 所在目录加入 PATH在 hook 配置中使用绝对路径。Refusing to overwrite existing pre-commit hook你已经有了一个非 dcg 安装的 pre-commit hook。可选方案加入现有 hook把dcg scan --staged追加到你的 hook 脚本替换 hook手动删除后重新执行dcg scan install-pre-commit。这正是哨兵标记设计的意义dcg 拒绝覆盖它无法确认来源的 hook避免破坏你已有的工作流。误报如果 dcg 标记了安全命令调查dcg explain the-command理解原因必要时加白添加 user 所有的条目并使用仓库根与后代--path作用域上报如果是模式 bug提交 issue。Hook 太慢扫描性能取决于暂存文件数量——只扫描变更的文件文件大小——用max_file_size跳过超大文件模式数量——在配置中只启用需要的 pack。另外源码中还有一个针对扫描路径的性能设计SCAN_HEREDOC_MIN_TIMEOUT_MS 200src/scan.rs。hook 热路径是每次 Bash 调用毫秒级预算而 scan 是离线批处理因此扫描模式会把 heredoc 抽取超时的下限抬到 200ms避免嵌入式脚本抽取因触碰热路径预算而被静默丢弃用户配置值大于该下限时仍以用户为准。总结安装dcg scan install-pre-commit配置创建.dcg/hooks.toml写入你的设置保守起步初始fail_on error逐步扩大增加文件类型考虑 warning-as-fail误报加白使用 user 所有、仓库路径作用域的条目CI 强制在 GitHub Actions / GitLab CI 中扫描 PR 差分。整个体系的两大基石值得反复强调extractor 的保守契约只在可执行上下文内抽取命令宁漏勿误保证了低误报率与 hook共享同一评估管道evaluate_command_with_pack_order_at_path_in_dialect见 src/scan.rs保证了本地拦截与提交扫描的判定完全一致。先观察、后扩权、再强制的 Warn-First 路径能让团队在不被打断的前提下完成从无防护到提交即拦截的平滑过渡。【免费下载链接】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

延伸阅读

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