syncable_cli/analyzer/vulnerability/
core.rs1use 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 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 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 let results: Vec<_> = dependencies.par_iter()
46 .map(|(language, deps)| {
47 self.check_language_dependencies(language, deps, project_path)
48 })
49 .collect();
50
51 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 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 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 checker = PythonVulnerabilityChecker::new();
122 checker.check_vulnerabilities(dependencies, project_path)
123 },
124 Language::Go => {
125 let checker = GoVulnerabilityChecker::new();
126 checker.check_vulnerabilities(dependencies, project_path)
127 },
128 Language::Java | Language::Kotlin => {
129 let 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}