use std::collections::BTreeMap;
use comfy_table::{Cell, Table};
use parlov_core::OracleVerdict;
use crate::ScanFinding;
pub(crate) fn add_repro_rows(table: &mut Table, finding: &ScanFinding) {
let Some(repro) = &finding.repro else { return };
if finding.result.verdict == OracleVerdict::NotPresent {
return;
}
table.add_row(vec![
Cell::new("Reproduce baseline:"),
Cell::new(""),
Cell::new(""),
Cell::new(""),
Cell::new(""),
Cell::new(&repro.baseline_curl),
]);
table.add_row(vec![
Cell::new("Reproduce probe:"),
Cell::new(""),
Cell::new(""),
Cell::new(""),
Cell::new(""),
Cell::new(&repro.probe_curl),
]);
}
pub(crate) fn add_probe_row(table: &mut Table, finding: &ScanFinding) {
if finding.result.verdict == OracleVerdict::NotPresent {
return;
}
let summary = format!(
"Probe: {} {} -> {} | {} -> {}",
finding.probe.method,
finding.probe.baseline_url,
finding.exchange.baseline_status,
finding.probe.probe_url,
finding.exchange.probe_status,
);
table.add_row(vec![
Cell::new(summary),
Cell::new(""),
Cell::new(""),
Cell::new(""),
Cell::new(""),
Cell::new(""),
]);
}
pub(crate) fn add_chain_row(table: &mut Table, finding: &ScanFinding) {
let Some(prov) = &finding.chain_provenance else {
return;
};
let summary = format!(
"Chain: derived from {}={}",
prov.producer_kind, prov.producer_value,
);
table.add_row(vec![
Cell::new(summary),
Cell::new(""),
Cell::new(""),
Cell::new(""),
Cell::new(""),
Cell::new(""),
]);
}
pub(crate) fn add_verbose_rows(table: &mut Table, finding: &ScanFinding) {
if let Some(req_hdrs) = finding.probe.headers.as_ref() {
push_header_section(table, "Request headers (baseline)", &req_hdrs.baseline);
push_header_section(table, "Request headers (probe)", &req_hdrs.probe);
}
if let Some(resp_hdrs) = finding.exchange.headers.as_ref() {
push_header_section(table, "Response headers (baseline)", &resp_hdrs.baseline);
push_header_section(table, "Response headers (probe)", &resp_hdrs.probe);
}
if let Some(samples) = finding.exchange.body_samples.as_ref() {
table.add_row(vec![
Cell::new("Body (baseline)"),
Cell::new(""),
Cell::new(""),
Cell::new(""),
Cell::new(""),
Cell::new(&samples.baseline),
]);
table.add_row(vec![
Cell::new("Body (probe)"),
Cell::new(""),
Cell::new(""),
Cell::new(""),
Cell::new(""),
Cell::new(&samples.probe),
]);
}
}
fn push_header_section(table: &mut Table, label: &str, headers: &BTreeMap<String, String>) {
if headers.is_empty() {
return;
}
let body: String = headers
.iter()
.map(|(k, v)| format!("{k}: {v}"))
.collect::<Vec<_>>()
.join("\n");
table.add_row(vec![
Cell::new(label),
Cell::new(""),
Cell::new(""),
Cell::new(""),
Cell::new(""),
Cell::new(body),
]);
}