From 8d2540ce409a702adcb9ddc9bc4518bdd53d7e05 Mon Sep 17 00:00:00 2001 From: Adam Cattermole Date: Mon, 20 Apr 2026 09:28:11 +0100 Subject: [PATCH 1/6] clippy: unnecessary sort_by Signed-off-by: Adam Cattermole --- src/data/cel.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data/cel.rs b/src/data/cel.rs index 4e3fc748..63abaddc 100644 --- a/src/data/cel.rs +++ b/src/data/cel.rs @@ -155,7 +155,7 @@ impl Expression { }) .collect(); - attributes.sort_by(|a, b| a.path.tokens().len().cmp(&b.path.tokens().len())); + attributes.sort_by_key(|a| a.path.tokens().len()); Ok(Self { attributes, From 5d8d0a50943786ecc864ec2d89a7aa142de297aa Mon Sep 17 00:00:00 2001 From: Adam Cattermole Date: Mon, 20 Apr 2026 09:31:21 +0100 Subject: [PATCH 2/6] clippy: collapsible match Signed-off-by: Adam Cattermole --- src/kuadrant/pipeline/tasks/token_usage/event_parser.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/kuadrant/pipeline/tasks/token_usage/event_parser.rs b/src/kuadrant/pipeline/tasks/token_usage/event_parser.rs index 1663d126..ef878eb5 100644 --- a/src/kuadrant/pipeline/tasks/token_usage/event_parser.rs +++ b/src/kuadrant/pipeline/tasks/token_usage/event_parser.rs @@ -85,11 +85,7 @@ impl EventBuilder { } self.event.data.push_str(val); } - "id" => { - if !val.contains('\u{0000}') { - self.event.id = val.to_string() - } - } + "id" if !val.contains('\u{0000}') => self.event.id = val.to_string(), "retry" => { if let Ok(val) = val.parse::() { self.event.retry = Some(Duration::from_millis(val)) From 2ba4af5d40bd5fd0efbd1fa137e23c89a76f4b7e Mon Sep 17 00:00:00 2001 From: Adam Cattermole Date: Fri, 29 May 2026 01:08:59 +0100 Subject: [PATCH 3/6] Add linker arg for rust 1.96 Signed-off-by: Adam Cattermole --- .cargo/config.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.cargo/config.toml b/.cargo/config.toml index e69de29b..424ebfbf 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -0,0 +1,2 @@ +[target.wasm32-wasip1] +rustflags = ["-C", "link-arg=--allow-undefined"] From e951e3d3e8dc0b6947eb4dd38af19cc65b150e2c Mon Sep 17 00:00:00 2001 From: Adam Cattermole Date: Fri, 29 May 2026 00:38:23 +0100 Subject: [PATCH 4/6] Address fail-open behaviour Signed-off-by: Adam Cattermole --- src/filter/kuadrant_filter.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/filter/kuadrant_filter.rs b/src/filter/kuadrant_filter.rs index 32832448..7415d313 100644 --- a/src/filter/kuadrant_filter.rs +++ b/src/filter/kuadrant_filter.rs @@ -1,5 +1,6 @@ use crate::kuadrant::{Pipeline, PipelineFactory, PipelineState, ReqRespCtx}; use crate::metrics::METRICS; +use proxy_wasm::hostcalls; use proxy_wasm::traits::{Context, HttpContext}; use proxy_wasm::types::Action; use std::ops::Not; @@ -122,7 +123,15 @@ impl HttpContext for KuadrantFilter { Err(e) => { error!("#{} failed to build pipeline: {:?}", self.context_id, e); METRICS.errors().increment(); - // todo(adam-cattermole): we should deny the request + #[allow(clippy::panic)] + hostcalls::send_http_response(500, Default::default(), Some(b"Internal Server Error.\n")) + .unwrap_or_else(|err| { + error!( + "#{} CRITICAL: Failed to send error response: {:?}. WASM runtime is in an invalid state", + self.context_id, err + ); + panic!("CRITICAL: Failed to send HTTP reply after pipeline build failure"); + }); Action::Continue } } From da35d6f766b3a22c9ea634d70c1022e9e982f7c7 Mon Sep 17 00:00:00 2001 From: Adam Cattermole Date: Fri, 24 Jul 2026 10:47:45 +0100 Subject: [PATCH 5/6] Case-insensitive hostname lookup Signed-off-by: Adam Cattermole --- src/kuadrant/pipeline/factory.rs | 37 ++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/src/kuadrant/pipeline/factory.rs b/src/kuadrant/pipeline/factory.rs index 44fa7958..6755e1f5 100644 --- a/src/kuadrant/pipeline/factory.rs +++ b/src/kuadrant/pipeline/factory.rs @@ -82,7 +82,7 @@ impl TryFrom for PipelineFactory { let blueprint = Rc::new(blueprint); for hostname in &config_action_set.route_rule_conditions.hostnames { - let key = reverse_subdomain(hostname); + let key = reverse_subdomain(&hostname.to_ascii_lowercase()); index.map_with_default( key, |blueprints| blueprints.push(Rc::clone(&blueprint)), @@ -189,7 +189,7 @@ impl PipelineFactory { match ctx.get_attribute::("request.host") { Ok(AttributeState::Available(Some(host))) => { let split_host = host.split_once(':').map_or(host.as_str(), |(h, _)| h); - Ok(split_host.to_owned()) + Ok(split_host.to_ascii_lowercase()) } Ok(AttributeState::Available(None)) => Err(BuildError::EvaluationError( "hostname not found".to_string(), @@ -585,6 +585,39 @@ mod tests { assert_eq!(factory.request_data.len(), 1); } + #[test] + fn build_matches_hostname_case_insensitively() { + let config = build_test_config(vec!["Example.COM".to_string()], vec![], "test-service"); + let factory = PipelineFactory::try_from(config).unwrap(); + + let mock_host = MockWasmHost::new() + .with_property("request.host".into(), "example.com".as_bytes().to_vec()); + let ctx = ReqRespCtx::new(Arc::new(mock_host)); + assert!(factory.build(ctx).unwrap().is_some()); + } + + #[test] + fn build_matches_mixed_case_request_hostname() { + let config = build_test_config(vec!["api.example.com".to_string()], vec![], "test-service"); + let factory = PipelineFactory::try_from(config).unwrap(); + + let mock_host = MockWasmHost::new() + .with_property("request.host".into(), "API.Example.COM".as_bytes().to_vec()); + let ctx = ReqRespCtx::new(Arc::new(mock_host)); + assert!(factory.build(ctx).unwrap().is_some()); + } + + #[test] + fn build_matches_wildcard_case_insensitively() { + let config = build_test_config(vec!["*.Example.COM".to_string()], vec![], "test-service"); + let factory = PipelineFactory::try_from(config).unwrap(); + + let mock_host = MockWasmHost::new() + .with_property("request.host".into(), "API.example.com".as_bytes().to_vec()); + let ctx = ReqRespCtx::new(Arc::new(mock_host)); + assert!(factory.build(ctx).unwrap().is_some()); + } + #[test] fn factory_handles_multiple_hostnames_for_same_action_set() { let config = build_test_config( From a519f6bf46813806995a0f4ee71695c09bbcdcc5 Mon Sep 17 00:00:00 2001 From: Adam Cattermole Date: Mon, 24 Aug 2026 10:46:21 +0100 Subject: [PATCH 6/6] clippy::drain-collect Signed-off-by: Adam Cattermole --- src/kuadrant/pipeline/executor.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kuadrant/pipeline/executor.rs b/src/kuadrant/pipeline/executor.rs index 29460bcf..b4155563 100644 --- a/src/kuadrant/pipeline/executor.rs +++ b/src/kuadrant/pipeline/executor.rs @@ -97,7 +97,7 @@ impl Pipeline { } pub fn eval(mut self) -> PipelineState { - let tasks_to_process: Vec<_> = self.task_queue.drain(..).collect(); + let tasks_to_process: Vec<_> = std::mem::take(&mut self.task_queue); for task in tasks_to_process { if task