use super::super::component_view::ComponentView;
use super::super::vulnerability_view::{
SeverityView, VulnerabilityReportView, VulnerabilitySummary, VulnerabilityView,
};
use crate::sbom_generation::domain::services::VulnerabilityCheckResult;
use crate::sbom_generation::domain::vulnerability::{
PackageVulnerabilities, Severity, Vulnerability,
};
use std::collections::HashSet;
pub(super) fn build_vulnerabilities(
result: &VulnerabilityCheckResult,
components: &[ComponentView],
) -> VulnerabilityReportView {
let actionable: Vec<VulnerabilityView> = result
.above_threshold
.iter()
.flat_map(|pkg| build_vulnerability_views_for_package(pkg, components))
.collect();
let informational: Vec<VulnerabilityView> = result
.below_threshold
.iter()
.flat_map(|pkg| build_vulnerability_views_for_package(pkg, components))
.collect();
let affected_packages: HashSet<&str> = result
.above_threshold
.iter()
.chain(result.below_threshold.iter())
.map(|pkg| pkg.package_name())
.collect();
let summary = VulnerabilitySummary {
total_count: result.actionable_count() + result.informational_count(),
actionable_count: result.actionable_count(),
informational_count: result.informational_count(),
affected_package_count: affected_packages.len(),
};
VulnerabilityReportView {
actionable,
informational,
threshold_exceeded: result.threshold_exceeded,
summary,
}
}
fn build_vulnerability_views_for_package(
package: &PackageVulnerabilities,
components: &[ComponentView],
) -> Vec<VulnerabilityView> {
package
.vulnerabilities()
.iter()
.map(|vuln| build_vulnerability_view(vuln, package, components))
.collect()
}
pub(super) fn build_vulnerability_view(
vuln: &Vulnerability,
package: &PackageVulnerabilities,
components: &[ComponentView],
) -> VulnerabilityView {
let component = components
.iter()
.find(|c| c.name == package.package_name() && c.version == package.current_version());
let affected_component = component
.map(|c| c.bom_ref.clone())
.unwrap_or_else(|| format!("{}-{}", package.package_name(), package.current_version()));
let bom_ref = format!("{}-{}", vuln.id(), affected_component);
VulnerabilityView {
bom_ref,
id: vuln.id().to_string(),
affected_component,
affected_component_name: package.package_name().to_string(),
affected_version: package.current_version().to_string(),
cvss_score: vuln.cvss_score().map(|s| s.value()),
cvss_vector: None, severity: map_severity(&vuln.severity()),
fixed_version: vuln.fixed_version().map(|s| s.to_string()),
description: None, source_url: None, }
}
pub(super) fn map_severity(severity: &Severity) -> SeverityView {
match severity {
Severity::Critical => SeverityView::Critical,
Severity::High => SeverityView::High,
Severity::Medium => SeverityView::Medium,
Severity::Low => SeverityView::Low,
Severity::None => SeverityView::None,
}
}