Policy-as-Code
Configure branch-specific quality gates with vertaa.policy.yml
Policy-as-Code
Policy-as-code lets you define UX quality standards as a YAML configuration file in your repository. Different branches can have different thresholds, and the CLI automatically enforces the right policy based on the current branch.
What is Policy-as-Code?
Instead of passing flags like --threshold 80 --fail-on error every time, define policies once:
version: 1
branches:
main:
pattern: "^main$"
assertions:
fail_on: error
overall_score: 85
max_new_errors: 0Then simply run:
# Policy automatically applies based on current branch
vertaa audit -u $PREVIEW_URLBenefits:
- Consistency - Same rules apply regardless of who runs the audit
- Visibility - Quality standards are visible in the repository
- Flexibility - Different standards for different contexts
- Version control - Policy changes are tracked with code changes
File Location
The policy file must be named vertaa.policy.yml and placed in your repository root:
your-repo/
vertaa.policy.yml # Policy file here
src/
package.jsonThe CLI automatically detects and uses this file when running in a Git repository.
Schema Reference
Top-Level Structure
version: 1 # Required. Only version 1 is currently supported
branches: # Required. Map of branch configurations
main: # Branch name (for display/organization)
pattern: "^main$" # Regex pattern to match branch names
assertions: # Quality gate rules
# ... assertion optionsBranch Pattern Syntax
The pattern field uses regular expressions to match branch names:
| Pattern | Matches |
|---|---|
"^main$" | Exactly "main" |
"^develop$" | Exactly "develop" |
"^feature/.*$" | Any branch starting with "feature/" |
"^release/v\\d+\\.\\d+$" | Release branches like "release/v1.0" |
"^hotfix/.*$" | Any branch starting with "hotfix/" |
".*" | Any branch (catch-all) |
Patterns are evaluated in order. The first matching pattern wins. Use a catch-all pattern at the end for defaults.
Assertion Options
| Assertion | Type | Description |
|---|---|---|
fail_on | 'error' | 'warning' | 'none' | Minimum severity to fail the audit |
overall_score | number (0-100) | Minimum overall score required |
max_new_errors | number | Maximum new errors compared to baseline |
max_new_warnings | number | Maximum new warnings compared to baseline |
max_regressions | number | Maximum rules that got worse vs baseline |
Assertion behavior:
fail_on: error- Fail if any error-severity issue existsfail_on: warning- Fail if any warning or error existsfail_on: none- Never fail based on severity (still checks other assertions)overall_score: 85- Fail if score < 85max_new_errors: 0- Fail if any new errors since baselinemax_new_warnings: 5- Allow up to 5 new warningsmax_regressions: 0- Fail if any rule scores got worse
Example Configurations
Strict Main Branch
Enforce high standards on production code:
version: 1
branches:
main:
pattern: "^main$"
assertions:
fail_on: error
overall_score: 90
max_new_errors: 0
max_new_warnings: 0
max_regressions: 0Relaxed Feature Branches
Allow work-in-progress on feature branches:
version: 1
branches:
main:
pattern: "^main$"
assertions:
fail_on: error
overall_score: 90
max_new_errors: 0
feature:
pattern: "^feature/.*$"
assertions:
fail_on: error
overall_score: 70
max_new_errors: 3
max_new_warnings: 10Staging Environment
Different rules for staging vs production:
version: 1
branches:
main:
pattern: "^main$"
assertions:
fail_on: error
overall_score: 90
max_new_errors: 0
staging:
pattern: "^staging$"
assertions:
fail_on: error
overall_score: 80
max_new_warnings: 5
develop:
pattern: "^develop$"
assertions:
fail_on: error
overall_score: 70Release Branches
Strict rules for release candidates:
version: 1
branches:
release:
pattern: "^release/.*$"
assertions:
fail_on: error
overall_score: 95
max_new_errors: 0
max_new_warnings: 0
hotfix:
pattern: "^hotfix/.*$"
assertions:
fail_on: error
overall_score: 85
max_new_errors: 0
main:
pattern: "^main$"
assertions:
fail_on: error
overall_score: 90
default:
pattern: ".*"
assertions:
fail_on: error
overall_score: 70Monorepo with Path-Based Rules
For monorepos, combine with --paths flag:
version: 1
branches:
main:
pattern: "^main$"
assertions:
fail_on: error
overall_score: 85
feature:
pattern: "^feature/.*$"
assertions:
fail_on: error
overall_score: 70Then in CI:
# Audit only changed paths
- run: |
CHANGED_PATHS=$(git diff --name-only origin/main | xargs dirname | sort -u)
for path in $CHANGED_PATHS; do
vertaa audit -u "$PREVIEW_URL/$path" --paths "$path/**"
doneProgressive Improvement
Start lenient and tighten over time:
version: 1
branches:
main:
pattern: "^main$"
assertions:
fail_on: error
overall_score: 60
max_new_errors: 0version: 1
branches:
main:
pattern: "^main$"
assertions:
fail_on: error
overall_score: 75
max_new_errors: 0
max_new_warnings: 0version: 1
branches:
main:
pattern: "^main$"
assertions:
fail_on: error
overall_score: 90
max_new_errors: 0
max_new_warnings: 0
max_regressions: 0Policy vs CLI Flags
When both policy file and CLI flags are present, CLI flags take precedence:
| Source | Priority |
|---|---|
| CLI flags | Highest (always wins) |
vertaa.policy.yml | Medium |
| Built-in defaults | Lowest |
Example:
version: 1
branches:
main:
pattern: "^main$"
assertions:
overall_score: 85# CLI flag overrides policy
vertaa audit -u $URL --threshold 70
# Uses threshold 70, not 85This allows one-off overrides without changing the policy file.
Using with Baselines
The max_new_errors, max_new_warnings, and max_regressions assertions require a baseline file:
# First, create baseline
vertaa baseline -u $PRODUCTION_URL --update baseline.json
# Then audit with baseline comparison
vertaa audit -u $PREVIEW_URL --baseline baseline.jsonWithout a baseline, these assertions are ignored:
| With Baseline | Without Baseline |
|---|---|
max_new_errors: 0 enforced | max_new_errors: 0 ignored |
max_new_warnings: 5 enforced | max_new_warnings: 5 ignored |
max_regressions: 0 enforced | max_regressions: 0 ignored |
See Baseline Management for CI workflows.
Validating Policy Files
Check your policy file for errors:
vertaa policy validateOutput:
vertaa.policy.yml: valid
- 3 branch patterns defined
- main: overall_score=85, fail_on=error
- feature: overall_score=70, fail_on=error
- default: overall_score=60, fail_on=errorIf invalid:
vertaa.policy.yml: invalid
Error at line 5: 'fail_on' must be 'error', 'warning', or 'none'Viewing Active Policy
See which policy applies to the current branch:
vertaa policy showOutput:
Current branch: feature/add-checkout
Matched pattern: ^feature/.*$
Active assertions:
fail_on: error
overall_score: 70
max_new_errors: 3
max_new_warnings: 10Best Practices
Start Lenient, Tighten Over Time
Don't block all builds on day one:
- Start with
overall_score: 60andmax_new_errors: 0 - Monitor baseline improvements
- Gradually increase thresholds
- Add warnings enforcement after errors are controlled
Use Baselines for Fairness
Without baselines, PRs inherit all existing issues. With baselines:
- Existing issues don't block PRs
- Only new issues are enforced
- Teams can improve incrementally
Different Rules for Different Contexts
| Context | Recommended Policy |
|---|---|
| Production (main) | Strictest: high score, no new issues |
| Staging | Moderate: medium score, limited warnings |
| Feature branches | Lenient: lower score, more warnings allowed |
| Hotfixes | Strict for safety, but skip baseline checks |
Keep Patterns Specific
Avoid patterns that match unexpectedly:
# Bad: too broad
branches:
all:
pattern: ".*main.*" # Matches "main", "domain", "maintenance"
# Good: specific
branches:
main:
pattern: "^main$" # Only matches exactly "main"Document Your Policies
Add comments explaining the rationale:
version: 1
branches:
# Production branch - highest standards
main:
pattern: "^main$"
assertions:
fail_on: error
overall_score: 90
max_new_errors: 0 # No new errors ever
max_regressions: 0 # No rule scores can get worse
# Feature branches - work in progress allowed
feature:
pattern: "^feature/.*$"
assertions:
fail_on: error # Block critical errors
overall_score: 70 # Lower threshold for WIP
max_new_errors: 3 # Some flexibility for iterationFull Schema
version: 1 # Required, integer
branches: # Required, object
<branch-name>: # String, for organization only
pattern: <regex> # Required, string (regex pattern)
assertions: # Required, object
fail_on: <severity> # Optional, 'error' | 'warning' | 'none'
overall_score: <number> # Optional, 0-100
max_new_errors: <number> # Optional, >= 0
max_new_warnings: <number> # Optional, >= 0
max_regressions: <number> # Optional, >= 0Related
GitHub Actions
Workflows with baseline management
CLI Commands
All CLI options for audit and baseline
.vertaaux.yml
Project configuration defaults
Was this page helpful?