Team Policies
Codify safety rules that travel with your code using .shellfirm.yaml
A .shellfirm.yaml file committed to your repository lets teams codify safety rules that travel with the code. When any team member works in the project directory, the policy is automatically discovered and merged with their personal settings.
The additive-only rule
Project policies are additive only -- they can escalate severity or add deny-listed patterns, but they can never weaken global protections. This means:
- Policies can add new check patterns
- Policies can escalate challenge types (Math to Enter, Enter to Yes)
- Policies can deny specific patterns unconditionally
- Policies can add context configuration (protected branches, k8s patterns)
- Policies cannot lower challenge types
- Policies cannot remove existing checks
- Policies cannot override the user's global severity threshold downward
Creating a policy
Generate a template
shellfirm policy init
This creates a .shellfirm.yaml template in the current directory:
# shellfirm project policy
version: 1
# Additional patterns specific to this project
checks: []
# Override severity for existing patterns
# overrides:
# - id: git:force_push
# challenge: Deny
# - id: git:reset
# on_branches: [main, master]
# challenge: Yes
# Patterns that are unconditionally denied in this project
deny: []
# - git:force_push
# - kubernetes:delete_namespace
# Project-specific context settings
# context:
# protected_branches: [main, master, develop, "release/*"]
# production_k8s_patterns: [prod, production]
Validate a policy
shellfirm policy validate
This checks the .shellfirm.yaml for syntax errors and reports warnings.
Policy features
Deny list
Unconditionally block specific patterns in this project. Denied commands are always rejected, regardless of the user's personal settings or challenge type.
version: 1
deny:
- git:force_push
- kubernetes:delete_namespace
- terraform:apply_with_auto_approve
Challenge overrides
Escalate the challenge type for specific patterns. Overrides can only make things stricter.
version: 1
overrides:
- id: git:reset
challenge: Yes
- id: docker:system_prune_all
challenge: Yes
Branch-specific overrides
Apply overrides only when working on specific branches:
version: 1
overrides:
- id: git:reset
on_branches: [main, master]
challenge: Yes
- id: git:force_push
on_branches: [main, master, "release/*"]
challenge: Yes
When on a feature branch, the override does not apply. When on main, it does.
Custom check patterns
Add project-specific patterns that do not exist in the built-in checks:
version: 1
checks:
- id: custom:deploy_prod
from: custom
test: deploy\s+--env\s+production
severity: Critical
description: "Deploying directly to production"
alternative: "deploy --env staging"
alternative_info: "Deploy to staging first and promote"
- id: custom:migration_run
from: custom
test: rake\s+db:migrate
severity: High
description: "Running database migration"
Context configuration
Add project-specific context settings that are merged with the user's global context:
version: 1
context:
protected_branches:
- main
- master
- develop
- "release/*"
production_k8s_patterns:
- prod
- production
- my-company-prod
How discovery works
When shellfirm runs, it walks up from the current working directory looking for a file named .shellfirm.yaml. The first one found is used. This means:
- A policy in
/repo/.shellfirm.yamlapplies to the entire repository - A policy in
/repo/services/api/.shellfirm.yamlapplies only to theapiservice - The search stops at the first policy found (no merging of multiple policy files)
Effective behavior
When a command is intercepted, the effective behavior is:
- User's global settings are loaded from
~/.config/shellfirm/settings.yaml - Project policy is discovered by walking up directories
- Merge applies the additive-only rule:
- Extra check patterns are appended
- Deny list entries are merged (union)
- Challenge overrides are applied only if they escalate
- Pipeline runs with the merged settings
Example: real-world policy
Here is a realistic policy for a production service:
version: 1
# Block the most dangerous operations
deny:
- git:force_push
- kubernetes:delete_namespace
- terraform:apply_with_auto_approve
# Escalate challenges on protected branches
overrides:
- id: git:reset
on_branches: [main, master, "release/*"]
challenge: Yes
- id: docker:compose_down_volumes
challenge: Yes
# Project-specific checks
checks:
- id: custom:deploy_prod
from: custom
test: deploy\s+--env\s+prod
severity: Critical
description: "Direct production deployment detected"
alternative: "deploy --env staging && promote staging prod"
alternative_info: "Deploy to staging first, then promote to production"
# Context
context:
protected_branches:
- main
- master
- "release/*"
production_k8s_patterns:
- prod
- production
Commit this to your repository and every team member gets the same safety rules automatically.