Files
git.stella-ops.org/docs/flows/05-notification-flow.md
StellaOps Bot ca578801fd save progress
2026-01-03 00:49:19 +02:00

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
Email 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 email 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
Email 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