Jobs & Progress
Understand the scan job lifecycle, real-time progress streaming, and how to interpret workflow stages.
Job Lifecycle
How a scan moves from upload to results.
Every scan job follows a state machine:
- queued — Job created after file upload. Waiting for a worker to pick it up.
- running — Worker is actively scanning. Progress events stream in real time.
- done — Scan completed. Full report available for download.
- failed — An error occurred. Check the last progress event for details.
Progress Streaming
Real-time visibility into scan stages.
The scanner writes NDJSON progress events to a file. The Go worker tails this file and inserts rows into the scan_events table. PostgreSQL NOTIFY triggers server-sent events (SSE) that push updates to your browser.
Progress Stages
What each stage prefix means.
| Stage Prefix | Meaning |
|---|---|
| scan.start | Scan initialization |
| container.extract / container.layers | Extracting container layers |
| container.packages | Detecting OS packages (dpkg, apk, rpm) |
| container.packages.app | Detecting application packages (npm, pip, gem, etc.) |
| archive.extract | Extracting ZIP archive (APK, JAR, wheel, etc.) |
| archive.type | Classified archive type |
| iso.detect / iso.repodata | ISO image analysis |
| osv.* / container.osv.* / archive.osv.* | OSV vulnerability query |
| nvd.* / container.enrich.nvd / archive.enrich.nvd | NVD enrichment |
| redhat.* | Red Hat CSAF enrichment |
| binary.* | Binary analysis (ELF/PE/Mach-O) |
| dmg.extract | DMG disk image extraction |
| scan.done / scan.summary | Scan completed |
| *.err / *.error | Error in that stage |
| *.timing | Duration of that stage (ms) |
Stale Job Detection
What happens when a scan gets stuck.
Workers send periodic heartbeats while processing a job. If no heartbeat arrives within 30 minutes, the job is automatically marked as failed with a "stale job timeout" message.
To retry a failed scan, upload the file again. The original job and its events are preserved for debugging.