Skip to content

Pipeline Overview

A scan is a single pass over a brand’s attack surface. ScanRun in Rails represents it; the Python orchestrator.start_scan runs it.

# Stage Phase fn Parallel? Output
1 Domain enumeration domain_enumeration_phase — (must finish first) (findings: dict, permutations: int)
2 Record information record_info_phase ✓ (2–4) enrichment deltas
3 Fingerprinting fingerprinting_phase ✓ (2–4) enrichment deltas
4 Handle enumeration handle_enumeration_phase ✓ (2–4) social findings
5 Identity matching identity_matching matched profiles
6 Severity assessment severity_assessment scores, flags, campaigns
7 Auditing auditing LLM verdicts
8 Report generation report_generation PDFs + webhook
  • Phase 1 finishes first; its findings feed phases 2–4.
  • Phases 2, 3, and 4 run in parallel via asyncio.gather with return_exceptions=True — one failing phase does not block the others.
  • Each phase runs in a worker thread via run_phase, which applies a timeout, publishes start/completion to Redis, and records per-stage progress.
  • resume_from_stage lets a completed/failed/cancelled scan restart from any later stage.
  • Cancellation is cooperative: phases check a shared cancel event.

During the scan, Python publishes:

  • scan_db_updates — status and per-stage progress (Rails merges into stage_states, broadcasts over ActionCable).
  • scan_findings — the initial finding batch, then deltas as enrichment and scoring refine them.
  • social_findings — social batch + deltas.

On completion, Rails enqueues ReportGenerationJob (fetches PDFs) and WebhookDeliveryJob (sends the snapshot + PDFs).

  • An unrecoverable error marks the scan failed and publishes the failure.
  • Phase exceptions are isolated in the parallel batch.
  • Optional capabilities (Shodan, Censys, JARM, screenshots) degrade instead of aborting.
  • Reports are always produced — the AI layer falls back deterministically.