$ shellfirm

Challenge Overrides

Override challenge types per pattern, optionally scoped to specific branches

Challenge overrides let you change the challenge type for specific patterns in your project. Unlike deny lists (which block entirely), overrides change the difficulty of the confirmation challenge.

How overrides work

An override specifies a pattern ID and a new challenge type. When a command matches that pattern, the override challenge is used instead of the default.

# .shellfirm.yaml
version: 1
overrides:
  - id: "fs:recursively_delete"
    challenge: Yes

With this override, rm -rf will always require typing "yes" to confirm, regardless of what the global challenge setting is.

Escalation only

Overrides follow the same escalation-only rule as everything else in shellfirm:

The override challenge must be stricter than the current challenge. If it is not, the stricter of the two is used.

Challenge strictness order: Math < Enter < Yes

Current challengeOverrideEffective challenge
MathEnterEnter
MathYesYes
EnterMathEnter (override ignored, Enter is stricter)
EnterYesYes
YesMathYes (override ignored, Yes is stricter)
YesEnterYes (override ignored, Yes is stricter)

Branch-scoped overrides

Overrides can be scoped to specific git branches using on_branches. The override only applies when the current branch matches one of the listed branches.

overrides:
  - id: "git:reset_hard"
    challenge: Yes
    on_branches:
      - main
      - production
      - staging

With this override:

  • On main, production, or staging: git reset --hard requires typing "yes"
  • On feature/my-thing or any other branch: the default challenge type applies

Multiple overrides

You can specify multiple overrides in a single policy:

overrides:
  # Always require "yes" for recursive deletes
  - id: "fs:recursively_delete"
    challenge: Yes

  # Require "yes" for git reset only on protected branches
  - id: "git:reset_hard"
    challenge: Yes
    on_branches:
      - main
      - production

  # Require "yes" for Docker system prune
  - id: "docker:system_prune_all"
    challenge: Yes

  # Require Enter (instead of Math) for stash drops
  - id: "git:stash_drop"
    challenge: Enter

Combining with global settings

Overrides in .shellfirm.yaml are merged with all other escalation layers. The effective challenge is always the strictest across the full pipeline:

Global challenge setting:         Math
Severity escalation (Critical):   Yes
Group escalation:                 (none)
Check-id escalation:              (none)
Context escalation (root):        Yes
Policy override for rm -rf:       Yes

Effective challenge for rm -rf as root: Yes

Policy overrides are the final layer — they can only escalate on top of everything else (severity, group/check-id, and context).

Practical examples

Protect database operations on production branches

version: 1
overrides:
  - id: "database:drop_database"
    challenge: Yes
    on_branches:
      - main
      - production
  - id: "database:truncate_table"
    challenge: Yes
    on_branches:
      - main
      - production

Strict protection for a shared infrastructure repo

version: 1
overrides:
  - id: "terraform:destroy"
    challenge: Yes
  - id: "kubernetes:delete_namespace"
    challenge: Yes
  - id: "aws:delete_stack"
    challenge: Yes
  - id: "docker:system_prune_all"
    challenge: Yes

Gradual escalation by branch

version: 1
overrides:
  # Feature branches: Enter confirmation
  - id: "fs:recursively_delete"
    challenge: Enter

  # Protected branches: Yes confirmation
  - id: "fs:recursively_delete"
    challenge: Yes
    on_branches:
      - main
      - production

When a pattern has multiple overrides (one without branches, one with), the branch-specific override takes priority when the branch matches.