14 KiB
14 KiB
Notification Flow
Overview
The Notification Flow describes how StellaOps delivers alerts and notifications to users through multiple channels including email, Slack, Microsoft Teams, and webhooks. Notifications are triggered by system events such as scan completions, policy violations, new advisories, and scheduled reports.
Business Value: Timely notifications ensure security teams are immediately aware of critical issues without constantly monitoring dashboards.
Actors
| Actor | Type | Role |
|---|---|---|
| Event Source | Service | Emits triggering events |
| Scheduler | Service | Manages scheduled notifications |
| Notify | Service | Routes and delivers notifications |
| Channel Adapters | Components | Email, Slack, Teams, Webhook |
| User | Human | Receives notifications |
Prerequisites
- Notification channels configured in tenant settings
- Channel credentials (SMTP, Slack webhook, Teams connector)
- User notification preferences set
Supported Channels
| Channel | Protocol | Configuration |
|---|---|---|
| SMTP/SMTPS | smtp.host, smtp.port, smtp.user, smtp.password |
|
| Slack | Webhook | slack.webhook_url |
| Microsoft Teams | Connector | teams.webhook_url |
| Webhook | HTTP POST | webhook.url, webhook.headers |
| PagerDuty | API | pagerduty.routing_key |
Flow Diagram
┌─────────────────────────────────────────────────────────────────────────────────┐
│ Notification Flow │
└─────────────────────────────────────────────────────────────────────────────────┘
┌──────────┐ ┌───────────┐ ┌────────┐ ┌─────────────────────────────────────────┐
│ Event │ │ Scheduler │ │ Notify │ │ Channel Adapters │
│ Source │ │ │ │ │ │ Email │ Slack │ Teams │ Webhook │ PD │
└────┬─────┘ └─────┬─────┘ └───┬────┘ └────┬───┴───┬───┴───┬───┴────┬────┴──┬──┘
│ │ │ │ │ │ │ │
│ Emit event │ │ │ │ │ │ │
│─────────────────────────>│ │ │ │ │ │
│ │ │ │ │ │ │ │
│ │ │ Match │ │ │ │ │
│ │ │ rules │ │ │ │ │
│ │ │───┐ │ │ │ │ │
│ │ │ │ │ │ │ │ │
│ │ │<──┘ │ │ │ │ │
│ │ │ │ │ │ │ │
│ │ │ Route to │ │ │ │ │
│ │ │ channels │ │ │ │ │
│ │ │───────────>│ │ │ │ │
│ │ │ │ │ │ │ │
│ │ │ │ Send │ │ │ │
│ │ │ │ email │ │ │ │
│ │ │ │──┐ │ │ │ │
│ │ │ │ │ │ │ │ │
│ │ │ │<─┘ │ │ │ │
│ │ │ │ │ │ │ │
│ │ │───────────────────>│ │ │ │
│ │ │ │ │ │ │ │
│ │ │ │ │ Post │ │ │
│ │ │ │ │ msg │ │ │
│ │ │ │ │──┐ │ │ │
│ │ │ │ │ │ │ │ │
│ │ │ │ │<─┘ │ │ │
│ │ │ │ │ │ │ │
│ │ │───────────────────────────>│ │ │
│ │ │ │ │ │ │ │
│ │ │ │ │ │ Post │ │
│ │ │ │ │ │ card │ │
│ │ │ │ │ │──┐ │ │
│ │ │ │ │ │ │ │ │
│ │ │ │ │ │<─┘ │ │
│ │ │ │ │ │ │ │
│ │ │ Log │ │ │ │ │
│ │ │ delivery │ │ │ │ │
│ │ │───┐ │ │ │ │ │
│ │ │ │ │ │ │ │ │
│ │ │<──┘ │ │ │ │ │
│ │ │ │ │ │ │ │
Step-by-Step
1. Event Emission
Various services emit notification-triggering events:
{
"event_type": "scan.complete",
"event_id": "evt-123456",
"timestamp": "2024-12-29T10:30:00Z",
"tenant_id": "acme-corp",
"payload": {
"scan_id": "scan-7f3a9b2c-...",
"image": "docker.io/library/nginx:1.25",
"verdict": "FAIL",
"violations": 3,
"severity_breakdown": {
"critical": 1,
"high": 2
}
}
}
2. Notification Rule Matching
Notify service matches event against configured rules:
# Notification Rules
rules:
- name: critical-scan-failure
description: Alert on critical vulnerabilities
event_type: scan.complete
conditions:
- field: payload.verdict
operator: eq
value: FAIL
- field: payload.severity_breakdown.critical
operator: gt
value: 0
channels:
- type: slack
config_ref: security-team-slack
urgency: high
- type: email
config_ref: security-leads
- type: pagerduty
config_ref: on-call-rotation
- name: daily-scan-summary
description: Daily summary of all scans
event_type: scheduled.daily_summary
channels:
- type: email
config_ref: security-distribution
3. Channel Routing
Notify determines which channels to activate:
| Rule Match | Channel | Priority |
|---|---|---|
| critical-scan-failure | slack | HIGH |
| critical-scan-failure | HIGH | |
| critical-scan-failure | pagerduty | HIGH |
4. Message Rendering
Each channel adapter renders the message in appropriate format:
Email Template
<!DOCTYPE html>
<html>
<body>
<h1>🚨 Critical Vulnerability Detected</h1>
<p>A scan has failed with critical vulnerabilities.</p>
<table>
<tr><th>Image</th><td>docker.io/library/nginx:1.25</td></tr>
<tr><th>Verdict</th><td style="color:red">FAIL</td></tr>
<tr><th>Critical</th><td>1</td></tr>
<tr><th>High</th><td>2</td></tr>
</table>
<p><a href="https://console.stellaops.local/scans/scan-7f3a9b2c-...">View Details</a></p>
</body>
</html>
Slack Block Kit
{
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": "🚨 Critical Vulnerability Detected"
}
},
{
"type": "section",
"fields": [
{"type": "mrkdwn", "text": "*Image:*\n`nginx:1.25`"},
{"type": "mrkdwn", "text": "*Verdict:*\n:x: FAIL"},
{"type": "mrkdwn", "text": "*Critical:*\n1"},
{"type": "mrkdwn", "text": "*High:*\n2"}
]
},
{
"type": "actions",
"elements": [
{
"type": "button",
"text": {"type": "plain_text", "text": "View Details"},
"url": "https://console.stellaops.local/scans/scan-7f3a9b2c-..."
}
]
}
]
}
Teams Adaptive Card
{
"type": "AdaptiveCard",
"version": "1.4",
"body": [
{
"type": "TextBlock",
"text": "🚨 Critical Vulnerability Detected",
"weight": "bolder",
"size": "large"
},
{
"type": "FactSet",
"facts": [
{"title": "Image", "value": "nginx:1.25"},
{"title": "Verdict", "value": "FAIL"},
{"title": "Critical", "value": "1"},
{"title": "High", "value": "2"}
]
}
],
"actions": [
{
"type": "Action.OpenUrl",
"title": "View Details",
"url": "https://console.stellaops.local/scans/scan-7f3a9b2c-..."
}
]
}
5. Delivery
Each adapter delivers to its channel:
| Channel | Protocol | Retry Policy |
|---|---|---|
| SMTP | 3 retries, exponential backoff | |
| Slack | HTTPS POST | 3 retries, 1s/2s/4s |
| Teams | HTTPS POST | 3 retries, 1s/2s/4s |
| Webhook | HTTPS POST | 5 retries, configurable |
| PagerDuty | HTTPS POST | 5 retries, 2s/4s/8s/16s/32s |
6. Delivery Logging
Notify logs delivery status to notify.delivery_log:
{
"delivery_id": "dlv-789abc",
"event_id": "evt-123456",
"channel": "slack",
"status": "delivered",
"attempts": 1,
"delivered_at": "2024-12-29T10:30:02Z",
"response": {"ok": true}
}
Data Contracts
Notification Event Schema
interface NotificationEvent {
event_type: string;
event_id: string;
timestamp: string;
tenant_id: string;
payload: Record<string, unknown>;
metadata?: {
source_service: string;
correlation_id?: string;
};
}
Channel Configuration Schema
interface ChannelConfig {
type: 'email' | 'slack' | 'teams' | 'webhook' | 'pagerduty';
name: string;
enabled: boolean;
config: EmailConfig | SlackConfig | TeamsConfig | WebhookConfig | PagerDutyConfig;
}
interface EmailConfig {
smtp_host: string;
smtp_port: number;
smtp_user?: string;
smtp_password?: string;
smtp_tls: boolean;
from_address: string;
to_addresses: string[];
}
interface SlackConfig {
webhook_url: string;
channel?: string;
username?: string;
icon_emoji?: string;
}
interface WebhookConfig {
url: string;
method: 'POST' | 'PUT';
headers?: Record<string, string>;
auth?: {
type: 'basic' | 'bearer' | 'api_key';
credentials: string;
};
}
Event Types
| Event Type | Source | Description |
|---|---|---|
scan.complete |
Scanner | Scan finished with results |
scan.failed |
Scanner | Scan execution failed |
policy.violation |
Policy | Policy rule triggered |
advisory.new |
Concelier | New advisory ingested |
advisory.update |
Concelier | Advisory modified |
vex.issued |
VexLens | New VEX statement |
exception.expiring |
Policy | Exception about to expire |
scheduled.daily_summary |
Scheduler | Daily digest |
scheduled.weekly_report |
Scheduler | Weekly report |
Error Handling
| Error | Recovery |
|---|---|
| SMTP connection failed | Retry with backoff, queue for later |
| Slack webhook 429 | Respect Retry-After header |
| Teams connector 502 | Retry up to 3 times |
| Webhook timeout | Retry with increased timeout |
| Invalid recipient | Skip recipient, log error |
Observability
Metrics
| Metric | Type | Labels |
|---|---|---|
notify_events_received_total |
Counter | event_type |
notify_deliveries_total |
Counter | channel, status |
notify_delivery_latency_ms |
Histogram | channel |
notify_retries_total |
Counter | channel, reason |
Key Log Events
| Event | Level | Fields |
|---|---|---|
notify.event.received |
INFO | event_type, event_id |
notify.rule.matched |
DEBUG | rule_name, channels |
notify.delivery.attempt |
DEBUG | channel, attempt |
notify.delivery.success |
INFO | channel, delivery_id |
notify.delivery.failed |
WARN | channel, error |
Related Flows
- Scan Submission Flow - Triggers scan notifications
- Advisory Drift Re-scan Flow - Advisory notifications
- Exception Approval Workflow - Exception notifications