destructive_command_guard
destructive_command_guard(简称 dcg)是一款专为 AI 编程助手设计的安全防护工具,旨在防止自动化代理执行危险命令导致代码或数据丢失。在使用 Claude Code、GitHub Copilot、Cursor 等 AI 工具时,模型偶尔会误生成如 rm -rf、git reset --hard 或数据库删除指令,瞬间摧毁数小时的工作成果。dcg 通过在命令执行前进行拦截,精准识别并阻断这些高风险操作,同时提供清晰的解释和更安全的替代建议。
这款工具特别适合依赖 AI 辅助编程的开发者、运维工程师及技术团队。它无需复杂配置即可开箱即用,支持 Git、文件系统以及 AWS、Kubernetes、Docker 等 49 多种环境的安全规则包。技术亮点在于其亚毫秒级的超低延迟过滤能力,采用 SIMD 加速技术,确保在保护安全的同时不影响开发流畅度;此外,它还具备智能上下文感知功能,能区分代码中的危险字符串与实际执行指令,避免误报。无论是本地开发还是 CI/CD 流程,destructive_command_guard 都能为你的项目构建一道坚实的安全防线,让 AI 协作更安心。
使用场景
某后端工程师正利用 Claude Code 自动重构遗留代码库,AI 代理在清理临时文件时误判了目录结构,准备执行高危指令。
没有 destructive_command_guard 时
- 瞬间丢失进度:AI 直接执行
rm -rf ./src或git reset --hard,导致数小时未提交的代码和本地修改在秒级内彻底消失。 - 缺乏二次确认:自动化流程中缺少对“删除”、“重置”等破坏性操作的风险评估,AI 盲目信任生成的命令并立即运行。
- 误伤正常数据:无法区分代码中的搜索关键词(如
grep "rm -rf")与真实执行指令,要么漏拦危险操作,要么因过度敏感阻断正常开发。 - 恢复成本高昂:一旦数据库执行了
DROP TABLE或容器被prune清理,往往需要花费大量时间从备份中恢复甚至面临数据永久丢失。
使用 destructive_command_guard 后
- 拦截致命指令:destructive_command_guard 在命令执行前毫秒级拦截,直接阻断
git reset --hard等高风险操作,并提示先用git stash保存现场。 - 智能上下文识别:工具精准识别意图,允许在代码注释或搜索中使用敏感词,仅在实际调用 Shell 执行破坏动作时触发警报。
- 多环境全面防护:开启 PostgreSQL 和 Docker 规则包后,自动拦截
DROP TABLE或docker system prune等针对数据库和容器的毁灭性指令。 - 提供安全替代方案:拦截时不仅报错,还给出具体建议(如“考虑先备份”),引导 AI 选择更安全的操作路径,保障开发流不中断。
destructive_command_guard 如同给 AI 代理人装上了“刹车系统”,在保持自动化效率的同时,彻底杜绝了因误操作导致的灾难性数据损失。
运行环境要求
- Linux
- macOS
- Windows (WSL)
未说明
未说明

