Builder Workflow
The builder workflow enables declarative policy construction through composable resources. Each resource type serves a specific purpose in the evaluation pipeline.
Resource Hierarchy
Esper resources follow a dependency hierarchy:
graph TD
A[Actions] --> P[Policies]
E[Entities] --> P
M[Mitigations] --> P
P --> R[Results]
Resources must be created in dependency order. Policies reference actions, entities, and mitigations by ID.
Development Workflow
1. Template Generation
Start with templates to understand resource schemas and accelerate development.
# Generate all templates for a new project
esper action create --template default > actions/login.json
esper entity create --template default > entities/user.json
esper mitigation create --template block > mitigations/block.json
esper policy create --template default > policies/auth-policy.json
Templates include:
- Field descriptions as comments
- Example values with correct types
- Required vs optional field markers
Templates are environment-aware. They'll include tenant-specific fields when connected to a live environment.
2. Resource Definition
Each resource type has specific responsibilities in the evaluation chain.
Actions
Actions identify business-relevant events in traffic.
{
"name": "user_login",
"description": "User authentication attempt",
"match_conditions": {
"request_path": "/api/auth/login",
"http_method": "POST"
},
"extraction_rules": {
"username": "$.body.username",
"ip_address": "$.headers.x-forwarded-for"
}
}
Key considerations:
- Match conditions use request metadata
- Extraction rules capture context for entity derivation
- Actions should be atomic and reusable
Entities
Entities establish identity across requests.
{
"name": "authenticated_user",
"description": "User identity from session or JWT",
"derivation_rules": [
{
"source": "jwt_claims",
"field": "sub"
},
{
"source": "session",
"field": "user_id"
}
],
"ttl_seconds": 3600
}
Entity design patterns:
- Multiple derivation sources for resilience
- TTL controls state lifecycle
- Hierarchical entities for granular tracking
Mitigations
Mitigations define response strategies.
{
"name": "progressive_challenge",
"type": "challenge",
"configuration": {
"challenge_type": "captcha",
"difficulty": "progressive",
"bypass_tokens": true
},
"duration_seconds": 900
}
Mitigation strategies:
- Monitor: Track without blocking
- Challenge: Require proof of legitimacy
- Block: Deny access
- Rate limit: Throttle activity
3. Local Validation
Validate resources locally before deployment.
# Syntax validation
esper validate --file ./policies/auth-policy.json
# Schema validation with detailed errors
esper validate --file ./actions/login.json --verbose
# Validate entire directory
esper validate --dir ./policies/
Validation checks:
- JSON syntax correctness
- Schema compliance
- Reference integrity
- Field type matching
Local validation doesn't check cross-resource references. Use dry-run for full validation.
4. Deployment Strategies
Individual Deployment
Deploy resources incrementally during development.
# Deploy dependencies first
esper action create --file ./actions/login.json
esper entity create --file ./entities/user.json
esper mitigation create --file ./mitigations/rate-limit.json
# Then deploy policy
esper policy create --file ./policies/auth-policy.json
Batch Deployment
Deploy complete configurations atomically.
# Deploy all resources in order
find ./resources -type f -name "*.json" | \
xargs -I {} esper resource apply --file {}
# Or use a manifest
esper apply --manifest ./deployment.yaml
GitOps Integration
Integrate with CI/CD for automated deployment.
# .github/workflows/deploy.yml
name: Deploy Policies
on:
push:
branches: [main]
paths:
- "policies/**"
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Deploy policies
env:
ESPER_AUTH_TOKEN: ${{ secrets.ESPER_TOKEN }}
run: |
for file in policies/*.json; do
esper policy apply --file "$file"
done
Testing & Validation
Dry Run Mode
Test changes without side effects.
# Validate policy would apply successfully
esper policy apply --file ./policy.json --dry-run
# Check what would be updated
esper policy apply --file ./policy.json --dry-run --diff
Dry run validates:
- Resource references exist
- Field types match expectations
- No circular dependencies
- Policy logic is valid
Replay Testing
Validate policies against historical traffic.
# Create replay job
esper replay create \
--policy-file ./new-policy.json \
--start-time "2024-01-01T00:00:00Z" \
--end-time "2024-01-02T00:00:00Z"
# Monitor replay progress
esper replay status <job-id>
# Analyze replay results
esper replay results <job-id> --format json | \
jq '.matches | group_by(.action) | map({action: .[0].action, count: length})'
Replay jobs run asynchronously. Use webhooks or polling to track completion.
Staged Rollout
Deploy policies gradually to minimize risk.
# Deploy in monitor mode first
esper policy apply --file ./policy.json --override-mitigation monitor
# Analyze results
esper results policy <policy-id> --duration 1h
# Promote to enforcement
esper policy update --file ./policy.json
Resource Management
Version Control
Track resource changes in git.
# Export current state
esper export --type all --output ./resources/
# Track in git
git add resources/
git commit -m "Policy snapshot $(date +%Y%m%d)"
# Diff against production
esper export --type policies --output - | \
diff - ./resources/policies/
Resource Dependencies
Understand resource relationships.
# Show policy dependencies
esper policy dependencies <policy-id>
# Find resources using an action
esper action usage <action-id>
# Dependency graph
esper graph generate --output dependencies.dot
dot -Tpng dependencies.dot -o dependencies.png
Cleanup & Maintenance
Remove unused resources safely.
# Find unused resources
esper resources unused --type actions
# Delete with confirmation
esper resources cleanup --dry-run
esper resources cleanup --confirm
# Archive before deletion
esper export --type all --output ./archive/$(date +%Y%m%d)/
Best Practices
Naming Conventions
Use consistent, descriptive names.
# Good: Clear purpose and scope
auth_failed_action
user_session_entity
rate_limit_mitigation
suspicious_login_policy
# Bad: Ambiguous or generic
action1
test_entity
new_mitigation
policy_v2
Resource Organization
Structure resources logically.
resources/
├── actions/
│ ├── authentication/
│ ├── api/
│ └── user/
├── entities/
│ ├── identity/
│ └── session/
├── mitigations/
│ ├── challenges/
│ └── blocks/
└── policies/
├── security/
└── rate-limiting/
Documentation
Document resource purpose and behavior.
{
"name": "brute_force_detection",
"description": "Detects brute force login attempts",
"_comment": "Triggers after 5 failed attempts in 1 minute",
"_dependencies": ["login_action", "user_entity"],
"_owner": "security-team@example.com",
"_last_updated": "2024-01-15"
}
Use _-prefixed fields for metadata. They're preserved but not evaluated.
Troubleshooting
Common Issues
Reference errors
Error: Action 'login_attempt' not found
Solution: Deploy dependencies before policies.
Validation failures
Error: Invalid field type for 'threshold': expected number, got string
Solution: Check schema with esper schema <resource-type>.
Deployment conflicts
Error: Resource already exists with name 'user_entity'
Solution: Use update instead of create, or use apply for idempotent operations.
Debug Mode
Enable verbose output for troubleshooting.
# Verbose logging
esper --debug policy apply --file ./policy.json
# Trace HTTP requests
ESPER_LOG_LEVEL=trace esper policy list
# Save debug output
esper --debug policy apply --file ./policy.json 2> debug.log