How to Create Custom Security Packs Using YAML Files in Destructive Command Guard

You can extend Destructive Command Guard (DCG) by placing a YAML file containing regex patterns in a directory listed under packs.enabled, then reloading the tool—no recompilation required.

Destructive Command Guard (DCG) is a protective layer for shell commands that matches inputs against security packs. These packs are data-driven definitions loaded at runtime from YAML files, allowing you to create custom security packs using YAML files that enforce organization-specific policies without modifying the Rust source code.

How Pack Discovery Works

When DCG initializes, it reads the packs.enabled array from your configuration—typically located in ~/.config/dcg/config.toml or a project-level dcg.toml—as defined in src/config.rs. The scanner in src/packs/mod.rs recursively searches every path in that array for *.yaml files.

Each discovered file is validated against the JSON Schema in docs/pack.schema.yaml. If validation passes, DCG deserializes the YAML using serde_yaml::from_str into the internal Pack struct. The patterns are compiled once into static Regex objects via lazy_static! and registered in a global registry.

YAML Pack Structure

A custom security pack consists of three top-level sections. The regex field uses fancy-regex syntax, supporting look-ahead and look-behind assertions for precise matching.

id: <pack-identifier>            # e.g., mycompany.cloud

description: <human readable>   # optional

patterns:                        # list of rule objects

  - name: <rule-id>                # stable identifier used for allow-listing

    type: safe | destructive       # safe = whitelist, destructive = blacklist

    severity: critical | high | medium | low
    regex: "<fancy-regex>"         # pattern matched against normalized command

    reason: <explanation>          # displayed in denial JSON

    remediation:                  # optional

      safe_alternative: "<cmd>"   # suggested safe command

The Loading and Evaluation Pipeline

After deserialization in src/packs/mod.rs, the evaluator (src/evaluator.rs) iterates over all loaded packs on every incoming command. It tests the command string against each pattern in the order defined, stopping at the first match. A type: safe pattern results in immediate allowance, while type: destructive triggers a denial JSON response that includes the reason and any remediation steps formatted by src/output/mod.rs.

Step-by-Step: Creating Your First Custom Pack

Follow these concrete steps to add a new rule set to DCG:

  1. Create a YAML file in a directory covered by packs.enabled (default: ./packs). According to src/packs/mod.rs, any file with the .yaml extension is automatically considered.

  2. Define a unique pack ID using reverse-DNS notation (e.g., myorg.database). This identifier must be unique across all loaded packs as specified in docs/pack.schema.yaml.

  3. Add pattern objects with a stable name, explicitly set type to safe or destructive, assign a severity level, and write a regex using fancy-regex syntax. Consult src/packs/core/mod.rs for examples of complex patterns.

  4. Provide a human-readable reason explaining the rule's purpose. This string populates the reason field in the denial JSON generated by src/evaluator.rs.

  5. Optionally specify remediation by adding safe_alternative under the remediation key. The text in src/output/mod.rs renders this suggestion to the user.

  6. Validate syntax by running cargo test --test pack_schema. The test in tests/pack_schema.rs loads every YAML file against the official schema, catching structural errors before runtime.

  7. Enable the pack by appending its relative or absolute path to the packs.enabled array in your TOML configuration.

  8. Reload DCG. The next invocation automatically picks up the new definitions without requiring a rebuild.

Practical Examples

Blocking Unencrypted S3 Uploads

Create ./packs/custom/s3_unencrypted.yaml to prevent aws s3 cp commands that lack server-side encryption flags:

id: mycompany.storage
description: "Prevent uploading files to S3 without server-side encryption"
patterns:
  - name: s3:unencrypted-upload
    type: destructive
    severity: high
    regex: >-
      ^\s*aws\s+s3\s+cp\s+.*\s+s3://[^ ]+(?<!--sse|--server-side-encryption)\s*$
    reason: "Uploading to S3 without SSE can expose data"
    remediation:
      safe_alternative: "aws s3 cp <src> s3://<dest> --sse AES256"

The negative look-behind (?<!--sse|--server-side-encryption) ensures the pattern only matches commands missing the encryption flags. When matched, DCG returns a denial with the specified remediation.

Preventing Destructive Git Commands

Define a pack at ./packs/custom/git_reset.yaml to block git reset --hard:

id: mycompany.git
patterns:
  - name: git:reset-hard
    type: destructive
    severity: critical
    regex: "^\\s*git\\s+reset\\s+--hard\\b"
    reason: "git reset --hard rewrites history and discards changes"
    remediation:
      safe_alternative: "git stash && git reset --hard HEAD"

Execution yields a JSON response:

{
  "hookSpecificOutput": {
    "permissionDecision": "deny",
    "ruleId": "git:reset-hard",
    "packId": "mycompany.git",
    "severity": "critical",
    "reason": "git reset --hard rewrites history and discards changes",
    "remediation": {
      "safeAlternative": "git stash && git reset --hard HEAD"
    }
  }
}

Whitelisting Safe Docker Operations

To explicitly allow docker compose up while other Docker commands remain subject to broader rules, create ./packs/custom/docker_compose.yaml:

id: mycompany.docker
patterns:
  - name: docker:compose-up
    type: safe
    severity: low
    regex: "^\\s*docker\\s+compose\\s+up\\b"
    reason: "docker compose up is considered safe"

Because this pattern uses type: safe, matching commands pass through silently without further evaluation.

Key Source Files for Pack Mechanics

Understanding these files helps debug custom pack behavior:

Summary

  • Custom security packs are YAML files that extend DCG without recompilation.
  • Place packs in directories listed under packs.enabled in your TOML config.
  • Each pack requires a unique id, a list of patterns with regex, type, severity, and a reason.
  • Use fancy-regex syntax for complex pattern matching, including look-behinds.
  • Validate changes using cargo test --test pack_schema before deploying.
  • The evaluator processes patterns in order, stopping at the first match to determine allow or deny.

Frequently Asked Questions

Can I include multiple patterns in a single YAML file?

Yes. A single pack YAML can define an arbitrary number of pattern objects under the patterns list. The evaluator checks them sequentially in the order they appear in the file, so place high-priority rules first.

What regex engine does DCG use for pattern matching?

DCG uses the fancy-regex crate, which supports advanced features like look-ahead and look-behind assertions. This allows you to write precise rules that match dangerous commands only when specific unsafe conditions are met.

How do I disable a core pack while keeping my custom packs?

Remove the core pack's path from the packs.enabled array in your config.toml. DCG only loads packs explicitly listed in that configuration, so simply omitting the path prevents registration without deleting source files.

Where should I store custom packs for system-wide use?

Store them in ~/.config/dcg/packs/ (or equivalent on your OS) and reference that directory in the packs.enabled array of your user-level ~/.config/dcg/config.toml. For project-specific rules, place packs in a ./packs directory and enable it via project-level dcg.toml.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →