Documentation
¶
Index ¶
- Constants
- Variables
- func ApplyNativePhaseSelection(opts *types.Options, enableExtensions func()) error
- func DiscoveryBudget(settings *config.Settings, options *types.Options) time.Duration
- func FormatBlockNoticeLine(n http.BlockNotice) string
- func FormatEdgePaceLine(n hostlimit.PreArmNotice) string
- func HygieneBannerCounts(opts *types.Options, settings *config.Settings, active []modules.ActiveModule, ...) (activeCount, passiveCount int, note string)
- func HygieneGateActive(opts *types.Options, settings *config.Settings) bool
- func IsNativePhaseSpelling(s string) bool
- func IsProbeOnlyRun(opts *types.Options) bool
- func NormalizeNativePhase(phase string) string
- func OnlyPhaseSet(raw string) map[string]bool
- func PhaseLabel(settings *config.Settings, name, phaseKey string, enabled bool, ...) string
- func PhaseNamesDesc(skippableOnly bool) string
- func PhaseSpeedDetail(settings *config.Settings, phaseKey string, effective time.Duration) string
- func PhaseVocabularyLines(skippableOnly bool) []string
- func SpiderFanOutReason(targetCount int) string
- func SpiderFanOutSuggestion(opts *types.Options, targetCount int) (flags string, ok bool)
- func SpideringBudget(settings *config.Settings, options *types.Options) time.Duration
- type HeuristicsResult
- type LaunchParams
- type LaunchResult
- type NativePhase
- type NativePhaseStep
- type NativeScanPlan
- type PhaseSpelling
- type Runner
- func (r *Runner) Close()
- func (r *Runner) Completion() database.ScanCompletion
- func (r *Runner) Discard()
- func (r *Runner) Finalized() bool
- func (r *Runner) IsPaused() bool
- func (r *Runner) Pause()
- func (r *Runner) Resume()
- func (r *Runner) RunNativeScan() (err error)
- func (r *Runner) ScanLogger() *database.ScanLogger
- func (r *Runner) SetRepository(repo *database.Repository)
- func (r *Runner) SetSettings(s *config.Settings)
- func (r *Runner) SetSharedInfra(infra *SharedInfra)
- type SharedInfra
Constants ¶
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 ¶
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 DiscoveryBudget ¶ added in v0.5.2
DiscoveryBudget returns the wall-clock budget one discovery target gets.
Same contract as SpideringBudget, for the phase whose fallback lived inside the input source: option (--discover-max-time, else the scanning_pace value) first, then scanning_pace.discovery.max_duration, then the source's own default. Without this the banner printed the unset option — 0, rendered as no budget at all — while every target ran for the source's default hour.
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 HygieneBannerCounts ¶ added in v0.4.9
func HygieneBannerCounts(opts *types.Options, settings *config.Settings, active []modules.ActiveModule, passive []modules.PassiveModule) (activeCount, passiveCount int, note string)
HygieneBannerCounts adjusts a scan banner's module counts for the hardening-advisory gate and returns the note to append, empty when the family runs. One implementation for the two pre-scan banners (CLI and runner).
func HygieneGateActive ¶ added in v0.4.9
HygieneGateActive reports whether a scan with these options and settings suppresses the hardening-advisory family: the resolved policy says no AND the operator has not named one of them explicitly.
Exported because the CLI prints its own pre-scan banner before a Runner exists, and a banner that counts modules the scan will not run makes the gate look like a lost finding. Both banners and the module filter read this.
func IsNativePhaseSpelling ¶
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 ¶
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 ¶
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 ¶
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 PhaseLabel ¶ added in v0.4.8
func PhaseLabel(settings *config.Settings, name, phaseKey string, enabled bool, effective time.Duration) string
PhaseLabel renders one entry of the banner's "Phases:" line: a status symbol, the phase name, and the budget it will run with ("Spidering (6m0s, x0.1)").
`--spider-max-time 5m` used to be announced as the profile's 6m0s -- 0.1 x the 1h scan budget -- while the phase went on to crawl for the 5m it was told to.
func PhaseNamesDesc ¶
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 PhaseSpeedDetail ¶ added in v0.4.8
PhaseSpeedDetail renders the budget fragment a phase prints on its own detail line -- "max-duration=6m0s (duration_factor=0.1)" -- or "" when the phase has no budget. Callers supply the separator, because one of them opens a line with it and the rest append to a list.
A factor never arrives without a duration: ResolvePhase only sets one in the branch that multiplies it into the other.
func PhaseVocabularyLines ¶
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 ¶
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 ¶
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), 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. Suggesting --db-isolate to a -S run is pointless for a different reason — runScanCmd drops the flag with a warning there, leaving -P to fail the gate anyway. 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.
func SpideringBudget ¶ added in v0.4.8
SpideringBudget returns the wall-clock budget one spidering target gets.
It exists so the phase and the banner cannot answer this differently. The budget comes from the option when set (--spider-max-time, else the scanning_pace value runNativeScan copies in) and otherwise from spidering.max_duration, a separate config key -- and a banner that read only one of those advertised a budget the phase would not use, which is the defect this whole file exists to close. runSpideringPhase calls it too.
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_native_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
// SkipsTarget marks a phase that never sends a request to the scan target.
// Declared here, in the same literal as the phase's own gate, rather than in
// a side table keyed by phase: this file is the single owner of the phase
// vocabulary, and a second per-phase map is exactly how the vocabulary and
// the plan drifted apart before. A new phase has to answer the question
// where it is declared.
SkipsTarget bool
}
type NativeScanPlan ¶
type NativeScanPlan struct {
Steps []NativePhaseStep
}
func BuildNativeScanPlan ¶
func BuildNativeScanPlan(opts *types.Options) NativeScanPlan
func (NativeScanPlan) SendsTargetTraffic ¶ added in v0.5.0
func (p NativeScanPlan) SendsTargetTraffic() bool
SendsTargetTraffic reports whether any enabled step in the plan will send a request to the scan target. Everything but ExternalHarvest reaches it, directly or through the shared requester, and so is affected by session headers and request hooks.
Infrastructure whose only purpose is to shape target traffic is built on the strength of this. Session hydration in particular EXECUTES LOGIN FLOWS, so `vigolium run external-harvest --auth-file admin.yaml` used to authenticate against a host it was never going to touch.
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 NewWithInputSource ¶
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) Completion ¶ added in v0.5.2
func (r *Runner) Completion() database.ScanCompletion
Completion is the scan-level verdict: whether every phase covered what it was given, and if not, the one reason worth reporting.
"complete" is deliberately hard to earn. Every phase must have ended completed or been skipped for having nothing to do, and no phase may have set a stop reason. Anything else is "partial", including a phase that failed — a scan that lost a phase is not a complete scan, whatever the remaining phases managed.
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 ¶
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) Resume ¶
func (r *Runner) Resume()
Resume unblocks paused workers and continues scan processing.
func (*Runner) RunNativeScan ¶
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 ¶
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 {
}
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.
Source Files
¶
- auth_wall.go
- banner_pace.go
- browser_policy.go
- extension_llm.go
- finding_grouper.go
- heuristics.go
- launch.go
- module_tiers.go
- native_plan.go
- phase_outcome.go
- port_sweep.go
- probe_scheme.go
- respider_eval.go
- runner.go
- runner_browser_auth.go
- runner_events.go
- runner_modules.go
- runner_output.go
- runner_phase_discovery.go
- runner_phase_probe.go
- runner_phase_respider.go
- runner_phases.go
- runner_sessions.go
- runner_targets.go
- spider_fanout.go
- tee_writer.go
- writer_outcome.go