use crate::core::{Confidence, Finding, Severity};
use std::path::PathBuf;
pub fn parse_redteam_findings(json_text: &str) -> Vec<Finding> {
let value: serde_json::Value = match serde_json::from_str(json_text) {
Ok(v) => v,
Err(_) => return Vec::new(),
};
let findings_array = value
.get("findings")
.and_then(|v| v.as_array())
.or_else(|| value.as_array());
let Some(items) = findings_array else {
return Vec::new();
};
items.iter().filter_map(parse_single_finding).collect()
}
fn parse_single_finding(value: &serde_json::Value) -> Option<Finding> {
let probe_name = value.get("probe_name")?.as_str()?;
let title = value
.get("title")
.and_then(|v| v.as_str())
.unwrap_or(probe_name);
let severity_str = value
.get("severity")
.and_then(|v| v.as_str())
.unwrap_or("medium");
let severity = Severity::parse_str(severity_str).unwrap_or(Severity::Medium);
let mut finding = Finding::new(
format!("redteam-{}", probe_name),
title.to_string(),
severity,
);
finding.confidence = Confidence::Medium;
if let Some(desc) = value.get("description").and_then(|v| v.as_str()) {
finding.description = desc.to_string();
}
if let Some(rem) = value.get("remediation").and_then(|v| v.as_str()) {
finding.remediation = Some(rem.to_string());
}
if let Some(category) = value.get("category").and_then(|v| v.as_str()) {
finding.tags.push("llm-security".to_string());
finding.tags.push(category.to_lowercase());
}
if let Some(input) = value.get("input").and_then(|v| v.as_str()) {
finding.evidence.push(format!("Input: {}", input));
}
if let Some(output) = value.get("output").and_then(|v| v.as_str()) {
finding.evidence.push(format!("Output: {}", output));
}
if let Some(tool) = value.get("tool_name").and_then(|v| v.as_str()) {
finding.file_path = Some(PathBuf::from(tool));
}
if let Some(cwe) = value.get("cwe").and_then(|v| v.as_u64()) {
finding.cwe_ids.push(cwe as u32);
}
Some(finding)
}
pub fn parse_mcp_scan_findings(json_text: &str, config_path: Option<&str>) -> Vec<Finding> {
let mut findings = parse_redteam_findings(json_text);
if let Some(path) = config_path {
for f in &mut findings {
if f.file_path.is_none() {
f.file_path = Some(PathBuf::from(path));
}
}
}
findings
}