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