Skip to main content

parlov_output/
lib.rs

1//! Output formatters for parlov: terminal table, structured JSON, and SARIF v2.1.0.
2
3#![deny(clippy::all)]
4#![warn(clippy::pedantic)]
5#![deny(missing_docs)]
6
7mod context;
8mod json;
9mod json_endpoint;
10mod repro;
11mod sarif;
12mod sarif_builder;
13#[cfg(not(target_arch = "wasm32"))]
14mod table;
15#[cfg(not(target_arch = "wasm32"))]
16mod table_rows;
17pub mod wire;
18
19#[cfg(test)]
20#[path = "repro_output_tests.rs"]
21mod repro_output_tests;
22
23#[cfg(test)]
24#[path = "context_output_tests.rs"]
25mod context_output_tests;
26
27pub use context::{BodySamplesBundle, ExchangeContext, HeadersBundle, ProbeContext};
28pub use json::{render_endpoint_verdict_json, render_json, render_scan_json};
29pub use parlov_elicit::ChainProvenance;
30pub use repro::build_curl;
31pub use sarif::{render_endpoint_verdict_sarif, render_sarif, render_scan_sarif};
32#[cfg(not(target_arch = "wasm32"))]
33pub use table::{render_endpoint_verdict_table, render_scan_table, render_table};
34
35use parlov_core::OracleResult;
36use serde::{Deserialize, Serialize};
37
38/// Reproducible `curl` commands for the baseline and probe requests of a finding.
39///
40/// Populated only when `--repro` is set on the scan CLI; emitted in JSON, SARIF,
41/// and table outputs. Headers (including `Authorization`) appear verbatim — the
42/// curls are designed to be copy-pasteable for hand verification.
43#[derive(Debug, Clone, Serialize, Deserialize)]
44#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
45pub struct ReproInfo {
46    /// Curl command for the baseline request — headers verbatim.
47    pub baseline_curl: String,
48    /// Curl command for the probe request — headers verbatim.
49    pub probe_curl: String,
50}
51
52/// A single finding from a scan run -- one strategy applied to one method.
53#[derive(Debug, Clone, Serialize, Deserialize)]
54#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
55pub struct ScanFinding {
56    /// e.g. `"https://api.example.com/users/1"`
57    pub target_url: String,
58    /// e.g. `"existence-get-200-404"`
59    pub strategy_id: String,
60    /// e.g. `"GET 200/404 existence"`
61    pub strategy_name: String,
62    /// e.g. `"GET"`
63    pub method: String,
64    /// Oracle analysis verdict, signals, and scoring breakdown.
65    pub result: OracleResult,
66    /// Reproducible curl commands — `Some` only when `--repro` was set.
67    #[serde(default, skip_serializing_if = "Option::is_none")]
68    pub repro: Option<ReproInfo>,
69    /// What was actually sent on the wire — always present.
70    pub probe: ProbeContext,
71    /// What came back — status codes always present; headers and body samples
72    /// only when `--verbose` was set.
73    pub exchange: ExchangeContext,
74    /// Phase-2 chain provenance — `None` for phase-1 findings, `Some` when the
75    /// underlying spec was generated by `generate_dag_chained_plan` from a
76    /// harvested phase-1 signal.
77    #[serde(default, skip_serializing_if = "Option::is_none")]
78    pub chain_provenance: Option<ChainProvenance>,
79}