$ shellfirm

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

FieldRequiredTypeDescription
idYesstringUnique ID in group:name format (e.g., team:deploy_prod)
fromYesstringCheck group for enable/disable filtering
testYesstringRegex pattern to match against the command
severityYesstringInfo, Low, Medium, High, or Critical
descriptionYesstringWhat the pattern detects and why it is risky
alternativeNostringSafer alternative command
alternative_infoNostringWhy the alternative is safer
filtersNoarrayPost-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"