790 lines
24 KiB
Markdown
790 lines
24 KiB
Markdown
# Webhook System Architecture
|
|
|
|
**Last Updated**: 2026-01-20
|
|
**Status**: Phase 3 Complete - Advanced Security Features Implemented
|
|
|
|
---
|
|
|
|
## Overview
|
|
|
|
Attune provides built-in webhook support as a first-class feature of the trigger system. Any trigger can be webhook-enabled, allowing external systems to fire events by posting to a unique webhook URL. This eliminates the need for generic webhook triggers and provides better security and traceability.
|
|
|
|
---
|
|
|
|
## Core Concepts
|
|
|
|
### Webhook-Enabled Triggers
|
|
|
|
Any trigger in Attune can have webhooks enabled:
|
|
|
|
1. **Pack declares trigger** (e.g., `github.push`, `stripe.payment_succeeded`)
|
|
2. **User enables webhooks** via toggle in UI or API
|
|
3. **System generates unique webhook key** (secure random token)
|
|
4. **Webhook URL is provided** for external system configuration
|
|
5. **External system POSTs to webhook URL** with payload
|
|
6. **Attune creates event** from webhook payload
|
|
7. **Rules evaluate normally** against the event
|
|
|
|
### Key Benefits
|
|
|
|
- **Per-Trigger Security**: Each trigger has its own unique webhook key
|
|
- **No Generic Triggers**: Webhooks are a feature, not a trigger type
|
|
- **Better Traceability**: Clear association between webhook and trigger
|
|
- **Flexible Payloads**: Each trigger defines its own payload schema
|
|
- **Multi-Tenancy Ready**: Webhook keys can be scoped to identities/organizations
|
|
|
|
---
|
|
|
|
## Architecture
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ External Systems │
|
|
├─────────────────────────────────────────────────────────────┤
|
|
│ GitHub │ Stripe │ Slack │ Custom Apps │ etc. │
|
|
└────┬──────────┬──────────┬──────────┬───────────────────────┘
|
|
│ │ │ │
|
|
│ POST │ POST │ POST │ POST
|
|
│ │ │ │
|
|
▼ ▼ ▼ ▼
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ Attune API - Webhook Receiver Endpoint │
|
|
│ POST /api/v1/webhooks/:webhook_key │
|
|
├─────────────────────────────────────────────────────────────┤
|
|
│ 1. Validate webhook key │
|
|
│ 2. Look up associated trigger │
|
|
│ 3. Parse and validate payload │
|
|
│ 4. Create event in database │
|
|
│ 5. Return 200 OK │
|
|
└────────────────────────┬────────────────────────────────────┘
|
|
│
|
|
▼
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ PostgreSQL Database │
|
|
│ ┌────────┐ ┌───────┐ ┌───────┐ │
|
|
│ │Trigger │───▶│ Event │───▶│ Rule │ │
|
|
│ │webhook │ │ │ │ │ │
|
|
│ │enabled │ │ │ │ │ │
|
|
│ │webhook │ │ │ │ │ │
|
|
│ │ key │ │ │ │ │ │
|
|
│ └────────┘ └───────┘ └───────┘ │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
│
|
|
▼
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ Rule Evaluation │
|
|
│ Execution Scheduling │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## Database Schema
|
|
|
|
### Existing `attune.trigger` Table Extensions
|
|
|
|
Add webhook-related columns to the trigger table:
|
|
|
|
```sql
|
|
ALTER TABLE attune.trigger ADD COLUMN IF NOT EXISTS
|
|
webhook_enabled BOOLEAN NOT NULL DEFAULT FALSE;
|
|
|
|
ALTER TABLE attune.trigger ADD COLUMN IF NOT EXISTS
|
|
webhook_key VARCHAR(64) UNIQUE;
|
|
|
|
ALTER TABLE attune.trigger ADD COLUMN IF NOT EXISTS
|
|
webhook_secret VARCHAR(128); -- For HMAC signature verification (optional)
|
|
|
|
-- Index for fast webhook key lookup
|
|
CREATE INDEX IF NOT EXISTS idx_trigger_webhook_key
|
|
ON attune.trigger(webhook_key)
|
|
WHERE webhook_key IS NOT NULL;
|
|
```
|
|
|
|
### Webhook Event Metadata
|
|
|
|
Events created from webhooks include additional metadata:
|
|
|
|
```json
|
|
{
|
|
"source": "webhook",
|
|
"webhook_key": "wh_abc123...",
|
|
"webhook_metadata": {
|
|
"received_at": "2024-01-20T12:00:00Z",
|
|
"source_ip": "192.168.1.100",
|
|
"user_agent": "GitHub-Hookshot/abc123",
|
|
"headers": {
|
|
"X-GitHub-Event": "push",
|
|
"X-GitHub-Delivery": "12345-67890"
|
|
}
|
|
},
|
|
"payload": {
|
|
// Original webhook payload from external system
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## API Endpoints
|
|
|
|
### Webhook Receiver
|
|
|
|
**Receive Webhook Event**
|
|
|
|
```http
|
|
POST /api/v1/webhooks/:webhook_key
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"ref": "refs/heads/main",
|
|
"commits": [...],
|
|
"repository": {...}
|
|
}
|
|
```
|
|
|
|
**Response (Success)**
|
|
```http
|
|
HTTP/1.1 200 OK
|
|
Content-Type: application/json
|
|
|
|
```
|
|
|
|
**Response (Invalid Key)**
|
|
```http
|
|
HTTP/1.1 404 Not Found
|
|
Content-Type: application/json
|
|
|
|
```
|
|
|
|
**Response (Disabled)**
|
|
```http
|
|
HTTP/1.1 403 Forbidden
|
|
Content-Type: application/json
|
|
|
|
```
|
|
|
|
### Webhook Management
|
|
|
|
**Enable Webhooks for Trigger**
|
|
|
|
```http
|
|
POST /api/v1/triggers/:id/webhook/enable
|
|
Authorization: Bearer <token>
|
|
```
|
|
|
|
**Response**
|
|
```json
|
|
{
|
|
"data": {
|
|
"id": 123,
|
|
"ref": "github.push",
|
|
"webhook_enabled": true,
|
|
"webhook_key": "wh_abc123xyz789...",
|
|
"webhook_url": "https://attune.example.com/api/v1/webhooks/wh_abc123xyz789..."
|
|
}
|
|
}
|
|
```
|
|
|
|
**Disable Webhooks for Trigger**
|
|
|
|
```http
|
|
POST /api/v1/triggers/:id/webhook/disable
|
|
Authorization: Bearer <token>
|
|
```
|
|
|
|
**Regenerate Webhook Key**
|
|
|
|
```http
|
|
POST /api/v1/triggers/:id/webhook/regenerate
|
|
Authorization: Bearer <token>
|
|
```
|
|
|
|
**Response**
|
|
```json
|
|
{
|
|
"data": {
|
|
"webhook_key": "wh_new_key_here...",
|
|
"webhook_url": "https://attune.example.com/api/v1/webhooks/wh_new_key_here...",
|
|
"previous_key_revoked": true
|
|
}
|
|
}
|
|
```
|
|
|
|
**Get Webhook Info**
|
|
|
|
```http
|
|
GET /api/v1/triggers/:id/webhook
|
|
Authorization: Bearer <token>
|
|
```
|
|
|
|
**Response**
|
|
```json
|
|
{
|
|
"data": {
|
|
"enabled": true,
|
|
"webhook_key": "wh_abc123xyz789...",
|
|
"webhook_url": "https://attune.example.com/api/v1/webhooks/wh_abc123xyz789...",
|
|
"created_at": "2024-01-20T10:00:00Z",
|
|
"last_used_at": "2024-01-20T12:30:00Z",
|
|
"total_events": 145
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Webhook Key Format
|
|
|
|
Webhook keys use a recognizable prefix and secure random suffix:
|
|
|
|
```
|
|
wh_[32 random alphanumeric characters]
|
|
```
|
|
|
|
**Example**: `wh_k7j2n9p4m8q1r5w3x6z0a2b5c8d1e4f7`
|
|
|
|
**Generation (Rust)**:
|
|
```rust
|
|
use rand::Rng;
|
|
use rand::distributions::Alphanumeric;
|
|
|
|
fn generate_webhook_key() -> String {
|
|
let random_part: String = rand::thread_rng()
|
|
.sample_iter(&Alphanumeric)
|
|
.take(32)
|
|
.map(char::from)
|
|
.collect();
|
|
|
|
format!("wh_{}", random_part)
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Security Considerations
|
|
|
|
### 1. Webhook Key as Bearer Token
|
|
|
|
The webhook key acts as a bearer token - anyone with the key can post events. Therefore:
|
|
|
|
- Keys must be long and random (32+ characters)
|
|
- Keys must be stored securely
|
|
- Keys should be transmitted over HTTPS only
|
|
- Keys can be regenerated if compromised
|
|
|
|
### 2. Optional Signature Verification
|
|
|
|
For enhanced security, triggers can require HMAC signature verification:
|
|
|
|
```http
|
|
POST /api/v1/webhooks/:webhook_key
|
|
X-Webhook-Signature: sha256=abc123...
|
|
Content-Type: application/json
|
|
|
|
{...}
|
|
```
|
|
|
|
The signature is computed as:
|
|
```
|
|
HMAC-SHA256(webhook_secret, request_body)
|
|
```
|
|
|
|
This prevents replay attacks and ensures payload integrity.
|
|
|
|
### 3. IP Whitelisting (Future)
|
|
|
|
Triggers can optionally restrict webhooks to specific IP ranges:
|
|
|
|
```json
|
|
{
|
|
"webhook_enabled": true,
|
|
"webhook_ip_whitelist": [
|
|
"192.30.252.0/22", // GitHub
|
|
"185.199.108.0/22" // GitHub
|
|
]
|
|
}
|
|
```
|
|
|
|
### 4. Rate Limiting
|
|
|
|
Apply rate limits to prevent abuse:
|
|
|
|
- Per webhook key: 100 requests per minute
|
|
- Per IP address: 1000 requests per minute
|
|
- Global: 10,000 requests per minute
|
|
|
|
### 5. Payload Size Limits
|
|
|
|
Limit webhook payload sizes:
|
|
|
|
- Maximum payload size: 1 MB
|
|
- Reject larger payloads with 413 Payload Too Large
|
|
|
|
---
|
|
|
|
## Event Creation from Webhooks
|
|
|
|
### Event Structure
|
|
|
|
```sql
|
|
INSERT INTO attune.event (
|
|
trigger,
|
|
trigger_ref,
|
|
payload,
|
|
metadata,
|
|
source
|
|
) VALUES (
|
|
<trigger_id>,
|
|
<trigger_ref>,
|
|
<webhook_payload>,
|
|
jsonb_build_object(
|
|
'source', 'webhook',
|
|
'webhook_key', <webhook_key>,
|
|
'received_at', NOW(),
|
|
'source_ip', <client_ip>,
|
|
'user_agent', <user_agent>,
|
|
'headers', <selected_headers>
|
|
),
|
|
'webhook'
|
|
);
|
|
```
|
|
|
|
### Payload Transformation
|
|
|
|
Webhooks can optionally transform payloads before creating events:
|
|
|
|
1. **Direct Pass-Through** (default): Entire webhook body becomes event payload
|
|
2. **JSONPath Extraction**: Extract specific fields from webhook payload
|
|
3. **Template Transformation**: Use templates to reshape payload
|
|
|
|
**Example (JSONPath)**:
|
|
```json
|
|
{
|
|
"webhook_payload_mapping": {
|
|
"commit_sha": "$.head_commit.id",
|
|
"branch": "$.ref",
|
|
"author": "$.head_commit.author.name"
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Web UI Integration
|
|
|
|
### Trigger Detail Page
|
|
|
|
Display webhook status for each trigger:
|
|
|
|
```
|
|
┌──────────────────────────────────────────────────────────┐
|
|
│ Trigger: github.push │
|
|
├──────────────────────────────────────────────────────────┤
|
|
│ │
|
|
│ Webhooks [Toggle: ● ON ] │
|
|
│ │
|
|
│ Webhook URL: │
|
|
│ ┌──────────────────────────────────────────────────────┐ │
|
|
│ │ https://attune.example.com/api/v1/webhooks/wh_k7j... │ │
|
|
│ └──────────────────────────────────────────────────────┘ │
|
|
│ [Copy URL] [Show Key] [Regenerate] │
|
|
│ │
|
|
│ Stats: │
|
|
│ • Events received: 145 │
|
|
│ • Last event: 2 minutes ago │
|
|
│ • Created: 2024-01-15 10:30:00 │
|
|
│ │
|
|
│ Configuration: │
|
|
│ □ Require signature verification │
|
|
│ □ Enable IP whitelisting │
|
|
│ │
|
|
└──────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### Webhook Key Display
|
|
|
|
Show webhook key with copy button and security warning:
|
|
|
|
```
|
|
┌──────────────────────────────────────────────────────────┐
|
|
│ Webhook Key │
|
|
├──────────────────────────────────────────────────────────┤
|
|
│ │
|
|
│ wh_k7j2n9p4m8q1r5w3x6z0a2b5c8d1e4f7g9h2 │
|
|
│ │
|
|
│ [Copy Key] [Hide] │
|
|
│ │
|
|
│ ⚠️ Keep this key secret. Anyone with this key can │
|
|
│ trigger events. If compromised, regenerate │
|
|
│ immediately. │
|
|
│ │
|
|
└──────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## Implementation Status
|
|
|
|
### ✅ Phase 1: Database & Core (Complete)
|
|
|
|
1. ✅ Add webhook columns to `attune.trigger` table
|
|
2. ✅ Create migration with indexes
|
|
3. ✅ Add webhook key generation function
|
|
4. ✅ Update trigger repository with webhook methods
|
|
5. ✅ All integration tests passing (6/6)
|
|
|
|
### ✅ Phase 2: API Endpoints (Complete)
|
|
|
|
1. ✅ Webhook receiver endpoint: `POST /api/v1/webhooks/:webhook_key`
|
|
2. ✅ Webhook management endpoints:
|
|
- `POST /api/v1/triggers/:ref/webhooks/enable`
|
|
- `POST /api/v1/triggers/:ref/webhooks/disable`
|
|
- `POST /api/v1/triggers/:ref/webhooks/regenerate`
|
|
3. ✅ Event creation logic with webhook metadata
|
|
4. ✅ Error handling and validation
|
|
5. ✅ OpenAPI documentation
|
|
6. ✅ Integration tests created
|
|
|
|
**Files Added/Modified:**
|
|
- `crates/api/src/routes/webhooks.rs` - Webhook routes implementation
|
|
- `crates/api/src/dto/webhook.rs` - Webhook DTOs
|
|
- `crates/api/src/dto/trigger.rs` - Added webhook fields to TriggerResponse
|
|
- `crates/api/src/openapi.rs` - Added webhook endpoints to OpenAPI spec
|
|
- `crates/api/tests/webhook_api_tests.rs` - Comprehensive integration tests
|
|
|
|
### ✅ Phase 3: Advanced Security Features (Complete)
|
|
|
|
1. ✅ HMAC signature verification (SHA256, SHA512, SHA1)
|
|
2. ✅ Rate limiting per webhook key with configurable windows
|
|
3. ✅ IP whitelist support with CIDR notation
|
|
4. ✅ Payload size limits (configurable per trigger)
|
|
5. ✅ Webhook event logging for audit and analytics
|
|
6. ✅ Database functions for security configuration
|
|
7. ✅ Repository methods for all Phase 3 features
|
|
8. ✅ Enhanced webhook receiver with security checks
|
|
9. ✅ Comprehensive error handling and logging
|
|
|
|
**Database Schema Extensions:**
|
|
- `webhook_hmac_enabled`, `webhook_hmac_secret`, `webhook_hmac_algorithm` columns
|
|
- `webhook_rate_limit_enabled`, `webhook_rate_limit_requests`, `webhook_rate_limit_window_seconds` columns
|
|
- `webhook_ip_whitelist_enabled`, `webhook_ip_whitelist` columns
|
|
- `webhook_payload_size_limit_kb` column
|
|
- `webhook_event_log` table for audit trail
|
|
- `webhook_rate_limit` table for rate limit tracking
|
|
- `webhook_stats_detailed` view for analytics
|
|
|
|
**Repository Methods Added:**
|
|
- `enable_webhook_hmac()` - Enable HMAC with secret generation
|
|
- `disable_webhook_hmac()` - Disable HMAC verification
|
|
- `configure_webhook_rate_limit()` - Configure rate limiting
|
|
- `configure_webhook_ip_whitelist()` - Configure IP whitelist
|
|
- `check_webhook_rate_limit()` - Check if request within limit
|
|
- `check_webhook_ip_whitelist()` - Verify IP against whitelist
|
|
- `log_webhook_event()` - Log webhook requests for analytics
|
|
|
|
**Security Module:**
|
|
- HMAC signature verification for SHA256, SHA512, SHA1
|
|
- Constant-time comparison for signatures
|
|
- CIDR notation support for IP whitelists (IPv4 and IPv6)
|
|
- Signature format: `sha256=<hex>` or just `<hex>`
|
|
- Headers: `X-Webhook-Signature` or `X-Hub-Signature-256`
|
|
|
|
**Webhook Receiver Enhancements:**
|
|
- Payload size limit enforcement (returns 413 if exceeded)
|
|
- IP whitelist validation (returns 403 if not allowed)
|
|
- Rate limit enforcement (returns 429 if exceeded)
|
|
- HMAC signature verification (returns 401 if invalid)
|
|
- Comprehensive event logging for all requests (success and failure)
|
|
- Processing time tracking
|
|
- Detailed error messages with proper HTTP status codes
|
|
|
|
**Files Added/Modified:**
|
|
- `attune/migrations/20260120000002_webhook_advanced_features.sql` (362 lines)
|
|
- `crates/common/src/models.rs` - Added Phase 3 fields and WebhookEventLog model
|
|
- `crates/common/src/repositories/trigger.rs` - Added Phase 3 methods (215 lines)
|
|
- `crates/api/src/webhook_security.rs` - HMAC and IP validation (274 lines)
|
|
- `crates/api/src/routes/webhooks.rs` - Enhanced receiver with security (350+ lines)
|
|
- `crates/api/src/middleware/error.rs` - Added TooManyRequests error type
|
|
- `crates/api/Cargo.toml` - Added hmac, sha1, sha2, hex dependencies
|
|
|
|
### 📋 Phase 4: Web UI Integration (In Progress)
|
|
|
|
1. ✅ Add webhook toggle to trigger detail page
|
|
2. ✅ Display webhook URL and key
|
|
3. ✅ Add copy-to-clipboard functionality
|
|
4. Show webhook statistics from `webhook_stats_detailed` view
|
|
5. Add regenerate key button with confirmation
|
|
6. HMAC configuration UI (enable/disable, view secret)
|
|
7. Rate limit configuration UI
|
|
8. IP whitelist management UI
|
|
9. Webhook event log viewer
|
|
10. Real-time webhook testing tool
|
|
|
|
### 📋 Phase 5: Additional Features (TODO)
|
|
|
|
1. Webhook retry on failure with exponential backoff
|
|
2. Payload transformation/mapping with JSONPath
|
|
3. Multiple webhook keys per trigger
|
|
4. Webhook health monitoring and alerts
|
|
5. Batch webhook processing
|
|
6. Webhook response validation
|
|
7. Custom header injection
|
|
8. Webhook forwarding/proxying
|
|
|
|
---
|
|
|
|
## Example Use Cases
|
|
|
|
### 1. GitHub Push Events
|
|
|
|
**Pack Definition:**
|
|
```yaml
|
|
# packs/github/triggers/push.yaml
|
|
name: push
|
|
ref: github.push
|
|
description: "Triggered when code is pushed to a repository"
|
|
type: webhook
|
|
|
|
payload_schema:
|
|
type: object
|
|
properties:
|
|
ref:
|
|
type: string
|
|
description: "Git reference (branch/tag)"
|
|
commits:
|
|
type: array
|
|
description: "Array of commits"
|
|
repository:
|
|
type: object
|
|
description: "Repository information"
|
|
```
|
|
|
|
**User Workflow:**
|
|
1. Navigate to trigger `github.push` in UI
|
|
2. Enable webhooks (toggle ON)
|
|
3. Copy webhook URL
|
|
4. Configure in GitHub repository settings:
|
|
- Payload URL: `https://attune.example.com/api/v1/webhooks/wh_abc123...`
|
|
- Content type: `application/json`
|
|
- Events: Just the push event
|
|
5. GitHub sends webhook on push
|
|
6. Attune creates event
|
|
7. Rules evaluate and trigger actions
|
|
|
|
### 2. Stripe Payment Events
|
|
|
|
**Pack Definition:**
|
|
```yaml
|
|
# packs/stripe/triggers/payment_succeeded.yaml
|
|
name: payment_succeeded
|
|
ref: stripe.payment_succeeded
|
|
description: "Triggered when a payment succeeds"
|
|
type: webhook
|
|
|
|
payload_schema:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
amount:
|
|
type: integer
|
|
currency:
|
|
type: string
|
|
customer:
|
|
type: string
|
|
```
|
|
|
|
**User Workflow:**
|
|
1. Enable webhooks for `stripe.payment_succeeded` trigger
|
|
2. Copy webhook URL
|
|
3. Configure in Stripe dashboard
|
|
4. Enable signature verification (recommended for Stripe)
|
|
5. Set webhook secret in Attune
|
|
6. Stripe sends webhook on successful payment
|
|
7. Attune verifies signature and creates event
|
|
8. Rules trigger actions (send receipt, update CRM, etc.)
|
|
|
|
### 3. Custom Application Events
|
|
|
|
**Pack Definition:**
|
|
```yaml
|
|
# packs/myapp/triggers/deployment_complete.yaml
|
|
name: deployment_complete
|
|
ref: myapp.deployment_complete
|
|
description: "Triggered when application deployment completes"
|
|
type: webhook
|
|
|
|
payload_schema:
|
|
type: object
|
|
properties:
|
|
environment:
|
|
type: string
|
|
enum: [dev, staging, production]
|
|
version:
|
|
type: string
|
|
deployed_by:
|
|
type: string
|
|
status:
|
|
type: string
|
|
enum: [success, failure]
|
|
```
|
|
|
|
**User Workflow:**
|
|
1. Enable webhooks for `myapp.deployment_complete` trigger
|
|
2. Get webhook URL
|
|
3. Add to CI/CD pipeline:
|
|
```bash
|
|
curl -X POST https://attune.example.com/api/v1/webhooks/wh_xyz789... \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"environment": "production",
|
|
"version": "v2.1.0",
|
|
"deployed_by": "jenkins",
|
|
"status": "success"
|
|
}'
|
|
```
|
|
4. Attune receives webhook and creates event
|
|
5. Rules trigger notifications, health checks, etc.
|
|
|
|
---
|
|
|
|
## Testing
|
|
|
|
### Manual Testing
|
|
|
|
```bash
|
|
# Enable webhooks for a trigger
|
|
curl -X POST http://localhost:8080/api/v1/triggers/123/webhook/enable \
|
|
-H "Authorization: Bearer $TOKEN"
|
|
|
|
# Get webhook info
|
|
curl http://localhost:8080/api/v1/triggers/123/webhook \
|
|
-H "Authorization: Bearer $TOKEN"
|
|
|
|
# Send test webhook
|
|
WEBHOOK_KEY="wh_k7j2n9p4m8q1r5w3x6z0a2b5c8d1e4f7"
|
|
curl -X POST http://localhost:8080/api/v1/webhooks/$WEBHOOK_KEY \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"test": "payload", "value": 123}'
|
|
|
|
# Verify event was created
|
|
curl http://localhost:8080/api/v1/events?limit=1 \
|
|
-H "Authorization: Bearer $TOKEN"
|
|
```
|
|
|
|
### Integration Tests
|
|
|
|
```rust
|
|
#[tokio::test]
|
|
async fn test_webhook_enable_disable() {
|
|
// Create trigger
|
|
// Enable webhooks
|
|
// Verify webhook key generated
|
|
// Disable webhooks
|
|
// Verify key removed
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_webhook_event_creation() {
|
|
// Enable webhooks for trigger
|
|
// POST to webhook endpoint
|
|
// Verify event created in database
|
|
// Verify event has correct payload and metadata
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_webhook_key_regeneration() {
|
|
// Enable webhooks
|
|
// Save original key
|
|
// Regenerate key
|
|
// Verify new key is different
|
|
// Verify old key no longer works
|
|
// Verify new key works
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_webhook_invalid_key() {
|
|
// POST to webhook endpoint with invalid key
|
|
// Verify 404 response
|
|
// Verify no event created
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_webhook_rate_limiting() {
|
|
// Send 101 requests in 1 minute
|
|
// Verify rate limit exceeded error
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Migration from Generic Webhooks
|
|
|
|
If Attune previously had generic webhook triggers, migration steps:
|
|
|
|
1. Create new webhook-enabled triggers for each webhook use case
|
|
2. Enable webhooks for new triggers
|
|
3. Provide mapping tool in UI to migrate old webhook URLs
|
|
4. Run migration script to update external systems
|
|
5. Deprecate generic webhook triggers
|
|
|
|
---
|
|
|
|
## Performance Considerations
|
|
|
|
### Webhook Endpoint Optimization
|
|
|
|
- Async processing: Return 200 OK immediately, process event async
|
|
- Connection pooling: Reuse database connections
|
|
- Caching: Cache webhook key lookups (with TTL)
|
|
- Bulk event creation: Batch multiple webhook events
|
|
|
|
### Database Indexes
|
|
|
|
```sql
|
|
-- Fast webhook key lookup
|
|
CREATE INDEX idx_trigger_webhook_key ON attune.trigger(webhook_key);
|
|
|
|
-- Webhook event queries
|
|
CREATE INDEX idx_event_source ON attune.event(source) WHERE source = 'webhook';
|
|
CREATE INDEX idx_event_webhook_key ON attune.event((metadata->>'webhook_key'));
|
|
```
|
|
|
|
---
|
|
|
|
## Related Documentation
|
|
|
|
- [Trigger and Sensor Architecture](./trigger-sensor-architecture.md)
|
|
- [Event System](./api-events-enforcements.md)
|
|
- [Pack Structure](./pack-structure.md)
|
|
- [Security Review](./security-review-2024-01-02.md)
|
|
|
|
---
|
|
|
|
## Conclusion
|
|
|
|
Built-in webhook support as a trigger feature provides:
|
|
|
|
- ✅ Better security with per-trigger webhook keys
|
|
- ✅ Clear association between webhooks and triggers
|
|
- ✅ Flexible payload handling per trigger type
|
|
- ✅ Easy external system integration
|
|
- ✅ Full audit trail and traceability
|
|
|
|
This design eliminates the need for generic webhook triggers while providing a more robust and maintainable webhook system.
|