This guide covers creating external YAML packs for dcg. Custom packs let you define organization-specific security policies without modifying the dcg binary.
- Create a pack file at
~/.config/dcg/packs/mycompany.yaml - Define at least one pattern (safe or destructive)
- Validate with
dcg pack validate ~/.config/dcg/packs/mycompany.yaml - Restart dcg or reload config
See examples/packs/example.yaml for a complete working example.
# Required fields
schema_version: 1 # Always use 1 (current version)
id: mycompany.policies # namespace.name format
name: MyCompany Security Policies # Human-readable name
version: 1.0.0 # Your pack's semantic version
# Optional fields
description: |
What this pack protects against.
keywords: # Trigger evaluation (recommended)
- mycommand
- mytool
destructive_patterns: # Patterns that block/warn
- name: pattern-id
pattern: regex-pattern
severity: critical # critical/high/medium/low
description: Short denial reason
explanation: | # Optional detailed explanation
Longer help text with alternatives.
safe_patterns: # Patterns that explicitly allow
- name: safe-pattern-id
pattern: safe-regex-pattern
description: Why this is allowed| Field | Type | Description |
|---|---|---|
id |
string | Unique identifier in namespace.name format. Must match ^[a-z][a-z0-9_]*\.[a-z][a-z0-9_]*$ |
name |
string | Human-readable pack name shown in messages |
version |
string | Semantic version (X.Y.Z) for your own tracking |
| Field | Type | Default | Description |
|---|---|---|---|
schema_version |
integer | 1 | Schema version for forward compatibility |
description |
string | none | What this pack protects against |
keywords |
array | [] |
Keywords that trigger pattern matching |
destructive_patterns |
array | [] |
Patterns that block or warn |
safe_patterns |
array | [] |
Patterns that explicitly allow |
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | yes | Stable identifier within the pack |
pattern |
string | yes | fancy-regex pattern to match |
severity |
string | no | critical, high (default), medium, low |
description |
string | no | Short reason shown on denial |
explanation |
string | no | Detailed explanation for verbose output |
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | yes | Stable identifier within the pack |
pattern |
string | yes | fancy-regex pattern to match |
description |
string | no | Why this command is allowed |
Severity determines the default action when a command matches:
| Severity | Default Action | Use Case |
|---|---|---|
critical |
Always deny | Irreversible operations (rm -rf /, DROP DATABASE) |
high |
Deny (allowlistable) | Dangerous but sometimes needed (force push, truncate) |
medium |
Warn but allow | Worth noting but not blocking (large deletes) |
low |
Log only | Learning/audit purposes |
Keywords gate pattern evaluation. Commands without any keywords skip the pack entirely, improving performance.
Do:
- Use specific, unambiguous keywords:
kubectl,terraform,mycompany-deploy - Include common aliases if applicable:
kfor kubectl - Keep the list short (< 10 keywords)
Don't:
- Use single letters or common words:
a,run,do - Include partial matches:
rminstead ofrm -rf - Omit keywords (forces evaluation on every command)
Patterns use fancy-regex syntax, which supports:
- Standard regex:
\s,\w,.*,[a-z]+ - Lookahead:
(?=...),(?!...) - Lookbehind:
(?<=...),(?<!...) - Backreferences:
\1,\2
dcg uses a dual regex engine:
- Linear engine (O(n)): For simple patterns without lookahead/lookbehind
- Backtracking engine: For patterns requiring advanced features
Simple patterns are faster. The validator reports which engine each pattern uses.
Write patterns that match exactly what you want to block:
# Too broad - matches "rm" anywhere
pattern: rm
# Too narrow - misses "rm -rf --no-preserve-root"
pattern: rm\s+-rf\s+/
# Good - matches rm -rf variations targeting root or system paths
pattern: \brm\s+(?:-[a-zA-Z]*r[a-zA-Z]*\s+)*(?:-[a-zA-Z]*f[a-zA-Z]*\s+)*(?:/|/\*|/usr|/etc|/var|/home)Use word boundaries (\b) to avoid matching substrings:
# Matches "deploy", "deployer", "redeploy"
pattern: deploy
# Only matches "deploy" as a word
pattern: \bdeploy\bMatch flags flexibly to handle different orderings:
# Handles: --env prod, --env=prod, --env prod
pattern: --env\s*[=\s]?\s*prodThe schema_version field enables forward compatibility:
- Version 1 (current): All fields documented in this guide
- Future versions may add new fields but will maintain backward compatibility
- Packs with
schema_versionhigher than supported are rejected with a clear error
When dcg adds new features (e.g., new pattern fields), the schema version
increments. Your existing packs continue working; only new features require
updating schema_version.
External packs cannot override built-in packs. This prevents accidental or malicious security bypasses.
core.*- Git, filesystem operationsdatabase.*- PostgreSQL, MySQL, MongoDB, Redis, SQLitecontainers.*- Docker, Podman, Composekubernetes.*- kubectl, Helm, Kustomizecloud.*- AWS, Azure, GCPstorage.*- S3, GCS, MinIO, Azure Blobinfrastructure.*- Terraform, Pulumi, Ansiblebackup.*- Restic, rclonecdn.*,apigateway.*,monitoring.*,messaging.*,search.*,secrets.*- ...and others (see
dcg packs listfor full list)
Use a unique namespace that identifies your organization:
# Good - unique to your organization
id: acmecorp.deploy
id: myproject.database
id: internal.tools
# Bad - collides with built-in
id: core.git # Error: collides with built-in pack 'Git'
id: database.custom # Might collide with future built-insThe validator checks for collisions:
$ dcg pack validate malicious.yaml
Error: Pack ID 'core.git' collides with built-in pack 'Git'.
External packs cannot override built-in security packs.
Always validate packs before deployment:
dcg pack validate ~/.config/dcg/packs/mycompany.yamlThe validator checks:
- YAML syntax
- Schema compliance
- ID format (
namespace.name) - Version format (semantic versioning)
- Pattern compilation (catches invalid regex)
- Duplicate pattern names
- Built-in pack collisions
- Regex engine selection (reports linear vs backtracking)
Validating: mycompany.yaml
Pack Information:
ID: mycompany.deploy
Name: MyCompany Deployment Policies
Version: 1.0.0
Patterns:
prod-direct-deploy (destructive, critical) [linear engine]
staging-dev-deploy (safe) [linear engine]
Engine Summary: 2 patterns, 100% linear (optimal performance)
Result: Valid
Add pack paths in your config file:
# ~/.config/dcg/config.toml or .dcg.toml
[packs]
custom_paths = [
"~/.config/dcg/packs/*.yaml",
".dcg/packs/*.yaml",
"/etc/dcg/packs/*.yaml"
]- Built-in packs load first (cannot be overridden)
- External packs load in path order (later paths override earlier)
- For duplicate external IDs, last loaded wins
This allows:
- System-wide packs in
/etc/dcg/packs/ - User overrides in
~/.config/dcg/packs/ - Project-specific packs in
.dcg/packs/
Invalid pack files generate warnings but don't block loading:
Warning: Failed to load pack from /etc/dcg/packs/broken.yaml: Invalid pattern 'test-pattern' ([unclosed): regex parse error
Loaded 3 external packs (1 warning)
This ensures a typo in one pack doesn't disable all protection.
Use dcg test with your command:
dcg test "deploy --env prod"This shows which packs evaluated and which patterns matched.
No. Built-in packs cannot be overridden by external packs for security. Instead, use allowlists to permit specific commands:
# ~/.config/dcg/allowlist.toml
[[rules]]
command_prefix = "git push --force origin feature/"
reason = "Force push allowed on feature branches"# Validate syntax and patterns
dcg pack validate mypack.yaml
# Test against specific commands
dcg test --pack-path mypack.yaml "dangerous-command"dcg rejects the pack with a clear error:
Error: Schema version 99 is not supported (max: 1)
This prevents newer packs from silently failing on older dcg versions.
Yes. fancy-regex supports all common regex features. However, patterns with lookahead/lookbehind use the backtracking engine, which is slightly slower. The validator reports which engine each pattern uses.
There's no hard limit, but for performance:
- Aim for < 50 patterns per pack
- Use keywords to skip evaluation when possible
- Prefer specific patterns over broad ones
Options:
- Check packs into your repo in
.dcg/packs/ - Host on a shared filesystem (
/etc/dcg/packs/) - Distribute via your configuration management system
docs/pack.schema.yaml- JSON Schema for pack filesdocs/configuration.md- General dcg configurationexamples/packs/example.yaml- Complete working example