Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
ci: add tests with postgres:13
  • Loading branch information
tembleking committed Sep 30, 2025
commit e44c496ef11f684354f4890c5e64d8c3c7b2bfa9
99 changes: 24 additions & 75 deletions src/app/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,34 +104,18 @@ where
};

if !scan_result.vulnerabilities().is_empty() {
let vulns = scan_result
.vulnerabilities()
.iter()
.counts_by(|v| v.severity());
diagnostic.message = format!(
"Vulnerabilities found for {}: {} Critical, {} High, {} Medium, {} Low, {} Negligible",
image_name,
scan_result
.vulnerabilities()
.iter()
.filter(|v| { matches!(v.severity(), Severity::Critical) })
.count(),
scan_result
.vulnerabilities()
.iter()
.filter(|v| { matches!(v.severity(), Severity::High) })
.count(),
scan_result
.vulnerabilities()
.iter()
.filter(|v| { matches!(v.severity(), Severity::Medium) })
.count(),
scan_result
.vulnerabilities()
.iter()
.filter(|v| { matches!(v.severity(), Severity::Low) })
.count(),
scan_result
.vulnerabilities()
.iter()
.filter(|v| { matches!(v.severity(), Severity::Negligible) })
.count(),
vulns.get(&Severity::Critical).unwrap_or(&0_usize),
vulns.get(&Severity::High).unwrap_or(&0_usize),
vulns.get(&Severity::Medium).unwrap_or(&0_usize),
vulns.get(&Severity::Low).unwrap_or(&0_usize),
vulns.get(&Severity::Negligible).unwrap_or(&0_usize),
);

diagnostic.severity = Some(if scan_result.evaluation_result().is_passed() {
Expand Down Expand Up @@ -245,33 +229,14 @@ pub fn diagnostics_for_layers(
layer_idx = layer_idx.and_then(|x| x.checked_sub(1));

if !layer.vulnerabilities().is_empty() {
let vulns = layer.vulnerabilities().iter().counts_by(|v| v.severity());
let msg = format!(
"Vulnerabilities found in layer: {} Critical, {} High, {} Medium, {} Low, {} Negligible",
layer
.vulnerabilities()
.iter()
.filter(|v| { matches!(v.severity(), Severity::Critical) })
.count(),
layer
.vulnerabilities()
.iter()
.filter(|v| { matches!(v.severity(), Severity::High) })
.count(),
layer
.vulnerabilities()
.iter()
.filter(|v| { matches!(v.severity(), Severity::Medium) })
.count(),
layer
.vulnerabilities()
.iter()
.filter(|v| { matches!(v.severity(), Severity::Low) })
.count(),
layer
.vulnerabilities()
.iter()
.filter(|v| { matches!(v.severity(), Severity::Negligible) })
.count(),
vulns.get(&Severity::Critical).unwrap_or(&0_usize),
vulns.get(&Severity::High).unwrap_or(&0_usize),
vulns.get(&Severity::Medium).unwrap_or(&0_usize),
vulns.get(&Severity::Low).unwrap_or(&0_usize),
vulns.get(&Severity::Negligible).unwrap_or(&0_usize),
);
let diagnostic = Diagnostic {
range: instr.range,
Expand Down Expand Up @@ -339,33 +304,17 @@ fn diagnostic_for_image(line: u32, document_text: &str, scan_result: &ScanResult
};

if !scan_result.vulnerabilities().is_empty() {
let vulns = scan_result
.vulnerabilities()
.iter()
.counts_by(|v| v.severity());
diagnostic.message = format!(
"Total vulnerabilities found: {} Critical, {} High, {} Medium, {} Low, {} Negligible",
scan_result
.vulnerabilities()
.iter()
.filter(|v| { matches!(v.severity(), Severity::Critical) })
.count(),
scan_result
.vulnerabilities()
.iter()
.filter(|v| { matches!(v.severity(), Severity::High) })
.count(),
scan_result
.vulnerabilities()
.iter()
.filter(|v| { matches!(v.severity(), Severity::Medium) })
.count(),
scan_result
.vulnerabilities()
.iter()
.filter(|v| { matches!(v.severity(), Severity::Low) })
.count(),
scan_result
.vulnerabilities()
.iter()
.filter(|v| { matches!(v.severity(), Severity::Negligible) })
.count(),
vulns.get(&Severity::Critical).unwrap_or(&0_usize),
vulns.get(&Severity::High).unwrap_or(&0_usize),
vulns.get(&Severity::Medium).unwrap_or(&0_usize),
vulns.get(&Severity::Low).unwrap_or(&0_usize),
vulns.get(&Severity::Negligible).unwrap_or(&0_usize),
);

diagnostic.severity = Some(if scan_result.evaluation_result().is_passed() {
Expand Down
2 changes: 1 addition & 1 deletion src/infra/sysdig_image_scanner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ impl SysdigImageScanner {
impl ImageScanner for SysdigImageScanner {
async fn scan_image(&self, image_pull_string: &str) -> Result<ScanResult, ImageScanError> {
let scan = self.scan(image_pull_string).await?;
Ok(ScanResult::from(&scan))
Ok(ScanResult::from(scan))
}
}

Expand Down
97 changes: 78 additions & 19 deletions src/infra/sysdig_image_scanner_json_scan_result_v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ use crate::domain::scanresult::{
severity::Severity,
};

impl From<&JsonScanResultV1> for ScanResult {
fn from(report: &JsonScanResultV1) -> Self {
impl From<JsonScanResultV1> for ScanResult {
fn from(report: JsonScanResultV1) -> Self {
let mut scan_result = ScanResult::from(&report.result.metadata);

add_layers(&report.result, &mut scan_result);
Expand Down Expand Up @@ -225,20 +225,20 @@ fn arch_from_str(string: &str) -> Architecture {
}
}

#[derive(Debug, Deserialize)]
#[derive(Debug, Deserialize, Clone)]
pub(super) struct JsonScanResultV1 {
pub info: JsonInfo,
pub scanner: JsonScanner,
pub result: JsonResult,
}

#[derive(Debug, Deserialize)]
#[derive(Debug, Deserialize, Clone)]
pub(super) struct JsonScanner {
pub name: String,
pub version: String,
}

#[derive(Debug, Deserialize)]
#[derive(Debug, Deserialize, Clone)]
pub(super) struct JsonInfo {
#[serde(rename = "scanTime")]
pub scan_time: DateTime<Utc>,
Expand Down Expand Up @@ -283,7 +283,7 @@ pub enum ImageMetadataArchitecture {
}

#[derive(Debug, Deserialize, PartialEq, Eq, Hash, Clone)]
#[serde(rename_all = "camelCase")]
#[serde(rename_all = "lowercase")]
pub enum JsonSeverity {
Critical,
High,
Expand All @@ -304,7 +304,7 @@ impl From<JsonSeverity> for Severity {
}
}

#[derive(Debug, Deserialize)]
#[derive(Debug, Deserialize, Clone)]
pub(super) struct JsonBundle {
#[serde(rename = "identifier", default)]
pub identifier: String,
Expand All @@ -316,15 +316,15 @@ pub(super) struct JsonBundle {
pub bundle_type: String,
}

#[derive(Debug, Deserialize)]
#[derive(Debug, Deserialize, Clone)]
pub(super) struct JsonCvssScore {
pub score: f32,
#[serde(default)] // FIXME(fede): test this
pub vector: String,
pub version: String,
}

#[derive(Debug, Deserialize)]
#[derive(Debug, Deserialize, Clone)]
pub(super) struct JsonLayer {
#[serde(rename = "command", default)]
pub command: Option<String>,
Expand All @@ -336,7 +336,7 @@ pub(super) struct JsonLayer {
pub size: Option<u64>,
}

#[derive(Debug, Deserialize)]
#[derive(Debug, Deserialize, Clone)]
pub(super) struct JsonPackage {
#[serde(rename = "isRemoved", default)]
pub is_removed: bool,
Expand Down Expand Up @@ -400,15 +400,15 @@ impl From<JsonPackageType> for PackageType {
}
}

#[derive(Debug, Deserialize, Default)]
#[derive(Debug, Deserialize, Default, Clone)]
pub(super) struct JsonPolicies {
#[serde(rename = "globalEvaluation", default)]
pub global_evaluation: String,
#[serde(rename = "evaluations", default)]
pub evaluations: Option<Vec<JsonPolicy>>,
}

#[derive(Debug, Deserialize)]
#[derive(Debug, Deserialize, Clone)]
pub(super) struct JsonPolicy {
#[serde(rename = "bundles", default)]
pub bundles: Option<Vec<JsonBundle>>,
Expand All @@ -426,13 +426,13 @@ pub(super) struct JsonPolicy {
pub updated_at: DateTime<Utc>,
}

#[derive(Debug, Deserialize, Default)]
#[derive(Debug, Deserialize, Default, Clone)]
pub(super) struct JsonProducer {
#[serde(rename = "producedAt", default)]
pub produced_at: DateTime<Utc>,
}

#[derive(Debug, Deserialize)]
#[derive(Debug, Deserialize, Clone)]
pub(super) struct JsonRiskAccept {
#[serde(rename = "createdAt")]
pub created_at: DateTime<Utc>,
Expand Down Expand Up @@ -479,7 +479,7 @@ impl From<JsonRiskAcceptReason> for AcceptedRiskReason {
}
}
}
#[derive(Debug, Deserialize)]
#[derive(Debug, Deserialize, Clone)]
pub(super) struct JsonRule {
#[serde(rename = "description")]
pub description: String,
Expand All @@ -495,7 +495,7 @@ pub(super) struct JsonRule {
pub rule_type: String,
}

#[derive(Debug, Deserialize)]
#[derive(Debug, Deserialize, Clone)]
pub(super) struct JsonFailure {
#[serde(rename = "remediation", default)]
pub remediation: String,
Expand All @@ -505,7 +505,7 @@ pub(super) struct JsonFailure {
pub vulnerability_ref: String,
}

#[derive(Debug, Deserialize)]
#[derive(Debug, Deserialize, Clone)]
pub(super) struct JsonResult {
#[serde(rename = "assetType")]
pub asset_type: String,
Expand All @@ -527,7 +527,7 @@ pub(super) struct JsonResult {
pub vulnerabilities: HashMap<String, JsonVulnerability>,
}

#[derive(Debug, Deserialize)]
#[derive(Debug, Deserialize, Clone)]
pub(super) struct JsonMetadata {
#[serde(rename = "architecture")]
pub architecture: String,
Expand All @@ -551,7 +551,7 @@ pub(super) struct JsonMetadata {
pub size: u64,
}

#[derive(Debug, Deserialize)]
#[derive(Debug, Deserialize, Clone)]
pub(super) struct JsonVulnerability {
#[serde(rename = "cvssScore")]
pub cvss_score: JsonCvssScore,
Expand All @@ -574,3 +574,62 @@ pub(super) struct JsonVulnerability {
#[serde(rename = "solutionDate", default)]
pub solution_date: Option<NaiveDate>,
}

#[cfg(test)]
mod tests {
use crate::{
domain::scanresult::{scan_result::ScanResult, severity::Severity},
infra::sysdig_image_scanner_json_scan_result_v1::JsonScanResultV1,
};

#[test]
fn it_loads_postgres13() {
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.clone().into();

assert_eq!(json_scan_result.result.vulnerabilities.len(), 100);
assert_eq!(
scan_result
.vulnerabilities()
.iter()
.filter(|v| v.severity() == Severity::Critical)
.count(),
2
);
assert_eq!(
scan_result
.vulnerabilities()
.iter()
.filter(|v| v.severity() == Severity::High)
.count(),
3
);
assert_eq!(
scan_result
.vulnerabilities()
.iter()
.filter(|v| v.severity() == Severity::Medium)
.count(),
1
);
assert_eq!(
scan_result
.vulnerabilities()
.iter()
.filter(|v| v.severity() == Severity::Low)
.count(),
2
);
assert_eq!(
scan_result
.vulnerabilities()
.iter()
.filter(|v| v.severity() == Severity::Negligible)
.count(),
32
);
// assert_eq!(scan_result.vulnerabilities().len(), 97);
}
}
Loading