syncable_cli/analyzer/vulnerability/
core.rs

1use std::collections::HashMap;
2use std::path::Path;
3use std::time::Instant;
4use log::{info, warn};
5use rayon::prelude::*;
6
7use crate::analyzer::dependency_parser::{DependencyInfo, Language};
8use crate::analyzer::tool_management::ToolInstaller;
9use super::types::{VulnerabilityReport, VulnerableDependency, VulnerabilityError, VulnerabilitySeverity};
10use super::checkers::{
11    RustVulnerabilityChecker, JavaScriptVulnerabilityChecker, PythonVulnerabilityChecker,
12    GoVulnerabilityChecker, JavaVulnerabilityChecker, LanguageVulnerabilityChecker
13};
14
15pub struct VulnerabilityChecker;
16
17impl VulnerabilityChecker {
18    pub fn new() -> Self {
19        Self
20    }
21    
22    /// Check all dependencies for vulnerabilities
23    pub async fn check_all_dependencies(
24        &self,
25        dependencies: &HashMap<Language, Vec<DependencyInfo>>,
26        project_path: &Path,
27    ) -> Result<VulnerabilityReport, VulnerabilityError> {
28        let start_time = Instant::now();
29        info!("Starting comprehensive vulnerability check");
30        
31        // Auto-install required tools
32        let mut installer = ToolInstaller::new();
33        let languages: Vec<Language> = dependencies.keys().cloned().collect();
34        
35        info!("🔧 Checking and installing required vulnerability scanning tools...");
36        installer.ensure_tools_for_languages(&languages)
37            .map_err(|e| VulnerabilityError::CommandError(format!("Tool installation failed: {}", e)))?;
38        
39        installer.print_tool_status(&languages);
40        
41        let mut all_vulnerable_deps = Vec::new();
42        
43        // Process each language in parallel
44        let results: Vec<_> = dependencies.par_iter()
45            .map(|(language, deps)| {
46                self.check_language_dependencies(language, deps, project_path)
47            })
48            .collect();
49        
50        // Collect results
51        for result in results {
52            match result {
53                Ok(mut vuln_deps) => all_vulnerable_deps.append(&mut vuln_deps),
54                Err(e) => warn!("Error checking vulnerabilities: {}", e),
55            }
56        }
57        
58        // Sort by severity
59        all_vulnerable_deps.sort_by(|a, b| {
60            let a_max = a.vulnerabilities.iter()
61                .map(|v| &v.severity)
62                .max()
63                .unwrap_or(&VulnerabilitySeverity::Info);
64            let b_max = b.vulnerabilities.iter()
65                .map(|v| &v.severity)
66                .max()
67                .unwrap_or(&VulnerabilitySeverity::Info);
68            b_max.cmp(a_max)
69        });
70        
71        // Count vulnerabilities by severity
72        let mut critical_count = 0;
73        let mut high_count = 0;
74        let mut medium_count = 0;
75        let mut low_count = 0;
76        let mut total_vulnerabilities = 0;
77        
78        for dep in &all_vulnerable_deps {
79            for vuln in &dep.vulnerabilities {
80                total_vulnerabilities += 1;
81                match vuln.severity {
82                    VulnerabilitySeverity::Critical => critical_count += 1,
83                    VulnerabilitySeverity::High => high_count += 1,
84                    VulnerabilitySeverity::Medium => medium_count += 1,
85                    VulnerabilitySeverity::Low => low_count += 1,
86                    VulnerabilitySeverity::Info => {},
87                }
88            }
89        }
90        
91        Ok(VulnerabilityReport {
92            checked_at: chrono::Utc::now(),
93            total_vulnerabilities,
94            critical_count,
95            high_count,
96            medium_count,
97            low_count,
98            vulnerable_dependencies: all_vulnerable_deps,
99        })
100    }
101    
102    fn check_language_dependencies(
103        &self,
104        language: &Language,
105        dependencies: &[DependencyInfo],
106        project_path: &Path,
107    ) -> Result<Vec<VulnerableDependency>, VulnerabilityError> {
108        info!("Checking {} dependencies for {:?}", dependencies.len(), language);
109        
110        match language {
111            Language::Rust => {
112                let checker = RustVulnerabilityChecker::new();
113                checker.check_vulnerabilities(dependencies, project_path)
114            },
115            Language::JavaScript | Language::TypeScript => {
116                let checker = JavaScriptVulnerabilityChecker::new();
117                checker.check_vulnerabilities(dependencies, project_path)
118            },
119            Language::Python => {
120                let checker = PythonVulnerabilityChecker::new();
121                checker.check_vulnerabilities(dependencies, project_path)
122            },
123            Language::Go => {
124                let checker = GoVulnerabilityChecker::new();
125                checker.check_vulnerabilities(dependencies, project_path)
126            },
127            Language::Java | Language::Kotlin => {
128                let checker = JavaVulnerabilityChecker::new();
129                checker.check_vulnerabilities(dependencies, project_path)
130            },
131            _ => {
132                warn!("Vulnerability checking not yet implemented for {:?}", language);
133                Ok(vec![])
134            }
135        }
136    }
137}