11use  std:: { 
22    path:: { Path ,  PathBuf } , 
33    str:: FromStr , 
4+     sync:: Arc , 
45} ; 
56
7+ use  itertools:: Itertools ; 
68use  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
1318use  super :: { 
14-     ImageBuilder ,  ImageScanResult ,  ImageScanner ,  InMemoryDocumentDatabase ,  LSPClient , 
15-     LayerScanResult ,  VulnSeverity ,  lsp_server:: WithContext , 
19+     ImageBuilder ,  ImageScanner ,  InMemoryDocumentDatabase ,  LSPClient ,  lsp_server:: WithContext , 
1620} ; 
1721
1822pub  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
200224pub  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
248292fn  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