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

15 KiB

Scan Submission Flow

Overview

The Scan Submission Flow describes the complete lifecycle of a container image scan from initial submission through SBOM generation, vulnerability matching, policy evaluation, and result storage. This is the core workflow that produces security verdicts for container images.

Business Value: Automated, deterministic scanning ensures every container image is evaluated against the latest advisories and policies before deployment.

Actors

Actor Type Role
Developer/CI Human/System Submits scan request
CLI / API Client System Initiates scan via API
Gateway Service Routes and authenticates
Scheduler Service Queues and dispatches work
Scanner Service Analyzes image and generates SBOM
Concelier Service Provides advisory data
VexLens Service Provides VEX statements
Policy Service Evaluates policy rules
Attestor Service Signs scan results
Notify Service Sends notifications

Prerequisites

  • Valid API credentials (JWT or API key)
  • Container registry accessible (or image pulled locally)
  • Registry credentials configured (if private registry)

Flow Diagram

┌─────────────────────────────────────────────────────────────────────────────────┐
│                           Scan Submission Flow                                   │
└─────────────────────────────────────────────────────────────────────────────────┘

┌───────┐   ┌─────────┐   ┌─────────┐   ┌───────────┐   ┌─────────┐
│  CLI  │   │ Gateway │   │Scheduler│   │  Scanner  │   │ Policy  │
└───┬───┘   └────┬────┘   └────┬────┘   └─────┬─────┘   └────┬────┘
    │            │             │              │              │
    │ POST /api/v1/scans       │              │              │
    │ {image: "..."}           │              │              │
    │───────────>│             │              │              │
    │            │             │              │              │
    │            │ Validate    │              │              │
    │            │ + Enqueue   │              │              │
    │            │────────────>│              │              │
    │            │             │              │              │
    │ 202 Accepted             │              │              │
    │ {scan_id: "..."}         │              │              │
    │<───────────│             │              │              │
    │            │             │              │              │
    │            │             │ Dispatch     │              │
    │            │             │─────────────>│              │
    │            │             │              │              │
    │            │             │              │ Pull image   │
    │            │             │              │──────┐       │
    │            │             │              │      │       │
    │            │             │              │<─────┘       │
    │            │             │              │              │
    │            │             │              │ Extract      │
    │            │             │              │ layers       │
    │            │             │              │──────┐       │
    │            │             │              │      │       │
    │            │             │              │<─────┘       │
    │            │             │              │              │
    │            │             │              │ Run 11       │
    │            │             │              │ analyzers    │
    │            │             │              │──────┐       │
    │            │             │              │      │       │
    │            │             │              │<─────┘       │
    │            │             │              │              │
    │            │             │              │ Generate     │
    │            │             │              │ SBOM         │
    │            │             │              │──────┐       │
    │            │             │              │      │       │
    │            │             │              │<─────┘       │
    │            │             │              │              │
    │            │             │              │  ┌──────────┐│
    │            │             │              │  │Concelier ││
    │            │             │              │  └────┬─────┘│
    │            │             │              │       │      │
    │            │             │              │ Match vulns  │
    │            │             │              │──────>│      │
    │            │             │              │       │      │
    │            │             │              │<──────│      │
    │            │             │              │              │
    │            │             │              │  ┌─────────┐ │
    │            │             │              │  │ VexLens │ │
    │            │             │              │  └────┬────┘ │
    │            │             │              │       │      │
    │            │             │              │ Get VEX      │
    │            │             │              │──────>│      │
    │            │             │              │       │      │
    │            │             │              │<──────│      │
    │            │             │              │              │
    │            │             │              │ Request      │
    │            │             │              │ verdict      │
    │            │             │              │─────────────>│
    │            │             │              │              │
    │            │             │              │ K4 lattice   │
    │            │             │              │ evaluation   │
    │            │             │              │<─────────────│
    │            │             │              │              │
    │            │             │              │  ┌─────────┐ │
    │            │             │              │  │ Attestor│ │
    │            │             │              │  └────┬────┘ │
    │            │             │              │       │      │
    │            │             │              │ Sign SBOM    │
    │            │             │              │──────>│      │
    │            │             │              │       │      │
    │            │             │              │<──────│      │
    │            │             │              │              │
    │            │             │ Complete     │              │
    │            │             │<─────────────│              │
    │            │             │              │              │
    │            │             │  ┌────────┐  │              │
    │            │             │  │ Notify │  │              │
    │            │             │  └───┬────┘  │              │
    │            │             │      │       │              │
    │            │             │ Send │       │              │
    │            │             │──────>       │              │
    │            │             │              │              │

Step-by-Step

1. Scan Request Submission

CLI Command:

stellaops scan docker.io/library/nginx:1.25

API Request:

POST /api/v1/scans HTTP/1.1
Host: gateway.stellaops.local
Authorization: Bearer {jwt}
X-Tenant-Id: acme-corp
Content-Type: application/json

{
  "image": "docker.io/library/nginx:1.25",
  "options": {
    "analyzers": ["all"],
    "sbom_format": "cyclonedx-1.6",
    "policy_set": "production",
    "attestation": true
  }
}

2. Gateway Processing

  • Validates JWT and extracts claims
  • Applies rate limiting
  • Validates request schema
  • Forwards to Scheduler

3. Scheduler Queuing

  • Creates scan job record in scheduler.jobs table
  • Assigns priority based on tenant tier
  • Returns scan ID immediately (async pattern)

Response:

