diff --git a/src/policy_evaluator/mod.rs b/src/policy_evaluator.rs similarity index 56% rename from src/policy_evaluator/mod.rs rename to src/policy_evaluator.rs index f93f4ff7..beb22bf0 100644 --- a/src/policy_evaluator/mod.rs +++ b/src/policy_evaluator.rs @@ -1,22 +1,17 @@ +mod evaluator; pub mod policy_evaluator_builder; -pub mod policy_evaluator_pre; +mod policy_evaluator_pre; +mod stack_pre; + +pub use evaluator::PolicyEvaluator; +pub use policy_evaluator_pre::PolicyEvaluatorPre; use anyhow::{anyhow, Result}; -use kubewarden_policy_sdk::metadata::ProtocolVersion; -use kubewarden_policy_sdk::settings::SettingsValidationResponse; use serde::Serialize; use serde_json::value; use std::{convert::TryFrom, fmt}; use crate::admission_request::AdmissionRequest; -use crate::admission_response::AdmissionResponse; -use crate::evaluation_context::EvaluationContext; -use crate::runtimes::rego::Runtime as BurregoRuntime; -use crate::runtimes::wapc::Runtime as WapcRuntime; -use crate::runtimes::wasi_cli::Runtime as WasiRuntime; -use crate::runtimes::Runtime; - -pub use policy_evaluator_pre::PolicyEvaluatorPre; #[derive(Copy, Clone, Default, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)] pub enum PolicyExecutionMode { @@ -82,87 +77,6 @@ impl TryFrom for RegoPolicyExecutionMode { /// Settings specified by the user for a given policy. pub type PolicySettings = serde_json::Map; -pub struct PolicyEvaluator { - runtime: Runtime, -} - -impl PolicyEvaluator { - pub(crate) fn new(runtime: Runtime) -> Self { - Self { runtime } - } - - #[tracing::instrument(skip(request, eval_ctx))] - pub fn validate( - &mut self, - request: ValidateRequest, - settings: &PolicySettings, - eval_ctx: &EvaluationContext, - ) -> AdmissionResponse { - match self.runtime { - Runtime::Wapc(ref mut wapc_stack) => { - WapcRuntime(wapc_stack).validate(settings, &request) - } - Runtime::Rego(ref mut burrego_evaluator) => { - let kube_ctx = burrego_evaluator.build_kubernetes_context( - eval_ctx.callback_channel.as_ref(), - &eval_ctx.ctx_aware_resources_allow_list, - ); - match kube_ctx { - Ok(ctx) => BurregoRuntime(burrego_evaluator).validate(settings, &request, &ctx), - Err(e) => { - AdmissionResponse::reject(request.uid().to_string(), e.to_string(), 500) - } - } - } - Runtime::Cli(ref mut cli_stack) => WasiRuntime(cli_stack).validate(settings, &request), - } - } - - #[tracing::instrument] - pub fn validate_settings(&mut self, settings: &PolicySettings) -> SettingsValidationResponse { - let settings_str = match serde_json::to_string(settings) { - Ok(settings) => settings, - Err(err) => { - return SettingsValidationResponse { - valid: false, - message: Some(format!("could not marshal settings: {err}")), - } - } - }; - - match self.runtime { - Runtime::Wapc(ref mut wapc_stack) => { - WapcRuntime(wapc_stack).validate_settings(settings_str) - } - Runtime::Rego(ref mut burrego_evaluator) => { - BurregoRuntime(burrego_evaluator).validate_settings(settings_str) - } - Runtime::Cli(ref mut cli_stack) => { - WasiRuntime(cli_stack).validate_settings(settings_str) - } - } - } - - pub fn protocol_version(&mut self) -> Result { - match &mut self.runtime { - Runtime::Wapc(ref mut wapc_stack) => WapcRuntime(wapc_stack).protocol_version(), - _ => Err(anyhow!( - "protocol_version is only applicable to a Kubewarden policy" - )), - } - } -} - -impl fmt::Debug for PolicyEvaluator { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let runtime = self.runtime.to_string(); - - f.debug_struct("PolicyEvaluator") - .field("runtime", &runtime) - .finish() - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/src/policy_evaluator/evaluator.rs b/src/policy_evaluator/evaluator.rs new file mode 100644 index 00000000..5821d6e2 --- /dev/null +++ b/src/policy_evaluator/evaluator.rs @@ -0,0 +1,96 @@ +use anyhow::{anyhow, Result}; +use kubewarden_policy_sdk::metadata::ProtocolVersion; +use kubewarden_policy_sdk::settings::SettingsValidationResponse; +use std::fmt; + +use crate::admission_response::AdmissionResponse; +use crate::evaluation_context::EvaluationContext; +use crate::policy_evaluator::{PolicySettings, ValidateRequest}; +use crate::runtimes::rego::Runtime as BurregoRuntime; +use crate::runtimes::wapc::Runtime as WapcRuntime; +use crate::runtimes::wasi_cli::Runtime as WasiRuntime; +use crate::runtimes::Runtime; + +pub struct PolicyEvaluator { + runtime: Runtime, + eval_ctx: EvaluationContext, +} + +impl PolicyEvaluator { + pub(crate) fn new(runtime: Runtime, eval_ctx: &EvaluationContext) -> Self { + Self { + runtime, + eval_ctx: eval_ctx.to_owned(), + } + } + + #[tracing::instrument(skip(request))] + pub fn validate( + &mut self, + request: ValidateRequest, + settings: &PolicySettings, + ) -> AdmissionResponse { + match self.runtime { + Runtime::Wapc(ref mut wapc_stack) => { + WapcRuntime(wapc_stack).validate(settings, &request) + } + Runtime::Rego(ref mut burrego_evaluator) => { + let kube_ctx = burrego_evaluator.build_kubernetes_context( + self.eval_ctx.callback_channel.as_ref(), + &self.eval_ctx.ctx_aware_resources_allow_list, + ); + match kube_ctx { + Ok(ctx) => BurregoRuntime(burrego_evaluator).validate(settings, &request, &ctx), + Err(e) => { + AdmissionResponse::reject(request.uid().to_string(), e.to_string(), 500) + } + } + } + Runtime::Cli(ref mut cli_stack) => WasiRuntime(cli_stack).validate(settings, &request), + } + } + + #[tracing::instrument] + pub fn validate_settings(&mut self, settings: &PolicySettings) -> SettingsValidationResponse { + let settings_str = match serde_json::to_string(settings) { + Ok(settings) => settings, + Err(err) => { + return SettingsValidationResponse { + valid: false, + message: Some(format!("could not marshal settings: {err}")), + } + } + }; + + match self.runtime { + Runtime::Wapc(ref mut wapc_stack) => { + WapcRuntime(wapc_stack).validate_settings(settings_str) + } + Runtime::Rego(ref mut burrego_evaluator) => { + BurregoRuntime(burrego_evaluator).validate_settings(settings_str) + } + Runtime::Cli(ref mut cli_stack) => { + WasiRuntime(cli_stack).validate_settings(settings_str) + } + } + } + + pub fn protocol_version(&mut self) -> Result { + match &mut self.runtime { + Runtime::Wapc(ref mut wapc_stack) => WapcRuntime(wapc_stack).protocol_version(), + _ => Err(anyhow!( + "protocol_version is only applicable to a Kubewarden policy" + )), + } + } +} + +impl fmt::Debug for PolicyEvaluator { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let runtime = self.runtime.to_string(); + + f.debug_struct("PolicyEvaluator") + .field("runtime", &runtime) + .finish() + } +} diff --git a/src/policy_evaluator/policy_evaluator_builder.rs b/src/policy_evaluator/policy_evaluator_builder.rs index d19c9075..78033731 100644 --- a/src/policy_evaluator/policy_evaluator_builder.rs +++ b/src/policy_evaluator/policy_evaluator_builder.rs @@ -2,9 +2,7 @@ use anyhow::{anyhow, Result}; use std::path::Path; use wasmtime_provider::wasmtime; -use crate::policy_evaluator::{ - policy_evaluator_pre::StackPre, PolicyEvaluatorPre, PolicyExecutionMode, -}; +use crate::policy_evaluator::{stack_pre::StackPre, PolicyEvaluatorPre, PolicyExecutionMode}; use crate::runtimes::{rego, wapc, wasi_cli}; /// Configure behavior of wasmtime [epoch-based interruptions](https://docs.rs/wasmtime/latest/wasmtime/struct.Config.html#method.epoch_interruption) @@ -197,7 +195,7 @@ impl PolicyEvaluatorBuilder { } }; - Ok(PolicyEvaluatorPre { stack_pre }) + Ok(PolicyEvaluatorPre::new(stack_pre)) } fn build_engine(&self) -> Result { diff --git a/src/policy_evaluator/policy_evaluator_pre.rs b/src/policy_evaluator/policy_evaluator_pre.rs index db2128e3..d1df8a68 100644 --- a/src/policy_evaluator/policy_evaluator_pre.rs +++ b/src/policy_evaluator/policy_evaluator_pre.rs @@ -1,48 +1,22 @@ use anyhow::Result; use crate::evaluation_context::EvaluationContext; -use crate::policy_evaluator::PolicyEvaluator; +use crate::policy_evaluator::{stack_pre::StackPre, PolicyEvaluator}; use crate::runtimes::{rego, wapc, wasi_cli, Runtime}; -/// Holds pre-initialized stacks for all the types of policies we run -/// -/// Pre-initialized instances are key to reduce the evaluation time when -/// using on-demand PolicyEvaluator instances; where on-demand means that -/// each validation request has a brand new PolicyEvaluator that is discarded -/// once the evaluation is done. -pub(crate) enum StackPre { - Wapc(crate::runtimes::wapc::StackPre), - Wasi(crate::runtimes::wasi_cli::StackPre), - Rego(crate::runtimes::rego::StackPre), -} - -impl From for StackPre { - fn from(wapc_stack_pre: wapc::StackPre) -> Self { - StackPre::Wapc(wapc_stack_pre) - } -} - -impl From for StackPre { - fn from(wasi_stack_pre: wasi_cli::StackPre) -> Self { - StackPre::Wasi(wasi_stack_pre) - } -} - -impl From for StackPre { - fn from(rego_stack_pre: rego::StackPre) -> Self { - StackPre::Rego(rego_stack_pre) - } -} - /// This struct provides a way to quickly allocate a `PolicyEvaluator` /// object. /// /// See the [`rehydrate`](PolicyEvaluatorPre::rehydrate) method. pub struct PolicyEvaluatorPre { - pub(crate) stack_pre: StackPre, + stack_pre: StackPre, } impl PolicyEvaluatorPre { + pub(crate) fn new(stack_pre: StackPre) -> Self { + PolicyEvaluatorPre { stack_pre } + } + /// Create a `PolicyEvaluator` instance. The creation of the instance is achieved by /// using wasmtime low level primitives (like `wasmtime::InstancePre`) to make the operation /// as fast as possible. @@ -66,6 +40,6 @@ impl PolicyEvaluatorPre { } }; - Ok(PolicyEvaluator::new(runtime)) + Ok(PolicyEvaluator::new(runtime, eval_ctx)) } } diff --git a/src/policy_evaluator/stack_pre.rs b/src/policy_evaluator/stack_pre.rs new file mode 100644 index 00000000..6bb1daa5 --- /dev/null +++ b/src/policy_evaluator/stack_pre.rs @@ -0,0 +1,31 @@ +use crate::runtimes::{rego, wapc, wasi_cli}; + +/// Holds pre-initialized stacks for all the types of policies we run +/// +/// Pre-initialized instances are key to reduce the evaluation time when +/// using on-demand PolicyEvaluator instances; where on-demand means that +/// each validation request has a brand new PolicyEvaluator that is discarded +/// once the evaluation is done. +pub(crate) enum StackPre { + Wapc(crate::runtimes::wapc::StackPre), + Wasi(crate::runtimes::wasi_cli::StackPre), + Rego(crate::runtimes::rego::StackPre), +} + +impl From for StackPre { + fn from(wapc_stack_pre: wapc::StackPre) -> Self { + StackPre::Wapc(wapc_stack_pre) + } +} + +impl From for StackPre { + fn from(wasi_stack_pre: wasi_cli::StackPre) -> Self { + StackPre::Wasi(wasi_stack_pre) + } +} + +impl From for StackPre { + fn from(rego_stack_pre: rego::StackPre) -> Self { + StackPre::Rego(rego_stack_pre) + } +}