快速开始
dcg(破坏性命令防护)
一个高性能的钩子,专为 AI 编码助手设计,在破坏性命令执行前将其拦截,从而保护你的工作成果不被意外删除。
支持的工具: Claude Code、Gemini CLI、GitHub Copilot CLI、Cursor IDE、OpenCode(通过社区插件)、Aider(有限支持——仅限 Git 钩子)、Continue(仅检测功能)、Codex CLI
快速安装
curl -fsSL "https://raw.githubusercontent.com/Dicklesworthstone/destructive_command_guard/main/install.sh?$(date +%s)" | bash -s -- --easy-mode
适用于 Linux、macOS 和 Windows (WSL)。自动检测你的平台并下载合适的二进制文件。
简要说明
问题描述: AI 编码助手(如 Claude、GPT 等)有时会执行诸如 git reset --hard、rm -rf ./src 或 DROP TABLE users 等灾难性命令,导致数小时未提交的工作在几秒钟内被彻底摧毁。
解决方案: dcg 是一个高性能的钩子,能够在破坏性命令执行之前对其进行拦截,并以清晰的解释和更安全的替代方案阻止这些命令的执行。
为什么使用 dcg?
| 功能 | 描述 |
|---|---|
| 零配置防护 | 开箱即用,直接阻止危险的 Git 和文件系统命令 |
| 49+ 安全包 | 数据库、Kubernetes、Docker、AWS/GCP/Azure、Terraform 等 |
| 亚毫秒级延迟 | 基于 SIMD 加速的过滤技术,几乎不会影响性能 |
| Heredoc/内联脚本扫描 | 能够捕获 python -c "os.remove(...)" 和嵌入式 Shell 脚本 |
| 智能上下文检测 | 不会阻止 grep "rm -rf"(数据操作),但会阻止 rm -rf /(实际执行) |
| CI 模式扫描 | 支持预提交钩子和 CI 集成,用于在代码审查阶段捕获危险命令 |
| 故障开放设计 | 绝不会因超时或解析错误而阻塞你的工作流程 |
| 解释模式 | dcg explain "command" 可显示具体为何该命令被拦截 |
快速示例
# AI 助手尝试运行:
$ git reset --hard HEAD~5
# dcg 拦截并阻止:
════════════════════════════════════════════════════════════════
已阻止 dcg
────────────────────────────────────────────────────────────────
原因: git reset --hard 会丢弃未提交的更改
命令: git reset --hard HEAD~5
提示: 建议先使用 'git stash' 保存你的更改。
════════════════════════════════════════════════════════════════
启用更多防护
# ~/.config/dcg/config.toml
[packs]
enabled = [
"database.postgresql", # 阻止 DROP TABLE、TRUNCATE
"kubernetes.kubectl", # 阻止 kubectl delete namespace
"cloud.aws", # 阻止 aws ec2 terminate-instances
"containers.docker", # 阻止 docker system prune
]
针对不同 AI 助手的配置文件
dcg 会自动检测调用它的 AI 编码助手,并应用特定于该助手的配置。trust_level 字段是一个建议性标签,记录在 JSON 输出和日志中——它并不会直接影响规则的评估。行为差异主要由其他配置字段决定:
| 选项 | 效果 |
|---|---|
disabled_packs |
从评估中移除指定的安全包 |
extra_packs |
向评估中添加额外的安全包 |
additional_allowlist |
添加可绕过拒绝规则的命令模式 |
disabled_allowlist |
当设置为 true 时,忽略所有允许列表条目 |
# 对 Claude Code 更加信任——放宽允许列表,减少启用的安全包
[agents.claude-code]
trust_level = "high"
additional_allowlist = ["npm run build", "cargo test"]
disabled_packs = ["kubernetes"]
# 限制未知助手——增加额外规则,禁止绕过允许列表
[agents.unknown]
trust_level = "low"
extra_packs = ["paranoid"]
disabled_allowlist = true
完整的支持助手列表、信任级别及配置选项,请参阅 docs/agents.md。
起源与作者
该项目最初是由 Jeffrey Emanuel 使用 Python 编写的脚本,他意识到尽管 AI 编码助手非常有用,但它们有时会执行灾难性的命令,导致数小时未提交的工作瞬间丢失。最初的实现是一个简单却有效的钩子,能够在危险的 Git 和文件系统命令执行前将其拦截。
- Jeffrey Emanuel —— 原始概念提出者及 Python 实现者(源代码链接);大幅扩展了 Rust 版本,引入模块化安全包系统(49+ 种安全包)、Heredoc/内联脚本扫描、三层架构、上下文分类、允许列表、扫描模式以及双正则引擎。
- Darin Gordon —— 初始 Rust 移植及性能优化。
Darin 的初始 Rust 移植保持了与原始 Python 实现的模式兼容性,同时通过 SIMD 加速的过滤技术和惰性编译的正则表达式模式实现了亚毫秒级的执行速度。随后,Jeffrey 对 Rust 代码库进行了大规模扩展,增加了上述提到的各项功能。
应急通道/绕过机制
如果 dcg 阻止了你确实需要运行的命令:
| 方法 | 适用范围 | 如何操作 |
|---|---|---|
| 环境变量绕过 | 单个命令 | DCG_BYPASS=1 <command> |
| 一次性允许 | 单个命令 | 复制拦截信息中的短代码,运行 dcg allow-once <code> |
| 永久允许列表 | 规则或命令 | dcg allowlist add core.git:reset-hard -r "reason" |
| 移除钩子 | 所有命令 | 删除或注释掉 ~/.claude/settings.json 中的 dcg 条目(或其他对应助手的配置文件) |
DCG_BYPASS=1 会禁用此次调用的所有防护措施。请谨慎使用此方法,对于经常需要执行的命令,建议使用允许列表。
模块化安全包系统
dcg 使用模块化的“安全包”系统来按类别组织破坏性命令模式。用户可以在配置文件中启用或禁用不同的安全包。
- 完整的安全包 ID 索引:
docs/packs/README.md - 标准化描述及模式数量:
dcg packs --verbose
核心插件(默认启用)
core.filesystem- 防御在临时目录之外执行危险的rm -rf命令core.git- 防御可能导致未提交工作丢失、重写历史或破坏暂存区的破坏性 Git 命令
默认启用的常用插件:
database.postgresql- 防御破坏性的 PostgreSQL 操作containers.docker- 防御系统清理等破坏性 Docker 操作
存储插件
storage.s3- 防御删除存储桶、递归删除以及sync --delete等破坏性 S3 操作storage.gcs- 防御删除存储桶、对象删除和递归删除等破坏性 GCS 操作storage.minio- 防御删除存储桶、对象删除以及管理操作等破坏性 MinIO Client (mc) 操作storage.azure_blob- 防御删除容器、Blob 对象以及使用azcopy remove等破坏性 Azure Blob Storage 操作
远程插件
remote.rsync- 防御带有--delete或其变体的破坏性 rsync 操作remote.scp- 防御覆盖系统路径等破坏性 SCP 操作remote.ssh- 防御远程命令执行和密钥管理等破坏性 SSH 操作
数据库插件
database.postgresql- 防御DROP DATABASE、TRUNCATE和dropdb等破坏性 PostgreSQL 操作database.mysql- 保护 MySQL/MariaDB 数据库database.mongodb- 防御dropDatabase、dropCollection和无条件删除等破坏性 MongoDB 操作database.redis- 防御FLUSHALL、FLUSHDB和批量删除键等破坏性 Redis 操作database.sqlite- 防御DROP TABLE、无条件DELETE以及意外数据丢失等破坏性 SQLite 操作database.supabase- 防御 Supabase CLI 中的破坏性操作,包括数据库重置、迁移回滚、函数/密钥/存储删除、项目移除以及基础设施变更
容器插件
containers.docker- 防御系统清理、卷清理和强制移除等破坏性 Docker 操作containers.compose- 防御带有-v的docker-compose down等破坏性操作,该操作会删除卷containers.podman- 防御系统清理、卷清理和强制移除等破坏性 Podman 操作
Kubernetes 插件
kubernetes.kubectl- 防御删除命名空间、节点排空以及批量删除等破坏性 kubectl 操作kubernetes.helm- 防御未经过试运行就卸载或回滚等破坏性 Helm 操作kubernetes.kustomize- 防御与 kubectl 结合使用时未经审查就执行删除操作的破坏性 Kustomize 操作
云服务商插件
cloud.aws- 防御终止实例、删除数据库实例以及递归删除 S3 对象等破坏性 AWS CLI 操作cloud.azure- 防御删除虚拟机、存储账户和资源组等破坏性 Azure CLI 操作cloud.gcp- 防御删除实例、SQL 实例以及递归删除对象等破坏性 gcloud 操作
CDN 插件
cdn.cloudflare_workers- 防御通过 Wrangler CLI 执行的 Cloudflare Workers、KV、R2 和 D1 等破坏性操作cdn.cloudfront- 防御删除分发点、缓存策略和函数等破坏性 AWS CloudFront 操作cdn.fastly- 防御删除服务、域名、后端和 VCL 等破坏性 Fastly CLI 操作
API 网关插件
apigateway.apigee- 防御 Google Apigee CLI 和 apigeecli 中的破坏性操作apigateway.aws- 防御 REST API 和 HTTP API 中的破坏性 AWS API Gateway CLI 操作apigateway.kong- 防御 Kong Gateway CLI、deck CLI 以及 Admin API 中的破坏性操作
基础设施插件
infrastructure.ansible- 防御 Ansible 中的破坏性操作,如危险的 shell 命令和未经检查的 playbook 执行infrastructure.pulumi- 防御 Pulumi 中的破坏性操作,如直接销毁资源或使用-y自动批准选项进行部署infrastructure.terraform- 防御 Terraform 中的破坏性操作,如直接销毁资源、标记污点或自动批准应用更改
系统插件
system.disk- 防御对磁盘的破坏性操作,包括向设备写入数据 (dd)、格式化分区 (mkfs)、修改分区表(fdisk/parted)、RAID 管理(mdadm)、Btrfs 文件系统操作、设备映射器操作(dmsetup)、网络块设备操作(nbd-client)以及 LVM 命令(pvremove、vgremove、lvremove、lvreduce、pvmove)system.permissions- 防御危险的权限更改,如将权限设置为777,或对系统目录进行递归式的chmod/chownsystem.services- 防御停止关键服务或修改初始化配置等危险的服务操作
CI/CD 插件
cicd.circleci- 防御删除上下文、移除密钥、删除 Orb/命名空间或管道等破坏性 CircleCI 操作cicd.github_actions- 防御删除密钥/变量,或使用gh api DELETE请求 GitHub Actions 的 API 端点等破坏性 GitHub Actions 操作cicd.gitlab_ci- 防御删除变量、移除构建产物以及注销 Runner 等破坏性 GitLab CI/CD 操作cicd.jenkins- 防御删除作业、节点、凭据或构建历史等破坏性 Jenkins CLI/API 操作
密钥管理插件
secrets.aws_secrets- 防御删除密钥和参数等破坏性 AWS Secrets Manager 和 SSM Parameter Store 操作secrets.doppler- 防御删除密钥、配置、环境或项目等破坏性 Doppler CLI 操作secrets.onepassword- 防御删除条目、文档、用户、群组和保险箱等破坏性 1Password CLI 操作secrets.vault- 防御删除密钥、禁用认证/秘密引擎、撤销租约/令牌以及删除策略等破坏性 Vault CLI 操作
平台插件
platform.github- 防御删除仓库、Gist、发布版本或 SSH 密钥等破坏性 GitHub CLI 操作platform.gitlab- 防御删除项目、发布版本、保护分支和 Webhook 等破坏性 GitLab 平台操作
DNS 插件
dns.cloudflare- 防御删除记录、区域以及针对性的 Terraform 销毁等破坏性 Cloudflare DNS 操作dns.generic- 防御使用nsupdate删除记录或进行区域传输等具有风险的 DNS 工具操作dns.route53- 防御删除托管区域和修改记录集等破坏性 AWS Route53 DNS 操作
邮件防护包
email.mailgun- 防护破坏性的 Mailgun API 操作,例如删除域名、路由和邮件列表。email.postmark- 防护破坏性的 Postmark API 操作,例如删除服务器、模板和发件人签名。email.sendgrid- 防护破坏性的 SendGrid API 操作,例如删除模板、API 密钥和域名认证。email.ses- 防护破坏性的 AWS Simple Email Service 操作,例如删除身份、模板和配置集。
功能标志防护包
featureflags.flipt- 防护破坏性的 Flipt CLI 和 API 操作。featureflags.launchdarkly- 防护破坏性的 LaunchDarkly CLI 和 API 操作。featureflags.split- 防护破坏性的 Split.io CLI 和 API 操作。featureflags.unleash- 防护破坏性的 Unleash CLI 和 API 操作。
负载均衡器防护包
loadbalancer.elb- 防护破坏性的 AWS Elastic Load Balancing(ELB/ALB/NLB)操作,例如删除负载均衡器、目标组或从实时流量中注销目标。loadbalancer.haproxy- 防护破坏性的 HAProxy 负载均衡器操作,例如通过运行时 API 停止服务或禁用后端。loadbalancer.nginx- 防护破坏性的 nginx 负载均衡器操作,例如停止服务或删除配置文件。loadbalancer.traefik- 防护破坏性的 Traefik 负载均衡器操作,例如停止容器、删除配置或执行 API 删除操作。
消息队列防护包
messaging.kafka- 防护破坏性的 Kafka CLI 操作,例如删除主题、消费者组,重置偏移量和删除记录。messaging.nats- 防护破坏性的 NATS/JetStream 操作,例如删除流、消费者、键值对、对象和账户。messaging.rabbitmq- 防护破坏性的 RabbitMQ 操作,例如删除队列/交换机、清空队列、删除虚拟主机和重置集群状态。messaging.sqs_sns- 防护破坏性的 AWS SQS 和 SNS 操作,例如删除队列、清空消息、删除主题和取消订阅。
监控防护包
monitoring.datadog- 防护破坏性的 Datadog CLI/API 操作,例如删除监控器和仪表板。monitoring.newrelic- 防护破坏性的 New Relic CLI/API 操作,例如删除实体或告警资源。monitoring.pagerduty- 防护破坏性的 PagerDuty CLI/API 操作,例如删除服务和计划(可能导致事件路由中断)。monitoring.prometheus- 防护破坏性的 Prometheus/Grafana 操作,例如删除时间序列数据或仪表板/数据源。monitoring.splunk- 防护破坏性的 Splunk CLI/API 操作,例如删除索引和 REST API 的 DELETE 请求。
支付防护包
payment.braintree- 防护破坏性的 Braintree/PayPal 支付操作,例如通过 API/SDK 调用删除客户或取消订阅。payment.square- 防护破坏性的 Square CLI/API 操作,例如删除目录对象或客户(可能中断支付流程)。payment.stripe- 防护破坏性的 Stripe CLI/API 操作,例如删除 Webhook 终结点和客户,或在未协调的情况下轮换 API 密钥。
搜索引擎防护包
search.algolia- 防护破坏性的 Algolia 操作,例如删除索引、清除文档、移除规则/同义词和删除 API 密钥。search.elasticsearch- 防护破坏性的 Elasticsearch REST API 操作,例如删除索引、按查询删除、关闭索引和更改集群设置。search.meilisearch- 防护破坏性的 Meilisearch REST API 操作,例如删除索引、文档、批量删除和移除 API 密钥。search.opensearch- 防护破坏性的 OpenSearch REST API 操作以及 AWS CLI 的域删除操作。
备份防护包
backup.borg- 防护破坏性的 borg 操作,例如删除、修剪、压缩和重建。backup.rclone- 防护破坏性的 rclone 操作,例如同步、删除、清理、去重和移动。backup.restic- 防护破坏性的 restic 操作,例如忘记快照、修剪数据、移除密钥和清理缓存。backup.velero- 防护破坏性的 velero 操作,例如删除备份、计划和位置。
其他防护包
package_managers- 防护危险的包管理操作,例如发布软件包和移除关键系统包。strict_git- 更严格的 Git 保护:阻止所有强制推送、变基和重写历史的操作。
在 ~/.config/dcg/config.toml 中启用防护包:
[packs]
enabled = [
# 数据库
"database.postgresql",
"database.redis",
"database.supabase",
# 容器与编排
"containers.docker",
"kubernetes", # 启用所有 Kubernetes 子防护包
# 云服务提供商
"cloud.aws",
"cloud.gcp",
# 秘密管理
"secrets.aws_secrets",
"secrets.vault",
# CI/CD
"cicd.jenkins",
"cicd.gitlab_ci",
# 消息队列
"messaging.kafka",
"messaging.sqs_sns",
# 搜索引擎
"search.elasticsearch",
# 备份
"backup.restic",
# 平台
"platform.github",
# 监控
"monitoring.splunk",
]
自定义防护包
使用 YAML 文件创建您组织特定的安全防护包。自定义防护包允许您为内部工具、部署脚本和专有系统定义模式,而无需修改 dcg。
[packs]
custom_paths = [
"~/.config/dcg/packs/*.yaml", # 用户防护包
".dcg/packs/*.yaml", # 项目本地防护包
]
有关详细的防护包编写指南、模式参考和示例,请参阅 docs/custom-packs.md。
在部署前验证您的防护包:
dcg pack validate mypack.yaml
Heredoc 扫描配置:
[heredoc]
# 启用 Heredoc 和内联脚本(python -c、bash -c 等)的扫描。
enabled = true
# 提取超时预算(毫秒)。
timeout_ms = 50
# 提取内容的资源限制。
max_body_bytes = 1048576
max_body_lines = 10000
max_heredocs = 10
# 可选的语言过滤器(仅扫描这些语言)。留空表示“全部”。
# languages = ["python", "bash", "javascript", "typescript", "ruby", "perl", "go"]
# 优雅降级(挂钩默认为故障开放)。
fallback_on_parse_error = true
fallback_on_timeout = true
CLI 对 here-doc 扫描的覆盖选项:
--heredoc-scan/--no-heredoc-scan--heredoc-timeout <ms>--heredoc-languages <lang1,lang2,...>
Heredoc 文档:
docs/adr-001-heredoc-scanning.md(架构与设计原理)docs/patterns.md(模式编写 + 模式库)docs/security.md(威胁模型与事件响应)
Heredoc 三层架构
Heredoc 和内联脚本扫描采用一种专为性能和准确性设计的三层流水线:
命令输入
│
▼
┌─────────────────┐
│ 第一层:触发器 │ ─── 不匹配 ──► 允许(快速路径,<100μs)
│ (RegexSet) │
└────────┬────────┘
│ 匹配
▼
┌─────────────────┐
│ 第二层:提取 │ ─── 错误/超时 ──► 允许 + 回退检查
│ (<1ms) │
└────────┬────────┘
│ 成功
▼
┌─────────────────┐
│ 第三层:AST │ ─── 不匹配 ──► 允许
│ (<5ms) │ ─── 匹配 ──► 阻止
└─────────────────┘
第一层:触发检测 (<100μs)
超快速正则表达式筛选,用于检测 heredoc 标志。使用编译后的 RegexSet 对所有触发模式进行 O(n) 同时匹配:
static HEREDOC_TRIGGERS: LazyLock<RegexSet> = LazyLock::new(|| {
RegexSet::new([
r"<<-?\s*(?:['\x22][^'\x22]*['\x22]|[\w.-]+)", // Heredocs
r"<<<", // Here-strings
r"\bpython[0-9.]*\b.*\s+-[A-Za-z]*[ce]", // python -c/-e
r"\bruby[0-9.]*\b.*\s+-[A-Za-z]*e", // ruby -e
r"\bnode(js)?[0-9.]*\b.*\s+-[A-Za-z]*[ep]", // node -e/-p
r"\b(sh|bash|zsh)\b.*\s+-[A-Za-z]*c", // bash -c
// ... 更多模式
])
});
不包含任何触发模式的命令会直接进入允许状态——无需进一步处理。
第二层:内容提取 (<1ms)
对于触发了检测的命令,提取实际需要评估的内容:
- Heredocs:
cat <<EOF ... EOF→ 提取分隔符之间的主体内容 - Here-strings:
cat <<< "content"→ 提取引号内的内容 - 内联脚本:
python -c "code"→ 提取代码参数
提取过程受可配置限制约束:
- 最大主体大小(默认:1MB)
- 最大行数(默认:10,000)
- 每个命令的最大 heredoc 数量(默认:10)
- 超时时间(默认:50ms)
pub struct ExtractionLimits {
pub max_body_bytes: usize,
pub max_body_lines: usize,
pub max_heredocs: usize,
pub timeout_ms: u64,
}
第三层:AST 模式匹配 (<5ms)
提取的内容使用语言特定的 AST 语法树解析器(通过 tree-sitter/ast-grep)进行解析,并与结构化模式进行匹配:
// 示例:检测 subprocess.run 且 shell=True 并执行 rm -rf
let pattern = r#"
call_expression {
function: attribute { object: "subprocess" attr: "run" }
arguments: argument_list {
contains string { contains "rm -rf" }
contains keyword_argument { keyword: "shell" value: "True" }
}
}
"#;
递归 Shell 分析:
当提取的内容本身是 Shell 脚本时(例如 bash -c "git reset --hard"),第三层会递归提取内部命令,并通过完整流水线重新评估它们:
if content.language == ScriptLanguage::Bash {
let inner_commands = extract_shell_commands(&content.content);
for inner in inner_commands {
// 将内部命令再次与所有规则包进行评估
if let Some(result) = evaluate_command(&inner, ...) {
if result.decision == Deny {
return result; // 阻止外部命令
}
}
}
}
如果您遇到应被阻止的命令,请提交问题。
环境变量
环境变量优先级高于配置文件(最高优先级):
DCG_PACKS="containers.docker,kubernetes":启用规则包(逗号分隔)DCG_DISABLE="kubernetes.helm":禁用规则包/子包(逗号分隔)DCG_VERBOSE=0-3:日志详细程度(0 = 静默,3 = 跟踪)DCG_QUIET=1:抑制非错误输出DCG_COLOR=auto|always|never:颜色模式DCG_NO_COLOR=1:禁用彩色输出(等同于 NO_COLOR)DCG_HIGH_CONTRAST=1:启用高对比度输出(ASCII 边框 + 单色调色板)DCG_FORMAT=text|json|sarif:默认输出格式(命令级别;SARIF 适用于dcg scan)DCG_BYPASS=1:完全绕过 dcg(逃生开关;谨慎使用)DCG_CONFIG=/path/to/config.toml:使用显式配置文件DCG_HEREDOC_ENABLED=true|false:启用/禁用 heredoc 扫描DCG_HEREDOC_TIMEOUT=50:heredoc 提取超时时间(毫秒)DCG_HEREDOC_TIMEOUT_MS=50:heredoc 提取超时时间(毫秒)DCG_HEREDOC_LANGUAGES=python,bash:过滤 heredoc 使用的语言DCG_POLICY_DEFAULT_MODE=deny|warn|log:全局默认决策模式DCG_HOOK_TIMEOUT_MS=200:挂钩评估超时预算(毫秒)
配置层级
dcg 支持来自多个来源的分层配置,高优先级来源会覆盖低优先级来源:
- 环境变量(DCG_* 前缀) [最高优先级]
- 显式配置文件(DCG_CONFIG 环境变量)
- 项目配置(仓库根目录下的 .dcg.toml)
- 用户配置(~/.config/dcg/config.toml)
- 系统配置(/etc/dcg/config.toml)
- 编译默认值 [最低优先级]
无障碍与主题
dcg 支持色盲友好配色方案和高对比度输出。颜色始终与符号/标签搭配使用,以避免仅通过颜色传达含义。
[output]
high_contrast = true # ASCII 边框 + 黑白配色方案
[theme]
palette = "colorblind" # 默认 | 色盲友好 | 高对比度
use_unicode = true # false 表示仅使用 ASCII 字符
use_color = true # false 表示单色输出
配置文件位置:
| 层级 | 路径 | 使用场景 |
|---|---|---|
| 系统 | /etc/dcg/config.toml |
组织范围的默认设置 |
| 用户 | ~/.config/dcg/config.toml |
个人偏好 |
| 项目 | .dcg.toml(仓库根目录) |
项目特定设置 |
| 显式指定 | DCG_CONFIG=/path/to/file |
测试或覆盖 |
合并行为:
配置层按优先级逐层叠加,高优先级来源会覆盖低优先级中的特定字段:
// 只有高优先级配置中显式设置的字段才会覆盖
// 缺失的字段将保留来自低优先级源的值
fn merge_layer(&mut self, other: ConfigLayer) {
if let Some(verbose) = other.general.verbose {
self.general.verbose = verbose; // 如果存在则覆盖
}
// 未设置的字段将保留之前的值
}
这意味着你可以在 /etc/dcg/config.toml 中设置组织默认值,在 ~/.config/dcg/config.toml 中设置个人偏好,并在 .dcg.toml 中为项目设置特定覆盖——每一层只需指定与默认不同的设置即可。
项目特定包配置:
[projects] 部分允许为不同仓库配置不同的包集合:
[projects."/home/user/work/production-api"]
packs = { enabled = ["database.postgresql", "cloud.aws"], disabled = [] }
[projects."/home/user/personal/experiments"]
packs = { enabled = [], disabled = ["core.git"] } # 更宽松的实验环境
宕机开放理念
dcg 采用 宕机开放 的设计理念:当工具因超时、解析错误或资源限制而无法安全分析命令时,它会允许命令继续执行,而不是阻止命令并中断用户的流程。
为什么是宕机开放?
- 流程连续性:被阻塞的合法命令比漏掉的危险命令更具破坏性。
- 性能保障:钩子绝不能成为瓶颈。
- 优雅降级:部分分析总比完全不分析好。
宕机开放场景:
| 场景 | 行为 | 理由 |
|---|---|---|
| Heredoc 解析错误 | 允许执行 + 警告 | 格式错误的输入不应阻断工作 |
| 提取超时 | 允许执行 + 警告 | 慢速输入不应卡住终端 |
| 文件大小超出限制 | 允许执行 + 回退检查 | 大文件只进行简化分析 |
| 正则引擎超时 | 允许执行 + 警告 | 极端模式不应阻塞 |
| AST 匹配错误 | 跳过该 Heredoc | 继续评估其他内容 |
| 截止时间超时 | 立即允许执行 | 硬性上限防止处理失控 |
可配置的严格程度:
对于高安全性环境,可以禁用宕机开放模式:
[heredoc]
fallback_on_parse_error = false # 解析错误时阻断
fallback_on_timeout = false # 超时时阻断
启用严格模式后,dcg 将在分析失败时阻断命令,并提供详细的错误信息说明原因。
回退模式检查:
即使跳过了完整分析,dcg 仍会针对关键的破坏性模式执行轻量级回退检查:
static FALLBACK_PATTERNS: LazyLock<RegexSet> = LazyLock::new(|| {
RegexSet::new([
r"shutil\.rmtree",
r"os\.remove",
r"fs\.rmSync",
r"\brm\s+-[a-zA-Z]*r[a-zA-Z]*f",
r"\bgit\s+reset\s+--hard\b",
// ... 其他关键模式
])
});
这确保了即使是过大或格式错误的输入,在被允许执行之前,也会被检查是否存在最危险的操作。
绝对超时机制:
为防止任何单个命令无限期阻塞,dcg 强制执行 200ms 的绝对最大处理时间。超过此阈值的命令将立即被允许执行,并记录警告日志。
安装
快速安装(推荐)
最简单的安装方式是使用安装脚本,它会为您的平台下载预编译的二进制文件:
curl -fsSL "https://raw.githubusercontent.com/Dicklesworthstone/destructive_command_guard/main/install.sh?$(date +%s)" | bash -s -- --easy-mode
简易模式会自动检测您的平台、下载正确的二进制文件、验证 SHA256 校验和、配置所有支持的 AI 代理钩子(Claude Code、Gemini CLI、Copilot CLI、Aider、Codex CLI),并更新您的 PATH。
其他选项:
交互式模式(每一步都会提示):
curl -fsSL "https://raw.githubusercontent.com/Dicklesworthstone/destructive_command_guard/main/install.sh?$(date +%s)" | bash
安装特定版本:
curl -fsSL "https://raw.githubusercontent.com/Dicklesworthstone/destructive_command_guard/main/install.sh?$(date +%s)" | bash -s -- --version v0.1.0
安装到 /usr/local/bin(系统范围,需要 sudo):
curl -fsSL "https://raw.githubusercontent.com/Dicklesworthstone/destructive_command_guard/main/install.sh?$(date +%s)" | sudo bash -s -- --system
从源码构建而不是下载二进制文件:
curl -fsSL "https://raw.githubusercontent.com/Dicklesworthstone/destructive_command_guard/main/install.sh?$(date +%s)" | bash -s -- --from-source
仅下载/安装(跳过代理钩子配置):
curl -fsSL "https://raw.githubusercontent.com/Dicklesworthstone/destructive_command_guard/main/install.sh?$(date +%s)" | bash -s -- --no-configure
注意: 如果您已安装 gum,安装程序将使用它来进行精美的终端格式化。
安装程序还会在可用时验证 Sigstore cosign 包(如果不可用则回退到仅校验和验证),如果没有预编译的二进制文件,则回退到从源码构建,并在存在时移除旧版 Python 前身(git_safety_guard.py)。
各代理特有说明
- Aider: 不提供 PreToolUse 风格的拦截功能。安装程序会在
~/.aider.conf.yml中启用git-commit-verify: true,以便运行 Git 钩子。要获得全面保护,请将 dcg 安装为 Git pre-commit 钩子。 - Continue: 没有拦截 Shell 命令的钩子。安装程序可以检测到 Continue,但无法自动配置保护。请改用 Git pre-commit 钩子。
- Codex CLI: 实验性 PreToolUse 钩子通过
~/.codex/hooks.json实现。其数据格式与 Claude Code 兼容。需要注意的是,该模型可以将脚本写入磁盘以绕过基于钩子的阻止机制。 - GitHub Copilot CLI: 钩子是仓库本地的(
.github/hooks/*.json)。请在您希望获得保护的每个仓库中运行安装程序。 - OpenCode: 不会自动配置。需要一个基于 Bun 的插件,其中包含
"tool.execute.before"钩子键。一个可用的社区插件:aspiers/ai-config/dcg-guard.js。
推荐: 安装后,请运行
dcg setup来添加一个 Shell 启动检查,它会在 dcg 钩子被悄无声息地从~/.claude/settings.json中移除时向您发出警告。
从源码构建(需要 Rust nightly)
该项目使用了 Rust 2024 版本的特性,因此需要 nightly 工具链。仓库中包含一个 rust-toolchain.toml 文件,可自动选择正确的工具链。
# 如果您还没有 Rust nightly,请安装
rustup install nightly
# 直接从 GitHub 安装(由于工作区结构,需要指定包名)
cargo +nightly install --git https://github.com/Dicklesworthstone/destructive_command_guard destructive_command_guard
手动构建
git clone https://github.com/Dicklesworthstone/destructive_command_guard
cd destructive_command_guard
# rust-toolchain.toml 会自动选择 nightly
cargo build --release
cp target/release/dcg ~/.local/bin/
更新
运行内置的更新程序以重新为您的平台运行安装程序:
dcg update
可选标志与安装脚本相同(示例):
dcg update --version v0.2.7
dcg update --system
dcg update --verify
如果您更喜欢,也可以直接重新运行 install.sh 或 install.ps1。
预编译二进制文件
预编译的二进制文件适用于以下平台:
- Linux x86_64 (
x86_64-unknown-linux-gnu) - Linux ARM64 (
aarch64-unknown-linux-gnu) - macOS Intel (
x86_64-apple-darwin) - macOS Apple Silicon (
aarch64-apple-darwin) - Windows (
x86_64-pc-windows-msvc)
请从 GitHub Releases 下载,并验证 SHA256 校验和。如果您已安装 cosign,每个发布还包含一个 Sigstore 包(.sigstore.json),您可以使用 cosign verify-blob 来验证来源。
卸载
移除 dcg 及其在各 AI 代理中的所有钩子:
curl -fsSL https://raw.githubusercontent.com/Dicklesworthstone/destructive_command_guard/main/uninstall.sh | bash
卸载程序会:
- 从 Claude Code、Gemini CLI、GitHub Copilot CLI(仓库本地)和 Aider 中移除 dcg 钩子
- 移除 dcg 二进制文件
- 移除配置文件(
~/.config/dcg/)和历史记录(~/.local/share/dcg/) - 在进行更改前提示确认
选项:
--yes- 跳过确认提示--keep-config- 保留配置文件--keep-history- 保留历史数据库--purge- 删除所有内容(覆盖保留选项)
Claude Code 配置
在 ~/.claude/settings.json 中添加以下内容:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "dcg"
}
]
}
]
}
}
重要提示: 添加钩子配置后,请重启 Claude Code。
Gemini CLI 配置
在 ~/.gemini/settings.json 中添加以下内容:
{
"hooks": {
"BeforeTool": [
{
"matcher": "run_shell_command",
"hooks": [
{
"name": "dcg",
"type": "command",
"command": "dcg",
"timeout": 5000
}
]
}
]
}
}
重要提示: 添加钩子配置后,请重启 Gemini CLI。
CLI 使用方法
虽然主要设计为钩子,但该二进制文件也支持直接调用,用于测试、调试以及了解命令为何被阻止或允许。
# 显示版本及构建元数据
dcg --version
# 显示帮助信息及被阻止的命令类别
dcg --help
# 手动测试命令(将 JSON 通过管道输入到标准输入)
echo '{"tool_name":"Bash","tool_input":{"command":"git reset --hard"}}' | dcg
测试模式 (dcg test)
使用 dcg test 可以评估命令 而不实际执行。这对于 CI 检查、误报调试以及上线前的配置验证非常有用。
基本用法
# 基本评估(人类可读的输出)
dcg test "rm -rf ./build"
# 面向自动化的结构化输出
dcg test --format json "kubectl delete namespace prod" | jq -r .decision
# 使用特定的配置文件
dcg test --config .dcg.prod.toml "docker system prune"
# 仅在此测试运行中临时启用额外的包
dcg test --with-packs containers.docker,database.postgresql "docker system prune"
# 打印完整的评估轨迹(与 `dcg explain` 使用相同的引擎)
dcg test --explain "git reset --hard"
退出码
0: 命令将被允许1: 命令将被阻止
标志和选项
-c, --config <PATH>: 使用特定的配置文件--with-packs <ID1,ID2>: 临时启用额外的包--explain: 打印详细的决策轨迹-f, --format <pretty|json|toon>: 输出格式(默认:pretty)--no-color: 禁用 ANSI 颜色输出--heredoc-scan: 强制启用 heredoc/内联脚本扫描--no-heredoc-scan: 强制禁用 heredoc/内联脚本扫描--heredoc-timeout <MS>: 覆盖 heredoc 提取超时预算--heredoc-languages <LANG1,LANG2>: 限制 heredoc AST 扫描的语言
输出格式
pretty: 人类可读的输出,包含命令上下文、匹配规则信息和建议json: 用于脚本/CI 的结构化负载;包括元数据,如schema_version、dcg_version、command、decision、规则/包字段,以及在存在时的白名单/代理上下文toon: 与json相同负载的令牌高效结构化编码(适用于代理间/工具流水线)
CI/CD 集成示例
在 Shell 流水线中快速失败:
dcg test --format json "rm -rf /" > /tmp/dcg.json
jq -e '.decision == "allow"' /tmp/dcg.json
GitHub Actions 的最小步骤:
- name: 验证危险命令策略
run: |
~/.local/bin/dcg test --format json "git reset --hard HEAD~1" > /tmp/dcg-test.json
jq -e '.decision == "allow"' /tmp/dcg-test.json
故障排除
- 使用
--format json(或DCG_FORMAT=json)以便机器解析。 - 如果日志或解析器因 ANSI 输出而卡住,请添加
--no-color。 - 如果不同环境的结果不一致,请检查配置优先级(
DCG_CONFIG、项目.dcg.toml、用户/系统配置)。 - 如果命令意外被允许,请检查当前生效的白名单(
dcg allowlist list)和已启用的包(dcg packs --verbose)。 - 若要获取完整的决策轨迹,请运行
dcg test --explain "<command>"(或dcg explain "<command>")。
解释模式
当您需要确切了解为何某条命令被阻止(或允许)时,dcg explain 命令会提供详细的决策过程跟踪:
# 解释为什么一条命令会被阻止
dcg explain "git reset --hard HEAD"
# 解释一条安全的命令
dcg explain "git status"
# 带有详细计时信息的解释
dcg explain --verbose "rm -rf /tmp/build"
# 以 JSON 格式输出,供程序使用
dcg explain --format json "kubectl delete namespace production"
JSON 输出通过 schema_version 进行版本控制(当前为 2)。v2 在检测到模式时,在 match 对象中增加了 matched_span、matched_text_preview 和 explanation。
示例输出:
命令: git reset --hard HEAD
规范化: git reset --hard HEAD
决定: 被阻止
包: core.git
规则: reset-hard
原因: git reset --hard 会破坏未提交的更改
评估轨迹:
[ 0.8μs] 快速拒绝:通过(包含 'git')
[ 2.1μs] 规范化:无变化
[ 5.3μs] 安全模式:未匹配(检查了 34 种模式)
[ 12.7μs] 破坏性模式:匹配模式 'reset-hard'
[ 12.9μs] 总耗时:12.9μs
建议:请先使用 'git stash' 保存您的更改。
解释模式会显示:
- 规范化后的命令:dcg 在路径规范化后如何看待该命令
- 决定:该命令是会被阻止还是允许
- 匹配的规则:触发该决定的是哪个包和模式
- 评估轨迹:每个评估阶段的逐步计时
- 建议:关于更安全替代方案的可操作指导
这对于调试误报、理解包的覆盖范围以及验证自定义白名单条目是否按预期工作非常有用。
一次性允许(临时例外)
有时您需要临时执行一条被阻止的命令,而无需永久修改白名单。一次性允许系统提供了短代码:
# 当一条命令被阻止时,dcg 会输出一个短代码
# 被阻止:git reset --hard HEAD
# 一次性允许代码:ab12
# 要允许此命令:dcg allow-once ab12
# 使用短代码创建临时例外
dcg allow-once ab12
# 或者使用 --single-use 使例外成为一次性的
dcg allow-once ab12 --single-use
一次性允许的工作原理:
- 当 dcg 阻止一条命令时,它会生成一个短代码(目前为 4 个十六进制字符;冲突可通过
--pick/--hash处理) - 该代码与被阻止的精确命令相关联
- 运行
dcg allow-once <code>会创建一个临时例外 - 例外存储在
~/.config/dcg/pending_exceptions.jsonl中 - 例外在 24 小时后过期(或如果使用了
--single-use,则在首次使用后过期) - 在有效期内,该例外允许在同一目录范围内执行相同的命令。
此工作流程适用于:
- 一次性且有意破坏性的管理操作
- 需要重置状态的迁移脚本
- 不适合进行永久性白名单更改的紧急修复
安全注意事项:
- 短代码由 SHA256(或在设置
DCG_ALLOW_ONCE_SECRET时使用 HMAC-SHA256)生成 - 代码绝不会被记录或传输
- 待处理例外文件仅对当前用户可读
- 过期的代码会自动清理。
--version 输出包含用于调试的构建元数据:
dcg 0.1.0
构建日期:2026-01-07T22:13:10.413872881Z
Rustc 版本:1.94.0-nightly
目标平台:x86_64-unknown-linux-gnu
这些元数据在编译时通过 vergen 嵌入,便于在故障排除时准确识别正在运行的构建版本。
仓库扫描
虽然挂钩保护的是交互式命令执行,但团队还需要防止那些被提交到仓库中的破坏性命令。dcg scan 命令可以从文件中提取可执行的命令上下文,并使用相同的模式引擎对其进行评估。
扫描是什么(以及不是什么)
它是:
- 基于提取器的扫描器,能够理解可执行上下文
- 使用与挂钩模式相同的评估器,以确保一致性
- 支持 CI 集成和预提交钩子
它不是:
- 一种在任何地方简单匹配字符串的 grep 工具
- 代码审查的替代品
- 用于任意语言的静态分析工具
与 grep 的关键区别在于:dcg scan 知道注释中的 "rm -rf /" 是数据,而不是代码。它使用能够理解文件结构的提取器(Shell 脚本、Dockerfile、GitHub Actions、Makefile),只查找实际被执行的命令。
支持的文件格式
dcg scan 为每种文件格式配备了专门的提取器,能够识别哪些部分包含可执行命令:
| 文件类型 | 检测模式 | 可执行上下文 |
|---|---|---|
| Shell 脚本 | *.sh、*.bash、*.zsh |
所有非注释、非赋值的行 |
| Dockerfile | Dockerfile、*.dockerfile |
RUN 指令(shell 和 exec 形式) |
| GitHub Actions | .github/workflows/*.yml |
步骤中的 run: 字段 |
| GitLab CI | .gitlab-ci.yml |
script:、before_script:、after_script: |
| Makefile | Makefile |
以制表符缩进的配方行 |
| Terraform | *.tf |
provisioner 块(local-exec、remote-exec) |
| Docker Compose | docker-compose.yml、compose.yml |
command: 和 entrypoint: 字段 |
上下文感知提取:
每个提取器都理解其对应格式的语义:
# GitHub Actions - 仅提取 'run:'
- name: Build
run: | # ← 提取
npm install
npm run build
env:
NODE_ENV: production # ← 跳过(非可执行)
# Dockerfile - 仅提取 RUN 指令
FROM node:18
COPY . /app # ← 跳过
RUN npm install # ← 提取
RUN ["node", "server.js"] # ← 提取(exec 形式)
ENV PORT=3000 # ← 跳过
# Makefile - 目标下的制表符缩进行
build:
npm install # ← 提取(配方行)
npm run build # ← 提取
SOURCES = $(wildcard *.js) # ← 跳过(变量赋值)
非可执行上下文过滤:
提取器会智能地跳过仅用于数据的部分:
- Shell:仅赋值的行(
export VAR=value) - YAML:
environment:、labels:、volumes:、variables:块 - Terraform:所有不在
provisioner块内的内容 - 所有格式:注释(根据格式使用
#、//等)
快速入门
# 安装 pre-commit 钩子
dcg scan install-pre-commit
# 或手动对暂存文件运行
dcg scan --staged
# 扫描特定路径
dcg scan --paths scripts/ .github/workflows/
推荐部署计划
从保守开始,避免开发者抵触:
# 第 1–2 周:先警告,范围较小
dcg scan --staged --fail-on error # 仅在严重规则时失败
创建 .dcg/hooks.toml 文件,设置保守默认值:
[scan]
fail_on = "error" # 仅在高置信度的严重规则时失败
format = "pretty" # 人类可读的输出
redact = "quoted" # 隐藏敏感字符串
truncate = 120 # 缩短过长命令
[scan.paths]
include = [
".github/workflows/**", # 从 CI 配置开始
"Dockerfile", # 容器构建
"Makefile", # 构建脚本
]
exclude = [
"target/**",
"node_modules/**",
"vendor/**",
]
逐步扩展:
- 第 1–2 周:仅扫描工作流和 Dockerfile,设置
--fail-on error - 第 3–4 周:添加 Makefile 和
scripts/中的 Shell 脚本 - 第 2 个月:审查结果后启用
--fail-on warning - 持续进行:随着团队信心增强,逐步添加新的提取器
Pre-commit 集成
一键安装
dcg scan install-pre-commit
这将创建一个 .git/hooks/pre-commit 文件,自动运行 dcg scan --staged。
手动设置
如果您更倾向于手动控制或使用钩子管理工具:
#!/bin/bash
# .git/hooks/pre-commit(或您使用的钩子管理工具的等效位置)
set -e
# 对暂存文件运行 dcg scan
dcg scan --staged --fail-on error
# 在下方添加其他钩子...
卸载
dcg scan uninstall-pre-commit
此命令仅移除由 dcg 安装的钩子(通过哨兵注释检测)。
结果解读
输出示例如下:
scripts/deploy.sh:42:5: [ERROR] core.git:reset-hard
命令:git reset --hard HEAD
原因:git reset --hard 会丢弃未提交的更改
建议:建议先使用 'git stash' 保存更改。
- 文件:行:列:源文件中的位置
- 严重程度:
ERROR(严重)或WARNING(需关注) - 规则 ID:稳定的标识符,如
core.git:reset-hard - 命令:提取的命令(可能被遮蔽或截断)
- 原因:为何该命令被标记
- 建议:如何使其更安全
修复发现的问题
选项 1:修改代码(推荐)
用更安全的替代方案替换危险命令:
# 替换:
git reset --hard
# 使用:
git stash push -m "before reset"
git reset --hard
选项 2:获取解释
获取详细分析:
dcg explain "git reset --hard HEAD"
选项 3:白名单(当确属有意时)
如果确实需要该命令:
# 项目级白名单(已提交并经过代码评审)
dcg allowlist add core.git:reset-hard --reason "用于 CI 清理" --project
# 或针对特定命令
dcg allowlist add-command "rm -rf ./build" --reason "构建清理" --project
结果输出中会附带方便复制粘贴的白名单命令。Heredoc 规则使用稳定 ID,如 heredoc.python.shutil_rmtree。
隐私与脱敏处理
扫描支持对输出中潜在敏感内容进行脱敏处理。使用 --redact quoted 可隐藏可能包含密钥的引号字符串:
# 原始命令:
curl -H "Authorization: Bearer $TOKEN" https://api.example.com
# 使用 --redact quoted 后:
curl -H "..." https://api.example.com
选项:
--redact none:显示完整命令(默认)--redact quoted:隐藏引号中的内容(推荐用于 CI 日志)--redact aggressive:隐藏更多潜在机密
配置参考
.dcg/hooks.toml(项目级,需提交):
[scan]
# 当发现的问题达到此阈值时退出非零状态
fail_on = "error" # 选项:none、warning、error
# 输出格式
format = "pretty" # 选项:pretty、json、markdown
# 最大扫描文件大小(字节)
max_file_size = 1000000
# 发现问题数量达到此上限后停止扫描
max_findings = 50
# 敏感内容的脱敏级别
redact = "quoted" # 选项:none、quoted、aggressive
# 截断过长命令(字符数;0 表示不截断)
truncate = 120
[scan.paths]
# 仅扫描匹配这些模式的文件
include = [
"scripts/**",
".github/workflows/**",
"Dockerfile*",
"Makefile",
]
# 跳过匹配这些模式的文件
exclude = [
"target/**",
"node_modules/**",
"*.md",
]
CLI 标志会覆盖配置文件中的值。
CI 集成
GitHub Actions
name: 安全扫描
on: [pull_request]
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: 安装 dcg
run: |
curl -fsSL "https://raw.githubusercontent.com/Dicklesworthstone/destructive_command_guard/main/install.sh" | bash
echo "$HOME/.local/bin" >> $GITHUB_PATH
- name: 扫描已更改文件
run: |
dcg scan --git-diff origin/${{ github.base_ref }}..HEAD \
--format markdown \
--fail-on error
GitLab CI
scan:
stage: test
script:
- curl -fsSL "https://raw.githubusercontent.com/Dicklesworthstone/destructive_command_guard/main/install.sh" | bash
- ~/.local/bin/dcg scan --git-diff origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME..HEAD --fail-on error
rules:
- if: $CI_MERGE_REQUEST_ID
紧急情况下的绕过
如果您需要临时绕过 pre-commit 钩子:
git commit --no-verify -m "紧急修复"
这会在 git 历史中被记录并可见。对于永久性的例外,建议使用白名单。
工作原理
您的 AI 代理在执行每个 shell 命令之前,会作为 PreToolUse 钩子调用 dcg。该钩子从标准输入接收命令的 JSON 数据,并通过一个四阶段的流程进行处理:
- JSON 解析 -- 验证钩子负载(Claude/Gemini/Copilot 变体),提取命令字符串。非 shell 工具会被立即允许。
- 规范化 -- 去除绝对路径(
/usr/bin/git变为git),同时保留参数。 - 快速拒绝 -- 使用 O(n) 子字符串搜索查找如“git”或“rm”等关键字。不包含这些子字符串的命令将完全跳过正则表达式匹配(可处理 99% 以上的非破坏性命令)。
- 模式匹配 -- 首先检查安全模式(匹配即允许)。其次检查破坏性模式(匹配即拒绝,并给出解释)。两者均未匹配则允许。
如果被阻止,dcg 会在标准输出上输出 JSON 拒绝信息,并在标准错误上显示彩色的人类可读警告。如果被允许,dcg 将静默退出(无输出)。当标准错误不是 TTY 时,颜色功能会自动禁用。
架构
┌─────────────────────────────────────────────────────────────────┐
│ Claude Code / Gemini CLI / Copilot CLI │
│ │
│ 用户: “删除构建产物” │
│ 代理: 执行 `rm -rf ./build` │
│ │
└─────────────────────┬───────────────────────────────────────────┘
│
▼ PreToolUse 钩子(标准输入:JSON)
┌─────────────────────────────────────────────────────────────────┐
│ dcg │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ 解析 │───▶│ 规范化 │───▶│ 快速拒绝 │ │
│ │ JSON │ │ 命令 │ │ 过滤 │ │
│ └──────────────┘ └──────────────┘ └──────┬───────┘ │
│ │ │
│ ┌───────────────────────────┘ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ 模式匹配 │ │
│ │ │ │
│ │ 1. 检查 SAFE_PATTERNS(白名单) ──▶ 匹配则允许 │ │
│ │ 2. 检查 DESTRUCTIVE_PATTERNS ──────▶ 匹配则拒绝 │ │
│ │ 3. 无匹配 ────────────────────────▶ 允许(默认) │ │
│ │ │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────┬───────────────────────────────────────────┘
│
▼ 标准输出:JSON(拒绝)或空(允许)
┌─────────────────────────────────────────────────────────────────┐
│ Claude Code / Gemini CLI / Copilot CLI │
│ │
│ 如果被拒绝:显示阻止消息,不会执行命令 │
│ 如果被允许:继续执行命令 │
│ │
└─────────────────────────────────────────────────────────────────┘
上下文分类系统
并非每次出现危险模式都真正具有危险性。字符串 git reset --hard 出现在注释、heredoc 文本块或引号内的情况,与它作为实际执行的命令完全不同。dcg 使用一套复杂的上下文分类系统来减少误报,同时不降低安全性。
SpanKind 分类
命令中的每个标记都会被归入以下类别之一:
| SpanKind | 描述 | 处理方式 |
|---|---|---|
Executed |
命令词和未加引号的参数 | 必须检查 - 最高优先级 |
InlineCode |
-c/-e 标志内的内容(bash -c、python -c) |
必须检查 - 代码将被执行 |
Argument |
已知安全命令的带引号参数 | 优先级较低,视具体情况而定 |
Data |
单引号字符串(shell 无法进行变量替换) | 可以跳过 - 被视为字面数据 |
HeredocBody |
heredoc 内部的内容 | 提升到第 2/3 层的 heredoc 扫描 |
Comment |
Shell 注释 (# ...) |
跳过 - 永远不会执行 |
Unknown |
无法确定上下文 | 保守地按 Executed 处理 |
为什么上下文很重要
考虑以下命令:
# 安全:危险模式出现在注释中
echo "提醒:切勿运行 git reset --hard" # git reset --hard 会丢失更改
# 安全:危险模式是用于搜索的数据
grep "git reset --hard" documentation.md
# 安全:危险模式出现在写入文件的 heredoc 中
cat <<EOF > safety_guide.md
警告:git reset --hard 会丢失未提交的更改
EOF
# 危险:该模式将被执行
git reset --hard HEAD
# 危险:该模式被传递给 bash -c 以执行
bash -c "git reset --hard"
如果没有上下文分类,前三个示例都会触发误报。上下文分类器会分析 AST(抽象语法树)结构,以了解模式出现的位置,并仅标记真正危险的情况。
实现细节
上下文分类器采用多轮处理方法:
- 词法分析:识别带引号的字符串、注释和 here document 标记
- 结构分析:构建命令结构树,识别管道、子 shell 和命令替换
- 标志分析:检测
-c、-e等引入内联代码上下文的标志 - 范围标注:为每个字符范围打上其 SpanKind 标签
这种方法在保持对实际命令执行零假阴性原则的同时,显著减少了误报。
设计原则
1. 白名单优先架构
安全模式会在破坏性模式之前进行检查。这种设计确保了明确安全的命令(如 git checkout -b)绝不会被意外阻止,即使它们部分匹配破坏性模式(如 git checkout)。
git checkout -b feature → 匹配 SAFE “checkout-new-branch” → 允许
git checkout -- file.txt → 没有安全匹配,匹配 DESTRUCTIVE → 拒绝
2. 安全默认策略
该钩子对未识别的命令采用默认允许策略。这确保:
- 钩子绝不会中断合法的工作流程
- 只有已知的危险模式会被阻止
- 新的 git 命令在被明确分类之前都会被允许
3. 零假阴性原则
模式集合优先考虑绝不允许危险命令,而不是避免误报。偶尔多几次手动确认提示是可以接受的;而丢失工作则是不可接受的。
4. 多层防御
此钩子只是一层保护措施。它与以下内容相辅而行(而非替代):
- 定期提交和推送
- 在执行风险操作前使用 Git stash
- 合理的备份策略
- 代码审查流程
5. 最小化延迟
所有 Bash 命令都会经过此钩子。性能至关重要:
- 惰性初始化的静态正则表达式模式(编译一次,重复使用)
- 快速拒绝过滤器可在正则表达式之前排除 99% 以上的命令
- 对于安全命令,在关键路径上不进行堆分配
- 对于典型命令,执行时间小于一毫秒
模式匹配系统
安全模式(白名单)
安全模式列表包含 34 种模式,涵盖以下类别:
| 类别 | 模式 | 目的 |
|---|---|---|
| 分支创建 | checkout -b, checkout --orphan |
创建分支是安全的 |
| 仅暂存 | restore --staged, restore -S |
取消暂存不会影响工作区 |
| 干运行 | clean -n, clean --dry-run |
预览模式,不会实际删除文件 |
| 临时清理 | rm -rf /tmp/*, rm -rf /var/tmp/* |
临时目录是安全的 |
| 变量扩展 | rm -rf $TMPDIR/*, rm -rf ${TMPDIR}/* |
Shell 变量形式 |
| 引用路径 | rm -rf "$TMPDIR/*" |
引用变量的形式 |
| 分开的标志 | rm -r -f /tmp/*, rm -r -f $TMPDIR/* |
标志顺序的不同变体 |
| 长选项 | rm --recursive --force /tmp/*, $TMPDIR/* |
GNU 风格的长选项 |
破坏性模式(黑名单)
破坏性模式列表包含 16 种模式,涵盖以下类别:
| 类别 | 模式 | 原因 |
|---|---|---|
| 破坏工作区 | reset --hard, reset --merge |
销毁未提交的更改 |
| 文件回滚 | checkout -- <path> |
丢弃文件修改 |
| 恢复工作区 | restore(无 --staged) |
丢弃未提交的更改 |
| 删除未跟踪文件 | clean -f |
永久删除未跟踪文件 |
| 重写历史记录 | push --force, push -f |
可能会破坏远程提交 |
| 不安全删除分支 | branch -D |
强制删除而不检查合并 |
| 销毁 Stash | stash drop, stash clear |
永久删除暂存的工作 |
| 文件系统清除 | rm -rf(非临时路径) |
递归删除临时目录之外的内容 |
模式语法
模式使用 fancy-regex 来实现高级功能:
// 负向前瞻:阻止 restore,除非存在 --staged
r"git\s+restore\s+(?!--staged\b)(?!-S\b)"
// 负向前瞻:不匹配 --force-with-lease
r"git\s+push\s+.*--force(?![-a-z])"
// 字符类:匹配任意标志顺序
r"rm\s+-[a-zA-Z]*[rR][a-zA-Z]*f[a-zA-Z]*"
处理的边缘情况
路径规范化
命令可能会使用二进制文件的绝对路径:
/usr/bin/git reset --hard # 被阻止 ✓
/usr/local/bin/git checkout -- . # 被阻止 ✓
/bin/rm -rf /home/user # 被阻止 ✓
规范化器使用正则表达式来剥离路径,同时保留参数:
git add /usr/bin/something # “/usr/bin/something” 是参数,被保留
标志顺序变体
rm 命令可以以多种方式接受标志:
rm -rf /path # 组合标志
rm -fr /path # 顺序颠倒
rm -r -f /path # 分开的标志
rm -f -r /path # 分开且顺序颠倒
rm --recursive --force /path # 长选项
rm --force --recursive /path # 长选项,顺序颠倒
rm -rf --no-preserve-root / # 额外的标志
所有变体都由灵活的正则表达式模式处理。
Shell 变量扩展
临时目录变量有多种形式:
rm -rf $TMPDIR/build # 未加引号,简单形式
rm -rf ${TMPDIR}/build # 未加引号,带大括号
rm -rf "$TMPDIR/build" # 加引号,简单形式
rm -rf "${TMPDIR}/build" # 加引号,带大括号
rm -rf "${TMPDIR:-/tmp}/build" # 带默认值
Git 标志组合
Git 命令的标志可以出现在不同的位置:
git push --force # 被阻止 ✓
git push origin main --force # 被阻止 ✓
git push --force origin main # 被阻止 ✓
git push -f # 被阻止 ✓
git push --force-with-lease # 被允许 ✓(安全替代方案)
暂存与工作区恢复
restore 命令的安全性较为微妙:
git restore --staged file.txt # 被允许 ✓(仅取消暂存)
git restore -S file.txt # 被允许 ✓(短标志)
git restore file.txt # 被阻止(丢弃更改)
git restore --worktree file.txt # 被阻止(明确指定工作区)
git restore --staged --worktree file # 被阻止(包括工作区)
git restore -S -W file.txt # 被阻止(包括工作区)
性能优化
双正则引擎架构
dcg 使用一种复杂的双引擎正则表达式系统,能够自动为每个模式选择最优的引擎。这既保证了性能,又提供了高级的模式匹配功能。
两种引擎:
| 引擎 | Crate | 时间复杂度 | 特性 | 使用场景 |
|---|---|---|---|---|
| 线性引擎 | regex |
保证 O(n) | 基础正则、字符类、交替 | 约 85% 的模式 |
| 回溯引擎 | fancy_regex |
最坏情况 O(2^n) | 前瞻、后瞻、反向引用 | 约 15% 的模式 |
自动引擎选择:
当一个模式被编译时,dcg 会分析它以决定使用哪种引擎:
pub enum CompiledRegex {
Linear(regex::Regex), // 保证 O(n),无前瞻
Backtracking(fancy_regex::Regex), // 支持前瞻/后瞻
}
impl CompiledRegex {
pub fn new(pattern: &str) -> Result<Self, Error> {
// 首先尝试线性引擎(更快、可预测)
if let Ok(re) = regex::Regex::new(pattern) {
return Ok(CompiledRegex::Linear(re));
}
// 对于高级特性,则回退到回溯引擎
Ok(CompiledRegex::Backtracking(fancy_regex::Regex::new(pattern)?))
}
}
为什么这很重要:
- 性能可预测性:线性引擎保证 O(n) 的匹配时间,这对于每个命令都要运行的钩子来说至关重要。
- 功能完整性:某些模式需要负向前瞻(例如,“匹配
--force但不匹配--force-with-lease”)。 - 自动优化:模式作者无需考虑引擎选择——dcg 会自动选择最优方案。
引擎选择示例:
// 线性引擎(简单模式)
r"git\s+reset\s+--hard" // 不需要高级特性
// 回溯引擎(负向前瞻)
r"git\s+push\s+.*--force(?![-a-z])" // 不能后面跟 "-with-lease"
// 线性引擎(字符类)
r"rm\s+-[a-zA-Z]*[rR][a-zA-Z]*f" // 复杂但没有前瞻
性能预算系统
dcg 在严格的延迟约束下运行——每个 Bash 命令都会经过这个钩子,因此即使是微小的延迟也会累积成明显的卡顿。性能预算系统通过“失败开放”的语义来强制执行这些约束。
延迟等级:
| 等级 | 阶段 | 目标 | 警告阈值 | 惊慌阈值 |
|---|---|---|---|---|
| 0 | 快速拒绝 | < 1μs | > 10μs | > 50μs |
| 1 | 规范化 | < 5μs | > 25μs | > 100μs |
| 2 | 安全模式检查 | < 50μs | > 200μs | > 500μs |
| 3 | 破坏性模式检查 | < 50μs | > 200μs | > 500μs |
| 4 | Heredoc 提取 | < 1ms | > 5ms | > 20ms |
| 5 | Heredoc 求值 | < 2ms | > 10ms | > 30ms |
| 6 | 完整管道 | < 5ms | > 15ms | > 50ms |
失败开放行为:
如果任何阶段超过其惊慌阈值,dcg 会记录警告并 允许命令继续执行:
[WARN] 性能预算超限:第二级(安全模式)耗时 1.2ms(惊慌阈值:500μs)
[WARN] 失败开放以避免阻塞工作流程
这种设计确保:
- 恶意输入不会导致用户终端卡死。
- 性能回归会在日志中清晰可见。
- 工具永远不会成为生产力瓶颈。
预算执行:
fn check_budget(tier: Tier, elapsed: Duration) -> BudgetResult {
let budget = TIER_BUDGETS[tier];
if elapsed > budget.panic {
log::warn!("Tier {} exceeded panic threshold", tier);
return BudgetResult::FailOpen;
}
if elapsed > budget.warning {
log::warn!("Tier {} exceeded warning threshold", tier);
}
BudgetResult::Continue
}
性能监控:
使用 dcg explain --verbose 可以查看各阶段的耗时:
评估轨迹:
[ 0.3μs] 第 0 级:快速拒绝(通过——低于 1μs 目标)
[ 1.2μs] 第 1 级:规范化(通过——低于 5μs 目标)
[ 8.7μs] 第 2 级:安全模式(通过——低于 50μs 目标)
[ 15.2μs] 第 3 级:破坏性模式(通过——低于 50μs 目标)
[ 15.4μs] 总计:15.4μs(通过——低于 5ms 目标)
基于关键词的包预过滤
在进行昂贵的正则匹配之前,dcg 使用多级关键词过滤系统快速跳过无关的包。这一点对性能至关重要——由于有 49 个以上的包可用,如果对每个命令都逐一检查所有模式,将会极其缓慢。
关键词过滤的工作原理:
每个包会声明一组关键词,只有当命令中出现这些关键词时,该包才相关:
Pack {
id: "database.postgresql".to_string(),
keywords: &["psql", "dropdb", "createdb", "DROP", "TRUNCATE", "DELETE"],
// ...
}
两级过滤:
全局快速拒绝:在开始任何包的评估之前,dcg 会检查命令中是否包含任何已启用包的关键词。如果没有,则直接跳过整个包的评估。
逐包快速拒绝:对于每个已启用的包,dcg 会先检查命令中是否包含该包的任何关键词,然后再运行昂贵的正则模式。
Aho-Corasick 自动机:
对于拥有多个关键词的包,dcg 会构建一个 Aho-Corasick 自动机,能够在一次 O(n) 的遍历中匹配所有关键词:
// 在首次访问包时惰性构建
pub keyword_matcher: Option<aho_corasick::AhoCorasick>,
pub fn might_match(&self, cmd: &str) -> bool {
if self.keywords.is_empty() {
return true; // 没有关键词则始终检查模式
}
// 无论关键词数量多少,都是 O(n) 匹配
if let Some(ref ac) = self.keyword_matcher {
return ac.is_match(cmd);
}
// 回退:顺序 memchr 搜索
self.keywords.iter()
.any(|kw| memmem::find(cmd.as_bytes(), kw.as_bytes()).is_some())
}
上下文感知的关键词匹配:
关键词仅在可执行范围内匹配(不在注释、引号字符串或数据中):
pub fn pack_aware_quick_reject(cmd: &str, enabled_keywords: &[&str]) -> bool {
// 第一步:快速子串检查
let any_substring = enabled_keywords.iter()
.any(|kw| memmem::find(cmd.as_bytes(), kw.as_bytes()).is_some());
if !any_substring {
return true; // 可以跳过所有包的评估
}
// 第二步:验证关键词是否出现在可执行上下文中
let spans = classify_command(cmd);
for span in spans.executable_spans() {
if span_matches_any_keyword(span.text(cmd), enabled_keywords) {
return false; // 必须评估包
}
}
true // 关键词只出现在非可执行上下文中,可以跳过
}
这种方法确保像 echo "psql" | grep DROP 这样的命令不会因为处理的数据中出现了关键词而触发 PostgreSQL 包的评估。
1. 延迟静态初始化
正则表达式模式通过 LazyLock 在首次使用时编译一次:
static SAFE_PATTERNS: LazyLock<Vec<Pattern>> = LazyLock::new(|| {
vec![
pattern!("checkout-new-branch", r"git\s+checkout\s+-b\s+"),
// ... 还有33个模式
]
});
后续调用会复用已编译好的模式,无需任何编译开销。
2. SIMD 加速的快速拒绝
在进行任何正则匹配之前,一个基于 SIMD 的子字符串搜索会过滤掉无关的命令。memchr crate 在可用时会利用 CPU 向量指令(SSE2、AVX2、NEON):
use memchr::memmem;
static GIT_FINDER: LazyLock<memmem::Finder<'static>> = LazyLock::new(|| memmem::Finder::new("git"));
static RM_FINDER: LazyLock<memmem::Finder<'static>> = LazyLock::new(|| memmem::Finder::new("rm"));
fn quick_reject(cmd: &str) -> bool {
let bytes = cmd.as_bytes();
GIT_FINDER.find(bytes).is_none() && RM_FINDER.find(bytes).is_none()
}
对于诸如 ls -la、cargo build 或 npm install 等命令,此检查会直接短路整个匹配流程。memmem::Finder 只需预编译一次并重复使用,避免了反复的初始化开销。
3. 安全匹配时提前退出
首先检查安全模式。一旦匹配成功,函数将立即返回,而无需再检查破坏性模式:
for pattern in SAFE_PATTERNS.iter() {
if pattern.regex.is_match(&normalized).unwrap_or(false) {
return; // 直接允许
}
}
4. 编译时模式验证
pattern! 和 destructive! 宏会在 panic 消息中包含模式名称,使得无效模式在首次执行时便能以清晰的诊断信息失败:
macro_rules! pattern {
($name:literal, $re:literal) => {
Pattern {
regex: Regex::new($re).expect(concat!("pattern '", $name, "' should compile")),
name: $name,
}
};
}
5. 零拷贝 JSON 解析
serde_json 解析器直接操作输入缓冲区,无需不必要的复制。命令字符串直接从解析后的 JSON 值中提取。
6. 零分配路径规范化
命令规范化使用 Cow<str>(写时复制)来避免常见情况下的堆分配:
fn normalize_command(cmd: &str) -> Cow<'_, str> {
// 快速路径:如果命令不以 '/' 开头,则无需规范化
if !cmd.starts_with('/') {
return Cow::Borrowed(cmd); // 无需分配
}
PATH_NORMALIZER.replace(cmd, "$1") // 仅在剥离路径时才分配内存
}
大多数命令并不会使用 git 或 rm 的绝对路径,因此这一快速路径能够为超过 99% 的输入完全避免分配。
7. Release 配置优化
Release 构建使用了激进的优化设置:
[profile.release]
opt-level = "z" # 优化大小(精简二进制文件)
lto = true # 跨 crate 的链接时优化
codegen-units = 1 # 单一代码生成单元以提升优化效果
panic = "abort" # 更小的二进制文件,无异常处理开销
strip = true # 移除调试符号
示例拦截消息
当拦截到破坏性命令时,hook 会向标准错误输出一条彩色警告(以下为去除 ANSI 代码后的示例):
════════════════════════════════════════════════════════════════════════
BLOCKED dcg
────────────────────────────────────────────────────────────────────────
原因: git reset --hard 会丢弃未提交的更改。请先使用 'git stash'。
命令: git reset --hard HEAD~1
提示: 如果您确实需要运行此命令,请手动在终端中执行。
建议先使用 'git stash' 保存您的更改。
════════════════════════════════════════════════════════════════════════
建议系统
dcg 不仅仅会阻止命令,还会提供可操作的指导,帮助用户做出更安全的选择。建议系统会根据被拦截的具体命令生成上下文相关的建议。
建议类别:
| 类别 | 目的 | 示例 |
|---|---|---|
PreviewFirst |
先运行试运行/预览命令 | “先运行 git clean -n 预览将要删除的内容” |
SaferAlternative |
使用实现类似目标的安全命令 | “使用 --force-with-lease 替代 --force” |
WorkflowFix |
改善工作流程以避免危险操作 | “在重置前先提交更改” |
Documentation |
链接到相关文档 | “参阅 man git-reset 了解重置选项” |
AllowSafely |
如何将操作加入白名单(若确属有意) | “添加至白名单: dcg allowlist add core.git:reset-hard” |
按命令类型提供的上下文建议:
| 命令类型 | 建议 |
|---|---|
git reset、git checkout -- |
“建议先使用 git stash 保存您的更改。” |
git clean |
“请先使用 git clean -n 预览将要删除的内容。” |
git push --force |
“建议使用 --force-with-lease 进行更安全的强制推送。” |
rm -rf |
“在手动执行 rm -rf 之前,请仔细核对路径。” |
kubectl delete |
“使用 kubectl delete --dry-run=client 预览将要删除的内容。” |
docker system prune |
“请先使用 --dry-run 查看将要移除的内容。” |
DROP TABLE |
“如果您只需删除数据而非模式,可以考虑使用 TRUNCATE。” |
打包自定义建议:
每个破坏性模式都可以指定针对特定操作的定制化建议:
destructive_pattern!(
"restic-forget",
r"restic(?:\s+--?\S+(?:\s+\S+)?)*\s+forget\b",
"restic forget 会移除快照,可能导致备份数据永久丢失。",
suggestion: "请先运行 'restic snapshots' 查看将受到影响的内容。"
)
这种方法确保建议始终与具体情境相关,而不是泛泛而谈的警告。
同时,hook 还会向标准输出输出用于 Claude Code 协议的 JSON 数据:
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "被 dcg 阻止\n\n原因:..."
}
}
安全性考量
保护范围
- 意外数据丢失:AI 代理在未提交更改的情况下运行
git checkout --或git reset --hard - 远程历史破坏:覆盖共享分支历史的强制推送
- 暂存区丢失:丢弃或清空包含重要未完成工作的暂存区
- 文件系统误操作:在指定临时目录之外进行递归删除
固有局限性
尽管 dcg 能够在多种工具和平台上提供全面的保护,但某些攻击向量本质上难以甚至无法防范:
- 恶意行为者:意志坚定的攻击者可以绕过此挂钩
- 非 Bash 命令:通过 Python/JavaScript、API 调用等直接写入文件的操作不会被拦截
- 已提交但未推送的工作:该挂钩无法防止仅存在于本地的提交丢失
- 允许命令中的漏洞:例如,
git commit命令意外包含了错误的文件 - 脚本中的命令:如果代理运行
./deploy.sh,我们不会检查脚本内部的内容
威胁模型
此挂钩假设 AI 代理是 善意但可能出错的。它旨在捕捉诚实的失误,而非对抗性攻击。该挂钩以与 Claude Code 进程相同的权限运行。
故障排除
挂钩未阻止命令
- 检查挂钩注册情况:确认
~/.claude/settings.json文件中包含挂钩配置 - 重启 Claude Code:配置更改需要重启
- 检查二进制文件位置:确保
dcg已添加到您的 PATH 中 - 手动测试:运行
echo '{"tool_name":"Bash","tool_input":{"command":"git reset --hard"}}' | dcg
挂钩被静默移除(建议添加 shell 启动检查)
Claude Code 在重写 ~/.claude/settings.json 文件时,可能会静默移除 dcg 挂钩。这意味着您可能会在没有任何警告的情况下失去保护。
自动设置——dcg setup 不仅会安装挂钩,还会提示您添加 shell 启动检查:
dcg setup # 交互式 —— 修改 RC 文件前会提示
dcg setup --shell-check # 非交互式 —— 自动添加检查
手动设置——将以下代码片段添加到您的 ~/.zshrc 和/或 ~/.bashrc 文件中:
# dcg:若挂钩从 Claude Code 设置中被静默移除则发出警告
if command -v dcg &>/dev/null && command -v jq &>/dev/null; then
if [ -f "$HOME/.claude/settings.json" ] && \
! jq -e '.hooks.PreToolUse[]? | select(.hooks[]?.command | test("dcg$"))' \
"$HOME/.claude/settings.json" &>/dev/null; then
printf '\033[1;33m[dcg] ~/.claude/settings.json 中缺少挂钩 —— 请运行:dcg install\033[0m\n'
fi
fi
此检查:
- 运行时间仅需几毫秒(不会明显延迟 shell 启动)
- 当挂钩存在时完全静默
- 仅在挂钩缺失时显示黄色警告
- 如果缺少
dcg、jq或settings.json,会优雅地跳过 - 在 bash 和 zsh 中表现一致
注意:
install.sh安装程序也会在安装过程中提示您添加此检查。
挂钩阻止了安全命令
- 检查误报情况:某些边缘情况可能未被安全模式覆盖
- 提交问题:报告被错误阻止的命令
- 临时绕过:让用户在另一个终端中手动运行该命令
- 加入白名单:使用下方的白名单功能进行持久性覆盖
使用白名单解决误报问题
如果 dcg 在特定情况下阻止了一个实际上安全的命令,您可以将其加入白名单。白名单支持三层(按顺序检查):
- 项目级(
.dcg/allowlist.toml):仅适用于当前项目 - 用户级(
~/.config/dcg/allowlist.toml):适用于所有项目 - 系统级(
/etc/dcg/allowlist.toml):适用于整个系统
向白名单添加规则:
# 按 ID 允许特定规则(推荐)
dcg allowlist add core.git:reset-hard -r "用于 CI 清理"
# 在项目级别允许(默认,若位于 git 仓库中)
dcg allowlist add core.git:reset-hard -r "CI 清理" --project
# 添加到用户级白名单
dcg allowlist add core.git:reset-hard -r "个人工作流" --user
# 允许并设置过期时间(ISO 8601 格式)
dcg allowlist add core.git:clean-force -r "迁移" --expires "2026-02-01T00:00:00Z"
# 使用 add-command 允许特定命令(精确匹配)
dcg allowlist add-command "rm -rf ./build" -r "构建清理"
列出白名单条目:
# 列出所有层级的所有条目
dcg allowlist list
# 仅列出项目级白名单
dcg allowlist list --project
# 仅列出用户级白名单
dcg allowlist list --user
# 以 JSON 格式输出
dcg allowlist list --format json
移除条目:
# 按 ID 移除规则
dcg allowlist remove core.git:reset-hard
# 仅从项目级白名单中移除
dcg allowlist remove core.git:reset-hard --project
验证白名单文件:
# 检查问题(过期条目、无效模式)
dcg allowlist validate
# 严格模式:将警告视为错误
dcg allowlist validate --strict
白名单示例:
[[allow]]
rule = "core.git:reset-hard"
reason = "用于 CI 管道清理"
added_at = "2026-01-08T12:00:00Z"
[[allow]]
exact_command = "rm -rf ./build"
reason = "安全的构建目录清理"
added_at = "2026-01-08T12:00:00Z"
expires_at = "2026-02-08T12:00:00Z" # 可选过期时间
[[allow]]
pattern = "rm -rf .*/build"
reason = "跨项目的构建目录"
risk_acknowledged = true # 基于模式的条目必须注明
added_at = "2026-01-08T12:00:00Z"
性能问题
- 检查模式数量:过多的自定义模式会降低匹配速度
- 使用
--release进行性能分析:调试版本的执行速度显著较慢 - 检查 stdin 缓冲:JSON 输入缓慢会导致处理延迟
运行测试
单元测试
cargo test
测试套件包含 80 多项测试,涵盖以下内容:
- normalize_command_tests:对 git 和 rm 二进制文件路径的规范化处理
- quick_reject_tests:针对非 git/rm 命令的快速过滤
- safe_pattern_tests:所有安全模式变体的白名单准确性
- destructive_pattern_tests:所有危险命令的黑名单覆盖范围
- input_parsing_tests:JSON 解析的鲁棒性和边缘案例
- deny_output_tests:输出格式验证
- integration_tests:端到端管道验证
带覆盖率的测试
cargo install cargo-tarpaulin
cargo tarpaulin --out Html
端到端测试
该仓库包含一个全面的 E2E 测试脚本,共 120 个测试用例:
# 运行完整的 E2E 测试套件
./scripts/e2e_test.sh
# 带详细输出
./scripts/e2e_test.sh --verbose
# 指定二进制文件路径
./scripts/e2e_test.sh --binary ./target/release/dcg
E2E 测试套件涵盖:
- 所有破坏性的 git 命令(reset、checkout、restore、clean、push、branch、stash)
- 所有安全的 git 命令(status、log、diff、add、commit、push、branch -d)
- 文件系统命令(rm -rf,涉及各种路径和标志顺序)
- 绝对路径处理(
/usr/bin/git、/bin/rm) - 非 Bash 工具(Read、Write、Edit、Grep、Glob)
- 格式不正确的 JSON 输入(空值、缺少字段、语法错误)
- 边缘情况(sudo 前缀、带引号的路径、变量扩展)
持续集成
该项目使用 GitHub Actions 进行 CI/CD:
CI 工作流(.github/workflows/ci.yml)
在每次推送和拉取请求时运行:
- 格式检查:
cargo fmt --check - Clippy 静态检查:
cargo clippy --all-targets -- -D warnings(启用严格模式和实验性规则) - 编译检查:
cargo check --all-targets - 单元测试:使用 JUnit XML 报告运行
cargo nextest run - 代码覆盖率:使用 LCOV 格式输出运行
cargo llvm-cov
发布工作流(.github/workflows/dist.yml)
在版本标签(v*)触发时运行:
- 为 5 种平台构建优化的二进制文件:
- Linux x86_64(
x86_64-unknown-linux-gnu) - Linux ARM64(
aarch64-unknown-linux-gnu) - macOS Intel(
x86_64-apple-darwin) - macOS Apple Silicon(
aarch64-apple-darwin) - Windows(
x86_64-pc-windows-msvc)
- Linux x86_64(
- 创建
.tar.xz归档文件(Unix)或.zip文件(Windows) - 生成 SHA256 校验和以供验证
- 发布到 GitHub Releases,并自动生成发布说明
创建发布版本的步骤如下:
git tag v0.1.0
git push origin v0.1.0
常见问题解答
问:为什么阻止 git branch -D,但允许 git branch -d?
小写的 -d 只会删除已完全合并的分支。而大写的 -D 会强制删除分支,无论是否已合并,可能会导致仅存在于该分支上的提交丢失。
问:为什么允许 git push --force-with-lease?
force-with-lease 是一种更安全的强制推送方式,它会在远程仓库存在你尚未看到的提交时拒绝推送。这样可以防止意外覆盖他人的工作。
问:为什么禁止在临时目录之外执行所有 rm -rf 命令?
递归强制删除是极其危险的文件系统操作之一。即使出于好意,一个拼写错误或变量扩展错误也可能导致关键文件被删除。临时目录的设计初衷就是短暂使用。
问:我可以添加自定义规则吗?
可以。您可以创建 YAML 规则包文件,并在配置中引用它们。请参阅“自定义规则包”部分以及 docs/custom-packs.md,了解规则包的架构和示例。
问:如果我确实需要运行被阻止的命令怎么办?
请参阅“逃生通道/绕过”部分。选项包括设置 DCG_BYPASS=1、一次性允许码、永久白名单,或者在单独的终端中手动运行该命令。
问:这是否适用于其他 AI 编程工具?
是的。dcg 原生支持 Claude Code、Gemini CLI 和 GitHub Copilot CLI 的钩子负载。对于其他工具,是否支持取决于它们是否提供了兼容 JSON 输入/输出的预执行 Shell 钩子。
问:数据库、Docker、Kubernetes 和云相关命令呢?
dcg 包含超过 49 个规则包,涵盖了这些领域。完整的列表请参阅“模块化规则包系统”部分。您只需在配置中启用所需的规则包即可。
贡献
关于贡献: 请不要误解我的意思,但我目前不接受任何外部贡献。我没有足够的时间和精力来审查这些内容,而且这些项目都以我的名义发布,因此我需要对可能出现的问题负责。从我的角度来看,这种风险与收益极不对称。此外,我还不得不考虑其他“利益相关者”的意见,但这对于我主要为自己免费开发的工具来说并不明智。欢迎提交问题,甚至提出修复建议的 PR,但请理解我不会直接合并它们。相反,我会让 Claude 或 Codex 通过 gh 工具审查这些提交,并独立决定是否以及如何处理这些问题。尤其是漏洞报告,我们非常欢迎。抱歉如果这听起来有些冒犯,但我希望避免浪费时间和产生不必要的误会。我明白这与当前倡导社区贡献的开源精神不太一致,但这却是我在保持高效开发的同时维持心理健康唯一可行的方式。
许可证
MIT
版本历史
v0.4.02026/02/10v0.3.02026/02/02v0.2.152026/01/20v0.2.102026/01/15v0.2.92026/01/14v0.2.72026/01/12v0.2.62026/01/12v0.2.52026/01/12v0.2.42026/01/12v0.2.32026/01/12v0.2.22026/01/12v0.2.12026/01/12常见问题
相似工具推荐
openclaw
OpenClaw 是一款专为个人打造的本地化 AI 助手,旨在让你在自己的设备上拥有完全可控的智能伙伴。它打破了传统 AI 助手局限于特定网页或应用的束缚,能够直接接入你日常使用的各类通讯渠道,包括微信、WhatsApp、Telegram、Discord、iMessage 等数十种平台。无论你在哪个聊天软件中发送消息,OpenClaw 都能即时响应,甚至支持在 macOS、iOS 和 Android 设备上进行语音交互,并提供实时的画布渲染功能供你操控。 这款工具主要解决了用户对数据隐私、响应速度以及“始终在线”体验的需求。通过将 AI 部署在本地,用户无需依赖云端服务即可享受快速、私密的智能辅助,真正实现了“你的数据,你做主”。其独特的技术亮点在于强大的网关架构,将控制平面与核心助手分离,确保跨平台通信的流畅性与扩展性。 OpenClaw 非常适合希望构建个性化工作流的技术爱好者、开发者,以及注重隐私保护且不愿被单一生态绑定的普通用户。只要具备基础的终端操作能力(支持 macOS、Linux 及 Windows WSL2),即可通过简单的命令行引导完成部署。如果你渴望拥有一个懂你
stable-diffusion-webui
stable-diffusion-webui 是一个基于 Gradio 构建的网页版操作界面,旨在让用户能够轻松地在本地运行和使用强大的 Stable Diffusion 图像生成模型。它解决了原始模型依赖命令行、操作门槛高且功能分散的痛点,将复杂的 AI 绘图流程整合进一个直观易用的图形化平台。 无论是希望快速上手的普通创作者、需要精细控制画面细节的设计师,还是想要深入探索模型潜力的开发者与研究人员,都能从中获益。其核心亮点在于极高的功能丰富度:不仅支持文生图、图生图、局部重绘(Inpainting)和外绘(Outpainting)等基础模式,还独创了注意力机制调整、提示词矩阵、负向提示词以及“高清修复”等高级功能。此外,它内置了 GFPGAN 和 CodeFormer 等人脸修复工具,支持多种神经网络放大算法,并允许用户通过插件系统无限扩展能力。即使是显存有限的设备,stable-diffusion-webui 也提供了相应的优化选项,让高质量的 AI 艺术创作变得触手可及。
everything-claude-code
everything-claude-code 是一套专为 AI 编程助手(如 Claude Code、Codex、Cursor 等)打造的高性能优化系统。它不仅仅是一组配置文件,而是一个经过长期实战打磨的完整框架,旨在解决 AI 代理在实际开发中面临的效率低下、记忆丢失、安全隐患及缺乏持续学习能力等核心痛点。 通过引入技能模块化、直觉增强、记忆持久化机制以及内置的安全扫描功能,everything-claude-code 能显著提升 AI 在复杂任务中的表现,帮助开发者构建更稳定、更智能的生产级 AI 代理。其独特的“研究优先”开发理念和针对 Token 消耗的优化策略,使得模型响应更快、成本更低,同时有效防御潜在的攻击向量。 这套工具特别适合软件开发者、AI 研究人员以及希望深度定制 AI 工作流的技术团队使用。无论您是在构建大型代码库,还是需要 AI 协助进行安全审计与自动化测试,everything-claude-code 都能提供强大的底层支持。作为一个曾荣获 Anthropic 黑客大奖的开源项目,它融合了多语言支持与丰富的实战钩子(hooks),让 AI 真正成长为懂上
opencode
OpenCode 是一款开源的 AI 编程助手(Coding Agent),旨在像一位智能搭档一样融入您的开发流程。它不仅仅是一个代码补全插件,而是一个能够理解项目上下文、自主规划任务并执行复杂编码操作的智能体。无论是生成全新功能、重构现有代码,还是排查难以定位的 Bug,OpenCode 都能通过自然语言交互高效完成,显著减少开发者在重复性劳动和上下文切换上的时间消耗。 这款工具专为软件开发者、工程师及技术研究人员设计,特别适合希望利用大模型能力来提升编码效率、加速原型开发或处理遗留代码维护的专业人群。其核心亮点在于完全开源的架构,这意味着用户可以审查代码逻辑、自定义行为策略,甚至私有化部署以保障数据安全,彻底打破了传统闭源 AI 助手的“黑盒”限制。 在技术体验上,OpenCode 提供了灵活的终端界面(Terminal UI)和正在测试中的桌面应用程序,支持 macOS、Windows 及 Linux 全平台。它兼容多种包管理工具,安装便捷,并能无缝集成到现有的开发环境中。无论您是追求极致控制权的资深极客,还是渴望提升产出的独立开发者,OpenCode 都提供了一个透明、可信
ComfyUI
ComfyUI 是一款功能强大且高度模块化的视觉 AI 引擎,专为设计和执行复杂的 Stable Diffusion 图像生成流程而打造。它摒弃了传统的代码编写模式,采用直观的节点式流程图界面,让用户通过连接不同的功能模块即可构建个性化的生成管线。 这一设计巧妙解决了高级 AI 绘图工作流配置复杂、灵活性不足的痛点。用户无需具备编程背景,也能自由组合模型、调整参数并实时预览效果,轻松实现从基础文生图到多步骤高清修复等各类复杂任务。ComfyUI 拥有极佳的兼容性,不仅支持 Windows、macOS 和 Linux 全平台,还广泛适配 NVIDIA、AMD、Intel 及苹果 Silicon 等多种硬件架构,并率先支持 SDXL、Flux、SD3 等前沿模型。 无论是希望深入探索算法潜力的研究人员和开发者,还是追求极致创作自由度的设计师与资深 AI 绘画爱好者,ComfyUI 都能提供强大的支持。其独特的模块化架构允许社区不断扩展新功能,使其成为当前最灵活、生态最丰富的开源扩散模型工具之一,帮助用户将创意高效转化为现实。
gemini-cli
gemini-cli 是一款由谷歌推出的开源 AI 命令行工具,它将强大的 Gemini 大模型能力直接集成到用户的终端环境中。对于习惯在命令行工作的开发者而言,它提供了一条从输入提示词到获取模型响应的最短路径,无需切换窗口即可享受智能辅助。 这款工具主要解决了开发过程中频繁上下文切换的痛点,让用户能在熟悉的终端界面内直接完成代码理解、生成、调试以及自动化运维任务。无论是查询大型代码库、根据草图生成应用,还是执行复杂的 Git 操作,gemini-cli 都能通过自然语言指令高效处理。 它特别适合广大软件工程师、DevOps 人员及技术研究人员使用。其核心亮点包括支持高达 100 万 token 的超长上下文窗口,具备出色的逻辑推理能力;内置 Google 搜索、文件操作及 Shell 命令执行等实用工具;更独特的是,它支持 MCP(模型上下文协议),允许用户灵活扩展自定义集成,连接如图像生成等外部能力。此外,个人谷歌账号即可享受免费的额度支持,且项目基于 Apache 2.0 协议完全开源,是提升终端工作效率的理想助手。