parlov 0.8.0

HTTP oracle detection tool — systematic probing for RFC-compliant information leakage.
Documentation
//! CLI argument definitions for parlov.
//!
//! Structured via `clap` derive macros. Each oracle class maps to a subcommand.

use clap::{Parser, Subcommand};

/// Output format for oracle results.
#[derive(Debug, Clone, Copy, PartialEq, Eq, clap::ValueEnum)]
pub enum OutputFormat {
    /// Human-readable terminal table with ANSI color.
    Table,
    /// Pretty-printed JSON — raw `OracleResult` or `ScanFinding` array.
    Json,
    /// SARIF v2.1.0 suitable for GitHub Advanced Security / Code Scanning integration.
    Sarif,
}

/// HTTP oracle detection tool.
///
/// Probes web applications and APIs to identify information leakage through RFC-compliant server
/// behavior.
#[derive(Debug, Parser)]
#[command(name = "parlov", version, about, long_about = None)]
pub struct Cli {
    /// Output format: table (default), json, or sarif.
    #[arg(long = "format", default_value = "table", global = true)]
    pub format: OutputFormat,

    /// Subcommand selecting which oracle class to probe.
    #[command(subcommand)]
    pub command: Command,
}

/// Top-level subcommands, one per oracle class.
#[derive(Debug, Subcommand)]
pub enum Command {
    /// Deprecated: use `scan --strategy` instead.
    Existence(ExistenceArgs),
    /// Automated elicitation scan: run all applicable strategies against a target endpoint.
    Scan(ScanArgs),
}

/// Arguments for the existence oracle subcommand.
#[derive(Debug, clap::Args)]
pub struct ExistenceArgs {
    /// Target URL template. `{id}` is substituted with the resource ID wherever it appears — in the URL, body, or both. The URL may be static if the ID is body-only.
    #[arg(long)]
    pub target: String,

    /// Resource ID to use as the baseline (known-existing resource).
    #[arg(long)]
    pub baseline_id: String,

    /// Resource ID to probe. Defaults to a randomly generated `UUIDv4` (nonexistent by design).
    #[arg(long)]
    pub probe_id: Option<String>,

    /// Additional request headers in `Name: Value` format. Repeatable.
    #[arg(long = "header", value_name = "HEADER")]
    pub headers: Vec<String>,

    /// HTTP method to use.
    #[arg(long, default_value = "GET")]
    pub method: String,

    /// Optional request body template. Use `{id}` as the placeholder.
    /// Required for POST when the identifier is in the body.
    /// Also used for PATCH and PUT to supply the patch payload.
    #[arg(long)]
    pub body: Option<String>,
}

/// Arguments for the automated elicitation scan subcommand.
#[derive(Debug, clap::Args)]
pub struct ScanArgs {
    /// Target URL template. `{id}` is substituted with the resource ID wherever it appears — in the URL, body, or both. The URL may be static if the ID is body-only.
    #[arg(long)]
    pub target: String,

    /// Known-existing resource ID (baseline).
    #[arg(long)]
    pub baseline_id: String,

    /// Known-nonexistent resource ID (probe). Defaults to a random `UUIDv4`.
    #[arg(long)]
    pub probe_id: Option<String>,

    /// Maximum risk level of strategies to run: safe | method-destructive | operation-destructive
    #[arg(long, default_value = "safe")]
    pub risk: String,

    /// Additional request headers in `Name: Value` format. Repeatable.
    #[arg(long = "header", value_name = "HEADER")]
    pub headers: Vec<String>,

    /// Under-scoped credential header for scope-manipulation strategy, e.g. `Authorization: Bearer ...`
    #[arg(long = "alt-credential", value_name = "HEADER")]
    pub alt_credential: Option<String>,

    /// Known-duplicate field=value for uniqueness strategy, e.g. `email=alice@example.com`
    #[arg(long)]
    pub known_duplicate: Option<String>,

    /// State field=value for state-transition strategy, e.g. `status=invalid`
    #[arg(long)]
    pub state_field: Option<String>,

    /// Filter strategies by vector. Format: `name` or `name:risk-level`.
    /// Repeatable. Mutually exclusive with --risk.
    /// Examples: `--vector cache-probing`, `--vector status-code-diff:method-destructive`
    #[arg(long = "vector", value_name = "VECTOR")]
    pub vectors: Vec<String>,

    /// Run only the named strategy. Repeatable. Mutually exclusive with --risk and --vector.
    /// Example: --strategy rd-percent-encoding
    #[arg(long = "strategy", value_name = "STRATEGY_ID")]
    pub strategies: Vec<String>,

    /// Optional request body template. `{id}` is substituted with the resource ID.
    /// Required when the target API identifies resources via request body rather than URL path.
    #[arg(long)]
    pub body: Option<String>,

    /// Run all strategies regardless of interim confidence. Records the strategy
    /// that first crossed the confirmation threshold in the output.
    #[arg(long, default_value = "false")]
    pub exhaustive: bool,

    /// Emit reproducible `curl` commands for the baseline and probe of each finding.
    /// Headers are NOT redacted — `Authorization` and other secrets appear verbatim
    /// so the curl commands actually work for hand verification. Use carefully.
    #[arg(long, default_value = "false")]
    pub repro: bool,

    /// Include filtered request/response headers and body samples in each finding.
    /// Headers are NOT redacted — `Authorization`, `Cookie`, and other secrets
    /// appear verbatim. Same opt-in stance as `--repro`. Use carefully.
    #[arg(long, default_value = "false")]
    pub verbose: bool,
}