(
vulns_value: Option<&serde_json::Value>,
component: &str,
)
| 502 | } |
| 503 | |
| 504 | fn parse_vulns_array( |
| 505 | vulns_value: Option<&serde_json::Value>, |
| 506 | component: &str, |
| 507 | ) -> Vec<WPVulnerability> { |
| 508 | let mut vulns = Vec::new(); |
| 509 | |
| 510 | if let Some(arr) = vulns_value.and_then(|v| v.as_array()) { |
| 511 | for vuln in arr { |
| 512 | let title = vuln |
| 513 | .get("title") |
| 514 | .and_then(|t| t.as_str()) |
| 515 | .unwrap_or("Unknown") |
| 516 | .to_string(); |
| 517 | |
| 518 | let vuln_type = vuln |
| 519 | .get("vuln_type") |
| 520 | .and_then(|t| t.as_str()) |
| 521 | .unwrap_or("unknown") |
| 522 | .to_string(); |
| 523 | |
| 524 | // WPScan uses "cvss" or infer severity from vuln_type |
| 525 | let severity = infer_severity(&title, &vuln_type, vuln); |
| 526 | |
| 527 | let cve = vuln |
| 528 | .get("references") |
| 529 | .and_then(|r| r.get("cve")) |
| 530 | .and_then(|c| c.as_array()) |
| 531 | .and_then(|arr| arr.first()) |
| 532 | .and_then(|v| v.as_str()) |
| 533 | .map(|s| format!("CVE-{}", s)); |
| 534 | |
| 535 | let fixed_in = vuln |
| 536 | .get("fixed_in") |
| 537 | .and_then(|f| f.as_str()) |
| 538 | .map(|s| s.to_string()); |
| 539 | |
| 540 | vulns.push(WPVulnerability { |
| 541 | title, |
| 542 | vuln_type, |
| 543 | severity, |
| 544 | cve, |
| 545 | fixed_in, |
| 546 | component: component.to_string(), |
| 547 | }); |
| 548 | } |
| 549 | } |
| 550 | |
| 551 | vulns |
| 552 | } |
| 553 | |
| 554 | fn infer_severity( |
| 555 | title: &str, |
no test coverage detected