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

426 lines
16 KiB
Markdown

# 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