18 KiB
Rule Parameter Mapping
Overview
Rules in Attune can specify parameters to pass to actions when triggered. These parameters can be:
- Static values - Hard-coded values defined in the rule
- Dynamic from event payload - Values extracted from the event that triggered the rule
- Dynamic from pack config - Values from the pack's configuration
This enables flexible parameter passing without hardcoding values or requiring custom code.
Parameter Mapping Format
Rule action_params uses a JSON object where each value can be:
- Static: A literal value (string, number, boolean, object, array)
- Dynamic: A template string using
{{ }}syntax to reference runtime values
Template Syntax
{{ source.path.to.value }}
Available Sources:
event.payload.*- Data from the event payloadpack.config.*- Configuration values from the packsystem.*- System-provided values (timestamp, execution context)
Static Parameter Example
The simplest form - just pass fixed values to the action:
{
"ref": "slack.notify_on_error",
"pack_ref": "slack",
"trigger_ref": "core.error_event",
"action_ref": "slack.post_message",
"action_params": {
"channel": "#alerts",
"message": "An error occurred in the system",
"color": "danger"
}
}
When this rule triggers, the action receives exactly these parameters.
Dynamic Parameters from Event Payload
Extract values from the event that triggered the rule.
Example: Alert with Event Data
Event Payload:
{
"severity": "error",
"service": "api-gateway",
"message": "Database connection failed",
"timestamp": "2024-01-15T10:30:00Z",
"metadata": {
"host": "api-01.example.com",
"error_code": "DB_CONN_TIMEOUT"
}
}
Rule Definition:
{
"ref": "alerts.error_notification",
"pack_ref": "alerts",
"trigger_ref": "core.error_event",
"action_ref": "slack.post_message",
"action_params": {
"channel": "#incidents",
"message": "Error in {{ event.payload.service }}: {{ event.payload.message }}",
"severity": "{{ event.payload.severity }}",
"host": "{{ event.payload.metadata.host }}",
"timestamp": "{{ event.payload.timestamp }}"
}
}
Resulting Action Parameters:
{
"channel": "#incidents",
"message": "Error in api-gateway: Database connection failed",
"severity": "error",
"host": "api-01.example.com",
"timestamp": "2024-01-15T10:30:00Z"
}
Dynamic Parameters from Pack Config
Use configuration values stored at the pack level (useful for API keys, URLs, etc.).
Example: Using Pack Configuration
Pack Configuration:
{
"ref": "slack",
"config": {
"api_token": "xoxb-1234567890-abcdefghijk",
"default_channel": "#general",
"webhook_url": "https://hooks.slack.com/services/...",
"bot_name": "Attune Bot"
}
}
Rule Definition:
{
"ref": "slack.auto_notify",
"pack_ref": "slack",
"trigger_ref": "core.notification_event",
"action_ref": "slack.post_message",
"action_params": {
"token": "{{ pack.config.api_token }}",
"channel": "{{ pack.config.default_channel }}",
"username": "{{ pack.config.bot_name }}",
"message": "{{ event.payload.message }}"
}
}
Benefits:
- Secrets stored in pack config, not in rules
- Easy to update credentials without changing rules
- Reuse configuration across multiple rules
Mixed Parameters (Static + Dynamic)
Combine static and dynamic values in the same rule:
{
"ref": "github.create_issue",
"pack_ref": "github",
"trigger_ref": "core.error_event",
"action_ref": "github.create_issue",
"action_params": {
"repo": "myorg/myrepo",
"token": "{{ pack.config.github_token }}",
"title": "Error: {{ event.payload.message }}",
"body": "Service {{ event.payload.service }} reported an error at {{ event.payload.timestamp }}",
"labels": ["bug", "automated"],
"assignees": ["oncall"]
}
}
Nested Object Access
Access nested properties using dot notation:
{
"action_params": {
"user_id": "{{ event.payload.user.id }}",
"user_name": "{{ event.payload.user.profile.name }}",
"metadata": {
"ip_address": "{{ event.payload.request.client_ip }}",
"user_agent": "{{ event.payload.request.headers.user_agent }}"
}
}
}
Array Access
Access array elements by index:
{
"action_params": {
"first_error": "{{ event.payload.errors.0 }}",
"primary_tag": "{{ event.payload.tags.0 }}"
}
}
Default Values and Fallbacks
Provide default values when the referenced field doesn't exist:
{
"action_params": {
"priority": "{{ event.payload.priority | default: 'medium' }}",
"assignee": "{{ event.payload.assignee | default: 'unassigned' }}"
}
}
Type Preservation
Template values preserve their JSON types:
{
"action_params": {
"count": "{{ event.payload.count }}", // Number: 42
"enabled": "{{ event.payload.enabled }}", // Boolean: true
"tags": "{{ event.payload.tags }}", // Array: ["a", "b"]
"metadata": "{{ event.payload.metadata }}" // Object: {"key": "value"}
}
}
System Variables
Access system-provided values:
{
"action_params": {
"execution_time": "{{ system.timestamp }}",
"rule_id": "{{ system.rule.id }}",
"rule_ref": "{{ system.rule.ref }}",
"event_id": "{{ system.event.id }}",
"enforcement_id": "{{ system.enforcement.id }}"
}
}
String Interpolation
Embed multiple values in a single string:
{
"action_params": {
"message": "User {{ event.payload.user_id }} performed {{ event.payload.action }} at {{ system.timestamp }}",
"subject": "[{{ event.payload.severity | upper }}] {{ event.payload.service }} Alert"
}
}
Filters (Future Enhancement)
Apply transformations to values:
{
"action_params": {
"uppercase_name": "{{ event.payload.name | upper }}",
"lowercase_email": "{{ event.payload.email | lower }}",
"formatted_date": "{{ event.payload.timestamp | date: '%Y-%m-%d' }}",
"truncated": "{{ event.payload.message | truncate: 100 }}"
}
}
Available Filters:
upper- Convert to uppercaselower- Convert to lowercasetrim- Remove whitespacedefault: <value>- Use default if null/missingdate: <format>- Format timestamptruncate: <length>- Truncate stringjson- Serialize to JSON stringbase64- Base64 encodelength- Get length/count
Real-World Examples
1. Webhook to Slack Alert
{
"ref": "monitoring.webhook_to_slack",
"pack_ref": "monitoring",
"trigger_ref": "core.webhook",
"action_ref": "slack.post_message",
"action_params": {
"channel": "{{ pack.config.alert_channel }}",
"token": "{{ pack.config.slack_token }}",
"message": "⚠️ Alert from {{ event.payload.source }}: {{ event.payload.message }}",
"attachments": [
{
"color": "{{ event.payload.severity | default: 'warning' }}",
"fields": [
{
"title": "Service",
"value": "{{ event.payload.service }}",
"short": true
},
{
"title": "Environment",
"value": "{{ event.payload.environment | default: 'production' }}",
"short": true
}
],
"footer": "Attune Automation",
"ts": "{{ system.timestamp }}"
}
]
}
}
2. Error to Ticket System
{
"ref": "errors.create_ticket",
"pack_ref": "errors",
"trigger_ref": "core.error_event",
"action_ref": "jira.create_issue",
"action_params": {
"project": "{{ pack.config.jira_project }}",
"auth": {
"username": "{{ pack.config.jira_username }}",
"token": "{{ pack.config.jira_token }}"
},
"issuetype": "Bug",
"summary": "[{{ event.payload.severity }}] {{ event.payload.service }}: {{ event.payload.message }}",
"description": {
"type": "doc",
"content": [
{
"type": "paragraph",
"content": [
{
"type": "text",
"text": "Error Details:\n\nService: {{ event.payload.service }}\nHost: {{ event.payload.host }}\nTimestamp: {{ event.payload.timestamp }}\n\nStack Trace:\n{{ event.payload.stack_trace }}"
}
]
}
]
},
"priority": "{{ event.payload.priority | default: 'Medium' }}",
"labels": ["automated", "{{ event.payload.service }}"]
}
}
3. Metric Threshold to PagerDuty
{
"ref": "monitoring.critical_alert",
"pack_ref": "monitoring",
"trigger_ref": "metrics.threshold_exceeded",
"action_ref": "pagerduty.trigger_incident",
"action_params": {
"routing_key": "{{ pack.config.pagerduty_routing_key }}",
"event_action": "trigger",
"payload": {
"summary": "{{ event.payload.metric_name }} exceeded threshold on {{ event.payload.host }}",
"severity": "critical",
"source": "{{ event.payload.host }}",
"custom_details": {
"metric": "{{ event.payload.metric_name }}",
"current_value": "{{ event.payload.current_value }}",
"threshold": "{{ event.payload.threshold }}",
"duration": "{{ event.payload.duration_seconds }}s"
}
},
"dedup_key": "{{ event.payload.host }}_{{ event.payload.metric_name }}"
}
}
4. Timer to HTTP Request
{
"ref": "healthcheck.periodic_ping",
"pack_ref": "healthcheck",
"trigger_ref": "core.interval_timer",
"action_ref": "http.request",
"action_params": {
"method": "POST",
"url": "{{ pack.config.healthcheck_endpoint }}",
"headers": {
"Authorization": "Bearer {{ pack.config.api_token }}",
"Content-Type": "application/json"
},
"body": {
"source": "attune",
"timestamp": "{{ system.timestamp }}",
"rule": "{{ system.rule.ref }}"
},
"timeout": 30
}
}
Implementation Details
Template Processing Flow
- Rule Evaluation - When an event matches a rule
- Template Extraction - Identify
{{ }}patterns inaction_params - Context Building - Assemble available data:
event.id- Event database IDevent.trigger- Trigger ref that generated the eventevent.created- Event creation timestampevent.payload- Event payload datapack.config- Pack configurationsystem.*- System-provided values (timestamp, rule info)
- Value Resolution - Extract values from context using dot notation paths
- Type Conversion - Preserve JSON types (string, number, boolean, object, array)
- Parameter Assembly - Build final parameter object
- Enforcement Creation - Store resolved parameters in enforcement config
- Execution Creation - Pass parameters to action execution
Error Handling
Missing Values:
- If a referenced value doesn't exist and no default is provided, use
null - Log warning:
"Template variable not found: event.payload.missing_field"
Invalid Syntax:
- If template syntax is invalid, log error and use the raw string
- Log error:
"Invalid template syntax: {{ incomplete"
Type Mismatches:
- Preserve JSON types when possible
- Convert to string as fallback for complex interpolation
Configuration in Pack
Pack configuration should be stored securely and can include:
{
"ref": "mypack",
"config": {
"api_token": "secret-token-here",
"api_url": "https://api.example.com",
"default_timeout": 30,
"retry_attempts": 3,
"enable_notifications": true,
"notification_channels": ["#alerts", "#monitoring"]
}
}
Security Note: Sensitive values (API keys, tokens, passwords) should be stored in pack config, not in rule definitions, since:
- Pack configs can be encrypted
- Easier to rotate credentials
- Rules can be version controlled without exposing secrets
Best Practices
1. Use Pack Config for Secrets
❌ Bad:
{
"action_params": {
"api_key": "sk_live_abc123xyz789" // Hardcoded secret
}
}
✅ Good:
{
"action_params": {
"api_key": "{{ pack.config.api_key }}"
}
}
2. Provide Defaults for Optional Fields
{
"action_params": {
"priority": "{{ event.payload.priority | default: 'medium' }}",
"assignee": "{{ event.payload.assignee | default: 'unassigned' }}"
}
}
3. Use Descriptive Template Paths
{
"action_params": {
"user_email": "{{ event.payload.user.email }}",
"user_id": "{{ event.payload.user.id }}"
}
}
4. Keep Static Values Where Appropriate
If a value never changes, keep it static:
{
"action_params": {
"service_name": "my-service", // Static - never changes
"error_code": "{{ event.payload.code }}" // Dynamic - from event
}
}
5. Test Your Templates
Create test events with sample payloads to verify your templates extract the correct values.
Testing Parameter Mapping
1. Manual Testing via API
Create a test event with known payload:
curl -X POST http://localhost:8080/api/v1/events \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"trigger_ref": "core.test_event",
"payload": {
"message": "Test message",
"severity": "info",
"user": {
"id": 123,
"name": "Alice"
}
}
}'
Check the resulting enforcement and execution to verify parameters were resolved correctly:
# Check enforcement
curl -X GET http://localhost:8080/api/v1/enforcements/1 \
-H "Authorization: Bearer $TOKEN"
# Check execution
curl -X GET http://localhost:8080/api/v1/executions/1 \
-H "Authorization: Bearer $TOKEN"
2. Validate Parameter Resolution
Look for the resolved parameters in the execution's config field:
{
"id": 1,
"config": {
"message": "Test message", // Resolved from event.payload.message
"severity": "info", // Resolved from event.payload.severity
"user_id": 123, // Resolved from event.payload.user.id
"user_name": "Alice" // Resolved from event.payload.user.name
"event_id": 456, // Resolved from event.id
"trigger": "core.test_event" // Resolved from event.trigger
}
}
Migration Guide
From Static to Dynamic Parameters
Before (Static):
{
"action_params": {
"message": "An error occurred"
}
}
After (Dynamic):
{
"action_params": {
"message": "Error: {{ event.payload.message }}"
}
}
From Hardcoded Secrets to Pack Config
Before (Hardcoded):
{
"action_params": {
"api_key": "sk_live_abc123"
}
}
Steps:
- Add secret to pack config
- Update rule to reference pack config
- Remove hardcoded value
After (Secure):
{
"action_params": {
"api_key": "{{ pack.config.api_key }}"
}
}
Troubleshooting
Templates Not Resolving
Problem: Parameters contain literal {{ ... }} strings instead of resolved values.
Solutions:
- Check template syntax is correct
- Verify the referenced path exists in the event payload
- Check sensor service logs for template resolution errors
- Use default values for optional fields
Incorrect Values
Problem: Parameters have wrong values.
Solutions:
- Inspect event payload structure:
SELECT payload FROM attune.event WHERE id = X; - Verify the dot notation path matches the payload structure
- Check for typos in template paths
- Use system logs to see template resolution details
Type Conversion Issues
Problem: Numbers or booleans become strings.
Solutions:
- Ensure the source value is the correct type in the payload
- Check if string interpolation is converting types
- Use direct references without string interpolation for non-string types
Future Enhancements
1. Conditional Parameters
{
"action_params": {
"channel": "{% if event.payload.severity == 'critical' %}#incidents{% else %}#monitoring{% endif %}"
}
}
2. Advanced Filters
- Mathematical operations:
{{ event.payload.value | multiply: 100 }} - String manipulation:
{{ event.payload.text | replace: 'old', 'new' }} - Array operations:
{{ event.payload.items | join: ', ' }}
3. Custom Functions
{
"action_params": {
"timestamp": "{{ now() }}",
"uuid": "{{ uuid() }}",
"hash": "{{ hash(event.payload.data) }}"
}
}
4. Multi-Source Merging
{
"action_params": {
"user": "{{ event.payload.user | merge: pack.config.default_user }}"
}
}
Related Documentation
- Rule Management API
- Event Management API
- Pack Management API
- Sensor Service Architecture
- Security Best Practices
- Secrets Management
Summary
Rule parameter mapping provides a powerful way to:
- Decouple rules from data - Rules reference data locations, not specific values
- Reuse pack configuration - Share credentials and settings across rules
- Dynamic automation - Respond to events with context-aware actions
- Secure secrets - Store sensitive data in pack config, not rule definitions
- Flexible workflows - Build complex automations without custom code
Key Concepts:
- Static values for constants
{{ event.payload.* }}for event payload data{{ event.id }},{{ event.trigger }},{{ event.created }}for event metadata{{ pack.config.* }}for pack configuration{{ system.* }}for system-provided values- Filters and defaults for robust templates
This feature enables Attune to match the flexibility of platforms like StackStorm while maintaining a clean, declarative approach to automation.