Files
wehub-resource-sync 161ef94b4f
Sirius CI/CD Pipeline / Merge API Manifest (push) Blocked by required conditions
Sirius CI/CD Pipeline / Build API (${{ matrix.platform }}) (push) Blocked by required conditions
Sirius CI/CD Pipeline / Build UI (${{ matrix.platform }}) (push) Blocked by required conditions
Sirius CI/CD Pipeline / Merge UI Manifest (push) Blocked by required conditions
Sirius CI/CD Pipeline / Build Engine (${{ matrix.platform }}) (push) Blocked by required conditions
Sirius CI/CD Pipeline / Merge Engine Manifest (push) Blocked by required conditions
Sirius CI/CD Pipeline / Build Infra (${{ matrix.service }}, ${{ matrix.platform }}) (push) Blocked by required conditions
Sirius CI/CD Pipeline / Merge Infra Manifest (sirius-postgres) (push) Blocked by required conditions
Sirius CI/CD Pipeline / Merge Infra Manifest (sirius-rabbitmq) (push) Blocked by required conditions
Sirius CI/CD Pipeline / Merge Infra Manifest (sirius-valkey) (push) Blocked by required conditions
Sirius CI/CD Pipeline / Integration Test (push) Blocked by required conditions
Sirius CI/CD Pipeline / Public Stack Contract (push) Blocked by required conditions
Sirius CI/CD Pipeline / Dispatch Demo Deployment (sirius-demo branch) (push) Blocked by required conditions
Sirius CI/CD Pipeline / Dispatch Demo Canary (main branch) (push) Blocked by required conditions
Check engine pin consistency / Dockerfile / CI pin consistency (push) Successful in 8s
Sirius CI/CD Pipeline / Detect Changes (push) Successful in 23s
Sirius CI/CD Pipeline / Guard Registry Namespace (push) Waiting to run
Validate Docker Configuration / Validate Docker Compose Configuration (push) Successful in 47s
chore: import upstream snapshot with attribution
2026-07-13 12:32:25 +08:00

7.4 KiB
Raw Permalink Blame History

title, description, template, version, last_updated, author, tags, categories, difficulty, prerequisites, related_docs, dependencies, llm_context, search_keywords
title description template version last_updated author tags categories difficulty prerequisites related_docs dependencies llm_context search_keywords
Sub-Scans Architecture - Modular Scan Methods Independent scan methods (network, agent) running in parallel, their data structure, lifecycle, progress aggregation, and cancellation. TEMPLATE.custom 1.0.0 2025-02-07 Sirius Team
scanner
sub-scan
architecture
progress
cancellation
architecture
scanner
intermediate
README.scanner.md
documentation/dev/apps/scanner/README.scanner.md
documentation/dev/apps/scanner/ARCHITECTURE.scanner-data-flow.md
documentation/dev/apps/scanner/ARCHITECTURE.host-deduplication.md
high
sub-scan
sub_scans
scan progress
network agent parallel
scan cancellation
SubScan

Sub-Scans Architecture

The Sirius scanner uses a sub-scan architecture: each scan method (e.g. network, agent) is an independent sub-scan with its own status and progress. Sub-scans run in parallel and are tracked in a single ScanResult via a registry map.

What Are Sub-Scans?

Sub-scans are independent scan methods that contribute to one logical “scan”:

  • network Traditional network scanning (e.g. Nmap, RustScan, Naabu) triggered via RabbitMQ and executed by app-scanner.
  • agent Agent-based scanning: templates run on remote hosts via app-agent over gRPC.

A scan can have zero, one, or both enabled. Each sub-scan has its own:

  • Lifecycle state (e.g. dispatching → running → completed/failed/cancelled)
  • Progress (e.g. completed/total hosts or agents)
  • Optional metadata (e.g. agent list, per-agent status for agent sub-scan)

The overall scan state is the union of all sub-scan states and their results (hosts/vulnerabilities are merged at the scan level).


Sub-Scan Data Structure

Go (go-api / shared types)

// SubScanProgress tracks completion progress for a sub-scan.
type SubScanProgress struct {
    Completed int    `json:"completed"`
    Total     int    `json:"total"`
    Label     string `json:"label,omitempty"` // e.g. "hosts", "agents"
}

