{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://stella-ops.org/schemas/notify-rules.schema.json", "title": "StellaOps Notification Rules Schema", "description": "Schema for notification rules, webhook payloads, and digest formats. Unblocks CLI-NOTIFY-38-001.", "type": "object", "definitions": { "NotifyRule": { "type": "object", "required": ["rule_id", "name", "event_types", "channels", "created_at"], "properties": { "rule_id": { "type": "string", "format": "uuid", "description": "Unique identifier for the notification rule" }, "name": { "type": "string", "minLength": 1, "maxLength": 128, "description": "Human-readable rule name" }, "description": { "type": "string", "maxLength": 512 }, "event_types": { "type": "array", "minItems": 1, "items": { "$ref": "#/definitions/EventType" }, "description": "Event types that trigger this rule" }, "filters": { "$ref": "#/definitions/NotifyFilters" }, "channels": { "type": "array", "minItems": 1, "items": { "$ref": "#/definitions/NotifyChannel" } }, "throttle": { "$ref": "#/definitions/ThrottleConfig" }, "digest": { "$ref": "#/definitions/DigestConfig" }, "templates": { "$ref": "#/definitions/NotifyTemplates" }, "enabled": { "type": "boolean", "default": true }, "priority": { "type": "integer", "minimum": 0, "maximum": 100, "default": 50, "description": "Rule priority (higher = processed first)" }, "tenant_id": { "type": "string", "format": "uuid" }, "created_at": { "type": "string", "format": "date-time" }, "updated_at": { "type": "string", "format": "date-time" }, "created_by": { "type": "string" } } }, "EventType": { "type": "string", "enum": [ "vulnerability.new", "vulnerability.updated", "vulnerability.resolved", "vulnerability.critical", "vex.status_changed", "vex.consensus_changed", "policy.violation", "policy.override_requested", "policy.override_approved", "policy.override_expired", "scan.completed", "scan.failed", "attestation.created", "attestation.verification_failed", "airgap.staleness_warning", "airgap.staleness_critical", "airgap.bundle_imported", "export.completed", "export.failed", "system.health_degraded", "system.error" ] }, "NotifyFilters": { "type": "object", "description": "Filters to apply before triggering notification", "properties": { "severity": { "type": "array", "items": { "type": "string", "enum": ["critical", "high", "medium", "low", "info"] }, "description": "Only trigger for these severities" }, "cvss_minimum": { "type": "number", "minimum": 0, "maximum": 10, "description": "Minimum CVSS score to trigger" }, "components": { "type": "array", "items": { "type": "string" }, "description": "PURL patterns to match" }, "environments": { "type": "array", "items": { "type": "string" } }, "tags": { "type": "array", "items": { "type": "string" } }, "kev_only": { "type": "boolean", "default": false, "description": "Only trigger for Known Exploited Vulnerabilities" }, "fix_available": { "type": "boolean", "description": "Filter by fix availability" } } }, "NotifyChannel": { "type": "object", "required": ["type"], "properties": { "type": { "type": "string", "enum": ["email", "slack", "teams", "webhook", "pagerduty", "opsgenie", "sns"] }, "name": { "type": "string" }, "enabled": { "type": "boolean", "default": true }, "config": { "type": "object", "additionalProperties": true } }, "allOf": [ { "if": { "properties": { "type": { "const": "email" } } }, "then": { "properties": { "config": { "type": "object", "required": ["recipients"], "properties": { "recipients": { "type": "array", "items": { "type": "string", "format": "email" } }, "cc": { "type": "array", "items": { "type": "string", "format": "email" } }, "subject_prefix": { "type": "string" } } } } } }, { "if": { "properties": { "type": { "const": "slack" } } }, "then": { "properties": { "config": { "type": "object", "required": ["webhook_url"], "properties": { "webhook_url": { "type": "string", "format": "uri" }, "channel": { "type": "string" }, "username": { "type": "string" }, "icon_emoji": { "type": "string" } } } } } }, { "if": { "properties": { "type": { "const": "teams" } } }, "then": { "properties": { "config": { "type": "object", "required": ["webhook_url"], "properties": { "webhook_url": { "type": "string", "format": "uri" } } } } } }, { "if": { "properties": { "type": { "const": "webhook" } } }, "then": { "properties": { "config": { "type": "object", "required": ["url"], "properties": { "url": { "type": "string", "format": "uri" }, "method": { "type": "string", "enum": ["POST", "PUT"], "default": "POST" }, "headers": { "type": "object", "additionalProperties": { "type": "string" } }, "auth_type": { "type": "string", "enum": ["none", "basic", "bearer", "hmac"] }, "auth_secret": { "type": "string" }, "retry_count": { "type": "integer", "minimum": 0, "maximum": 5, "default": 3 }, "timeout_seconds": { "type": "integer", "minimum": 1, "maximum": 60, "default": 30 } } } } } }, { "if": { "properties": { "type": { "const": "pagerduty" } } }, "then": { "properties": { "config": { "type": "object", "required": ["routing_key"], "properties": { "routing_key": { "type": "string" }, "severity_mapping": { "type": "object", "additionalProperties": { "type": "string", "enum": ["critical", "error", "warning", "info"] } } } } } } } ] }, "ThrottleConfig": { "type": "object", "description": "Throttling configuration to prevent notification storms", "properties": { "enabled": { "type": "boolean", "default": true }, "max_per_hour": { "type": "integer", "minimum": 1, "default": 100 }, "max_per_day": { "type": "integer", "minimum": 1, "default": 1000 }, "dedupe_window_seconds": { "type": "integer", "minimum": 0, "default": 300, "description": "Window for deduplicating identical notifications" }, "dedupe_key_fields": { "type": "array", "items": { "type": "string" }, "default": ["event_type", "cve_id", "purl"], "description": "Fields to use for deduplication key" } } }, "DigestConfig": { "type": "object", "description": "Configuration for digest/summary notifications", "properties": { "enabled": { "type": "boolean", "default": false }, "frequency": { "type": "string", "enum": ["hourly", "daily", "weekly"], "default": "daily" }, "schedule": { "type": "string", "description": "Cron expression for digest delivery" }, "timezone": { "type": "string", "default": "UTC" }, "min_events": { "type": "integer", "minimum": 1, "default": 1, "description": "Minimum events required to send digest" }, "group_by": { "type": "array", "items": { "type": "string", "enum": ["severity", "event_type", "component", "environment"] }, "description": "Fields to group events by in digest" }, "include_summary": { "type": "boolean", "default": true }, "include_details": { "type": "boolean", "default": false, "description": "Include full event details in digest" } } }, "NotifyTemplates": { "type": "object", "description": "Custom notification templates", "properties": { "subject": { "type": "string", "description": "Template for notification subject (supports {{variables}})" }, "body": { "type": "string", "description": "Template for notification body" }, "body_html": { "type": "string", "description": "HTML template for email body" } } }, "WebhookPayload": { "type": "object", "description": "Standard webhook payload format", "required": ["id", "timestamp", "event_type", "data"], "properties": { "id": { "type": "string", "format": "uuid", "description": "Unique notification ID" }, "timestamp": { "type": "string", "format": "date-time" }, "event_type": { "$ref": "#/definitions/EventType" }, "version": { "type": "string", "default": "1.0.0" }, "tenant_id": { "type": "string", "format": "uuid" }, "data": { "type": "object", "description": "Event-specific payload data", "additionalProperties": true }, "metadata": { "type": "object", "properties": { "rule_id": { "type": "string", "format": "uuid" }, "rule_name": { "type": "string" }, "retry_count": { "type": "integer" }, "digest_id": { "type": "string", "format": "uuid" } } } } }, "DigestPayload": { "type": "object", "description": "Digest/summary notification payload", "required": ["id", "timestamp", "period", "summary"], "properties": { "id": { "type": "string", "format": "uuid" }, "timestamp": { "type": "string", "format": "date-time" }, "period": { "type": "object", "required": ["start", "end"], "properties": { "start": { "type": "string", "format": "date-time" }, "end": { "type": "string", "format": "date-time" } } }, "summary": { "type": "object", "properties": { "total_events": { "type": "integer" }, "by_severity": { "type": "object", "additionalProperties": { "type": "integer" } }, "by_event_type": { "type": "object", "additionalProperties": { "type": "integer" } }, "new_vulnerabilities": { "type": "integer" }, "resolved_vulnerabilities": { "type": "integer" }, "policy_violations": { "type": "integer" } } }, "events": { "type": "array", "items": { "$ref": "#/definitions/WebhookPayload" }, "description": "Optional detailed event list" }, "groups": { "type": "array", "items": { "type": "object", "properties": { "key": { "type": "string" }, "count": { "type": "integer" }, "sample_events": { "type": "array", "items": { "$ref": "#/definitions/WebhookPayload" } } } } } } }, "NotifySimulationRequest": { "type": "object", "description": "Request to simulate a notification rule", "required": ["event"], "properties": { "rule_id": { "type": "string", "format": "uuid", "description": "Rule to simulate (optional, uses all matching if not specified)" }, "event": { "$ref": "#/definitions/WebhookPayload" }, "dry_run": { "type": "boolean", "default": true, "description": "If true, don't actually send notifications" } } }, "NotifySimulationResult": { "type": "object", "required": ["matched_rules", "would_notify"], "properties": { "matched_rules": { "type": "array", "items": { "type": "object", "properties": { "rule_id": { "type": "string", "format": "uuid" }, "rule_name": { "type": "string" }, "matched": { "type": "boolean" }, "reason": { "type": "string" } } } }, "would_notify": { "type": "array", "items": { "type": "object", "properties": { "channel_type": { "type": "string" }, "channel_name": { "type": "string" }, "payload_preview": { "type": "object" } } } }, "throttled": { "type": "boolean" }, "throttle_reason": { "type": "string" } } }, "NotifyAckToken": { "type": "object", "description": "Acknowledgement token for notifications", "required": ["token", "notification_id", "expires_at"], "properties": { "token": { "type": "string", "description": "Opaque acknowledgement token" }, "notification_id": { "type": "string", "format": "uuid" }, "event_type": { "$ref": "#/definitions/EventType" }, "expires_at": { "type": "string", "format": "date-time" }, "ack_url": { "type": "string", "format": "uri", "description": "URL to acknowledge the notification" } } } }, "properties": { "rules": { "type": "array", "items": { "$ref": "#/definitions/NotifyRule" } } }, "examples": [ { "rules": [ { "rule_id": "550e8400-e29b-41d4-a716-446655440002", "name": "Critical Vulnerability Alert", "description": "Immediate notification for critical vulnerabilities", "event_types": ["vulnerability.critical", "vulnerability.new"], "filters": { "severity": ["critical"], "kev_only": false }, "channels": [ { "type": "slack", "name": "security-alerts", "config": { "webhook_url": "https://hooks.slack.com/services/xxx", "channel": "#security-alerts", "icon_emoji": ":warning:" } }, { "type": "pagerduty", "name": "security-oncall", "config": { "routing_key": "xxx", "severity_mapping": { "critical": "critical", "high": "error" } } } ], "throttle": { "enabled": true, "max_per_hour": 50, "dedupe_window_seconds": 300 }, "enabled": true, "priority": 100, "created_at": "2025-12-01T00:00:00Z" } ] } ] }