use log::{info, warn};
use rayon::prelude::*;
use std::collections::HashMap;
use std::path::Path;
use std::time::Instant;
use super::checkers::{
GoVulnerabilityChecker, JavaScriptVulnerabilityChecker, JavaVulnerabilityChecker,
LanguageVulnerabilityChecker, MutableLanguageVulnerabilityChecker, PythonVulnerabilityChecker,
RustVulnerabilityChecker,
};
use super::types::{
VulnerabilityError, VulnerabilityReport, VulnerabilitySeverity, VulnerableDependency,
};
use crate::analyzer::dependency_parser::{DependencyInfo, Language};
use crate::analyzer::tool_management::ToolInstaller;
#[derive(Default)]
pub struct VulnerabilityChecker;
impl VulnerabilityChecker {
pub fn new() -> Self {
Self
}
pub async fn check_all_dependencies(
&self,
dependencies: &HashMap<Language, Vec<DependencyInfo>>,
project_path: &Path,
) -> Result<VulnerabilityReport, VulnerabilityError> {
let _start_time = Instant::now();
info!("Starting comprehensive vulnerability check");
let mut installer = ToolInstaller::new();
let languages: Vec<Language> = dependencies.keys().cloned().collect();
info!("🔧 Checking and installing required vulnerability scanning tools...");
installer
.ensure_tools_for_languages(&languages)
.map_err(|e| {
VulnerabilityError::CommandError(format!("Tool installation failed: {}", e))
})?;
installer.print_tool_status(&languages);
let mut all_vulnerable_deps = Vec::new();
let results: Vec<_> = dependencies
.par_iter()
.map(|(language, deps)| self.check_language_dependencies(language, deps, project_path))
.collect();
for result in results {
match result {
Ok(mut vuln_deps) => all_vulnerable_deps.append(&mut vuln_deps),
Err(e) => warn!("Error checking vulnerabilities: {}", e),
}
}
all_vulnerable_deps.sort_by(|a, b| {
let a_max = a
.vulnerabilities
.iter()
.map(|v| &v.severity)
.max()
.unwrap_or(&VulnerabilitySeverity::Info);
let b_max = b
.vulnerabilities
.iter()
.map(|v| &v.severity)
.max()
.unwrap_or(&VulnerabilitySeverity::Info);
b_max.cmp(a_max)
});
let mut critical_count = 0;
let mut high_count = 0;
let mut medium_count = 0;
let mut low_count = 0;
let mut total_vulnerabilities = 0;
for dep in &all_vulnerable_deps {
for vuln in &dep.vulnerabilities {
total_vulnerabilities += 1;
match vuln.severity {
VulnerabilitySeverity::Critical => critical_count += 1,
VulnerabilitySeverity::High => high_count += 1,
VulnerabilitySeverity::Medium => medium_count += 1,
VulnerabilitySeverity::Low => low_count += 1,
VulnerabilitySeverity::Info => {}
}
}
}
Ok(VulnerabilityReport {
checked_at: chrono::Utc::now(),
total_vulnerabilities,
critical_count,
high_count,
medium_count,
low_count,
vulnerable_dependencies: all_vulnerable_deps,
})
}
fn check_language_dependencies(
&self,
language: &Language,
dependencies: &[DependencyInfo],
project_path: &Path,
) -> Result<Vec<VulnerableDependency>, VulnerabilityError> {
info!(
"Checking {} dependencies for {:?}",
dependencies.len(),
language
);
match language {
Language::Rust => {
let checker = RustVulnerabilityChecker::new();
checker.check_vulnerabilities(dependencies, project_path)
}
Language::JavaScript | Language::TypeScript => {
let mut checker = JavaScriptVulnerabilityChecker::new();
checker.check_vulnerabilities(dependencies, project_path)
}
Language::Python => {
let mut checker = PythonVulnerabilityChecker::new();
checker.check_vulnerabilities(dependencies, project_path)
}
Language::Go => {
let mut checker = GoVulnerabilityChecker::new();
checker.check_vulnerabilities(dependencies, project_path)
}
Language::Java | Language::Kotlin => {
let mut checker = JavaVulnerabilityChecker::new();
checker.check_vulnerabilities(dependencies, project_path)
}
_ => {
warn!(
"Vulnerability checking not yet implemented for {:?}",
language
);
Ok(vec![])
}
}
}
}