diff --git a/src/domain/scanresult/scan_result.rs b/src/domain/scanresult/scan_result.rs index 83755bd..e2b2df3 100644 --- a/src/domain/scanresult/scan_result.rs +++ b/src/domain/scanresult/scan_result.rs @@ -21,7 +21,7 @@ use std::sync::Arc; pub struct ScanResult { scan_type: ScanType, metadata: Metadata, - layers: HashMap>, + layers: Vec>, packages: HashMap, ()>, vulnerabilities: HashMap>, policies: HashMap>, @@ -54,7 +54,7 @@ impl ScanResult { labels, created_at, ), - layers: HashMap::new(), + layers: Vec::new(), packages: HashMap::new(), vulnerabilities: HashMap::new(), policies: HashMap::new(), @@ -79,19 +79,26 @@ impl ScanResult { command: String, ) -> Arc { let layer = Arc::new(Layer::new(digest.clone(), index, size, command)); - self.layers.insert(digest, layer.clone()); + self.layers.push(layer.clone()); layer } pub fn find_layer_by_digest(&self, digest: &str) -> Option> { - self.layers.get(digest).cloned() + if digest.trim().is_empty() { + return None; + } + + self.layers + .iter() + .find(|l| l.digest() == Some(digest)) + .cloned() } pub fn layers(&self) -> Vec> { self.layers - .values() - .cloned() + .iter() .sorted_by(|a, b| a.index().cmp(&b.index())) + .cloned() .collect() } @@ -651,8 +658,8 @@ mod tests { // Add layer twice let layer = scan_result.add_layer("layer-1".to_string(), 0, None, "CMD".to_string()); let layer2 = scan_result.add_layer("layer-1".to_string(), 0, None, "CMD".to_string()); - assert_ne!(Arc::as_ptr(&layer), Arc::as_ptr(&layer2)); // It creates a new Arc and replaces. - assert_eq!(scan_result.layers().len(), 1); + assert_ne!(Arc::as_ptr(&layer), Arc::as_ptr(&layer2)); // It creates a new Arc and adds it. + assert_eq!(scan_result.layers().len(), 2); // Add package twice let pkg = scan_result.add_package( diff --git a/src/infra/sysdig_image_scanner_json_scan_result_v1.rs b/src/infra/sysdig_image_scanner_json_scan_result_v1.rs index f08c312..6d576d2 100644 --- a/src/infra/sysdig_image_scanner_json_scan_result_v1.rs +++ b/src/infra/sysdig_image_scanner_json_scan_result_v1.rs @@ -30,18 +30,14 @@ impl From for ScanResult { } fn add_layers(report: &JsonResult, scan_result: &mut ScanResult) { - report - .layers - .values() - .filter(|json_layer| !json_layer.digest.is_empty()) - .for_each(|json_layer| { - scan_result.add_layer( - json_layer.digest.clone(), - json_layer.index, - json_layer.size, - json_layer.command.clone().unwrap_or_default(), - ); - }); + report.layers.values().for_each(|json_layer| { + scan_result.add_layer( + json_layer.digest.clone(), + json_layer.index, + json_layer.size, + json_layer.command.clone().unwrap_or_default(), + ); + }); } fn add_risk_accepts(result: &JsonResult, scan_result: &mut ScanResult) { @@ -632,4 +628,51 @@ mod tests { ); // assert_eq!(scan_result.vulnerabilities().len(), 97); } + + #[test] + fn test_handles_layers_without_digest() { + let postgres_13_json = include_bytes!("../../tests/fixtures/scan-results/postgres_13.json"); + let json_scan_result: JsonScanResultV1 = serde_json::from_slice(postgres_13_json).unwrap(); + let scan_result: ScanResult = json_scan_result.into(); + + assert_eq!( + scan_result.layers().len(), + 25, + "Should have 25 layers in total" + ); + + let layers_with_digest = scan_result + .layers() + .into_iter() + .filter(|l| l.digest().is_some()) + .count(); + assert_eq!( + layers_with_digest, 14, + "Should have 14 layers with a digest" + ); + + let layers_without_digest = scan_result + .layers() + .into_iter() + .filter(|l| l.digest().is_none()) + .count(); + assert_eq!( + layers_without_digest, 11, + "Should have 11 layers without a digest" + ); + + assert!( + scan_result.find_layer_by_digest("").is_none(), + "Searching for an empty digest should return None" + ); + assert!( + scan_result.find_layer_by_digest(" ").is_none(), + "Searching for a whitespace digest should return None" + ); + + let digest = "sha256:04d52f0a5b32b0f627bbd4427a0374f0a8d2d409dbbfda0099d89b87c774df36"; + let found_layer = scan_result.find_layer_by_digest(digest); + assert!(found_layer.is_some(), "Should find layer by valid digest"); + assert_eq!(found_layer.unwrap().digest(), Some(digest)); + } } diff --git a/tests/fixtures/Dockerfile b/tests/fixtures/Dockerfile index 61b79b4..fac5a2c 100644 --- a/tests/fixtures/Dockerfile +++ b/tests/fixtures/Dockerfile @@ -8,6 +8,9 @@ RUN curl -L https://get.jenkins.io/war-stable/2.401.3/jenkins.war -o /jenkins.wa FROM nginx:latest + RUN apt update && apt full-upgrade -y COPY --from=builder /jenkins.war /jenkins.war + +ENV foo=bar