Skip to content

Commit

Permalink
Merge pull request #8 from fabriziosestito/fix/vuln-report-fetching
Browse files Browse the repository at this point in the history
fix: fetch VulnerabilityReport using the digest field selector
  • Loading branch information
flavio authored Dec 2, 2024
2 parents af863f2 + 3d8cb12 commit 512e44a
Showing 1 changed file with 57 additions and 19 deletions.
76 changes: 57 additions & 19 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ use std::collections::{HashMap, HashSet};

use errors::{CVEViolationStats, ImageValidationError, Violation};
use guest::prelude::*;
use kubewarden_policy_sdk::wapc_guest as guest;
use kubewarden_policy_sdk::{
host_capabilities::kubernetes::ListResourcesByNamespaceRequest, wapc_guest as guest,
};

use k8s_openapi::{
api::{
Expand All @@ -23,20 +25,22 @@ use k8s_openapi::{
Metadata, Resource,
};
use kubewarden_policy_sdk::{
accept_request, host_capabilities::kubernetes::GetResourceRequest, logging,
protocol_version_guest, reject_request, request::ValidationRequest, validate_settings,
accept_request, logging, protocol_version_guest, reject_request, request::ValidationRequest,
validate_settings,
};
use lazy_static::lazy_static;
use sarif::Vulnerability;
use serde::de::DeserializeOwned;
use slog::{info, o, warn, Logger};

#[cfg(test)]
use crate::tests::{mock_kubernetes_sdk::get_resource, mock_oci_sdk::get_manifest_digest};
use crate::tests::{
mock_kubernetes_sdk::list_resources_by_namespace, mock_oci_sdk::get_manifest_digest,
};

#[cfg(not(test))]
use kubewarden_policy_sdk::host_capabilities::{
kubernetes::get_resource, oci::get_manifest_digest,
kubernetes::list_resources_by_namespace, oci::get_manifest_digest,
};

type ImageValidationErrors = HashMap<String, ImageValidationError>;
Expand Down Expand Up @@ -242,13 +246,15 @@ fn verify_image_vulnerabilities(
) -> Result<(), ImageValidationError> {
let namespace = settings.vulnerability_report_namespace.as_str();

let vulnerability_report: VulnerabilityReport = match get_resource(&GetResourceRequest {
api_version: "storage.sbombastic.rancher.io/v1alpha1".to_string(),
kind: "VulnerabilityReport".to_string(),
name: digest.to_string(),
namespace: Some(namespace.to_string()),
disable_cache: false,
}) {
let vulnerability_reports = match list_resources_by_namespace(
&ListResourcesByNamespaceRequest {
api_version: "storage.sbombastic.rancher.io/v1alpha1".to_string(),
kind: "VulnerabilityReport".to_string(),
namespace: namespace.to_string(),
label_selector: None,
field_selector: Some(format!("spec.imageMetadata.digest={}", digest)),
},
) {
Ok(report) => report,
Err(e) => {
if settings.ignore_missing_vulnerability_report {
Expand All @@ -272,7 +278,23 @@ fn verify_image_vulnerabilities(
}
};

let trivy_report: sarif::trivy::Report = vulnerability_report.try_into()?;
if vulnerability_reports.items.is_empty() {
if settings.ignore_missing_vulnerability_report {
info!(LOG_DRAIN,
"ignoring missing vulnerability report because ignoreMissingVulnerabilityReport is enabled";
"digest" => digest,
"namespace" => namespace,
);

return Ok(());
}

return Err(ImageValidationError::VulnerabilityReportNotFound());
}

let vulnerability_report: &VulnerabilityReport = vulnerability_reports.items.first().unwrap();

let trivy_report: sarif::trivy::Report = vulnerability_report.clone().try_into()?;
let report = sarif::Report::new(trivy_report, &settings.allow_always)?;

verify_vulnerability_report(&report, settings)?;
Expand Down Expand Up @@ -402,10 +424,15 @@ mod tests {

#[automock()]
pub mod kubernetes_sdk {
use kubewarden_policy_sdk::host_capabilities::kubernetes::GetResourceRequest;
use kubewarden_policy_sdk::host_capabilities::kubernetes::ListResourcesByNamespaceRequest;

#[allow(dead_code)]
pub fn get_resource<T: 'static>(_req: &GetResourceRequest) -> anyhow::Result<T> {
pub fn list_resources_by_namespace<T>(
_req: &ListResourcesByNamespaceRequest,
) -> anyhow::Result<k8s_openapi::List<T>>
where
T: k8s_openapi::ListableResource + serde::de::DeserializeOwned + Clone + 'static,
{
Err(anyhow::anyhow!("not mocked"))
}
}
Expand Down Expand Up @@ -596,7 +623,7 @@ mod tests {
}
});

let ctx_get_resource = mock_kubernetes_sdk::get_resource_context();
let ctx_get_resource = mock_kubernetes_sdk::list_resources_by_namespace_context();
ctx_get_resource
.expect::<sbombastic::storage::v1alpha1::VulnerabilityReport>()
.times(1)
Expand All @@ -607,7 +634,12 @@ mod tests {
if req.kind != "VulnerabilityReport" {
return Err(anyhow!("it's not searching the expected Kind"));
}
if req.name != image_digest {
if req.namespace != "sbombastic" {
return Err(anyhow!("it's not searching the expected namespace"));
}
if req.field_selector
!= Some(format!("spec.imageMetadata.digest={}", image_digest).to_owned())
{
return Err(anyhow!(
"it's not searching the expected VulnerabilityReport"
));
Expand All @@ -622,10 +654,16 @@ mod tests {
let vulnerability_report: VulnerabilityReport =
serde_yaml::from_reader(fixture_file).expect("cannot parse fixture file");

return Ok(vulnerability_report);
return Ok(k8s_openapi::List {
items: vec![vulnerability_report],
..Default::default()
});
};

Err(anyhow!("VulnerabilityReport not found"))
Ok(k8s_openapi::List {
items: vec![],
..Default::default()
})
});

let response = validate(serde_json::to_vec(&request).unwrap().as_slice()).unwrap();
Expand Down

0 comments on commit 512e44a

Please sign in to comment.