runner

package
v0.4.7 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 18, 2026 License: MIT Imports: 68 Imported by: 0

Documentation

Index

Constants

View Source
const (
	NoticeMarkerBlock  = "[waf-block-detected]"
	NoticeMarkerPacing = "[waf-pacing-armed]"
)

FormatBlockNoticeLine renders the one-line WAF/CDN block warning (with a trailing newline) shown when the edge starts filtering scan traffic. It is shared by every scan front-end so the message and the "unrecognized vendor" fallback stay identical whether the scan runs through the Runner or the direct scan-url/scan-request path. NoticeMarkerBlock and NoticeMarkerPacing are the bracketed tags the two operator notices are rendered with. Exported because a reader has to find them again in a rendered log (`vigolium log` reprints any that fell above the tail window) — matching on the marker rather than the prose is deliberate, since the prose is a sentence that gets reworded and the marker is what it tags.

Variables

View Source
var (
	ValidOnlyPhasesDesc = phaseVocabularyDesc(false)
	ValidSkipPhasesDesc = phaseVocabularyDesc(true)
)

ValidOnlyPhasesDesc and ValidSkipPhasesDesc are the human-readable phase lists rendered in --only/--skip validation error messages. Derived from nativePhaseVocabulary rather than hand-written, so a spelling that works can never go unlisted and a listed one can never fail to resolve.

Functions

func ApplyNativePhaseSelection

func ApplyNativePhaseSelection(opts *types.Options, enableExtensions func()) error

func FormatBlockNoticeLine

func FormatBlockNoticeLine(n http.BlockNotice) string

func FormatEdgePaceLine

func FormatEdgePaceLine(n hostlimit.PreArmNotice) string

FormatEdgePaceLine renders the one-line notice shown when a host is fingerprinted behind a CDN/WAF edge and its active-scan concurrency is proactively paced to keep a burst from arming a rate-based WAF. It spells out the concurrency drop so the operator understands the scan will run slower against that host. Companion to FormatBlockNoticeLine — a caution, not a failure: the scan continues, just gentler.

func IsNativePhaseSpelling

func IsNativePhaseSpelling(s string) bool

IsNativePhaseSpelling reports whether s names a native scan phase under any accepted spelling. Callers that need to branch on "is this a phase?" ask here rather than re-listing spellings, so a new alias reaches them for free.

func IsProbeOnlyRun

func IsProbeOnlyRun(opts *types.Options) bool

IsProbeOnlyRun reports whether this invocation is a standalone host sweep: `vigolium run probe`, `scan --only probe`, or REST {"only":"probe"}.

The probe's own defaults apply only here. When the phase rides along inside a full scan, the scan's redirect and recording policy governs — silently swapping it out from under the other phases would be a surprise.

func NormalizeNativePhase

func NormalizeNativePhase(phase string) string

NormalizeNativePhase maps every accepted spelling of a phase to its canonical id. Input is trimmed and lowercased first: --only already trimmed, --skip did not, so `--skip Discovery` (or ` discovery`) reached the switch verbatim, fell through to default, and was reported as an invalid phase. Aliases are extra surface for a driver to get subtly wrong; normalizing here means every caller — --only, --skip, `run <phase>`, the pace-flag qualifiers, and the scan.started event's canonical phase list — agrees on what a spelling means.

func OnlyPhaseSet

func OnlyPhaseSet(raw string) map[string]bool

OnlyPhaseSet returns the set of normalized phases listed in a comma-separated --only value. Callers use it to gate behavior that depends on which phases are active (e.g. validating that --format=html was scoped to phases that produce a report). Returns nil for empty input.

func PhaseNamesDesc

func PhaseNamesDesc(skippableOnly bool) string

PhaseNamesDesc renders the canonical phase ids alone, comma-separated. Flag help uses this (the full alias vocabulary is too long for one --help line); the error a wrong value produces quotes ValidOnlyPhasesDesc/ValidSkipPhasesDesc instead, which spells every accepted alias out.

func PhaseVocabularyLines

func PhaseVocabularyLines(skippableOnly bool) []string

