diff --git a/src/errors.rs b/src/errors.rs index f9748ae6..44ced13b 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -29,3 +29,12 @@ pub enum ArtifactHubError { #[error("annotation \"{0}\" in policy metadata is malformed, must be a string \"true\" or \"false\"")] MalformedBoolString(String), } + +#[derive(Error, Debug)] +pub enum PolicyEvaluatorError { + #[error("protocol_version is only applicable to a Kubewarden policy")] + InvalidProtocolVersion(), + + #[error("protocol_version is only applicable to a Kubewarden policy")] + InvokeWapcProtocolVersion(#[source] crate::runtimes::wapc::errors::WapcRuntimeError), +} diff --git a/src/policy_evaluator/evaluator.rs b/src/policy_evaluator/evaluator.rs index 5821d6e2..b8c63c8d 100644 --- a/src/policy_evaluator/evaluator.rs +++ b/src/policy_evaluator/evaluator.rs @@ -1,9 +1,9 @@ -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::errors::PolicyEvaluatorError; use crate::evaluation_context::EvaluationContext; use crate::policy_evaluator::{PolicySettings, ValidateRequest}; use crate::runtimes::rego::Runtime as BurregoRuntime; @@ -75,12 +75,12 @@ impl PolicyEvaluator { } } - pub fn protocol_version(&mut self) -> Result { + 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" - )), + Runtime::Wapc(ref mut wapc_stack) => Ok(WapcRuntime(wapc_stack) + .protocol_version() + .map_err(PolicyEvaluatorError::InvokeWapcProtocolVersion)?), + _ => Err(PolicyEvaluatorError::InvalidProtocolVersion()), } } } diff --git a/src/runtimes/rego/errors.rs b/src/runtimes/rego/errors.rs index ca5807e5..b4c2cc3e 100644 --- a/src/runtimes/rego/errors.rs +++ b/src/runtimes/rego/errors.rs @@ -51,4 +51,7 @@ pub enum RegoRuntimeError { #[error("cannot allocate Rego evaluator: {0}")] EvaluatorError(String), + + #[error("cannot build Rego engine: {0}")] + RegoEngineBuilder(#[source] burrego::errors::BurregoError), } diff --git a/src/runtimes/rego/stack_pre.rs b/src/runtimes/rego/stack_pre.rs index 35905a89..792beb63 100644 --- a/src/runtimes/rego/stack_pre.rs +++ b/src/runtimes/rego/stack_pre.rs @@ -1,7 +1,6 @@ -use anyhow::Result; - use crate::policy_evaluator::RegoPolicyExecutionMode; use crate::policy_evaluator_builder::EpochDeadlines; +use crate::runtimes::rego::errors::{RegoRuntimeError, Result}; /// This struct allows to follow the `StackPre -> Stack` /// "pattern" also for Rego policies. @@ -50,7 +49,9 @@ impl StackPre { if let Some(deadlines) = self.epoch_deadlines { builder = builder.enable_epoch_interruptions(deadlines.wapc_func); } - let evaluator = builder.build()?; + let evaluator = builder + .build() + .map_err(RegoRuntimeError::RegoEngineBuilder)?; Ok(evaluator) } } diff --git a/src/runtimes/wapc/errors.rs b/src/runtimes/wapc/errors.rs new file mode 100644 index 00000000..8c28277f --- /dev/null +++ b/src/runtimes/wapc/errors.rs @@ -0,0 +1,28 @@ +use thiserror::Error; + +pub type Result = std::result::Result; + +#[derive(Error, Debug)] +pub enum WapcRuntimeError { + #[error("invalid response format: {0}")] + InvalidResponseFormat(#[source] anyhow::Error), + + #[error("invalid response from policy: {0}")] + InvalidResponseWithError(#[source] serde_json::Error), + + #[error("cannot create ProtocolVersion object from {res:?}: {error}")] + CreateProtocolVersion { + res: std::vec::Vec, + #[source] + error: wasmtime::Error, + }, + + #[error("cannot invoke 'protocol_version' waPC function : {0}")] + InvokeProtocolVersion(#[source] wapc::errors::Error), + + #[error("cannot build Wasmtime engine: {0}")] + WasmtimeEngineBuilder(#[source] wasmtime_provider::errors::Error), + + #[error("cannot build Wapc host: {0}")] + WapcHostBuilder(#[source] wapc::errors::Error), +} diff --git a/src/runtimes/wapc/mod.rs b/src/runtimes/wapc/mod.rs index 0da6bcbd..ab384dc5 100644 --- a/src/runtimes/wapc/mod.rs +++ b/src/runtimes/wapc/mod.rs @@ -1,4 +1,5 @@ mod callback; +pub mod errors; mod runtime; mod stack; mod stack_pre; diff --git a/src/runtimes/wapc/runtime.rs b/src/runtimes/wapc/runtime.rs index 6ba4d50d..192e3c75 100644 --- a/src/runtimes/wapc/runtime.rs +++ b/src/runtimes/wapc/runtime.rs @@ -1,4 +1,4 @@ -use anyhow::{anyhow, Result}; +use crate::runtimes::wapc::errors::{Result, WapcRuntimeError}; use kubewarden_policy_sdk::metadata::ProtocolVersion; use kubewarden_policy_sdk::response::ValidationResponse as PolicyValidationResponse; use kubewarden_policy_sdk::settings::SettingsValidationResponse; @@ -58,7 +58,7 @@ impl<'a> Runtime<'a> { match self.0.call("validate", validate_str.as_bytes()) { Ok(res) => { let pol_val_resp: Result = serde_json::from_slice(&res) - .map_err(|e| anyhow!("cannot deserialize policy validation response: {:?}", e)); + .map_err(WapcRuntimeError::InvalidResponseWithError); pol_val_resp .and_then(|pol_val_resp| { AdmissionResponse::from_policy_validation_response( @@ -66,6 +66,9 @@ impl<'a> Runtime<'a> { req_obj, &pol_val_resp, ) + .map_err(|e| -> WapcRuntimeError { + WapcRuntimeError::InvalidResponseFormat(e) + }) }) .unwrap_or_else(|e| { error!( @@ -129,7 +132,7 @@ impl<'a> Runtime<'a> { match self.0.call("validate_settings", settings.as_bytes()) { Ok(res) => { let vr: Result = serde_json::from_slice(&res) - .map_err(|e| anyhow!("cannot convert response: {:?}", e)); + .map_err(WapcRuntimeError::InvalidResponseWithError); vr.unwrap_or_else(|e| SettingsValidationResponse { valid: false, message: Some(format!("error: {e:?}")), @@ -146,17 +149,9 @@ impl<'a> Runtime<'a> { pub fn protocol_version(&self) -> Result { match self.0.call("protocol_version", &[0; 0]) { - Ok(res) => ProtocolVersion::try_from(res.clone()).map_err(|e| { - anyhow!( - "Cannot create ProtocolVersion object from '{:?}': {:?}", - res, - e - ) - }), - Err(err) => Err(anyhow!( - "Cannot invoke 'protocol_version' waPC function: {:?}", - err - )), + Ok(res) => ProtocolVersion::try_from(res.clone()) + .map_err(|e| WapcRuntimeError::CreateProtocolVersion { res, error: e }), + Err(e) => Err(WapcRuntimeError::InvokeProtocolVersion(e)), } } } diff --git a/src/runtimes/wapc/stack.rs b/src/runtimes/wapc/stack.rs index 15bd6a0e..682544c4 100644 --- a/src/runtimes/wapc/stack.rs +++ b/src/runtimes/wapc/stack.rs @@ -1,8 +1,10 @@ -use anyhow::Result; use std::sync::Arc; use crate::evaluation_context::EvaluationContext; -use crate::runtimes::wapc::callback::new_host_callback; +use crate::runtimes::wapc::{ + callback::new_host_callback, + errors::{Result, WapcRuntimeError}, +}; use super::StackPre; @@ -56,7 +58,8 @@ impl WapcStack { ) -> Result { let engine_provider = pre.rehydrate()?; let wapc_host = - wapc::WapcHost::new(Box::new(engine_provider), Some(new_host_callback(eval_ctx)))?; + wapc::WapcHost::new(Box::new(engine_provider), Some(new_host_callback(eval_ctx))) + .map_err(WapcRuntimeError::WapcHostBuilder)?; Ok(wapc_host) } } diff --git a/src/runtimes/wapc/stack_pre.rs b/src/runtimes/wapc/stack_pre.rs index 7b8b6506..2f489ae7 100644 --- a/src/runtimes/wapc/stack_pre.rs +++ b/src/runtimes/wapc/stack_pre.rs @@ -1,7 +1,7 @@ -use anyhow::Result; use wasmtime_provider::wasmtime; use crate::policy_evaluator_builder::EpochDeadlines; +use crate::runtimes::wapc::errors::{Result, WapcRuntimeError}; /// Reduce allocation time of new `WasmtimeProviderEngine`, see the `rehydrate` method #[derive(Clone)] @@ -22,7 +22,9 @@ impl StackPre { builder = builder.enable_epoch_interruptions(deadlines.wapc_init, deadlines.wapc_func); } - let engine_provider_pre = builder.build_pre()?; + let engine_provider_pre = builder + .build_pre() + .map_err(WapcRuntimeError::WasmtimeEngineBuilder)?; Ok(Self { engine_provider_pre, }) @@ -30,7 +32,10 @@ impl StackPre { /// Allocate a new `WasmtimeEngineProvider` instance by using a pre-allocated instance pub(crate) fn rehydrate(&self) -> Result { - let engine = self.engine_provider_pre.rehydrate()?; + let engine = self + .engine_provider_pre + .rehydrate() + .map_err(WapcRuntimeError::WasmtimeEngineBuilder)?; Ok(engine) } }