# Advisory Drift Re-scan Flow ## Overview The Advisory Drift Re-scan Flow describes how StellaOps automatically re-evaluates previously scanned images when new vulnerability advisories are published or existing advisories are updated. This ensures that security verdicts remain current without requiring manual re-scans. **Business Value**: Continuous security posture updates as new vulnerabilities are disclosed, catching newly-vulnerable images before they're exploited. ## Actors | Actor | Type | Role | |-------|------|------| | Concelier | Service | Ingests new advisories | | Scheduler | Service | Triggers re-evaluation jobs | | Scanner | Service | Re-matches against new data | | Policy Engine | Service | Re-evaluates verdicts | | Notify | Service | Alerts on status changes | | SbomService | Service | Provides stored SBOMs | ## Prerequisites - Advisory connectors configured (NVD, GHSA, OSV, etc.) - Images previously scanned with stored SBOMs - Re-scan policies configured ## Advisory Sources StellaOps ingests advisories from 32+ sources: | Category | Sources | |----------|---------| | **National DBs** | NVD, GHSA, OSV, CISA KEV | | **Vendor PSIRTs** | Microsoft, Red Hat, Oracle, Cisco, VMware | | **Distros** | Ubuntu, Debian, Alpine, RHEL, SUSE | | **Ecosystems** | npm, PyPI, Go, RubyGems, Packagist | | **CERTs** | CERT/CC, JPCERT, BSI | ## Flow Diagram ``` ┌─────────────────────────────────────────────────────────────────────────────────┐ │ Advisory Drift Re-scan Flow │ └─────────────────────────────────────────────────────────────────────────────────┘ ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌─────────┐ ┌────────┐ ┌────────┐ │ Advisory │ │ Concelier │ │ Scheduler │ │ Scanner │ │ Policy │ │ Notify │ │ Source │ │ │ │ │ │ │ │ │ │ │ └─────┬─────┘ └─────┬─────┘ └─────┬─────┘ └────┬────┘ └───┬────┘ └───┬────┘ │ │ │ │ │ │ │ New CVE │ │ │ │ │ │ published │ │ │ │ │ │─────────────>│ │ │ │ │ │ │ │ │ │ │ │ │ Ingest & │ │ │ │ │ │ normalize │ │ │ │ │ │──────┐ │ │ │ │ │ │ │ │ │ │ │ │ │<─────┘ │ │ │ │ │ │ │ │ │ │ │ │ Emit event: │ │ │ │ │ │ advisory.new │ │ │ │ │ │─────────────>│ │ │ │ │ │ │ │ │ │ │ │ │ Query │ │ │ │ │ │ affected │ │ │ │ │ │ SBOMs │ │ │ │ │ │───┐ │ │ │ │ │ │ │ │ │ │ │ │ │<──┘ │ │ │ │ │ │ │ │ │ │ │ │ For each │ │ │ │ │ │ affected: │ │ │ │ │ │ │ │ │ │ │ │ Re-match │ │ │ │ │ │────────────>│ │ │ │ │ │ │ │ │ │ │ │ │ Load SBOM │ │ │ │ │ │ from store│ │ │ │ │ │───┐ │ │ │ │ │ │ │ │ │ │ │ │ │<──┘ │ │ │ │ │ │ │ │ │ │ │ │ Match new │ │ │ │ │ │ advisory │ │ │ │ │ │───┐ │ │ │ │ │ │ │ │ │ │ │ │ │<──┘ │ │ │ │ │ │ │ │ │ │ │ │ Re-eval │ │ │ │ │ │──────────>│ │ │ │ │ │ │ │ │ │ │ │ │ │ Compare │ │ │ │ │ │ old vs │ │ │ │ │ │ new │ │ │ │ │ │───┐ │ │ │ │ │ │ │ │ │ │ │ │ │<──┘ │ │ │ │ │ │ │ │ │ │ │ Verdict │ │ │ │ │ │ changed │ │ │ │ │ │<──────────│ │ │ │ │ │ │ │ │ │ │ Complete │ │ │ │ │ │<────────────│ │ │ │ │ │ │ │ │ │ │ │ [if changed]│ │ │ │ │ │ Alert │ │ │ │ │ │─────────────────────────────────────>│ │ │ │ │ │ │ │ │ │ │ │ │ Send │ │ │ │ │ │ notif │ │ │ │ │ │──┐ │ │ │ │ │ │ │ │ │ │ │ │ │<─┘ │ │ │ │ │ │ ``` ## Step-by-Step ### 1. Advisory Ingestion Concelier connector fetches new advisory: ```json { "source": "nvd", "advisory_id": "CVE-2024-1234", "published": "2024-12-29T08:00:00Z", "severity": "critical", "cvss": { "v3": {"score": 9.8, "vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"} }, "affected": [ { "ecosystem": "npm", "package": "lodash", "versions": { "vulnerable": ["<4.17.21"], "fixed": ["4.17.21"] } } ], "references": [ {"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-1234"} ] } ``` ### 2. Event Emission Concelier emits `advisory.new` event to Valkey stream: ```json { "event_type": "advisory.new", "event_id": "evt-adv-123", "timestamp": "2024-12-29T08:01:00Z", "payload": { "advisory_id": "CVE-2024-1234", "source": "nvd", "severity": "critical", "affected_purls": [ "pkg:npm/lodash" ] } } ``` ### 3. Affected SBOM Query Scheduler queries for SBOMs containing affected packages: ```sql SELECT DISTINCT s.scan_id, s.image_ref, s.digest, s.tenant_id FROM scanner.scans s JOIN scanner.sbom_components c ON s.sbom_id = c.sbom_id WHERE c.purl LIKE 'pkg:npm/lodash@%' AND s.status = 'completed' AND s.created_at > NOW() - INTERVAL '90 days' ORDER BY s.created_at DESC; ``` Result: ```json { "affected_images": [ { "scan_id": "scan-abc123", "image_ref": "docker.io/myorg/app:v1.2.3", "digest": "sha256:...", "tenant_id": "acme-corp", "matched_component": "pkg:npm/lodash@4.17.20" }, { "scan_id": "scan-def456", "image_ref": "docker.io/myorg/api:v2.0.0", "digest": "sha256:...", "tenant_id": "acme-corp", "matched_component": "pkg:npm/lodash@4.17.19" } ], "total_affected": 2 } ``` ### 4. Re-evaluation Jobs Scheduler creates re-evaluation jobs (not full re-scans): ```json { "job_type": "advisory_drift_reevaluate", "job_id": "job-reeval-789", "priority": "high", "batch": [ { "scan_id": "scan-abc123", "new_advisories": ["CVE-2024-1234"], "affected_packages": ["pkg:npm/lodash@4.17.20"] }, { "scan_id": "scan-def456", "new_advisories": ["CVE-2024-1234"], "affected_packages": ["pkg:npm/lodash@4.17.19"] } ] } ``` ### 5. SBOM-Based Re-matching Scanner loads stored SBOM and matches against new advisory: ```json { "scan_id": "scan-abc123", "new_findings": [ { "cve": "CVE-2024-1234", "package": "pkg:npm/lodash@4.17.20", "severity": "critical", "fixed_version": "4.17.21", "source": "nvd" } ], "reused_data": { "sbom": true, "reachability": true, "vex": false // Re-query VEX for new CVE } } ``` ### 6. Policy Re-evaluation Policy engine re-evaluates with new findings: ```json { "reevaluation": { "scan_id": "scan-abc123", "previous_verdict": "PASS", "new_verdict": "FAIL", "verdict_changed": true, "reason": "New critical CVE-2024-1234 matched", "delta": { "added_findings": [ {"cve": "CVE-2024-1234", "severity": "critical"} ], "removed_findings": [], "changed_findings": [] } } } ``` ### 7. Status Change Notification If verdict changed, Notify sends alerts: ```json { "event_type": "scan.verdict_changed", "payload": { "scan_id": "scan-abc123", "image": "docker.io/myorg/app:v1.2.3", "previous_verdict": "PASS", "new_verdict": "FAIL", "trigger": "advisory_drift", "new_cve": "CVE-2024-1234", "severity": "critical" } } ``` ## Re-scan Policies ### Immediate Re-evaluation ```yaml advisory_drift: trigger: immediate severity_threshold: critical batch_size: 100 parallelism: 10 ``` ### Scheduled Re-evaluation ```yaml advisory_drift: trigger: scheduled schedule: "0 */4 * * *" # Every 4 hours severity_threshold: high include_new_vex: true ``` ### Smart Batching ```yaml advisory_drift: trigger: smart rules: - severity: critical delay: 0s - severity: high delay: 15m batch_with_same_package: true - severity: medium delay: 1h - severity: low delay: 24h ``` ## Material Risk Detection The flow uses Smart-Diff rules to identify material changes: | Rule | ID | Trigger | |------|-----|---------| | Verdict flip PASS→FAIL | R1 | Immediately actionable | | New critical/high finding | R2 | Review required | | KEV addition | R3 | Urgent remediation | | VEX invalidation | R4 | Re-review VEX statement | ## Data Contracts ### Advisory Drift Event Schema ```typescript interface AdvisoryDriftEvent { event_type: 'advisory.new' | 'advisory.update' | 'advisory.withdrawn'; advisory_id: string; source: string; severity?: 'critical' | 'high' | 'medium' | 'low'; affected_purls: string[]; timestamp: string; } ``` ### Re-evaluation Result Schema ```typescript interface ReevaluationResult { scan_id: string; image: string; previous_verdict: Verdict; new_verdict: Verdict; verdict_changed: boolean; delta: { added_findings: Finding[]; removed_findings: Finding[]; changed_findings: Finding[]; }; trigger: 'advisory_drift' | 'vex_update' | 'policy_change'; triggered_by: string; // Advisory ID or VEX ID evaluated_at: string; } ``` ## Performance Optimizations | Optimization | Description | |--------------|-------------| | SBOM reuse | Load stored SBOM instead of re-analyzing | | Incremental matching | Only match new advisories | | Batch processing | Group by package for efficient queries | | Priority queue | Critical advisories processed first | | Parallel evaluation | Evaluate multiple images concurrently | ## Error Handling | Error | Recovery | |-------|----------| | SBOM not found | Mark scan as stale, suggest re-scan | | Advisory parse error | Skip advisory, log for review | | Evaluation timeout | Retry with lower parallelism | | Notification failure | Queue for retry | ## Observability ### Metrics | Metric | Type | Labels | |--------|------|--------| | `advisory_drift_events_total` | Counter | `source`, `severity` | | `advisory_drift_affected_images` | Gauge | `advisory_id` | | `advisory_drift_reevaluations_total` | Counter | `verdict_changed` | | `advisory_drift_latency_seconds` | Histogram | `batch_size` | ### Key Log Events | Event | Level | Fields | |-------|-------|--------| | `advisory.ingested` | INFO | `advisory_id`, `source`, `severity` | | `advisory.drift_scan_started` | INFO | `advisory_id`, `affected_count` | | `advisory.verdict_changed` | WARN | `scan_id`, `previous`, `new` | | `advisory.drift_scan_complete` | INFO | `advisory_id`, `duration_ms` | ## Related Flows - [Scan Submission Flow](02-scan-submission-flow.md) - Original scan process - [Policy Evaluation Flow](04-policy-evaluation-flow.md) - Policy details - [Notification Flow](05-notification-flow.md) - Alert delivery - [Reachability Drift Alert Flow](19-reachability-drift-alert-flow.md) - Runtime drift