Custom Check Patterns
Add your own check patterns to shellfirm's pattern database
You can add custom check patterns in your settings file or in project policies. Custom patterns go through the same matching pipeline as built-in patterns.
Adding patterns in settings
Add custom checks to ~/.shellfirm/settings.yaml:
# Note: custom checks are typically added via project policies (.shellfirm.yaml)
# rather than global settings, but both approaches work.
The recommended approach is to add custom patterns in project-level .shellfirm.yaml files, which are version-controlled and shared across the team:
# .shellfirm.yaml
version: 1
checks:
- id: "team:deploy_prod"
from: base
test: "deploy\\s+--env\\s+prod"
severity: High
description: "Production deployment detected"
alternative: "deploy --env staging"
alternative_info: "Deploy to staging first"
Pattern format
Each custom check requires these fields:
- id: "group:pattern_name" # Unique ID
from: base # Check group (for enable/disable filtering)
test: "regex_pattern" # Regex to match against commands
severity: High # Info | Low | Medium | High | Critical
description: "Why it's risky" # Shown when the pattern matches
Optional fields:
alternative: "safer command" # Suggested safer command
alternative_info: "Why it's safer" # Explanation
filters: # Post-match filters
- type: NotContains
value: "--dry-run"
Writing effective regex patterns
Basic patterns
# Match a specific command with arguments
test: "deploy\\s+--env\\s+production"
# Matches: deploy --env production
# Matches: deploy --env production (multiple spaces)
# Match a command with optional arguments
test: "npm\\s+publish"
# Matches: npm publish
# Matches: npm publish --tag beta
Using alternation
# Match multiple variants
test: "deploy\\s+--(env|environment)\\s+(prod|production)"
# Matches: deploy --env prod
# Matches: deploy --environment production
Negative lookahead
# Match --force but NOT --force-with-lease
test: "--force(?!-with-lease)"
# Matches: git push --force
# Does NOT match: git push --force-with-lease
Anchored patterns
# Match only at the start of a command
test: "^sudo\\s+rm"
# Matches: sudo rm -rf /
# Does NOT match: echo "sudo rm" (in quoted context)
Filter types
Filters are applied after the regex matches. They reduce false positives.
NotContains
The command must NOT contain this substring:
filters:
- type: NotContains
value: "--dry-run"
Use case: Allow deploy --dry-run but flag deploy without it.
Contains
The command MUST contain this substring:
filters:
- type: Contains
value: "--privileged"
Use case: Only flag docker run when --privileged is present.
PathExists
The match only triggers if a specific path exists on the filesystem:
filters:
- type: PathExists
value: "/data/production"
Use case: Only flag deletion commands when the production data directory exists.
ID naming conventions
Pattern IDs follow the group:name convention:
team:deploy_prod-- team-specific deployment checkcustom:db_migrate-- custom database migration checkinfra:delete_lb-- infrastructure-specific check
The group prefix is informational. Use something that identifies the source of the pattern.
Examples
Deployment safety
checks:
- id: "team:deploy_prod_force"
from: base
test: "deploy.*--force.*production|deploy.*production.*--force"
severity: Critical
description: "Forced production deployment bypasses safety checks"
filters:
- type: NotContains
value: "--dry-run"
alternative: "deploy --env production"
alternative_info: "Deploy without --force to use normal safety checks"
Custom tool protection
checks:
- id: "team:admin_reset"
from: base
test: "admin-tool\\s+reset\\s+--all"
severity: Critical
description: "Resets all data in the admin tool"
alternative: "admin-tool reset --scope limited"
alternative_info: "Reset only the specific scope you need"
- id: "team:cache_purge"
from: base
test: "cache-manager\\s+purge\\s+--global"
severity: High
description: "Global cache purge affects all users"
alternative: "cache-manager purge --scope user"
alternative_info: "Purge only user-scoped cache"
Preventing accidental data exposure
checks:
- id: "team:env_dump"
from: base
test: "env\\s*\\|.*curl|printenv.*\\|.*curl"
severity: Critical
description: "Piping environment variables to an external URL"
- id: "team:cat_secrets"
from: base
test: "cat.*(credentials|secrets|passwords)"
severity: Medium
description: "Reading files that may contain secrets"