Skip to content

Commit 41cee47

Browse files
committed
refactor: use the new domain model
1 parent 0e3f275 commit 41cee47

16 files changed

+861
-786
lines changed

Cargo.lock

Lines changed: 35 additions & 21 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,16 @@ reqwest = "0.12.14"
2525
semver = "1.0.26"
2626
serde = { version = "1.0.219", features = ["alloc", "derive"] }
2727
serde_json = "1.0.135"
28-
serde_yaml = "0.9.34"
2928
serial_test = { version = "3.2.0", features = ["file_locks"] }
3029
tar = "0.4.44"
3130
thiserror = "2.0.12"
3231
tokio = { version = "1.43.0", features = ["full"] }
3332
tower-lsp = "0.20.0"
34-
tower-service = "0.3.3"
3533
tracing = "0.1.41"
3634
tracing-subscriber = "0.3.19"
3735

3836
[dev-dependencies]
3937
itertools = "0.14.0"
4038
lazy_static = "1.5.0"
39+
tracing-subscriber = { version = "0.3.19", features = ["fmt", "env-filter"] }
40+
tracing-test = "0.2.5"

flake.nix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
cargo
4343
cargo-audit
4444
cargo-expand
45+
cargo-machete
4546
cargo-nextest
4647
cargo-tarpaulin
4748
cargo-watch

src/app/commands.rs

Lines changed: 102 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,22 @@
11
use std::{
22
path::{Path, PathBuf},
33
str::FromStr,
4+
sync::Arc,
45
};
56

7+
use itertools::Itertools;
68
use tower_lsp::{
79
jsonrpc::{Error, Result},
810
lsp_types::{Diagnostic, DiagnosticSeverity, MessageType, Position, Range},
911
};
1012

11-
use crate::infra::parse_dockerfile;
13+
use crate::{
14+
domain::scanresult::{layer::Layer, scan_result::ScanResult, severity::Severity},
15+
infra::parse_dockerfile,
16+
};
1217

1318
use super::{
14-
ImageBuilder, ImageScanResult, ImageScanner, InMemoryDocumentDatabase, LSPClient,
15-
LayerScanResult, VulnSeverity, lsp_server::WithContext,
19+
ImageBuilder, ImageScanner, InMemoryDocumentDatabase, LSPClient, lsp_server::WithContext,
1620
};
1721

1822
pub struct CommandExecutor<C> {
@@ -99,18 +103,38 @@ where
99103
..Default::default()
100104
};
101105

