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

16 KiB

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:

{
  "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:

{
  "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:

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:

{
  "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):

{
  "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:

{
  "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:

{
  "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:

{
  "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

advisory_drift:
  trigger: immediate
  severity_threshold: critical
  batch_size: 100
  parallelism: 10

Scheduled Re-evaluation

advisory_drift:
  trigger: scheduled
  schedule: "0 */4 * * *"  # Every 4 hours
  severity_threshold: high
  include_new_vex: true

Smart Batching

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

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

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