跳到主要内容
    ↑↓ 选择↵ 打开esc 关闭
    中文English
    whjvenyl

    Damage Control

    v1.5.0工具与命令
    opencode-damage-control

    OpenCode plugin that blocks dangerous commands and protects sensitive paths

    GitHub 星标

    8

    月装机量

    120

    近 7 天 25

    综合评分SCORE

    31.5

    生态多维模型

    最近提交

    5 个月前

    2026-03-03

    快速安装与配置

    opencode.json

    写入当前项目的 opencode.json,只对这个仓库生效。

    opencode.json

    {
      "$schema": "https://opencode.ai/config.json",
      "plugin": ["opencode-damage-control@1.5.0"]
    }

    opencode 启动时会通过内嵌运行时自动加载 npm 依赖并缓存至本地目录,无需手动在全局环境执行安装。

    Defense-in-depth security plugin for OpenCode. Blocks dangerous commands and protects sensitive files before they execute.

    CI npm version npm downloads License: MIT Built with OpenCode Zero Dependencies

    Documentation · Issues · Contributing · Security


    Why

    AI coding agents have shell access, file read/write, and broad autonomy. A single bad command -- whether from a hallucination, prompt injection, or honest mistake -- can:

    • rm -rf / your filesystem
    • DROP TABLE your production database
    • Leak ~/.ssh keys or ~/.aws credentials
    • git push --force over your team's work
    • terraform destroy your infrastructure

    This plugin intercepts every tool call and either blocks or asks for confirmation before dangerous ones run.


    Quick Start

    Add to your opencode.json:

    {
      "$schema": "https://opencode.ai/config.json",
      "plugin": ["opencode-damage-control"]
    }
    

    Restart OpenCode. Done -- all protections are active with zero configuration.


    What It Protects

    144 Command Patterns

    56 hard-blocked, 88 require confirmation. Covers system destruction (rm -rf /, fork bombs, dd), SQL (DROP TABLE, DELETE FROM, TRUNCATE), git (--force push, filter-branch, stash clear), cloud infrastructure (AWS, GCP, Azure, Terraform, Pulumi), Docker/Kubernetes, databases (Redis, Postgres, MySQL, MongoDB), hosting platforms (Vercel, Netlify, Heroku, Fly.io, Cloudflare, Firebase, Serverless), process/system manipulation (crontab -r, systemctl, iptables, launchctl), and Windows-specific commands (del /s /q, rd /s /q, diskpart, reg delete, bcdedit, PowerShell Remove-Item, Stop-Service, Uninstall-Package).

    Shell wrapper unwrapping: Commands wrapped in bash -c "...", sh -c "...", python -c "...", cmd /c "...", powershell -Command "...", pwsh -c "...", env bash -c "...", etc. are automatically unwrapped and inspected. Nested wrappers are handled recursively.

    Full pattern list →

    103 Protected Paths

    Three-tier protection system for sensitive files:

    Level Read Write Delete Examples
    zeroAccess Block Block Block ~/.ssh, ~/.aws, .env*, *.pem
    readOnly Allow Block Block /etc/, lock files, node_modules/, dist/
    noDelete Allow Allow Block .git/, LICENSE, Dockerfile, CI configs

    Full path list →

    Actions

    Action Behavior When
    block Hard block. Tool never executes. Catastrophic commands (rm -rf /, DROP TABLE, terraform destroy)
    ask User sees confirmation dialog. Risky-but-valid commands (git reset --hard, rm -rf, DELETE ... WHERE)

    How It Works

    flowchart TD
        CALL["OpenCode Tool Call"]
    
        CALL --> EXEC["bash / shell / cmd"]
        CALL --> READ["read / glob / grep"]
        CALL --> WRITE["edit / write / create"]
    
        EXEC --> UNWRAP["Unwrap Shell Wrappers"]
        UNWRAP --> PP["Pattern + Path Check"]
        READ --> PC1["Path Check"]
        WRITE --> PC2["Path Check"]
    
        PP --> |block| THROW["THROW (hard block)"]
        PP --> |ask| STASH["STASH by callID"]
        PP --> |no match| ALLOW1["ALLOW"]
    
        PC1 --> |zeroAccess| BLOCK1["BLOCK"]
        PC1 --> |otherwise| ALLOW2["ALLOW"]
    
        PC2 --> |zeroAccess / readOnly| BLOCK2["BLOCK"]
        PC2 --> |otherwise| ALLOW3["ALLOW"]
    
        STASH --> PERM["permission.ask hook"]
        PERM --> DIALOG["CONFIRM DIALOG"]
    
        style THROW fill:#dc2626,color:#fff,stroke:#991b1b
        style BLOCK1 fill:#dc2626,color:#fff,stroke:#991b1b
        style BLOCK2 fill:#dc2626,color:#fff,stroke:#991b1b
        style DIALOG fill:#f59e0b,color:#000,stroke:#d97706
        style ALLOW1 fill:#16a34a,color:#fff,stroke:#15803d
        style ALLOW2 fill:#16a34a,color:#fff,stroke:#15803d
        style ALLOW3 fill:#16a34a,color:#fff,stroke:#15803d
    

    Hook 1: tool.execute.before -- inspects every tool call. Matches with block throw immediately. Matches with ask are stashed by callID and proceed to the permission system. Protected paths are enforced based on their tier and the operation type.

    Hook 2: permission.ask -- looks up stashed matches and forces output.status = 'ask', ensuring the user sees the confirmation dialog even if their permission config would normally auto-allow.


    Configuration

    Everything works out of the box. To customize, create a damage-control.json in either or both locations:

    Location Scope
    ~/.config/opencode/damage-control.json Global (all projects)
    .opencode/damage-control.json Project (this repo only)

    Both optional. Project merges on top of global. Invalid config logs warnings and uses defaults.

    Schema

    {
      "patterns": {
        "add": [
          { "pattern": "my-dangerous-cmd", "reason": "Custom block", "action": "block" }
        ],
        "remove": ["SQL DROP TABLE"],
        "override": {
          "Recursive delete from root": "ask"
        }
      },
      "paths": {
        "add": [
          { "path": "~/.my-secrets", "level": "zeroAccess" }
        ],
        "remove": ["~/.npmrc"],
        "override": {
          "~/.docker": "none"
        }
      }
    }
    

    Operations

    Operation What it does
    add Append new patterns/paths after defaults
    remove Remove by exact reason (patterns) or path (paths)
    override Change action or level. Use "none" to unprotect a path.

    Processing order: defaults → remove → override → add.

    When both global and project configs exist: add arrays concatenate, remove arrays union, override objects shallow-merge (project wins).

    Examples

    Relax a block to ask:

    { "patterns": { "override": { "Terraform destroy": "ask" } } }
    

    Add a custom pattern:

    {
      "patterns": {
        "add": [{ "pattern": "prod-db-wipe", "reason": "Wipes production DB", "action": "block" }]
      }
    }
    

    Unprotect a path:

    { "paths": { "override": { "~/.npmrc": "none" } } }
    

    What Happens

    When something is blocked

    The AI agent sees an error and adjusts:

    DAMAGE_CONTROL_BLOCKED: SQL DROP TABLE
    
    Command: DROP TABLE
    

    When something triggers a confirmation

    OpenCode shows the standard permission dialog:

    damage-control flagged: git reset --hard
    
    [once]  [always]  [reject]
    

    Limitations

    • Substring matching for paths. A command that merely mentions a protected path (e.g., in a comment) will be blocked.
    • Shell only, not subprocesses. Inspects command strings passed to bash/shell/cmd. Cannot inspect commands spawned by scripts (but does unwrap bash -c, python -c, etc.).
    • Pattern ordering matters. First match wins. Specific patterns are ordered before generic ones.
    • Ask requires permission system. The permission.ask hook forces the dialog even if the user's config auto-allows, but exact UX depends on OpenCode version.

    Development

    git clone https://github.com/whjvenyl/opencode-damage-control.git
    cd opencode-damage-control
    npm install
    npm run build    # output in dist/
    npm test         # 454 tests
    

    Architecture

    src/
      patterns.ts        144 patterns, 103 paths, shell unwrapping, matching helpers
      config.ts          Config loading, validation, merging
      index.ts           Plugin entry point (2 hooks)
      patterns.test.ts   428 pattern + unwrapping tests
      config.test.ts     26 config tests
    
    Module Exports
    patterns.ts DEFAULT_PATTERNS, DEFAULT_PROTECTED_PATHS, matchPattern(), checkPathProtection(), checkShellPathViolation(), unwrapShellCommand()
    config.ts loadConfig(), applyConfig(), DamageControlConfig
    index.ts DamageControl plugin -- loads config at init, returns tool.execute.before + permission.ask hooks

    Contributing

    See CONTRIBUTING.md for setup, architecture, and PR conventions.

    For security vulnerabilities, see SECURITY.md.


    Acknowledgments

    Based on the concept from claude-code-damage-control by @disler. Reimplemented as a native OpenCode plugin with zero runtime dependencies.


    License

    MIT