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