From fae3fd97841be4de95f98f8e2edd494ae80c0877 Mon Sep 17 00:00:00 2001 From: "ZhengYu, Xu" Date: Wed, 2 Nov 2022 13:49:35 +0800 Subject: [PATCH] fix(admission): fix admission reject request when serde failed (#32) --- crates/habitat-admission/Cargo.toml | 2 ++ crates/habitat-admission/src/lib.rs | 2 ++ crates/habitat-admission/src/mutate.rs | 27 ++++++++++++++++-------- crates/habitat-admission/src/util.rs | 13 ++++++++++++ crates/habitat-admission/src/validate.rs | 26 +++++++++++++++-------- 5 files changed, 52 insertions(+), 18 deletions(-) create mode 100644 crates/habitat-admission/src/util.rs diff --git a/crates/habitat-admission/Cargo.toml b/crates/habitat-admission/Cargo.toml index 2d8cc85..dbc824a 100644 --- a/crates/habitat-admission/Cargo.toml +++ b/crates/habitat-admission/Cargo.toml @@ -18,3 +18,5 @@ serde_json = "1" tracing = "0.1" tracing-subscriber = "0.3" warp = { version = "0.3", default-features = false, features = ["tls"] } +regex = "1" +lazy_static = "1" diff --git a/crates/habitat-admission/src/lib.rs b/crates/habitat-admission/src/lib.rs index d80415a..609a278 100644 --- a/crates/habitat-admission/src/lib.rs +++ b/crates/habitat-admission/src/lib.rs @@ -1,2 +1,4 @@ pub mod mutate; pub mod validate; + +mod util; diff --git a/crates/habitat-admission/src/mutate.rs b/crates/habitat-admission/src/mutate.rs index 18f0eff..428aec9 100644 --- a/crates/habitat-admission/src/mutate.rs +++ b/crates/habitat-admission/src/mutate.rs @@ -1,14 +1,16 @@ use habitat_api::Job; use kube::core::{ admission::{AdmissionRequest, AdmissionResponse, AdmissionReview}, - ResourceExt, + DynamicObject, ResourceExt, }; use std::{convert::Infallible, error::Error}; use tracing::*; use warp::{reply, Reply}; +use crate::util::try_cast_dynamic_obj_into_job; -pub async fn handler(body: AdmissionReview) -> Result { + +pub async fn handler(body: AdmissionReview) -> Result { // Parse incoming webhook AdmissionRequest first let req: AdmissionRequest<_> = match body.try_into() { Ok(req) => req, @@ -25,14 +27,21 @@ pub async fn handler(body: AdmissionReview) -> Result { - info!("accepted: {:?} on Job {}", req.operation, name); - res - } + + res = match try_cast_dynamic_obj_into_job(&obj) { + Ok(job) => match mutate(res.clone(), &job) { + Ok(res) => { + info!("accepted: {:?} on Job {}", req.operation, name); + res + } + Err(err) => { + warn!("denied: {:?} on {} ({})", req.operation, name, err); + res.deny(err.to_string()) + } + }, Err(err) => { - warn!("denied: {:?} on {} ({})", req.operation, name, err); - res.deny(err.to_string()) + warn!("invalid job: {:?} on {} ({})", req.operation, name, err); + res.deny(err) } }; }; diff --git a/crates/habitat-admission/src/util.rs b/crates/habitat-admission/src/util.rs new file mode 100644 index 0000000..02dab45 --- /dev/null +++ b/crates/habitat-admission/src/util.rs @@ -0,0 +1,13 @@ +use habitat_api::Job; +use kube::core::DynamicObject; +use lazy_static::lazy_static; +use regex::Regex; + +pub fn try_cast_dynamic_obj_into_job(obj: &DynamicObject) -> Result { + lazy_static! { + static ref RE: Regex = Regex::new(r" at line \d+ column \d+").unwrap(); + } + + let obj_json = serde_json::to_string(obj).unwrap(); + serde_json::from_str(&obj_json).map_err(|e| RE.replace(&e.to_string(), "").to_string()) +} diff --git a/crates/habitat-admission/src/validate.rs b/crates/habitat-admission/src/validate.rs index e13610a..fb95b9b 100644 --- a/crates/habitat-admission/src/validate.rs +++ b/crates/habitat-admission/src/validate.rs @@ -1,14 +1,16 @@ use habitat_api::Job; use kube::core::{ admission::{AdmissionRequest, AdmissionResponse, AdmissionReview}, - ResourceExt, + DynamicObject, ResourceExt, }; use std::{convert::Infallible, error::Error}; use tracing::*; use warp::{reply, Reply}; +use crate::util::try_cast_dynamic_obj_into_job; -pub async fn handler(body: AdmissionReview) -> Result { + +pub async fn handler(body: AdmissionReview) -> Result { // Parse incoming webhook AdmissionRequest first let req: AdmissionRequest<_> = match body.try_into() { Ok(req) => req, @@ -25,14 +27,20 @@ pub async fn handler(body: AdmissionReview) -> Result { - info!("accepted: {:?} on Job {}", req.operation, name); - res - } + res = match try_cast_dynamic_obj_into_job(&obj) { + Ok(job) => match validate(res.clone(), &job) { + Ok(res) => { + info!("accepted: {:?} on Job {}", req.operation, name); + res + } + Err(err) => { + warn!("denied: {:?} on {} ({})", req.operation, name, err); + res.deny(err.to_string()) + } + }, Err(err) => { - warn!("denied: {:?} on {} ({})", req.operation, name, err); - res.deny(err.to_string()) + warn!("invalid job: {:?} on {} ({})", req.operation, name, err); + res.deny(err) } }; };