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