102-
if scan_result.has_vulnerabilities() {
106+
if !scan_result.vulnerabilities().is_empty() {
103107
diagnostic.message = format!(
104108
"Vulnerabilities found for {}: {} Critical, {} High, {} Medium, {} Low, {} Negligible",
105109
image_name,
106-
scan_result.count_vulns_of_severity(VulnSeverity::Critical),
107-
scan_result.count_vulns_of_severity(VulnSeverity::High),
108-
scan_result.count_vulns_of_severity(VulnSeverity::Medium),
109-
scan_result.count_vulns_of_severity(VulnSeverity::Low),
110-
scan_result.count_vulns_of_severity(VulnSeverity::Negligible),
110+
scan_result
111+
.vulnerabilities()
112+
.iter()
113+
.filter(|v| { matches!(v.severity(), Severity::Critical) })
114+
.count(),
115+
scan_result
116+
.vulnerabilities()
117+
.iter()
118+
.filter(|v| { matches!(v.severity(), Severity::High) })
119+
.count(),
120+
scan_result
121+
.vulnerabilities()
122+
.iter()
123+
.filter(|v| { matches!(v.severity(), Severity::Medium) })
124+
.count(),
125+
scan_result
126+
.vulnerabilities()
127+
.iter()
128+
.filter(|v| { matches!(v.severity(), Severity::Low) })
129+
.count(),
130+
scan_result
131+
.vulnerabilities()
132+
.iter()
133+
.filter(|v| { matches!(v.severity(), Severity::Negligible) })
134+
.count(),
111135
);
112136

113-
diagnostic.severity = Some(if scan_result.is_compliant {
137+
diagnostic.severity = Some(if scan_result.evaluation_result().is_passed() {
114138
DiagnosticSeverity::INFORMATION
115139
} else {
116140
DiagnosticSeverity::ERROR
@@ -199,10 +223,10 @@ where
199223

200224
pub fn diagnostics_for_layers(
201225
document_text: &str,
202-
scan_result: &ImageScanResult,
226+
scan_result: &ScanResult,
203227
) -> Result<Vec<Diagnostic>> {
204228
let instructions = parse_dockerfile(document_text);
205-
let layers = &scan_result.layers;
229+
let layers = &scan_result.layers();
206230

207231
let mut instr_idx = instructions.len().checked_sub(1);
208232
let mut layer_idx = layers.len().checked_sub(1);
@@ -220,14 +244,34 @@ pub fn diagnostics_for_layers(
220244
instr_idx = instr_idx.and_then(|x| x.checked_sub(1));
221245
layer_idx = layer_idx.and_then(|x| x.checked_sub(1));
222246

223-
if layer.has_vulnerabilities() {
247+
if !layer.vulnerabilities().is_empty() {
224248
let msg = format!(
225249
"Vulnerabilities found in layer: {} Critical, {} High, {} Medium, {} Low, {} Negligible",
226-
layer.count_vulns_of_severity(VulnSeverity::Critical),
227-
layer.count_vulns_of_severity(VulnSeverity::High),
228-
layer.count_vulns_of_severity(VulnSeverity::Medium),
229-
layer.count_vulns_of_severity(VulnSeverity::Low),
230-
layer.count_vulns_of_severity(VulnSeverity::Negligible),
250+
layer
251+
.vulnerabilities()
252+
.iter()
253+
.filter(|v| { matches!(v.severity(), Severity::Critical) })
254+
.count(),
255+
layer
256+
.vulnerabilities()
257+
.iter()
258+
.filter(|v| { matches!(v.severity(), Severity::High) })
259+
.count(),
260+
layer
261+
.vulnerabilities()
262+
.iter()
263+
.filter(|v| { matches!(v.severity(), Severity::Medium) })
264+
.count(),
265+
layer
266+
.vulnerabilities()
267+
.iter()
268+
.filter(|v| { matches!(v.severity(), Severity::Low) })
269+
.count(),
270+
layer
271+
.vulnerabilities()
272+
.iter()
273+
.filter(|v| { matches!(v.severity(), Severity::Negligible) })
274+
.count(),
231275
);
232276
let diagnostic = Diagnostic {
233277
range: instr.range,
@@ -246,40 +290,35 @@ pub fn diagnostics_for_layers(
246290
}
247291

248292
fn fill_vulnerability_hints_for_layer(
249-
layer: &LayerScanResult,
293+
layer: &Arc<Layer>,
250294
range: Range,
251295
diagnostics: &mut Vec<Diagnostic>,
252296
) {
253-
let vulnerability_types = [
254-
VulnSeverity::Critical,
255-
VulnSeverity::High,
256-
VulnSeverity::Medium,
257-
VulnSeverity::Low,
258-
VulnSeverity::Negligible,
259-
];
260-
261-
let vulns_per_severity = vulnerability_types
297+
let vulns_per_severity = layer
298+
.vulnerabilities()
262299
.iter()
263-
.flat_map(|sev| layer.vulnerabilities.iter().filter(|l| l.severity == *sev));
300+
.cloned()
301+
.sorted_by_key(|v| v.severity());
264302

265303
// TODO(fede): eventually we would want to add here a .take() to truncate the number
266304
// of vulnerabilities shown as hint per layer.
267305
vulns_per_severity.for_each(|vuln| {
268-
let url = format!("https://nvd.nist.gov/vuln/detail/{}", vuln.id);
306+
let url = format!("https://nvd.nist.gov/vuln/detail/{}", vuln.cve());
269307
diagnostics.push(Diagnostic {
270308
range,
271309
severity: Some(DiagnosticSeverity::HINT),
272-
message: format!("Vulnerability: {} ({:?}) {}", vuln.id, vuln.severity, url),
310+
message: format!(
311+
"Vulnerability: {} ({:?}) {}",
312+
vuln.cve(),
313+
vuln.severity(),
314+
url
315+
),
273316
..Default::default()
274317
});
275318
});
276319
}
277320

278-
fn diagnostic_for_image(
279-
line: u32,
280-
document_text: &str,
281-
scan_result: &ImageScanResult,
282-
) -> Diagnostic {
321+
fn diagnostic_for_image(line: u32, document_text: &str, scan_result: &ScanResult) -> Diagnostic {
283322
let range_for_selected_line = Range::new(
284323
Position::new(line, 0),
285324
Position::new(
@@ -299,17 +338,37 @@ fn diagnostic_for_image(
299338
..Default::default()
300339
};
301340

302-
if scan_result.has_vulnerabilities() {
341+
if !scan_result.vulnerabilities().is_empty() {
303342
diagnostic.message = format!(
304343
"Total vulnerabilities found: {} Critical, {} High, {} Medium, {} Low, {} Negligible",
305-
scan_result.count_vulns_of_severity(VulnSeverity::Critical),
306-
scan_result.count_vulns_of_severity(VulnSeverity::High),
307-
scan_result.count_vulns_of_severity(VulnSeverity::Medium),
308-
scan_result.count_vulns_of_severity(VulnSeverity::Low),
309-
scan_result.count_vulns_of_severity(VulnSeverity::Negligible),
344+
scan_result
345+
.vulnerabilities()
346+
.iter()
347+
.filter(|v| { matches!(v.severity(), Severity::Critical) })
348+
.count(),
349+
scan_result
350+
.vulnerabilities()
351+
.iter()
352+
.filter(|v| { matches!(v.severity(), Severity::High) })
353+
.count(),
354+
scan_result
355+
.vulnerabilities()
356+
.iter()
357+
.filter(|v| { matches!(v.severity(), Severity::Medium) })
358+
.count(),
359+
scan_result
360+
.vulnerabilities()
361+
.iter()
362+
.filter(|v| { matches!(v.severity(), Severity::Low) })
363+
.count(),
364+
scan_result
365+
.vulnerabilities()
366+
.iter()
367+
.filter(|v| { matches!(v.severity(), Severity::Negligible) })
368+
.count(),
310369
);
311370

312-
diagnostic.severity = Some(if scan_result.is_compliant {
371+
diagnostic.severity = Some(if scan_result.evaluation_result().is_passed() {
313372
DiagnosticSeverity::INFORMATION
314373
} else {
315374
DiagnosticSeverity::ERROR

0 commit comments

Comments
 (0)