PhaseVocabularyLines renders one "canonical (alias, alias)" entry per phase, for help text that lists them vertically. skippableOnly restricts it to the phases --skip accepts. Returned as lines rather than a joined string because the alias lists are themselves comma-separated — splitting the flat form on ", " to lay it out would break entries apart mid-list.

func SpiderFanOutReason

func SpiderFanOutReason(targetCount int) string

SpiderFanOutReason states why a serial crawl is the wrong shape for this target list. Two readings of the same fact: past the budget cap the ceiling is the headline — targets are dropped outright — while below it the only cost is wall clock. Telling an operator with 2 targets that "most won't be reached" is untrue, and a hint that overstates once is discounted from then on.

Rendered here rather than in pkg/cli so it reads spideringPhaseBudgetCap directly: a hardcoded figure in the message would keep printing the old budget after the cap moved, and the operator sizes their fan-out against it.

func SpiderFanOutSuggestion

func SpiderFanOutSuggestion(opts *types.Options, targetCount int) (flags string, ok bool)

SpiderFanOutSuggestion returns the flags that would fan a multi-target spidering run out across child processes, and whether the suggestion applies.

It exists because spidering is the one phase where the pace flags cannot help. It drives a browser rather than the executor, so -c/--concurrency (the executor's worker count) never reaches it, and its host loop is strictly serial — one crawl at a time, whatever the flags say. On top of that the phase stops after SpideringPhaseBudgetCap targets' worth of budget, so a long -T list is not merely slow, most of it is never reached: an operator who asked for 682 hosts gets about eight and a skip warning at the end. The only real parallelism available is the -P fan-out, which runs each target as its own process with its own browser and its own ceiling.

Every condition here mirrors one the -P fan-out itself enforces, because a hint naming a command that gets rejected — or silently degraded back to one serial scan — is worse than no hint. validateParallelScan admits -P > 1 only under --db-isolate or -S --split-by-host (anything else would share a database or an output file across concurrent scans), rejects --db-isolate alongside -S outright, and needs a -T file to split in the first place: a -t-only or piped run has nothing to fan out and is warned back down to Parallel = 1. Flags already present are not repeated back.

Lives here rather than in pkg/cli because both the pre-scan banner hint and the phase's own ceiling-reached line quote it, and pkg/cli imports this package (not the reverse) — one owner, so the two can never suggest different flags.

Types

type HeuristicsResult

type HeuristicsResult struct {
	Target        string
	StatusCode    int16
	ContentType   string // "blank", "html", "json", "xml", "text"
	BodyLength    int
	LinkCount     int  // advanced only
	IsSPA         bool // advanced only
	SkipSpidering bool
	Reason        string
}

HeuristicsResult holds the analysis of a single target's root page.

type LaunchParams

type LaunchParams struct {
	// Targets lists URLs / file paths the scan should ingest. Required.
	Targets []string

	// ProjectUUID scopes the scan. Empty leaves it unscoped — the same
	// behavior as `vigolium scan-url` without --project.
	ProjectUUID string

	// Modules optionally narrows the active-module set. Empty = no
	// restriction (CLI default).
	Modules []string

	// PassiveModules narrows the passive set. Empty = ["all"].
	PassiveModules []string

	// ExtensionPaths supplies extra JS extension files to load alongside
	// any built-ins. Each path is appended to ExtensionsConfig.CustomDir
	// before the runner builds its phase infra.
	ExtensionPaths []string

	// ExtensionsOnly skips all built-in Go modules; runs only JS
	// extensions. Used by run_extension when the agent wants its supplied
	// script to run in isolation.
	ExtensionsOnly bool

	// ScanningStrategy selects a named strategy ("lite", "balanced",
	// "deep"). Empty inherits the settings default.
	ScanningStrategy string

	// ScanMaxDuration caps total wall-clock time for the whole native scan.
	// Zero leaves the scan unbounded (it runs until ctx cancellation) — which
	// is a foot-gun for library callers like the autopilot pre-scan that share
	// a long-lived ctx: an unbounded scan will consume the entire budget and
	// starve whatever runs after it. Set a bounded value for such callers.
	ScanMaxDuration time.Duration

	// EnableDiscovery turns on the discovery phase. Default false — most
	// agent invocations want a targeted dynamic-assessment-only scan.
	EnableDiscovery bool

	// EnableSpidering turns on browser-based spidering. Default false.
	EnableSpidering bool

	// ConfigPath overrides the path to vigolium-configs.yaml. Empty =
	// default search order.
	ConfigPath string

	// Repository is the DB handle used for persistence and final result
	// readback. Nil is allowed — the scan still runs but results aren't
	// persisted and LaunchResult fields will be zero.
	Repository *database.Repository

	// Concurrency overrides the worker count. 0 = settings default.
	Concurrency int

	// OnlyPhase, when non-empty, isolates one or more phases via the same
	// comma-separated syntax `vigolium scan --only` accepts (e.g.
	// "discovery", "dynamic-assessment", "discovery,dynamic-assessment").
	// Phase aliases (deparos, dast, ext, etc.) are accepted and normalized.
	// Empty preserves the default phase plan derived from settings.
	OnlyPhase string

	// SkipPhases disables one or more phases while keeping the rest of the
	// plan intact. Mutually exclusive with OnlyPhase. Same alias normalization.
	SkipPhases []string

	// SkipIngestion skips the discovery ingestion phase. When you've already
	// got records in the project and just want to (re)run dynamic-assessment
	// against them, set this true and the runner will scan existing records
	// instead of crawling new ones.
	SkipIngestion bool
}

LaunchParams configures a one-shot scan started from a library caller. The intended consumer is the olium agent's run_scan / run_extension tools — anything that wants to drive a scan without rebuilding the full CLI option matrix. Only Targets is required; the rest fall back to sensible defaults.

type LaunchResult

type LaunchResult struct {
	ScanUUID      string
	Status        string
	FindingCount  int64
	TotalRequests int64
	Critical      int64
	High          int64
	Medium        int64
	Low           int64
	Info          int64
	Suspect       int64
	DurationMs    int64
}

LaunchResult summarizes a completed scan. Populated from the Scan DB row after RunNativeScan returns. When Repository is nil at launch time, only ScanUUID and DurationMs are populated.

func LaunchScan

func LaunchScan(ctx context.Context, params LaunchParams) (*LaunchResult, error)

LaunchScan runs a single scan synchronously. Blocks until RunNativeScan returns (success, failure, or ctx cancellation).

The scan UUID is generated up-front so callers can correlate post-hoc even if the run errors before any work is recorded — the UUID is real and queryable from the moment LaunchScan is invoked.

type NativePhase

type NativePhase string
const (
	PhaseHeuristicsCheck   NativePhase = "heuristics-check"
	PhasePortSweep         NativePhase = "port-sweep"
	PhaseExternalHarvest   NativePhase = "external-harvest"
	PhaseSpidering         NativePhase = "spidering"
	PhaseProbe             NativePhase = "probe"
	PhaseDiscovery         NativePhase = "discovery"
	PhaseTargetedReSpider  NativePhase = "targeted-respider"
	PhaseSeed              NativePhase = "seed"
	PhaseKnownIssueScan    NativePhase = "known-issue-scan"
	PhaseDynamicAssessment NativePhase = "dynamic-assessment"
)

type NativePhaseStep

type NativePhaseStep struct {
	Phase   NativePhase
	Enabled bool
}

type NativeScanPlan

type NativeScanPlan struct {
	Steps []NativePhaseStep
}

func BuildNativeScanPlan

func BuildNativeScanPlan(opts *types.Options) NativeScanPlan

type PhaseSpelling

type PhaseSpelling struct {
	Canonical string   `json:"canonical"`
	Aliases   []string `json:"aliases,omitempty"`
	Skippable bool     `json:"skippable"`
}

PhaseSpelling is the public projection of one vocabulary entry, for callers that need the structure rather than a rendered line — notably the machine output of `vigolium strategy`, which is how a caller discovers what --only and --skip accept without parsing help text.

func PhaseVocabulary

func PhaseVocabulary() []PhaseSpelling

PhaseVocabulary returns the accepted phase spellings, derived from the same single table every other consumer reads. Building the machine list here rather than restating it in pkg/cli is what keeps a new phase from being runnable but undiscoverable.

type Runner

type Runner struct {
	// contains filtered or unexported fields
}

Runner is a client for running the enumeration process.

func New

func New(options *types.Options) (*Runner, error)

New creates a new client for running the enumeration process.

func NewWithInputSource

func NewWithInputSource(options *types.Options, inputSource source.InputSource) (*Runner, error)

NewWithInputSource creates a new Runner with a custom InputSource. Used by server mode to provide queue-based input.

func (*Runner) Close

func (r *Runner) Close()

Close cancels the run, waits (bounded) for RunNativeScan to finish, then releases resources. Safe to call concurrently and repeatedly — a stop handler and the background-completion path can both call it, so the resource release (which decrements the process-global network dialer refcount) is guarded by sync.Once to avoid a double teardown of the shared dialer.

func (*Runner) Discard

func (r *Runner) Discard()

Discard releases a runner's resources without waiting for RunNativeScan. Used when a scan is rejected (queue full / project busy) before it ever starts: r.done is never closed in that case, so a normal Close would block for the full shutdown timeout. Shares closeOnce with Close so the network refcount is released exactly once.

func (*Runner) Finalized

func (r *Runner) Finalized() bool

Finalized reports whether RunNativeScan already wrote the scan's terminal status. The API server uses this so its safety-net CompleteScan only runs when the runner never reached its finalizer (e.g. infrastructure setup failed), avoiding a second write that would clobber the runner's truthful outcome.

func (*Runner) IsPaused

func (r *Runner) IsPaused() bool

IsPaused returns whether the scan is currently paused.

func (*Runner) Pause

func (r *Runner) Pause()

func (*Runner) Resume

func (r *Runner) Resume()

Resume unblocks paused workers and continues scan processing.

func (*Runner) RunNativeScan

func (r *Runner) RunNativeScan() (err error)

RunNativeScan orchestrates the native scan plan:

HeuristicsCheck   — optional root-page probe to optimize downstream phase selection
ExternalHarvest   — harvest URLs from external intelligence sources (opt-in)
Spidering         — browser-based crawling (opt-in)
Discovery         — ingest all input + deparos content discovery into DB (no modules)
Seed              — ingest CLI targets when discovery is skipped but DB-backed phases still need records
KnownIssueScan    — nuclei + secret scan (opt-in via --known-issue-scan)
DynamicAssessment — modules + extensions scan DB records

func (*Runner) ScanLogger

func (r *Runner) ScanLogger() *database.ScanLogger

ScanLogger returns the scan logger (may be nil if no repository is set).

func (*Runner) SetRepository

func (r *Runner) SetRepository(repo *database.Repository)

SetRepository sets the database repository for storing scan results

func (*Runner) SetSettings

func (r *Runner) SetSettings(s *config.Settings)

SetSettings sets the configuration settings for notifications and other YAML-based config

func (*Runner) SetSharedInfra

func (r *Runner) SetSharedInfra(infra *SharedInfra)

SetSharedInfra allows the runner to reuse pre-built infrastructure instead of building fresh.

type SharedInfra

type SharedInfra struct {
	HTTPRequester *http.Requester
	ScopeMatcher  *config.ScopeMatcher
	HostLimiter   *hostlimit.HostRateLimiter
	Services      *services.Services
	JSEngine      *jsext.Engine
	HookChain     *jsext.HookChain
}

SharedInfra holds reusable infrastructure components that can be shared across multiple scan runs (e.g., rescans in agent swarm mode). This avoids rebuilding expensive resources like HTTP requesters and scope matchers for each rescan.

func BuildSharedInfra

func BuildSharedInfra(opts *types.Options, settings *config.Settings, repo *database.Repository) (*SharedInfra, error)

BuildSharedInfra creates a SharedInfra from the given options and settings. It extracts the reusable portions of buildInfrastructure.

func (*SharedInfra) Close

func (s *SharedInfra) Close()

Close releases resources held by SharedInfra.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL