parlov-output 0.8.0

Output formatters for parlov: SARIF, terminal table, and raw JSON.
Documentation
//! Reproducible `curl` command construction from `ProbeDefinition`.
//!
//! Used when the operator passes `--repro` to the scan CLI: each `ScanFinding`
//! carries a `baseline_curl` and `probe_curl` so the finding can be verified
//! by hand. Output is POSIX-shell-safe via `shell-escape` — URL, header values,
//! and request body are single-quoted. No header redaction: `Authorization`
//! and other secrets pass through verbatim, by design.

use std::borrow::Cow;

use parlov_core::ProbeDefinition;
use shell_escape::unix::escape;

/// Builds a multi-line curl command from a `ProbeDefinition`.
///
/// Method is uppercased; URL, header values, and body are POSIX-shell-quoted.
/// Headers are emitted one per continuation line. `--data` is emitted only
/// when `body.is_some()` (an empty `Some(Bytes::new())` still produces `--data ''`).
#[must_use]
pub fn build_curl(probe: &ProbeDefinition) -> String {
    let method = probe.method.as_str().to_ascii_uppercase();
    let url = quote(&probe.url);
    let mut out = format!("curl -X {method} {url}");
    for (name, value) in &probe.headers {
        let value_str = value.to_str().unwrap_or("");
        let header_line = format!("{}: {}", name.as_str(), value_str);
        out.push_str(" \\\n  -H ");
        out.push_str(&quote(&header_line));
    }
    if let Some(body) = &probe.body {
        let body_str = std::str::from_utf8(body).unwrap_or("");
        out.push_str(" \\\n  --data ");
        out.push_str(&quote(body_str));
    }
    out
}

fn quote(input: &str) -> String {
    escape(Cow::Borrowed(input)).into_owned()
}

#[cfg(test)]
#[path = "repro_tests.rs"]
mod tests;