1+ use crate :: domain:: scanresult:: scan_result:: ScanResult ;
2+ use crate :: domain:: scanresult:: severity:: Severity ;
3+ use itertools:: Itertools ;
4+
5+ impl From < ScanResult > for MarkdownData {
6+ fn from ( value : ScanResult ) -> Self {
7+ Self {
8+ summary : summary_from ( & value) ,
9+ fixable_packages : fixable_packages_from ( & value) ,
10+ policies : policies_from ( & value) ,
11+ vulnerabilities : vulnerabilities_from ( & value) ,
12+ }
13+ }
14+ }
15+
16+ fn summary_from ( value : & ScanResult ) -> MarkdownSummary {
17+ MarkdownSummary {
18+ pull_string : value. metadata ( ) . pull_string ( ) . to_string ( ) ,
19+ image_id : value. metadata ( ) . image_id ( ) . to_string ( ) ,
20+ digest : value. metadata ( ) . digest ( ) . unwrap_or ( "" ) . to_string ( ) ,
21+ base_os : value. metadata ( ) . base_os ( ) . name ( ) . to_string ( ) ,
22+ total_vulns_found : summary_vulns_from ( value) ,
23+ }
24+ }
25+
26+ fn summary_vulns_from ( value : & ScanResult ) -> MarkdownSummaryVulns {
27+ let mut summary = MarkdownSummaryVulns :: default ( ) ;
28+
29+ for vuln in value. vulnerabilities ( ) {
30+ summary. total_found += 1 ;
31+ let fixable = vuln. fixable ( ) ;
32+ match vuln. severity ( ) {
33+ Severity :: Critical => {
34+ summary. critical += 1 ;
35+ if fixable {
36+ summary. critical_fixable += 1 ;
37+ }
38+ }
39+ Severity :: High => {
40+ summary. high += 1 ;
41+ if fixable {
42+ summary. high_fixable += 1 ;
43+ }
44+ }
45+ Severity :: Medium => {
46+ summary. medium += 1 ;
47+ if fixable {
48+ summary. medium_fixable += 1 ;
49+ }
50+ }
51+ Severity :: Low => {
52+ summary. low += 1 ;
53+ if fixable {
54+ summary. low_fixable += 1 ;
55+ }
56+ }
57+ Severity :: Negligible => {
58+ summary. negligible += 1 ;
59+ if fixable {
60+ summary. negligible_fixable += 1 ;
61+ }
62+ }
63+ Severity :: Unknown => { }
64+ }
65+ }
66+ summary
67+ }
68+
69+ fn fixable_packages_from ( value : & ScanResult ) -> Vec < FixablePackage > {
70+ value
71+ . packages ( )
72+ . into_iter ( )
73+ . filter ( |p| p. vulnerabilities ( ) . iter ( ) . any ( |v| v. fixable ( ) ) )
74+ . map ( |p| {
75+ let mut vulns = FixablePackageVulnerabilities :: default ( ) ;
76+ let mut exploits = 0 ;
77+ for v in p. vulnerabilities ( ) {
78+ if v. exploitable ( ) {
79+ exploits += 1 ;
80+ }
81+ match v. severity ( ) {
82+ Severity :: Critical => vulns. critical += 1 ,
83+ Severity :: High => vulns. high += 1 ,
84+ Severity :: Medium => vulns. medium += 1 ,
85+ Severity :: Low => vulns. low += 1 ,
86+ Severity :: Negligible => vulns. negligible += 1 ,
87+ Severity :: Unknown => { }
88+ }
89+ }
90+
91+ FixablePackage {
92+ name : p. name ( ) . to_string ( ) ,
93+ package_type : p. package_type ( ) . to_string ( ) ,
94+ version : p. version ( ) . to_string ( ) ,
95+ suggested_fix : p
96+ . vulnerabilities ( )
97+ . iter ( )
98+ . find_map ( |v| v. fix_version ( ) . map ( |s| s. to_string ( ) ) ) ,
99+ vulnerabilities : vulns,
100+ exploits,
101+ }
102+ } )
103+ . collect ( )
104+ }
105+
106+ fn policies_from ( value : & ScanResult ) -> Vec < PolicyEvaluated > {
107+ value
108+ . policies ( )
109+ . iter ( )
110+ . map ( |p| PolicyEvaluated {
111+ name : p. name ( ) . to_string ( ) ,
112+ passed : p. evaluation_result ( ) . is_passed ( ) ,
113+ failures : p. bundles ( ) . iter ( ) . map ( |b| b. rules ( ) . len ( ) ) . sum :: < usize > ( ) as u32 ,
114+ risks_accepted : 0 , // Cannot determine this from the current data model
115+ } )
116+ . collect ( )
117+ }
118+
119+ fn vulnerabilities_from ( value : & ScanResult ) -> Vec < VulnerabilityEvaluated > {
120+ value
121+ . vulnerabilities ( )
122+ . iter ( )
123+ . map ( |v| VulnerabilityEvaluated {
124+ cve : v. cve ( ) . to_string ( ) ,
125+ severity : v. severity ( ) . to_string ( ) ,
126+ packages_found : v. found_in_packages ( ) . len ( ) as u32 ,
127+ fixable : v. fixable ( ) ,
128+ exploitable : v. exploitable ( ) ,
129+ accepted_risk : !v. accepted_risks ( ) . is_empty ( ) ,
130+ age : "N/A" , // Calculating age requires current time, which is not ideal here.
131+ } )
132+ . sorted_by ( |a, b| a. cve . cmp ( & b. cve ) )
133+ . collect ( )
134+ }
135+
136+ #[ derive( Clone , Debug , Default ) ]
1137pub struct MarkdownData {
2138 pub summary : MarkdownSummary ,
3139 pub fixable_packages : Vec < FixablePackage > ,
4140 pub policies : Vec < PolicyEvaluated > ,
5141 pub vulnerabilities : Vec < VulnerabilityEvaluated > ,
6142}
7143
144+ #[ derive( Clone , Debug , Default ) ]
8145pub struct MarkdownSummary {
9146 pub pull_string : String ,
10147 pub image_id : String ,
@@ -13,6 +150,7 @@ pub struct MarkdownSummary {
13150 pub total_vulns_found : MarkdownSummaryVulns ,
14151}
15152
153+ #[ derive( Clone , Debug , Default ) ]
16154pub struct MarkdownSummaryVulns {
17155 pub total_found : u32 ,
18156 pub critical : u32 ,
@@ -27,6 +165,7 @@ pub struct MarkdownSummaryVulns {
27165 pub negligible_fixable : u32 ,
28166}
29167
168+ #[ derive( Clone , Debug , Default ) ]
30169pub struct FixablePackage {
31170 pub name : String ,
32171 pub package_type : String ,
@@ -36,6 +175,7 @@ pub struct FixablePackage {
36175 pub exploits : u32 ,
37176}
38177
178+ #[ derive( Clone , Debug , Default ) ]
39179pub struct FixablePackageVulnerabilities {
40180 pub critical : u32 ,
41181 pub high : u32 ,
@@ -44,13 +184,15 @@ pub struct FixablePackageVulnerabilities {
44184 pub negligible : u32 ,
45185}
46186
187+ #[ derive( Clone , Debug , Default ) ]
47188pub struct PolicyEvaluated {
48189 pub name : String ,
49190 pub passed : bool ,
50191 pub failures : u32 ,
51192 pub risks_accepted : u32 ,
52193}
53194
195+ #[ derive( Clone , Debug , Default ) ]
54196pub struct VulnerabilityEvaluated {
55197 pub cve : String ,
56198 pub severity : String ,
0 commit comments