Skip to main content

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
tip

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
caution

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})'
info

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"
}
note

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