Skip to content

Commit

Permalink
refactor: remove traits for simplicity
Browse files Browse the repository at this point in the history
Signed-off-by: Fabrizio Sestito <[email protected]>
  • Loading branch information
fabriziosestito committed Nov 21, 2024
1 parent b14ffa6 commit 3031d3b
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 165 deletions.
125 changes: 76 additions & 49 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,34 @@
mod sbombastic;
use sbombastic::storage::v1alpha1::VulnerabilityReport;

mod settings;
use settings::{Settings, SeverityCount};

mod errors;
mod sarif;

use std::collections::{HashMap, HashSet};

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

use k8s_openapi::api::{
apps::v1::{DaemonSet, Deployment, ReplicaSet, StatefulSet},
batch::v1::{CronJob, Job},
core::v1::{Pod, PodSpec, ReplicationController},
use k8s_openapi::{
api::{
apps::v1::{DaemonSet, Deployment, ReplicaSet, StatefulSet},
batch::v1::{CronJob, Job},
core::v1::{Pod, PodSpec, ReplicationController},
},
apimachinery::pkg::apis::meta::v1::ObjectMeta,
Metadata, Resource,
};
use kubewarden_policy_sdk::{
accept_request, host_capabilities::kubernetes::GetResourceRequest, logging,
protocol_version_guest, reject_request, request::ValidationRequest, validate_settings,
};
use lazy_static::lazy_static;
use sarif::Vulnerability;
use serde::{de::DeserializeOwned, Serialize};
use serde::de::DeserializeOwned;
use slog::{info, o, warn, Logger};

#[cfg(test)]
Expand All @@ -26,18 +39,6 @@ use kubewarden_policy_sdk::host_capabilities::{
kubernetes::get_resource, oci::get_manifest_digest,
};

mod workload_helpers;
use workload_helpers::{ImageHolder, ValidatingResource};

mod sbombastic;
use sbombastic::storage::v1alpha1::VulnerabilityReport;

mod settings;
use settings::{Settings, SeverityCount};

mod errors;
mod sarif;

type ImageValidationErrors = HashMap<String, ImageValidationError>;

lazy_static! {
Expand All @@ -56,17 +57,39 @@ fn validate(payload: &[u8]) -> CallResult {
let validation_request: ValidationRequest<Settings> = ValidationRequest::new(payload)?;

match validation_request.request.kind.kind.as_str() {
"Deployment" => validate_resource::<Deployment>(validation_request),
"ReplicaSet" => validate_resource::<ReplicaSet>(validation_request),
"StatefulSet" => validate_resource::<StatefulSet>(validation_request),
"DaemonSet" => validate_resource::<DaemonSet>(validation_request),
"ReplicationController" => validate_resource::<ReplicationController>(validation_request),
"Job" => validate_resource::<Job>(validation_request),
"CronJob" => validate_resource::<CronJob>(validation_request),
"Pod" => validate_resource::<Pod>(validation_request),
"Deployment" => validate_resource::<Deployment>(validation_request, |deployment| {
deployment.spec.as_ref()?.template.spec.clone()
}),
"ReplicaSet" => validate_resource::<ReplicaSet>(validation_request, |replicaset| {
replicaset.spec.as_ref()?.template.as_ref()?.spec.clone()
}),
"StatefulSet" => validate_resource::<StatefulSet>(validation_request, |statefulset| {
statefulset.spec.as_ref()?.template.spec.clone()
}),
"DaemonSet" => validate_resource::<DaemonSet>(validation_request, |daemonset| {
daemonset.spec.as_ref()?.template.spec.clone()
}),
"ReplicationController" => {
validate_resource::<ReplicationController>(validation_request, |rc| {
rc.spec.as_ref()?.template.as_ref()?.spec.clone()
})
}
"Job" => validate_resource::<Job>(validation_request, |job| {
job.spec.as_ref()?.template.spec.clone()
}),
"CronJob" => validate_resource::<CronJob>(validation_request, |cronjob| {
cronjob
.spec
.as_ref()?
.job_template
.spec
.as_ref()?
.template
.spec
.clone()
}),
"Pod" => validate_resource::<Pod>(validation_request, |pod| pod.spec.clone()),
_ => {
// We were forwarded a request we cannot unmarshal or
// understand, just accept it
warn!(LOG_DRAIN, "cannot unmarshal resource: this policy does not know how to evaluate this resource; accept it");
accept_request()
}
Expand All @@ -75,20 +98,22 @@ fn validate(payload: &[u8]) -> CallResult {

// validate any resource that contains a Pod. e.g. Deployment, StatefulSet, ...
// it does not modify the container with the manifest digest.
fn validate_resource<T: ValidatingResource + DeserializeOwned + Serialize>(
fn validate_resource<T>(
validation_request: ValidationRequest<Settings>,
) -> CallResult {
extract_spec: fn(&T) -> Option<PodSpec>,
) -> CallResult
where
T: Resource + Metadata<Ty = ObjectMeta> + DeserializeOwned,
{
let resource = match serde_json::from_value::<T>(validation_request.request.object.clone()) {
Ok(resource) => resource,
Err(_) => {
// We were forwarded a request we cannot unmarshal or
// understand, just accept it
warn!(LOG_DRAIN, "cannot unmarshal resource: this policy does not know how to evaluate this resource; accept it");
return accept_request();
}
};

let spec = match resource.spec() {
let spec = match extract_spec(&resource) {
Some(spec) => spec,
None => {
return accept_request();
Expand Down Expand Up @@ -116,43 +141,45 @@ fn validate_resource<T: ValidatingResource + DeserializeOwned + Serialize>(
reject_request(
Some(format!(
"Resource {} is not accepted: {}",
&resource.name(),
resource.metadata().name.as_ref().unwrap(),
rejection_details,
)),
None,
None,
None,
)
}

/// verify all images defined in the PodSpec. The violations are stored in the `image_validation_errors` map.
fn verify_all_images_in_podspec(
spec: &PodSpec,
settings: &Settings,
image_validation_errors: &mut ImageValidationErrors,
) {
verify_container_images(&spec.containers, settings, image_validation_errors);
let mut images: Vec<String> = spec
.containers
.iter()
.map(|c| c.image.clone().unwrap())
.collect();

if let Some(init_containers) = &spec.init_containers {
verify_container_images(init_containers, settings, image_validation_errors);
let init_images: Vec<String> = init_containers
.iter()
.map(|c| c.image.clone().unwrap())
.collect();
images.extend(init_images);
}

if let Some(ephemeral_containers) = &spec.ephemeral_containers {
verify_container_images(ephemeral_containers, settings, image_validation_errors);
let ephemeral_images: Vec<String> = ephemeral_containers
.iter()
.map(|c| c.image.clone().unwrap())
.collect();

images.extend(ephemeral_images);
}
}

/// verify all images defined in the list of containers. The violations are stored in the `image_validation_errors` map.
fn verify_container_images<T>(
containers: &[T],
settings: &Settings,
image_validation_errors: &mut ImageValidationErrors,
) where
T: ImageHolder + PartialEq,
{
for container in containers {
let container_image = container.get_image().unwrap();
verify_container_image(&container_image, settings, image_validation_errors);
for image in images {
verify_container_image(&image, settings, image_validation_errors);
}
}

Expand Down
116 changes: 0 additions & 116 deletions src/workload_helpers.rs

This file was deleted.

0 comments on commit 3031d3b

Please sign in to comment.