parlov docs

parlov (binary)

CLI binary crate — argument parsing, subcommand dispatch, adaptive probe scheduling, vector filtering, and the demo server.

Implemented

Version: 0.6.0 | Files: 9 | Lines: 1,300 | Dependencies: bytes, clap, http, parlov-core, parlov-probe, parlov-analysis, parlov-elicit, parlov-output, tokio, tracing, uuid

The CLI binary crate. Composes all library crates into the command-line tool. Owns argument parsing, subcommand dispatch, the async runtime, and the adaptive probe scheduling loop. Also contains an optional demo server for integration testing.


Public API

The binary crate has a minimal library surface. Only the demo module is publicly exposed, and only when the demo feature flag is enabled:

#[cfg(feature = "demo")]
pub mod demo;

All other modules are internal to the binary.


Internal Architecture

CLI Argument Parsing (cli.rs)

Uses clap with derive macros. Defines the command structure:

pub struct Cli {
    pub format: OutputFormat,
    pub command: Command,
}

pub enum Command {
    Existence(ExistenceArgs),
    Scan(ScanArgs),
}

ExistenceArgs — Single-target probing:

FlagTypeDescription
targetStringURL with {id} placeholder
baseline_idStringKnown-existing resource ID
probe_idStringKnown-nonexistent resource ID
--methodOption<String>HTTP method override
--headerVec<String>Request headers (Key: Value format)
--bodyOption<String>Request body

ScanArgs — Multi-strategy scanning:

Independently declared struct (no structural inheritance from ExistenceArgs). Shares similar base fields but defines them separately. The scan runner iterates all applicable strategies, executes probe plans, and aggregates ScanFinding results.

FlagTypeDescription
targetStringURL with {id} placeholder
baseline_idStringKnown-existing resource ID
probe_idStringKnown-nonexistent resource ID
--methodOption<String>HTTP method override
--headerVec<String>Request headers (Key: Value format)
--bodyOption<String>Request body
--riskOption<RiskLevel>Max risk level (mutually exclusive with --vector)
--vectorOption<Vector>Filter to specific vector (mutually exclusive with --risk)
--known-duplicate-field/valueOption<String>For uniqueness strategies
--state-field/valueOption<String>For state-transition strategies
--alt-credentialVec<String>Alt credential headers for scope manipulation

OutputFormat enum: Table, Json, Sarif

Subcommand Runners

existence.rs — Direct probe execution (bypasses strategy/elicitation system):

  1. Parse method, headers, and probe ID directly from args
  2. Build two ProbeDefinitions via build_probe_def (baseline + probe)
  3. Call collect_until_verdict directly with HttpProbe
  4. Render result via selected output format

scan.rs — Multi-strategy scan pipeline:

  1. Parse args into ScanContext
  2. Call generate_plan(&ctx) from parlov-elicit registry
  3. For each ProbeSpec in the plan:
    • Execute probes via dispatch_spec
    • Collect all ScanFinding results regardless of verdict
    • Log and skip on error
  4. Render all findings via selected output format (SARIF renderer excludes NotPresent at output time)

scan_context.rs — Builds ScanContext from CLI args. Handles header parsing, alt credential assembly, and optional field construction.

Vector Filtering (vector_filter.rs)

When --vector is specified, filters the strategy list to only strategies whose Technique.vector matches. This is an alternative to --risk filtering — the two are mutually exclusive.

Utility (util.rs)

CLI-level helpers: header parsing from Key: Value strings, error formatting, etc.

Demo Server (demo.rs)

Feature-gated (#[cfg(feature = "demo")]). An Axum-based HTTP server that simulates API endpoints with predictable differential behavior for integration testing. Not shipped in release builds.


Execution Flow

CLI args

  ├── clap::parse()

  ├── Build ScanContext

  ├── Dispatch
  │   ├── existence: build_probe_def directly from args
  │   └── scan: generate_plan() with risk/vector filter

  ├── For each ProbeSpec (scan) / single pair (existence):
  │   ├── HttpProbe.execute(baseline)
  │   ├── HttpProbe.execute(probe)
  │   ├── Build DifferentialSet
  │   ├── ExistenceAnalyzer.evaluate()
  │   ├── If NeedMore: loop (up to max samples)
  │   └── Collect OracleResult

  └── Render output
      ├── table: render_table() / render_scan_table()
      ├── json:  render_json() / render_scan_json()
      └── sarif: render_sarif() / render_scan_sarif()

Extension Points

Adding a new subcommand: Add a variant to the Command enum in cli.rs, define args struct, implement a runner module, and add dispatch in main.rs.

Adding a new output format: Add a variant to OutputFormat in cli.rs, implement the render function in parlov-output, and wire it into the subcommand runners.

Custom probe clients: The runners construct HttpProbe::new(). The Probe trait uses RPITIT and is not dyn-compatible, so Box<dyn Probe> does not compile. To swap implementations, use a generic parameter bounded by Probe, or wrap behind async-trait.

On this page