// SubScan represents a modular scanner contribution to a scan.
// Metadata is json.RawMessage so other scanners preserve it on read-modify-write.
type SubScan struct {
    Type     string          `json:"type"`     // "network", "agent"
    Enabled  bool            `json:"enabled"`
    Status   string          `json:"status"`   // see Lifecycle states
    Progress SubScanProgress `json:"progress"`
    Metadata json.RawMessage `json:"metadata,omitempty"`
}

// ScanResult holds the top-level scan and a registry of sub-scans.
type ScanResult struct {
    ID              string
    Status          string
    Targets         []string
    Hosts           []HostEntry
    HostsCompleted  int
    Vulnerabilities []VulnerabilitySummary
    StartTime       string
    EndTime         string
    SubScans        map[string]SubScan `json:"sub_scans,omitempty"`
}

TypeScript (sirius-ui)

interface SubScanProgress {
  completed: number;
  total: number;
  label?: string;
}

interface SubScan {
  type: string;
  enabled: boolean;
  status: "pending" | "dispatching" | "running" | "completed" | "failed";
  progress: SubScanProgress;
  metadata?: Record<string, unknown>;
}

// ScanResult.sub_scans: Record<string, SubScan>

Agent-specific metadata in SubScan.metadata can include mode, dispatched_agents, agent_statuses (per-agent status, hosts/vulns found, etc.).


Sub-Scan Registry Pattern

Sub-scans are stored in a map keyed by scanner identifier:

  • map[string]SubScan in Go (sub_scans in JSON)
  • Record<string, SubScan> in TypeScript

Common keys:

  • "network" Network scan (app-scanner).
  • "agent" Agent scan (app-agent).

Only enabled methods are present. When starting a scan, the UI (or API) builds this map (e.g. subScans["network"], subScans["agent"]) and writes the initial ScanResult to ValKey. Consumers (app-scanner, go-api/agent path) update only their own key when merging back into currentScan, preserving other keys and metadata they dont understand.


Lifecycle States

Each sub-scan moves through a small set of states:

State Meaning
pending Not yet started (optional; may go straight to dispatching).
dispatching Work is being dispatched (e.g. message to RabbitMQ, or gRPC dispatch to agents).
running Actively running (targets being scanned, agents executing templates).
completed Finished successfully.
failed Finished with error.
cancelled Stopped by user or system.

The overall scan status is typically derived from sub-scans (e.g. “running” if any sub-scan is dispatching or running, “completed” when all are completed/failed/cancelled).


Progress Aggregation

  • Per sub-scan: progress.completed, progress.total, and optional progress.label (e.g. "hosts", "agents"). Each scanner updates its own sub-scans progress when writing to ValKey.
  • Overall scan: The UI (or API) can compute an aggregate, for example:
    • Total progress = sum of completed across sub-scans, divided by sum of total (or 0 if no total).
    • Or: “running” if any sub-scan has status === "running" or "dispatching", and overall completion when all sub-scans are in a terminal state.

The UI displays persub-scan progress (e.g. in ScanStatus) and can show an overall progress bar or status from these fields.


Cancellation Handling

When the user cancels a scan:

  1. UI/API calls the cancel endpoint (e.g. POST /api/v1/scans/cancel with optional scan_id).
  2. go-api (or the component that owns the scan) sets the overall scan and/or sub-scans to a terminal state (e.g. cancelled) and writes the updated ScanResult back to ValKey.
  3. Network: Cancellation can be implemented by app-scanner checking a shared “cancelled” flag (e.g. from ValKey or a separate key) or by receiving a cancel message, then stopping workers and updating its sub-scan status to cancelled in currentScan.
  4. Agent: go-api (or agent coordinator) can signal agents to stop and then set sub_scans.agent.status to cancelled when updating ValKey.

So: cancelling the scan means ensuring all sub-scans are stopped and their status (and optionally the overall scan status) is set to cancelled in the same currentScan document.


Summary

  • Sub-scans = independent scan methods (network, agent) with their own status and progress.
  • Data structure: SubScan { type, enabled, status, progress, metadata } in a map[string]SubScan (sub_scans).
  • Lifecycle: dispatching → running → completed | failed | cancelled.
  • Progress: persub-scan completed/total; overall progress can be aggregated from all sub-scans.
  • Cancellation: cancel request stops all sub-scans and updates their status (and overall scan) in ValKey currentScan.
  • Registry: Use a single sub_scans map; each scanner only updates its own key and preserves others metadata.

Related Documentation


Last Updated: 2025-02-07
Version: 1.0.0
Maintainer: Sirius Team