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

> Learn to create custom security packs in Destructive Command Guard using YAML files. Extend DCG functionality easily without recompilation.

- Repository: [Jeff Emanuel/destructive_command_guard](https://github.com/Dicklesworthstone/destructive_command_guard)
- Tags: how-to-guide
- Published: 2026-07-22

---

**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`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/dcg.toml)—as defined in [`src/config.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/config.rs). The scanner in [`src/packs/mod.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/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`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/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.

```yaml
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`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/packs/mod.rs), the evaluator ([`src/evaluator.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/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`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/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`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/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`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/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`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/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`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/evaluator.rs).

5. **Optionally specify remediation** by adding `safe_alternative` under the `remediation` key. The text in [`src/output/mod.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/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`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/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`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/./packs/custom/s3_unencrypted.yaml) to prevent `aws s3 cp` commands that lack server-side encryption flags:

```yaml
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`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/./packs/custom/git_reset.yaml) to block `git reset --hard`:

```yaml
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:

```json
{
  "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`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/./packs/custom/docker_compose.yaml):

```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:

- [`src/packs/mod.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/packs/mod.rs) – Handles directory scanning, YAML deserialization, and pack registration.
- [`src/config.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/config.rs) – Parses [`config.toml`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/config.toml) and extracts the `packs.enabled` list.
- [`docs/pack.schema.yaml`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/docs/pack.schema.yaml) – The JSON Schema validating every pack definition.
- [`src/evaluator.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/evaluator.rs) – Core matching engine that iterates over packs and patterns.
- [`src/output/mod.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/output/mod.rs) – Formats denial JSON and renders remediation text.
- [`tests/pack_schema.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/tests/pack_schema.rs) – Unit test suite validating all YAML files against the schema.
- [`examples/packs/example.yaml`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/examples/packs/example.yaml) – Canonical reference pack shipped with the repository.

## 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`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/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`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/dcg.toml).