Creating a Policy
Step-by-step guide to creating your first .shellfirm.yaml team policy
This guide walks you through creating a .shellfirm.yaml policy file for your team.
Quick start
Create a .shellfirm.yaml file in your repository root:
shellfirm policy init
This generates a template policy file that you can customize.
Policy format
Every policy file has this structure:
# .shellfirm.yaml
version: 1
# Optional: deny specific patterns entirely
deny: []
# Optional: override challenge types
overrides: []
# Optional: add custom check patterns
checks: []
# Optional: project-specific context configuration
context: {}
The version field is required and must be 1.
Step-by-step: your first policy
Step 1: Identify your team's risky operations
Think about what operations are dangerous in your project:
- Force pushing to protected branches?
- Deleting Kubernetes namespaces?
- Running database migrations in production?
- Recursive file deletions in the project root?
Step 2: Create the policy file
# .shellfirm.yaml
version: 1
# Block force pushes entirely
deny:
- "git:force_push"
# Require explicit "yes" for these operations
overrides:
- id: "fs:recursively_delete"
challenge: Yes
- id: "git:reset_hard"
challenge: Yes
on_branches:
- main
- production
Step 3: Add custom checks for team-specific commands
If your team has custom deployment scripts or tools, add patterns for them:
checks:
- id: "team:deploy_prod"
from: base
test: "deploy\\s+--env\\s+prod"
severity: High
description: "Production deployment - requires explicit approval"
alternative: "deploy --env staging"
alternative_info: "Test in staging first"
- id: "team:db_migrate_prod"
from: base
test: "rake\\s+db:migrate.*RAILS_ENV=production"
severity: Critical
description: "Production database migration"
Step 4: Configure project context (optional)
Add project-specific protected branches or environment variables:
context:
protected_branches:
- staging
- "release/*"
production_env_vars:
DEPLOY_ENV: production
Step 5: Validate the policy
shellfirm policy validate
This checks the YAML syntax and validates all pattern IDs and regex patterns.
Step 6: Commit to your repository
git add .shellfirm.yaml
git commit -m "Add shellfirm team policy"
Complete example for a web application team
# .shellfirm.yaml
version: 1
deny:
# Never allow these in this repository
- "git:force_push"
- "fs:format_filesystem"
overrides:
# Always require "yes" for destructive file operations
- id: "fs:recursively_delete"
challenge: Yes
# Require "yes" for git reset --hard on protected branches
- id: "git:reset_hard"
challenge: Yes
on_branches:
- main
- production
- staging
# Require "yes" for database drops
- id: "database:drop_database"
challenge: Yes
checks:
# Team-specific deployment check
- id: "team:deploy_production"
from: base
test: "deploy\\s+--target\\s+production"
severity: High
description: "Direct production deployment"
alternative: "deploy --target staging"
alternative_info: "Deploy to staging and promote after verification"
# Prevent running seed data in production
- id: "team:seed_production"
from: base
test: "seed.*production|production.*seed"
severity: Critical
description: "Seeding production database can corrupt data"
context:
protected_branches:
- main
- production
- staging
- "release/*"
production_env_vars:
APP_ENV: production
DEPLOY_TARGET: live
Field reference
| Field | Required | Type | Description |
|---|---|---|---|
version | Yes | integer | Schema version, must be 1 |
deny | No | string[] | Pattern IDs to deny entirely |
overrides | No | Override[] | Challenge type overrides per pattern |
checks | No | Check[] | Custom check patterns |
context | No | object | Project-specific context configuration |
Override fields
| Field | Required | Type | Description |
|---|---|---|---|
id | Yes | string | Pattern ID to override (e.g., fs:recursively_delete) |
challenge | No | string | Challenge type: Math, Enter, or Yes |
on_branches | No | string[] | Only apply on these branches |
Custom check fields
| Field | Required | Type | Description |
|---|---|---|---|
id | Yes | string | Unique ID in group:name format |
from | Yes | string | Check group (used for enabling/disabling) |
test | Yes | string | Regex pattern to match |
severity | Yes | string | Info, Low, Medium, High, or Critical |
description | Yes | string | Human-readable description |
alternative | No | string | Safer alternative command |
alternative_info | No | string | Explanation of why the alternative is safer |
filters | No | Filter[] | Post-match filters (NotContains, Contains, PathExists) |