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.jobstable - 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
Related Flows
- SBOM Generation Flow - Detailed SBOM creation
- Policy Evaluation Flow - K4 lattice details
- CI/CD Gate Flow - Pipeline integration