{
  "scan_id": "scan-7f3a9b2c-1234-5678-abcd-ef0123456789",
  "status": "queued",
  "estimated_wait": "PT30S",
  "status_url": "/api/v1/scans/scan-7f3a9b2c-1234-5678-abcd-ef0123456789"
}

4. Scanner Dispatch

Scheduler dispatches to available Scanner worker:

{
  "job_id": "scan-7f3a9b2c-...",
  "image_ref": "docker.io/library/nginx:1.25",
  "resolved_digest": "sha256:abc123...",
  "analyzers": ["os", "dotnet", "java", "node", "python", "go", "rust", "php", "ruby", "deno", "binary"],
  "options": {...}
}

5. Image Analysis

Scanner performs multi-stage analysis:

Stage Duration Description
Pull 5-30s Fetch image manifest and layers
Extract 2-10s Unpack layer tarballs
OS Detection <1s Identify base OS (Alpine, Debian, etc.)
Analyzer Fan-out 10-60s Run 11 parallel language analyzers
Dependency Resolution 5-20s Resolve transitive dependencies
SBOM Assembly 1-5s Merge results into unified SBOM

6. Vulnerability Matching

Scanner queries Concelier for matching advisories:

POST /internal/match HTTP/1.1
Content-Type: application/json

{
  "components": [
    {"purl": "pkg:npm/lodash@4.17.20", "type": "library"},
    {"purl": "pkg:deb/debian/openssl@1.1.1k-1", "type": "library"}
  ]
}

Response includes matched CVEs with affected version ranges.

7. VEX Application

Scanner queries VexLens for applicable VEX statements:

POST /internal/vex/apply HTTP/1.1
Content-Type: application/json

{
  "product": "docker.io/library/nginx:1.25",
  "vulnerabilities": ["CVE-2024-1234", "CVE-2024-5678"]
}

VEX statements modify vulnerability status (e.g., not_affected, fixed).

8. Policy Evaluation

Scanner requests policy verdict from Policy engine:

POST /internal/evaluate HTTP/1.1
Content-Type: application/json

{
  "scan_id": "scan-7f3a9b2c-...",
  "policy_set": "production",
  "findings": [
    {
      "cve": "CVE-2024-1234",
      "severity": "critical",
      "vex_status": "affected",
      "reachability": "StaticallyReachable"
    }
  ]
}

Policy engine applies K4 lattice logic and returns verdict:

{
  "verdict": "FAIL",
  "confidence": 0.92,
  "violations": [
    {
      "rule": "no-critical-reachable",
      "cve": "CVE-2024-1234",
      "message": "Critical CVE with reachable code path"
    }
  ]
}

9. Attestation

Scanner requests DSSE attestation from Attestor:

POST /internal/attest HTTP/1.1
Content-Type: application/json

{
  "subject": {
    "name": "docker.io/library/nginx",
    "digest": {"sha256": "abc123..."}
  },
  "predicate_type": "https://stellaops.io/attestation/scan/v1",
  "predicate": {
    "scan_id": "scan-7f3a9b2c-...",
    "sbom_digest": "sha256:def456...",
    "verdict": "FAIL",
    "timestamp": "2024-12-29T10:30:00Z"
  }
}

10. Result Storage

Scanner stores results:

Store Data
PostgreSQL scanner.scans Scan metadata and verdict
PostgreSQL scanner.findings Individual vulnerability findings
RustFS blobs/{sha256}/ SBOM document
RustFS attestations/{sha256}/ DSSE envelope
Valkey scan:{digest} Cache for quick lookup

11. Notification

Scheduler triggers Notify service for configured channels:

{
  "event": "scan.complete",
  "scan_id": "scan-7f3a9b2c-...",
  "verdict": "FAIL",
  "channels": ["slack", "webhook"]
}

Data Contracts

Scan Request Schema

interface ScanRequest {
  image: string;          // Container image reference
  options?: {
    analyzers?: string[]; // List or "all"
    sbom_format?: 'spdx-3.0' | 'cyclonedx-1.6';
    policy_set?: string;  // Policy set name
    attestation?: boolean;
    labels?: Record<string, string>;
  };
}

Scan Result Schema

interface ScanResult {
  scan_id: string;
  image: string;
  digest: string;
  status: 'queued' | 'running' | 'completed' | 'failed';
  started_at: string;
  completed_at?: string;
  verdict: 'PASS' | 'FAIL' | 'WARN' | 'PENDING';
  confidence: number;
  summary: {
    critical: number;
    high: number;
    medium: number;
    low: number;
    unknown: number;
  };
  sbom_url: string;
  attestation_url?: string;
  findings_url: string;
}

Error Handling

Error HTTP Status Recovery
Image not found 404 Verify image reference and credentials
Registry auth failed 401 Re-configure registry credentials
Analyzer timeout 504 Retry with increased timeout
Policy set not found 400 Verify policy set exists
Attestation signing failed 500 Check Signer service health

Observability

Metrics

Metric Type Labels
scan_submitted_total Counter tenant
scan_completed_total Counter tenant, verdict
scan_duration_seconds Histogram tenant, image_size
scan_analyzer_duration_seconds Histogram analyzer
scan_findings_total Counter severity

Trace Context

scan-submission
├── gateway-auth
├── scheduler-enqueue
└── scanner-execute
    ├── image-pull
    ├── layer-extract
    ├── analyzer-dotnet
    ├── analyzer-java
    ├── analyzer-node
    ├── ...
    ├── concelier-match
    ├── vexlens-apply
    ├── policy-evaluate
    └── attestor-sign