Custom Checks
Add team-specific check patterns to your project policy
Team policies can include custom check patterns that match commands specific to your project's tools, scripts, and workflows. These custom checks work exactly like built-in checks -- they go through the same pattern matching pipeline, support filters, and integrate with escalation logic.
Adding custom checks
Add checks to your .shellfirm.yaml under the checks key:
# .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 and verify"
Check fields
| Field | Required | Type | Description |
|---|---|---|---|
id | Yes | string | Unique ID in group:name format (e.g., team:deploy_prod) |
from | Yes | string | Check group for enable/disable filtering |
test | Yes | string | Regex pattern to match against the command |
severity | Yes | string | Info, Low, Medium, High, or Critical |
description | Yes | string | What the pattern detects and why it is risky |
alternative | No | string | Safer alternative command |
alternative_info | No | string | Why the alternative is safer |
filters | No | array | Post-match filters for reducing false positives |
Writing regex patterns
The test field is a regular expression. Some tips:
- Use
\\s+for one or more whitespace characters - Use
\\s{1,}as an alternative to\\s+ - Escape special characters:
\\.,\\(,\\),\\[,\\] - Use
.*for "anything in between" - Remember to double-escape backslashes in YAML strings
Examples
# Match: deploy --env production
test: "deploy\\s+--env\\s+production"
# Match: npm publish (with or without flags)
test: "npm\\s+publish"
# Match: rake db:drop or rake db:reset
test: "rake\\s+db:(drop|reset)"
# Match: curl with POST method
test: "curl.*-X\\s+POST"
# Match: any command with --force flag
test: "--force(?!-with-lease)" # negative lookahead to exclude --force-with-lease
Using filters
Filters refine matches after the regex hits. They reduce false positives by checking additional conditions.
NotContains filter
Allow the match only if the command does NOT contain a specific substring:
checks:
- id: "team:npm_publish"
from: base
test: "npm\\s+publish"
severity: High
description: "Publishing to npm registry"
filters:
- type: NotContains
value: "--dry-run"
alternative: "npm publish --dry-run"
alternative_info: "Preview what would be published without actually publishing"
This matches npm publish but NOT npm publish --dry-run.
Contains filter
Allow the match only if the command DOES contain a specific substring:
checks:
- id: "team:docker_run_privileged"
from: base
test: "docker\\s+run"
severity: High
description: "Running Docker container in privileged mode"
filters:
- type: Contains
value: "--privileged"
This matches docker run --privileged ... but not docker run ... (without the flag).
PathExists filter
Allow the match only if a specific path exists on the filesystem:
checks:
- id: "team:delete_data_dir"
from: base
test: "rm\\s+-rf\\s+/data"
severity: Critical
description: "Deleting the data directory"
filters:
- type: PathExists
value: "/data"
Complete examples
Deployment safety
checks:
- id: "team:deploy_production"
from: base
test: "deploy\\s+--target\\s+(production|prod)"
severity: High
description: "Direct production deployment"
alternative: "deploy --target staging"
alternative_info: "Deploy to staging and promote after verification"
- id: "team:deploy_force"
from: base
test: "deploy.*--force"
severity: Critical
description: "Forced deployment bypasses safety checks"
filters:
- type: NotContains
value: "--dry-run"
Database safety
checks:
- id: "team:migrate_production"
from: base
test: "migrate.*--env\\s+production"
severity: High
description: "Production database migration"
- id: "team:seed_production"
from: base
test: "(seed|fixtures).*production"
severity: Critical
description: "Seeding production database can corrupt data"
Infrastructure safety
checks:
- id: "team:scale_zero"
from: base
test: "scale.*--replicas\\s*=?\\s*0"
severity: High
description: "Scaling to zero replicas will cause downtime"
alternative: "scale --replicas=1"
alternative_info: "Scale to minimum instead of zero"
- id: "team:restart_all_pods"
from: base
test: "kubectl\\s+rollout\\s+restart.*--all"
severity: High
description: "Restarting all pods simultaneously may cause downtime"