From 2e26e151c273cbcc063eba2d08d28dc2ba5a33ec Mon Sep 17 00:00:00 2001 From: mo khan Date: Thu, 19 Jun 2025 17:45:39 -0600 Subject: refactor: split types into separate files --- src/authorization/authorizer.rs | 5 ++ src/authorization/cedar_authorizer.rs | 103 ++++++++++++++++++++++++++++++++++ src/authorization/check_service.rs | 97 ++++++++++++++++++++++++++++++++ src/authorization/mod.rs | 7 +++ 4 files changed, 212 insertions(+) create mode 100644 src/authorization/authorizer.rs create mode 100644 src/authorization/cedar_authorizer.rs create mode 100644 src/authorization/check_service.rs create mode 100644 src/authorization/mod.rs (limited to 'src/authorization') diff --git a/src/authorization/authorizer.rs b/src/authorization/authorizer.rs new file mode 100644 index 00000000..0f700ba7 --- /dev/null +++ b/src/authorization/authorizer.rs @@ -0,0 +1,5 @@ +use envoy_types::ext_authz::v3::pb::CheckRequest; + +pub trait Authorizer { + fn authorize(&self, request: CheckRequest) -> bool; +} diff --git a/src/authorization/cedar_authorizer.rs b/src/authorization/cedar_authorizer.rs new file mode 100644 index 00000000..2efbda28 --- /dev/null +++ b/src/authorization/cedar_authorizer.rs @@ -0,0 +1,103 @@ +use super::authorizer::Authorizer; +use envoy_types::ext_authz::v3::pb::CheckRequest; + +pub struct CedarAuthorizer {} + +impl CedarAuthorizer { + pub fn new() -> CedarAuthorizer { + CedarAuthorizer {} + } +} + +impl Default for CedarAuthorizer { + fn default() -> Self { + Self::new() + } +} + +impl Authorizer for CedarAuthorizer { + fn authorize(&self, request: CheckRequest) -> bool { + let headers = request + .attributes + .as_ref() + .and_then(|attr| attr.request.as_ref()) + .and_then(|req| req.http.as_ref()) + .map(|http| &http.headers) + .unwrap(); + + if let Some(authorization) = headers.get("authorization") { + if authorization == "Bearer valid-token" { + return true; + } + } + + false + } +} + +#[cfg(test)] +mod tests { + use super::*; + use envoy_types::pb::envoy::service::auth::v3::{AttributeContext, attribute_context}; + use std::collections::HashMap; + + fn create_test_request_with_headers(headers: HashMap) -> CheckRequest { + let http_request = attribute_context::HttpRequest { + headers, + ..Default::default() + }; + + let request_context = attribute_context::Request { + http: Some(http_request), + ..Default::default() + }; + + let attributes = AttributeContext { + request: Some(request_context), + ..Default::default() + }; + + CheckRequest { + attributes: Some(attributes), + ..Default::default() + } + } + + #[test] + fn test_cedar_authorizer_allows_valid_token() { + let authorizer = CedarAuthorizer::new(); + let mut headers = HashMap::new(); + headers.insert( + "authorization".to_string(), + "Bearer valid-token".to_string(), + ); + let request = create_test_request_with_headers(headers); + + let result = authorizer.authorize(request); + assert!(result); + } + + #[test] + fn test_cedar_authorizer_denies_invalid_token() { + let authorizer = CedarAuthorizer::new(); + let mut headers = HashMap::new(); + headers.insert( + "authorization".to_string(), + "Bearer invalid-token".to_string(), + ); + let request = create_test_request_with_headers(headers); + + let result = authorizer.authorize(request); + assert!(!result); + } + + #[test] + fn test_cedar_authorizer_denies_missing_header() { + let authorizer = CedarAuthorizer::new(); + let headers = HashMap::new(); + let request = create_test_request_with_headers(headers); + + let result = authorizer.authorize(request); + assert!(!result); + } +} diff --git a/src/authorization/check_service.rs b/src/authorization/check_service.rs new file mode 100644 index 00000000..7ca39fcd --- /dev/null +++ b/src/authorization/check_service.rs @@ -0,0 +1,97 @@ +use envoy_types::ext_authz::v3::CheckResponseExt; +use envoy_types::ext_authz::v3::pb::{CheckRequest, CheckResponse}; +use tonic::{Request, Response, Status}; + +use super::authorizer::Authorizer; +use super::cedar_authorizer::CedarAuthorizer; + +#[derive(Debug, Default)] +pub struct CheckService; + +#[tonic::async_trait] +impl envoy_types::ext_authz::v3::pb::Authorization for CheckService { + async fn check( + &self, + request: Request, + ) -> Result, Status> { + let request = request.into_inner(); + + let authorizer = CedarAuthorizer::new(); + if authorizer.authorize(request) { + Ok(Response::new(CheckResponse::with_status(Status::ok("OK")))) + } else { + Ok(Response::new(CheckResponse::with_status( + Status::unauthenticated("Unauthorized"), + ))) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use envoy_types::ext_authz::v3::pb::{Authorization, CheckRequest}; + use envoy_types::pb::envoy::service::auth::v3::{AttributeContext, attribute_context}; + use std::collections::HashMap; + use tonic::Request; + + fn create_test_request_with_headers(headers: HashMap) -> Request { + let http_request = attribute_context::HttpRequest { + headers, + ..Default::default() + }; + + let request_context = attribute_context::Request { + http: Some(http_request), + ..Default::default() + }; + + let attributes = AttributeContext { + request: Some(request_context), + ..Default::default() + }; + + let check_request = CheckRequest { + attributes: Some(attributes), + ..Default::default() + }; + + Request::new(check_request) + } + + fn create_headers_with_auth(auth_value: &str) -> HashMap { + let mut headers = HashMap::new(); + headers.insert("authorization".to_string(), auth_value.to_string()); + headers + } + + #[tokio::test] + async fn test_check_allows_valid_bearer_token() { + let token = String::from("valid-token"); + let server = CheckService::default(); + let headers = create_headers_with_auth(&format!("Bearer {}", token)); + let request = create_test_request_with_headers(headers); + + let response = server.check(request).await; + + assert!(response.is_ok()); + let check_response = response.unwrap().into_inner(); + assert!(check_response.status.is_some()); + let status = check_response.status.unwrap(); + assert_eq!(status.code, tonic::Code::Ok.into()); + } + + #[tokio::test] + async fn test_check_denies_invalid_bearer_token() { + let server = CheckService::default(); + let request = create_test_request_with_headers(HashMap::new()); + + let response = server.check(request).await; + + assert!(response.is_ok()); + let check_response = response.unwrap().into_inner(); + assert!(check_response.status.is_some()); + let status = check_response.status.unwrap(); + assert_eq!(status.code, tonic::Code::Unauthenticated.into()); + } +} diff --git a/src/authorization/mod.rs b/src/authorization/mod.rs new file mode 100644 index 00000000..7d3856a5 --- /dev/null +++ b/src/authorization/mod.rs @@ -0,0 +1,7 @@ +pub mod authorizer; +pub mod cedar_authorizer; +pub mod check_service; + +pub use authorizer::Authorizer; +pub use cedar_authorizer::CedarAuthorizer; +pub use check_service::CheckService; -- cgit v1.2.3 From e3fec7bf38d6070c9fb547ab08670e556ec974ab Mon Sep 17 00:00:00 2001 From: mo khan Date: Fri, 20 Jun 2025 10:37:56 -0600 Subject: refactor: experiment with rust generics --- src/authorization/cedar_authorizer.rs | 38 +++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) (limited to 'src/authorization') diff --git a/src/authorization/cedar_authorizer.rs b/src/authorization/cedar_authorizer.rs index 2efbda28..ff4c3c5b 100644 --- a/src/authorization/cedar_authorizer.rs +++ b/src/authorization/cedar_authorizer.rs @@ -41,11 +41,22 @@ mod tests { use envoy_types::pb::envoy::service::auth::v3::{AttributeContext, attribute_context}; use std::collections::HashMap; + fn build() -> T { + T::default() + } + + fn build_with(initializer: impl std::ops::FnOnce(T) -> T) -> T { + let item = build::(); + initializer(item) + } + fn create_test_request_with_headers(headers: HashMap) -> CheckRequest { - let http_request = attribute_context::HttpRequest { - headers, - ..Default::default() - }; + let http_request = build_with::( + |mut item: attribute_context::HttpRequest| { + item.headers = headers; + item + }, + ); let request_context = attribute_context::Request { http: Some(http_request), @@ -100,4 +111,23 @@ mod tests { let result = authorizer.authorize(request); assert!(!result); } + + // test css passthrough + // test javascript passthrough + // test ico passthrough + // test png,jpg,bmp passthrough + // test html passthrough + // #[test] + // fn authorize_test_css_passthrough() { + // let authorizer = CedarAuthorizer::new(); + + // let request = CheckRequest { + // attributes: Some(AttributeContext { + // ..Default::default() + // }), + // }; + // let result = authorizer.authorize(request); + + // assert!(result) + // } } -- cgit v1.2.3 From e88297eb165bc680bfaa7adc3f5feaf3691bf51c Mon Sep 17 00:00:00 2001 From: mo khan Date: Fri, 20 Jun 2025 10:41:35 -0600 Subject: refactor: collapse object initializers into a single one --- src/authorization/cedar_authorizer.rs | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) (limited to 'src/authorization') diff --git a/src/authorization/cedar_authorizer.rs b/src/authorization/cedar_authorizer.rs index ff4c3c5b..cefdef2b 100644 --- a/src/authorization/cedar_authorizer.rs +++ b/src/authorization/cedar_authorizer.rs @@ -51,22 +51,20 @@ mod tests { } fn create_test_request_with_headers(headers: HashMap) -> CheckRequest { - let http_request = build_with::( - |mut item: attribute_context::HttpRequest| { - item.headers = headers; - item - }, - ); - - let request_context = attribute_context::Request { - http: Some(http_request), - ..Default::default() - }; - - let attributes = AttributeContext { - request: Some(request_context), - ..Default::default() - }; + let attributes = build_with::(|mut item: AttributeContext| { + item.request = Some(build_with::( + |mut item: attribute_context::Request| { + item.http = Some(build_with::( + |mut item: attribute_context::HttpRequest| { + item.headers = headers; + item + }, + )); + item + }, + )); + item + }); CheckRequest { attributes: Some(attributes), -- cgit v1.2.3 From 57c7bd667bc9fc809d1e1ee49c0696a13d3bfd8d Mon Sep 17 00:00:00 2001 From: mo khan Date: Fri, 20 Jun 2025 10:43:27 -0600 Subject: refactor: collapse initializers in a functional chain --- src/authorization/cedar_authorizer.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'src/authorization') diff --git a/src/authorization/cedar_authorizer.rs b/src/authorization/cedar_authorizer.rs index cefdef2b..cc1fc93b 100644 --- a/src/authorization/cedar_authorizer.rs +++ b/src/authorization/cedar_authorizer.rs @@ -51,12 +51,17 @@ mod tests { } fn create_test_request_with_headers(headers: HashMap) -> CheckRequest { - let attributes = build_with::(|mut item: AttributeContext| { - item.request = Some(build_with::( - |mut item: attribute_context::Request| { - item.http = Some(build_with::( - |mut item: attribute_context::HttpRequest| { - item.headers = headers; + build_with::(|mut item: CheckRequest| { + item.attributes = Some(build_with::( + |mut item: AttributeContext| { + item.request = Some(build_with::( + |mut item: attribute_context::Request| { + item.http = Some(build_with::( + |mut item: attribute_context::HttpRequest| { + item.headers = headers; + item + }, + )); item }, )); @@ -64,12 +69,7 @@ mod tests { }, )); item - }); - - CheckRequest { - attributes: Some(attributes), - ..Default::default() - } + }) } #[test] -- cgit v1.2.3 From e88052fe49c42350d392624101af4be1b10680cb Mon Sep 17 00:00:00 2001 From: mo khan Date: Fri, 20 Jun 2025 10:51:56 -0600 Subject: refactor: improve generic builder methods --- src/authorization/cedar_authorizer.rs | 37 +++++++++++++++-------------------- 1 file changed, 16 insertions(+), 21 deletions(-) (limited to 'src/authorization') diff --git a/src/authorization/cedar_authorizer.rs b/src/authorization/cedar_authorizer.rs index cc1fc93b..547a1318 100644 --- a/src/authorization/cedar_authorizer.rs +++ b/src/authorization/cedar_authorizer.rs @@ -45,30 +45,25 @@ mod tests { T::default() } - fn build_with(initializer: impl std::ops::FnOnce(T) -> T) -> T { - let item = build::(); - initializer(item) + fn build_with(initializer: F) -> T + where + T: Default, + F: std::ops::FnOnce(&mut T), + { + let mut item = build::(); + initializer(&mut item); + item } fn create_test_request_with_headers(headers: HashMap) -> CheckRequest { - build_with::(|mut item: CheckRequest| { - item.attributes = Some(build_with::( - |mut item: AttributeContext| { - item.request = Some(build_with::( - |mut item: attribute_context::Request| { - item.http = Some(build_with::( - |mut item: attribute_context::HttpRequest| { - item.headers = headers; - item - }, - )); - item - }, - )); - item - }, - )); - item + build_with(|item: &mut CheckRequest| { + item.attributes = Some(build_with(|item: &mut AttributeContext| { + item.request = Some(build_with(|item: &mut attribute_context::Request| { + item.http = Some(build_with(|item: &mut attribute_context::HttpRequest| { + item.headers = headers; + })); + })); + })); }) } -- cgit v1.2.3 From 468f1b652080c94d5d8668cf8f6e650af00a782d Mon Sep 17 00:00:00 2001 From: mo khan Date: Fri, 20 Jun 2025 11:09:15 -0600 Subject: refactor: extract an x module --- src/authorization/cedar_authorizer.rs | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) (limited to 'src/authorization') diff --git a/src/authorization/cedar_authorizer.rs b/src/authorization/cedar_authorizer.rs index 547a1318..16a3f405 100644 --- a/src/authorization/cedar_authorizer.rs +++ b/src/authorization/cedar_authorizer.rs @@ -35,17 +35,12 @@ impl Authorizer for CedarAuthorizer { } } -#[cfg(test)] -mod tests { - use super::*; - use envoy_types::pb::envoy::service::auth::v3::{AttributeContext, attribute_context}; - use std::collections::HashMap; - - fn build() -> T { +mod x { + pub fn build() -> T { T::default() } - fn build_with(initializer: F) -> T + pub fn build_with(initializer: F) -> T where T: Default, F: std::ops::FnOnce(&mut T), @@ -54,14 +49,23 @@ mod tests { initializer(&mut item); item } +} + +#[cfg(test)] +mod tests { + use super::*; + use envoy_types::pb::envoy::service::auth::v3::{AttributeContext, attribute_context}; + use std::collections::HashMap; fn create_test_request_with_headers(headers: HashMap) -> CheckRequest { - build_with(|item: &mut CheckRequest| { - item.attributes = Some(build_with(|item: &mut AttributeContext| { - item.request = Some(build_with(|item: &mut attribute_context::Request| { - item.http = Some(build_with(|item: &mut attribute_context::HttpRequest| { - item.headers = headers; - })); + x::build_with(|item: &mut CheckRequest| { + item.attributes = Some(x::build_with(|item: &mut AttributeContext| { + item.request = Some(x::build_with(|item: &mut attribute_context::Request| { + item.http = Some(x::build_with( + |item: &mut attribute_context::HttpRequest| { + item.headers = headers; + }, + )); })); })); }) -- cgit v1.2.3 From 63ce8f874564369ceabfbb023c7516c9bcfd3838 Mon Sep 17 00:00:00 2001 From: mo khan Date: Fri, 20 Jun 2025 11:45:59 -0600 Subject: refactor: use please builders --- Cargo.lock | 6 ++++++ Cargo.toml | 1 + src/authorization/cedar_authorizer.rs | 36 +++++++++++------------------------ 3 files changed, 18 insertions(+), 25 deletions(-) (limited to 'src/authorization') diff --git a/Cargo.lock b/Cargo.lock index 9d1c3bdc..9ceb88cf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -76,6 +76,7 @@ name = "authzd" version = "0.1.0" dependencies = [ "envoy-types", + "please", "tokio", "tokio-test", "tonic", @@ -567,6 +568,11 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "please" +version = "0.1.0" +source = "git+https://github.com/xlgmokha/please.git#bff13caf9ee2f806dd32c5d77f0e4ac9eb28c7f5" + [[package]] name = "prettyplease" version = "0.2.34" diff --git a/Cargo.toml b/Cargo.toml index a13b9464..5eeecac3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ path = "src/lib.rs" [dependencies] envoy-types = "0.6.0" +please = { git = "https://github.com/xlgmokha/please.git", version = "0.1.0" } tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] } tonic = "*" tonic-health = "0.13.1" diff --git a/src/authorization/cedar_authorizer.rs b/src/authorization/cedar_authorizer.rs index 16a3f405..c1f5455d 100644 --- a/src/authorization/cedar_authorizer.rs +++ b/src/authorization/cedar_authorizer.rs @@ -35,22 +35,6 @@ impl Authorizer for CedarAuthorizer { } } -mod x { - pub fn build() -> T { - T::default() - } - - pub fn build_with(initializer: F) -> T - where - T: Default, - F: std::ops::FnOnce(&mut T), - { - let mut item = build::(); - initializer(&mut item); - item - } -} - #[cfg(test)] mod tests { use super::*; @@ -58,15 +42,17 @@ mod tests { use std::collections::HashMap; fn create_test_request_with_headers(headers: HashMap) -> CheckRequest { - x::build_with(|item: &mut CheckRequest| { - item.attributes = Some(x::build_with(|item: &mut AttributeContext| { - item.request = Some(x::build_with(|item: &mut attribute_context::Request| { - item.http = Some(x::build_with( - |item: &mut attribute_context::HttpRequest| { - item.headers = headers; - }, - )); - })); + please::build_with(|item: &mut CheckRequest| { + item.attributes = Some(please::build_with(|item: &mut AttributeContext| { + item.request = Some(please::build_with( + |item: &mut attribute_context::Request| { + item.http = Some(please::build_with( + |item: &mut attribute_context::HttpRequest| { + item.headers = headers; + }, + )); + }, + )); })); }) } -- cgit v1.2.3 From b7c3a1c50d616cf68155e76a9f143b98bc29fb35 Mon Sep 17 00:00:00 2001 From: mo khan Date: Fri, 20 Jun 2025 14:29:40 -0600 Subject: test: extract helper function to create a check request --- src/authorization/cedar_authorizer.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'src/authorization') diff --git a/src/authorization/cedar_authorizer.rs b/src/authorization/cedar_authorizer.rs index c1f5455d..49659d35 100644 --- a/src/authorization/cedar_authorizer.rs +++ b/src/authorization/cedar_authorizer.rs @@ -41,15 +41,15 @@ mod tests { use envoy_types::pb::envoy::service::auth::v3::{AttributeContext, attribute_context}; use std::collections::HashMap; - fn create_test_request_with_headers(headers: HashMap) -> CheckRequest { + fn create_request( + f: impl std::ops::FnOnce(&mut attribute_context::HttpRequest), + ) -> CheckRequest { please::build_with(|item: &mut CheckRequest| { item.attributes = Some(please::build_with(|item: &mut AttributeContext| { item.request = Some(please::build_with( |item: &mut attribute_context::Request| { item.http = Some(please::build_with( - |item: &mut attribute_context::HttpRequest| { - item.headers = headers; - }, + |item: &mut attribute_context::HttpRequest| f(item), )); }, )); @@ -57,6 +57,12 @@ mod tests { }) } + fn create_test_request_with_headers(headers: HashMap) -> CheckRequest { + return create_request(|item: &mut attribute_context::HttpRequest| { + item.headers = headers; + }); + } + #[test] fn test_cedar_authorizer_allows_valid_token() { let authorizer = CedarAuthorizer::new(); -- cgit v1.2.3 From 081dafdebcb7369b918f483dd135219980160304 Mon Sep 17 00:00:00 2001 From: mo khan Date: Fri, 20 Jun 2025 14:54:21 -0600 Subject: test: delegate to create_request helper --- src/authorization/cedar_authorizer.rs | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) (limited to 'src/authorization') diff --git a/src/authorization/cedar_authorizer.rs b/src/authorization/cedar_authorizer.rs index 49659d35..44bc9e06 100644 --- a/src/authorization/cedar_authorizer.rs +++ b/src/authorization/cedar_authorizer.rs @@ -38,31 +38,20 @@ impl Authorizer for CedarAuthorizer { #[cfg(test)] mod tests { use super::*; - use envoy_types::pb::envoy::service::auth::v3::{AttributeContext, attribute_context}; + use envoy_types::pb::envoy::service::auth::v3::AttributeContext; + use envoy_types::pb::envoy::service::auth::v3::attribute_context::{HttpRequest, Request}; use std::collections::HashMap; - fn create_request( - f: impl std::ops::FnOnce(&mut attribute_context::HttpRequest), - ) -> CheckRequest { + fn create_request(f: impl std::ops::FnOnce(&mut HttpRequest)) -> CheckRequest { please::build_with(|item: &mut CheckRequest| { item.attributes = Some(please::build_with(|item: &mut AttributeContext| { - item.request = Some(please::build_with( - |item: &mut attribute_context::Request| { - item.http = Some(please::build_with( - |item: &mut attribute_context::HttpRequest| f(item), - )); - }, - )); + item.request = Some(please::build_with(|item: &mut Request| { + item.http = Some(please::build_with(|item: &mut HttpRequest| f(item))); + })); })); }) } - fn create_test_request_with_headers(headers: HashMap) -> CheckRequest { - return create_request(|item: &mut attribute_context::HttpRequest| { - item.headers = headers; - }); - } - #[test] fn test_cedar_authorizer_allows_valid_token() { let authorizer = CedarAuthorizer::new(); @@ -71,7 +60,9 @@ mod tests { "authorization".to_string(), "Bearer valid-token".to_string(), ); - let request = create_test_request_with_headers(headers); + let request = create_request(|item: &mut HttpRequest| { + item.headers = headers; + }); let result = authorizer.authorize(request); assert!(result); @@ -85,7 +76,9 @@ mod tests { "authorization".to_string(), "Bearer invalid-token".to_string(), ); - let request = create_test_request_with_headers(headers); + let request = create_request(|item: &mut HttpRequest| { + item.headers = headers; + }); let result = authorizer.authorize(request); assert!(!result); @@ -95,7 +88,9 @@ mod tests { fn test_cedar_authorizer_denies_missing_header() { let authorizer = CedarAuthorizer::new(); let headers = HashMap::new(); - let request = create_test_request_with_headers(headers); + let request = create_request(|item: &mut HttpRequest| { + item.headers = headers; + }); let result = authorizer.authorize(request); assert!(!result); -- cgit v1.2.3 From 85490a4cfa7f3836d3d2f1e7cbfe48b668aa484b Mon Sep 17 00:00:00 2001 From: mo khan Date: Tue, 24 Jun 2025 14:36:58 -0600 Subject: feat: connect check service to a minimal cedar policy --- Cargo.lock | 1234 ++++++++++++++++++++++++++++++++- Cargo.toml | 9 +- mise.toml | 6 - policies/auth_policy.cedar | 23 + src/authorization/authorizer.rs | 2 +- src/authorization/cedar_authorizer.rs | 123 +++- src/authorization/check_service.rs | 29 +- src/main.rs | 8 +- tests/integration_tests.rs | 15 +- 9 files changed, 1381 insertions(+), 68 deletions(-) delete mode 100644 mise.toml create mode 100644 policies/auth_policy.cedar (limited to 'src/authorization') diff --git a/Cargo.lock b/Cargo.lock index 9ceb88cf..45af23e3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,12 +26,42 @@ dependencies = [ "memchr", ] +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "anyhow" version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + +[[package]] +name = "ascii-canvas" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef1e3e699d84ab1b0911a1010c5c106aa34ae89aeac103be5ce0c3859db1e891" +dependencies = [ + "term", +] + [[package]] name = "async-stream" version = "0.3.6" @@ -75,6 +105,7 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" name = "authzd" version = "0.1.0" dependencies = [ + "cedar-policy", "envoy-types", "please", "tokio", @@ -85,6 +116,12 @@ dependencies = [ "tonic-reflection", ] +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + [[package]] name = "axum" version = "0.8.4" @@ -142,7 +179,7 @@ dependencies = [ "miniz_oxide", "object", "rustc-demangle", - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -151,30 +188,319 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "beef" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1" + +[[package]] +name = "bit-set" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" + [[package]] name = "bitflags" version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "borsh" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad8646f98db542e39fc66e68a20b2144f6a732636df7c2354e74645faaa433ce" +dependencies = [ + "cfg_aliases", +] + +[[package]] +name = "bumpalo" +version = "3.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" + [[package]] name = "bytes" version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +[[package]] +name = "cc" +version = "1.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc" +dependencies = [ + "shlex", +] + +[[package]] +name = "cedar-policy" +version = "4.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d37df3afde553492d8413d02a733e86a786c29f5b36c6d8d72bc6e5c0c7f63" +dependencies = [ + "cedar-policy-core", + "cedar-policy-formatter", + "cedar-policy-validator", + "itertools 0.14.0", + "lalrpop-util", + "lazy_static", + "miette", + "nonempty", + "ref-cast", + "semver", + "serde", + "serde_json", + "serde_with", + "smol_str", + "thiserror", +] + +[[package]] +name = "cedar-policy-core" +version = "4.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd896075d493e8283e960c94cf85d85773dc3359cf948a5f5ea88a6f249e8665" +dependencies = [ + "chrono", + "educe", + "either", + "itertools 0.14.0", + "lalrpop", + "lalrpop-util", + "lazy_static", + "miette", + "nonempty", + "ref-cast", + "regex", + "rustc_lexer", + "serde", + "serde_json", + "serde_with", + "smol_str", + "stacker", + "thiserror", +] + +[[package]] +name = "cedar-policy-formatter" +version = "4.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95db50a024d5ed3efe4b9b513124b564313716ada017860c17995ec227ab46b1" +dependencies = [ + "cedar-policy-core", + "itertools 0.14.0", + "lazy_static", + "logos", + "miette", + "pretty", + "regex", + "smol_str", +] + +[[package]] +name = "cedar-policy-validator" +version = "4.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f40762e669e4ec5a4b3a2b3d3aa2567d768aa74b735760f13197312c1150f69" +dependencies = [ + "cedar-policy-core", + "educe", + "itertools 0.14.0", + "lalrpop", + "lalrpop-util", + "lazy_static", + "miette", + "nonempty", + "ref-cast", + "serde", + "serde_json", + "serde_with", + "smol_str", + "stacker", + "thiserror", + "unicode-security", +] + [[package]] name = "cfg-if" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chrono" +version = "0.4.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "num-traits", + "serde", + "windows-link", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "deranged" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" +dependencies = [ + "powerfmt", + "serde", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "dyn-clone" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c7a8fb8a9fbf66c1f703fe16184d10ca0ee9d23be5b4436400408ba54a95005" + +[[package]] +name = "educe" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "either" version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +[[package]] +name = "ena" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d248bdd43ce613d87415282f69b9bb99d947d290b10962dd6c56233312c2ad5" +dependencies = [ + "log", +] + +[[package]] +name = "enum-ordinalize" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea0dcfa4e54eeb516fe454635a95753ddd39acda650ce703031c6973e315dd5" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "envoy-types" version = "0.6.0" @@ -194,12 +520,12 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.12" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" +checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -214,6 +540,12 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" +[[package]] +name = "fixedbitset" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" + [[package]] name = "fnv" version = "1.0.7" @@ -259,6 +591,16 @@ dependencies = [ "pin-utils", ] +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "getrandom" version = "0.3.3" @@ -289,13 +631,19 @@ dependencies = [ "futures-core", "futures-sink", "http", - "indexmap", + "indexmap 2.9.0", "slab", "tokio", "tokio-util", "tracing", ] +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + [[package]] name = "hashbrown" version = "0.15.4" @@ -308,6 +656,21 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "home" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" +dependencies = [ + "windows-sys 0.59.0", +] + [[package]] name = "http" version = "1.3.1" @@ -409,6 +772,47 @@ dependencies = [ "tracing", ] +[[package]] +name = "iana-time-zone" +version = "0.1.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + [[package]] name = "indexmap" version = "2.9.0" @@ -416,7 +820,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.15.4", + "serde", ] [[package]] @@ -443,6 +848,63 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +[[package]] +name = "js-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lalrpop" +version = "0.22.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba4ebbd48ce411c1d10fb35185f5a51a7bfa3d8b24b4e330d30c9e3a34129501" +dependencies = [ + "ascii-canvas", + "bit-set", + "ena", + "itertools 0.14.0", + "lalrpop-util", + "petgraph 0.7.1", + "pico-args", + "regex", + "regex-syntax", + "sha3", + "string_cache", + "term", + "unicode-xid", + "walkdir", +] + +[[package]] +name = "lalrpop-util" +version = "0.22.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5baa5e9ff84f1aefd264e6869907646538a52147a755d494517a8007fb48733" +dependencies = [ + "regex-automata", + "rustversion", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + [[package]] name = "libc" version = "0.2.174" @@ -455,6 +917,16 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" +[[package]] +name = "lock_api" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +dependencies = [ + "autocfg", + "scopeguard", +] + [[package]] name = "log" version = "0.4.27" @@ -462,17 +934,74 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] -name = "matchit" -version = "0.8.4" +name = "logos" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" +checksum = "ab6f536c1af4c7cc81edf73da1f8029896e7e1e16a219ef09b184e76a296f3db" +dependencies = [ + "logos-derive", +] [[package]] -name = "memchr" -version = "2.7.5" +name = "logos-codegen" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" - +checksum = "189bbfd0b61330abea797e5e9276408f2edbe4f822d7ad08685d67419aafb34e" +dependencies = [ + "beef", + "fnv", + "lazy_static", + "proc-macro2", + "quote", + "regex-syntax", + "rustc_version", + "syn", +] + +[[package]] +name = "logos-derive" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebfe8e1a19049ddbfccbd14ac834b215e11b85b90bab0c2dba7c7b92fb5d5cba" +dependencies = [ + "logos-codegen", +] + +[[package]] +name = "matchit" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" + +[[package]] +name = "memchr" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" + +[[package]] +name = "miette" +version = "7.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f98efec8807c63c752b5bd61f862c165c115b0a35685bdcfd9238c7aeb592b7" +dependencies = [ + "cfg-if", + "miette-derive", + "serde", + "unicode-width", +] + +[[package]] +name = "miette-derive" +version = "7.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db5b29714e950dbb20d5e6f74f9dcec4edbcc1067bb7f8ed198c097b8c1a818b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "mime" version = "0.3.17" @@ -505,6 +1034,36 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084" +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + +[[package]] +name = "nonempty" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "303e8749c804ccd6ca3b428de7fe0d86cb86bc7606bc15291f100fd487960bb8" +dependencies = [ + "serde", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + [[package]] name = "object" version = "0.36.7" @@ -520,6 +1079,29 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[package]] +name = "parking_lot" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.6", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -532,10 +1114,35 @@ version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ - "fixedbitset", - "indexmap", + "fixedbitset 0.4.2", + "indexmap 2.9.0", ] +[[package]] +name = "petgraph" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772" +dependencies = [ + "fixedbitset 0.5.7", + "indexmap 2.9.0", +] + +[[package]] +name = "phf_shared" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pico-args" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" + [[package]] name = "pin-project" version = "1.1.10" @@ -573,11 +1180,34 @@ name = "please" version = "0.1.0" source = "git+https://github.com/xlgmokha/please.git#bff13caf9ee2f806dd32c5d77f0e4ac9eb28c7f5" +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + +[[package]] +name = "pretty" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac98773b7109bc75f475ab5a134c9b64b87e59d776d31098d8f346922396a477" +dependencies = [ + "arrayvec", + "typed-arena", + "unicode-width", +] + [[package]] name = "prettyplease" -version = "0.2.34" +version = "0.2.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6837b9e10d61f45f987d50808f83d1ee3d206c66acf650c3e4ae2e1f6ddedf55" +checksum = "061c1221631e079b26479d25bbf2275bfe5917ae8419cd7e34f13bfc2aa7539a" dependencies = [ "proc-macro2", "syn", @@ -624,7 +1254,7 @@ dependencies = [ "log", "multimap", "once_cell", - "petgraph", + "petgraph 0.6.5", "prettyplease", "prost 0.12.6", "prost-types 0.12.6", @@ -677,6 +1307,15 @@ dependencies = [ "prost 0.13.5", ] +[[package]] +name = "psm" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e944464ec8536cd1beb0bbfd96987eb5e3b72f2ecdafdc5c769a37f1fa2ae1f" +dependencies = [ + "cc", +] + [[package]] name = "quote" version = "1.0.40" @@ -692,6 +1331,35 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "redox_syscall" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" +dependencies = [ + "bitflags", +] + +[[package]] +name = "ref-cast" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "regex" version = "1.11.1" @@ -727,6 +1395,24 @@ version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" +[[package]] +name = "rustc_lexer" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c86aae0c77166108c01305ee1a36a1e77289d7dc6ca0a3cd91ff4992de2d16a5" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + [[package]] name = "rustix" version = "1.0.7" @@ -746,6 +1432,45 @@ version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schemars" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "semver" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" + [[package]] name = "serde" version = "1.0.219" @@ -766,6 +1491,72 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_json" +version = "1.0.140" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +dependencies = [ + "indexmap 2.9.0", + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_with" +version = "3.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf65a400f8f66fb7b0552869ad70157166676db75ed8181f8104ea91cf9d0b42" +dependencies = [ + "base64", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.9.0", + "schemars", + "serde", + "serde_derive", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81679d9ed988d5e9a5e6531dc3f2c28efbd639cbd1dfb628df08edea6004da77" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest", + "keccak", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "siphasher" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" + [[package]] name = "slab" version = "0.4.10" @@ -778,6 +1569,16 @@ version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +[[package]] +name = "smol_str" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9676b89cd56310a87b93dec47b11af744f34d5fc9f367b829474eec0a891350d" +dependencies = [ + "borsh", + "serde", +] + [[package]] name = "socket2" version = "0.5.10" @@ -788,11 +1589,42 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "stacker" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cddb07e32ddb770749da91081d8d0ac3a16f1a569a18b20348cd371f5dead06b" +dependencies = [ + "cc", + "cfg-if", + "libc", + "psm", + "windows-sys 0.59.0", +] + +[[package]] +name = "string_cache" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f" +dependencies = [ + "new_debug_unreachable", + "parking_lot", + "phf_shared", + "precomputed-hash", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "syn" -version = "2.0.103" +version = "2.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4307e30089d6fd6aff212f2da3a1f9e32f3223b1f010fb09b7c95f90f3ca1e8" +checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" dependencies = [ "proc-macro2", "quote", @@ -818,6 +1650,82 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "term" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a984c8d058c627faaf5e8e2ed493fa3c51771889196de1016cf9c1c6e90d750" +dependencies = [ + "home", + "windows-sys 0.59.0", +] + +[[package]] +name = "thiserror" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "time" +version = "0.3.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" + +[[package]] +name = "time-macros" +version = "0.2.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinyvec" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + [[package]] name = "tokio" version = "1.45.1" @@ -958,7 +1866,7 @@ checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" dependencies = [ "futures-core", "futures-util", - "indexmap", + "indexmap 2.9.0", "pin-project-lite", "slab", "sync_wrapper", @@ -1018,12 +1926,77 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "typed-arena" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" + +[[package]] +name = "typenum" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" + [[package]] name = "unicode-ident" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +[[package]] +name = "unicode-normalization" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-script" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb421b350c9aff471779e262955939f565ec18b86c15364e6bdf0d662ca7c1f" + +[[package]] +name = "unicode-security" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e4ddba1535dd35ed8b61c52166b7155d7f4e4b8847cec6f48e71dc66d8b5e50" +dependencies = [ + "unicode-normalization", + "unicode-script", +] + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "want" version = "0.3.1" @@ -1048,13 +2021,139 @@ dependencies = [ "wit-bindgen-rt", ] +[[package]] +name = "wasm-bindgen" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "windows-core" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", ] [[package]] @@ -1063,7 +2162,16 @@ version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.2", ] [[package]] @@ -1072,14 +2180,30 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef" +dependencies = [ + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", ] [[package]] @@ -1088,48 +2212,96 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + [[package]] name = "wit-bindgen-rt" version = "0.39.0" diff --git a/Cargo.toml b/Cargo.toml index 5eeecac3..415f3806 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,13 +12,14 @@ name = "authzd" path = "src/lib.rs" [dependencies] +cedar-policy = "4.4.1" envoy-types = "0.6.0" please = { git = "https://github.com/xlgmokha/please.git", version = "0.1.0" } -tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] } -tonic = "*" +tokio = { version = "1.0.0", features = ["macros", "rt-multi-thread"] } +tonic = "0.13.1" tonic-health = "0.13.1" tonic-reflection = "0.13.1" [dev-dependencies] -tokio-test = "0.4" -tonic-build = "0.10" +tokio-test = "0.4.0" +tonic-build = "0.10.0" diff --git a/mise.toml b/mise.toml deleted file mode 100644 index c466bc2b..00000000 --- a/mise.toml +++ /dev/null @@ -1,6 +0,0 @@ -[tools] -cargo = "latest" -grpcurl = "latest" -make = "latest" -rust = "stable" -yamlfmt = "latest" diff --git a/policies/auth_policy.cedar b/policies/auth_policy.cedar new file mode 100644 index 00000000..27e2bd1b --- /dev/null +++ b/policies/auth_policy.cedar @@ -0,0 +1,23 @@ +// Authorization policies for the authzd service + +// Allow requests with valid Bearer tokens +permit(principal, action == Action::"check", resource) +when { + context has bearer_token && + context.bearer_token == "valid-token" +}; + +// Allow static assets to pass through without authentication +permit(principal, action == Action::"check", resource) +when { + context has path && + (context.path like "*.css" || + context.path like "*.js" || + context.path like "*.ico" || + context.path like "*.png" || + context.path like "*.jpg" || + context.path like "*.jpeg" || + context.path like "*.gif" || + context.path like "*.bmp" || + context.path like "*.html") +}; \ No newline at end of file diff --git a/src/authorization/authorizer.rs b/src/authorization/authorizer.rs index 0f700ba7..14a7df27 100644 --- a/src/authorization/authorizer.rs +++ b/src/authorization/authorizer.rs @@ -1,5 +1,5 @@ use envoy_types::ext_authz::v3::pb::CheckRequest; -pub trait Authorizer { +pub trait Authorizer: std::fmt::Debug { fn authorize(&self, request: CheckRequest) -> bool; } diff --git a/src/authorization/cedar_authorizer.rs b/src/authorization/cedar_authorizer.rs index 44bc9e06..577b75ba 100644 --- a/src/authorization/cedar_authorizer.rs +++ b/src/authorization/cedar_authorizer.rs @@ -1,11 +1,28 @@ use super::authorizer::Authorizer; +use cedar_policy::{ + Authorizer as CedarAuth, Context, Entities, EntityId, EntityTypeName, EntityUid, PolicySet, + Request as CedarRequest, RestrictedExpression, +}; use envoy_types::ext_authz::v3::pb::CheckRequest; +use std::collections::HashMap; +use std::str::FromStr; -pub struct CedarAuthorizer {} +#[derive(Debug)] +pub struct CedarAuthorizer { + policies: PolicySet, + authorizer: CedarAuth, +} impl CedarAuthorizer { pub fn new() -> CedarAuthorizer { - CedarAuthorizer {} + let policy_src = include_str!("../../policies/auth_policy.cedar"); + let policies = policy_src.parse().expect("Failed to parse Cedar policies"); + let authorizer = CedarAuth::new(); + + CedarAuthorizer { + policies, + authorizer, + } } } @@ -17,21 +34,83 @@ impl Default for CedarAuthorizer { impl Authorizer for CedarAuthorizer { fn authorize(&self, request: CheckRequest) -> bool { - let headers = request + let headers = match request .attributes .as_ref() .and_then(|attr| attr.request.as_ref()) .and_then(|req| req.http.as_ref()) .map(|http| &http.headers) - .unwrap(); - - if let Some(authorization) = headers.get("authorization") { - if authorization == "Bearer valid-token" { - return true; + { + Some(headers) => headers, + None => return false, + }; + + // Extract authorization token + let bearer_token = headers + .get("authorization") + .and_then(|auth| auth.strip_prefix("Bearer ")) + .unwrap_or(""); + + // Extract request path for static asset checking + let path = headers + .get(":path") + .or_else(|| headers.get("path")) + .map_or("", |v| v.as_str()); + + // Create Cedar entities and request + match self.create_cedar_request(bearer_token, path) { + Ok(cedar_request) => { + let entities = Entities::empty(); + let response = + self.authorizer + .is_authorized(&cedar_request, &self.policies, &entities); + matches!(response.decision(), cedar_policy::Decision::Allow) } + Err(_) => false, } + } +} - false +impl CedarAuthorizer { + fn create_cedar_request( + &self, + bearer_token: &str, + path: &str, + ) -> Result> { + // Create principal entity + let principal_id = EntityId::from_str("client")?; + let principal_type = EntityTypeName::from_str("User")?; + let principal = EntityUid::from_type_name_and_id(principal_type, principal_id); + + // Create action entity + let action_id = EntityId::from_str("check")?; + let action_type = EntityTypeName::from_str("Action")?; + let action = EntityUid::from_type_name_and_id(action_type, action_id); + + // Create resource entity + let resource_id = EntityId::from_str("resource")?; + let resource_type = EntityTypeName::from_str("Resource")?; + let resource = EntityUid::from_type_name_and_id(resource_type, resource_id); + + // Create context with bearer token and path + let mut context_map = HashMap::new(); + if !bearer_token.is_empty() { + context_map.insert( + "bearer_token".to_string(), + RestrictedExpression::from_str(&format!("\"{}\"", bearer_token))?, + ); + } + if !path.is_empty() { + context_map.insert( + "path".to_string(), + RestrictedExpression::from_str(&format!("\"{}\"", path))?, + ); + } + + let context = Context::from_pairs(context_map.into_iter().collect::>())?; + + CedarRequest::new(principal, action, resource, context, None) + .map_err(|e| Box::new(e) as Box) } } @@ -96,6 +175,32 @@ mod tests { assert!(!result); } + #[test] + fn test_cedar_authorizer_allows_static_assets() { + let authorizer = CedarAuthorizer::new(); + let mut headers = HashMap::new(); + headers.insert(":path".to_string(), "/static/style.css".to_string()); + let request = create_request(|item: &mut HttpRequest| { + item.headers = headers; + }); + + let result = authorizer.authorize(request); + assert!(result); + } + + #[test] + fn test_cedar_authorizer_allows_js_assets() { + let authorizer = CedarAuthorizer::new(); + let mut headers = HashMap::new(); + headers.insert(":path".to_string(), "/app.js".to_string()); + let request = create_request(|item: &mut HttpRequest| { + item.headers = headers; + }); + + let result = authorizer.authorize(request); + assert!(result); + } + // test css passthrough // test javascript passthrough // test ico passthrough diff --git a/src/authorization/check_service.rs b/src/authorization/check_service.rs index 7ca39fcd..a4d0ec7b 100644 --- a/src/authorization/check_service.rs +++ b/src/authorization/check_service.rs @@ -1,12 +1,20 @@ use envoy_types::ext_authz::v3::CheckResponseExt; use envoy_types::ext_authz::v3::pb::{CheckRequest, CheckResponse}; +use std::sync::Arc; use tonic::{Request, Response, Status}; use super::authorizer::Authorizer; -use super::cedar_authorizer::CedarAuthorizer; -#[derive(Debug, Default)] -pub struct CheckService; +#[derive(Debug)] +pub struct CheckService { + authorizer: Arc, +} + +impl CheckService { + pub fn new(authorizer: Arc) -> Self { + Self { authorizer } + } +} #[tonic::async_trait] impl envoy_types::ext_authz::v3::pb::Authorization for CheckService { @@ -16,8 +24,7 @@ impl envoy_types::ext_authz::v3::pb::Authorization for CheckService { ) -> Result, Status> { let request = request.into_inner(); - let authorizer = CedarAuthorizer::new(); - if authorizer.authorize(request) { + if self.authorizer.authorize(request) { Ok(Response::new(CheckResponse::with_status(Status::ok("OK")))) } else { Ok(Response::new(CheckResponse::with_status( @@ -30,9 +37,11 @@ impl envoy_types::ext_authz::v3::pb::Authorization for CheckService { #[cfg(test)] mod tests { use super::*; + use super::super::cedar_authorizer::CedarAuthorizer; use envoy_types::ext_authz::v3::pb::{Authorization, CheckRequest}; use envoy_types::pb::envoy::service::auth::v3::{AttributeContext, attribute_context}; use std::collections::HashMap; + use std::sync::Arc; use tonic::Request; fn create_test_request_with_headers(headers: HashMap) -> Request { @@ -68,7 +77,8 @@ mod tests { #[tokio::test] async fn test_check_allows_valid_bearer_token() { let token = String::from("valid-token"); - let server = CheckService::default(); + let authorizer = Arc::new(CedarAuthorizer::new()); + let server = CheckService::new(authorizer); let headers = create_headers_with_auth(&format!("Bearer {}", token)); let request = create_test_request_with_headers(headers); @@ -78,12 +88,13 @@ mod tests { let check_response = response.unwrap().into_inner(); assert!(check_response.status.is_some()); let status = check_response.status.unwrap(); - assert_eq!(status.code, tonic::Code::Ok.into()); + assert_eq!(status.code, tonic::Code::Ok as i32); } #[tokio::test] async fn test_check_denies_invalid_bearer_token() { - let server = CheckService::default(); + let authorizer = Arc::new(CedarAuthorizer::new()); + let server = CheckService::new(authorizer); let request = create_test_request_with_headers(HashMap::new()); let response = server.check(request).await; @@ -92,6 +103,6 @@ mod tests { let check_response = response.unwrap().into_inner(); assert!(check_response.status.is_some()); let status = check_response.status.unwrap(); - assert_eq!(status.code, tonic::Code::Unauthenticated.into()); + assert_eq!(status.code, tonic::Code::Unauthenticated as i32); } } diff --git a/src/main.rs b/src/main.rs index 57f98b9a..8eb7b5ef 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,9 @@ use envoy_types::ext_authz::v3::pb::AuthorizationServer; +use std::sync::Arc; use tonic::transport::Server; pub mod authorization; -use authorization::CheckService; +use authorization::{CedarAuthorizer, CheckService}; #[tokio::main] async fn main() -> Result<(), Box> { @@ -10,8 +11,11 @@ async fn main() -> Result<(), Box> { let (_health_reporter, health_service) = tonic_health::server::health_reporter(); + let authorizer = Arc::new(CedarAuthorizer::new()); + let check_service = CheckService::new(authorizer); + Server::builder() - .add_service(AuthorizationServer::new(CheckService::default())) + .add_service(AuthorizationServer::new(check_service)) .add_service(health_service) .add_service( tonic_reflection::server::Builder::configure() diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index a3603c11..9bbeaea5 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -1,11 +1,13 @@ -use authzd::CheckService; +use authzd::{CedarAuthorizer, CheckService}; use envoy_types::ext_authz::v3::pb::Authorization; +use std::sync::Arc; mod common; #[tokio::test] async fn test_success_response() { - let server = CheckService::default(); + let authorizer = Arc::new(CedarAuthorizer::new()); + let server = CheckService::new(authorizer); let headers = common::create_headers_with_auth("Bearer valid-token"); let request = common::create_test_request_with_headers(headers); @@ -17,12 +19,13 @@ async fn test_success_response() { assert!(check_response.status.is_some()); let status = check_response.status.unwrap(); - assert_eq!(status.code, tonic::Code::Ok.into()); + assert_eq!(status.code, tonic::Code::Ok as i32); } #[tokio::test] async fn test_multiple() { - let server = CheckService::default(); + let authorizer = Arc::new(CedarAuthorizer::new()); + let server = CheckService::new(authorizer); let test_cases = vec![ ("Bearer valid-token", true), @@ -42,9 +45,9 @@ async fn test_multiple() { let status = check_response.status.unwrap(); if should_succeed { - assert_eq!(status.code, tonic::Code::Ok.into()); + assert_eq!(status.code, tonic::Code::Ok as i32); } else { - assert_eq!(status.code, tonic::Code::Unauthenticated.into()); + assert_eq!(status.code, tonic::Code::Unauthenticated as i32); } } } -- cgit v1.2.3 From d4e3bb8f30c4b9edeb392881bd7b4a6baf79d415 Mon Sep 17 00:00:00 2001 From: mo khan Date: Tue, 24 Jun 2025 16:41:03 -0600 Subject: refactor: copy duplicate test helper method --- src/authorization/check_service.rs | 59 ++++++++++++++++---------------------- src/lib.rs | 1 - src/main.rs | 13 ++++----- 3 files changed, 30 insertions(+), 43 deletions(-) (limited to 'src/authorization') diff --git a/src/authorization/check_service.rs b/src/authorization/check_service.rs index a4d0ec7b..c0a05e21 100644 --- a/src/authorization/check_service.rs +++ b/src/authorization/check_service.rs @@ -36,51 +36,38 @@ impl envoy_types::ext_authz::v3::pb::Authorization for CheckService { #[cfg(test)] mod tests { - use super::*; use super::super::cedar_authorizer::CedarAuthorizer; + use super::*; use envoy_types::ext_authz::v3::pb::{Authorization, CheckRequest}; - use envoy_types::pb::envoy::service::auth::v3::{AttributeContext, attribute_context}; + use envoy_types::pb::envoy::service::auth::v3::AttributeContext; + use envoy_types::pb::envoy::service::auth::v3::attribute_context::{HttpRequest, Request}; use std::collections::HashMap; use std::sync::Arc; - use tonic::Request; - - fn create_test_request_with_headers(headers: HashMap) -> Request { - let http_request = attribute_context::HttpRequest { - headers, - ..Default::default() - }; - - let request_context = attribute_context::Request { - http: Some(http_request), - ..Default::default() - }; - - let attributes = AttributeContext { - request: Some(request_context), - ..Default::default() - }; - - let check_request = CheckRequest { - attributes: Some(attributes), - ..Default::default() - }; - Request::new(check_request) + pub fn create_request(f: impl std::ops::FnOnce(&mut HttpRequest)) -> CheckRequest { + please::build_with(|item: &mut CheckRequest| { + item.attributes = Some(please::build_with(|item: &mut AttributeContext| { + item.request = Some(please::build_with(|item: &mut Request| { + item.http = Some(please::build_with(|item: &mut HttpRequest| f(item))); + })); + })); + }) } - fn create_headers_with_auth(auth_value: &str) -> HashMap { - let mut headers = HashMap::new(); - headers.insert("authorization".to_string(), auth_value.to_string()); - headers + pub fn create_token() -> String { + return String::from("valid-token"); } #[tokio::test] async fn test_check_allows_valid_bearer_token() { - let token = String::from("valid-token"); - let authorizer = Arc::new(CedarAuthorizer::new()); - let server = CheckService::new(authorizer); - let headers = create_headers_with_auth(&format!("Bearer {}", token)); - let request = create_test_request_with_headers(headers); + let token = create_token(); + let server = CheckService::new(Arc::new(CedarAuthorizer::new())); + + let mut headers = HashMap::new(); + headers.insert("authorization".to_string(), format!("Bearer {}", token)); + let request = tonic::Request::new(create_request(|item: &mut HttpRequest| { + item.headers = headers; + })); let response = server.check(request).await; @@ -95,7 +82,9 @@ mod tests { async fn test_check_denies_invalid_bearer_token() { let authorizer = Arc::new(CedarAuthorizer::new()); let server = CheckService::new(authorizer); - let request = create_test_request_with_headers(HashMap::new()); + let request = tonic::Request::new(create_request(|item: &mut HttpRequest| { + item.headers = HashMap::new(); + })); let response = server.check(request).await; diff --git a/src/lib.rs b/src/lib.rs index c24db79b..210699b5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,2 @@ pub mod authorization; - pub use authorization::{Authorizer, CedarAuthorizer, CheckService}; diff --git a/src/main.rs b/src/main.rs index 8eb7b5ef..8fa32b33 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,18 +1,17 @@ -use envoy_types::ext_authz::v3::pb::AuthorizationServer; -use std::sync::Arc; -use tonic::transport::Server; - pub mod authorization; -use authorization::{CedarAuthorizer, CheckService}; #[tokio::main] async fn main() -> Result<(), Box> { + use envoy_types::ext_authz::v3::pb::AuthorizationServer; + use std::sync::Arc; + use tonic::transport::Server; + let addr = "[::1]:50051".parse()?; let (_health_reporter, health_service) = tonic_health::server::health_reporter(); - let authorizer = Arc::new(CedarAuthorizer::new()); - let check_service = CheckService::new(authorizer); + let authorizer = Arc::new(authorization::CedarAuthorizer::new()); + let check_service = authorization::CheckService::new(authorizer); Server::builder() .add_service(AuthorizationServer::new(check_service)) -- cgit v1.2.3 From 654b31287617c56f8e148faabc63916e316f56c6 Mon Sep 17 00:00:00 2001 From: mo khan Date: Tue, 24 Jun 2025 16:42:01 -0600 Subject: test: remove commented out test --- policies/auth_policy.cedar | 2 +- src/authorization/cedar_authorizer.rs | 21 +-------------------- 2 files changed, 2 insertions(+), 21 deletions(-) (limited to 'src/authorization') diff --git a/policies/auth_policy.cedar b/policies/auth_policy.cedar index 27e2bd1b..c7eb6ce5 100644 --- a/policies/auth_policy.cedar +++ b/policies/auth_policy.cedar @@ -20,4 +20,4 @@ when { context.path like "*.gif" || context.path like "*.bmp" || context.path like "*.html") -}; \ No newline at end of file +}; diff --git a/src/authorization/cedar_authorizer.rs b/src/authorization/cedar_authorizer.rs index 577b75ba..19886222 100644 --- a/src/authorization/cedar_authorizer.rs +++ b/src/authorization/cedar_authorizer.rs @@ -179,7 +179,7 @@ mod tests { fn test_cedar_authorizer_allows_static_assets() { let authorizer = CedarAuthorizer::new(); let mut headers = HashMap::new(); - headers.insert(":path".to_string(), "/static/style.css".to_string()); + headers.insert(":path".to_string(), "/public/style.css".to_string()); let request = create_request(|item: &mut HttpRequest| { item.headers = headers; }); @@ -200,23 +200,4 @@ mod tests { let result = authorizer.authorize(request); assert!(result); } - - // test css passthrough - // test javascript passthrough - // test ico passthrough - // test png,jpg,bmp passthrough - // test html passthrough - // #[test] - // fn authorize_test_css_passthrough() { - // let authorizer = CedarAuthorizer::new(); - - // let request = CheckRequest { - // attributes: Some(AttributeContext { - // ..Default::default() - // }), - // }; - // let result = authorizer.authorize(request); - - // assert!(result) - // } } -- cgit v1.2.3 From d099e77eaa8e51eef14cd775234bfd4b12098a4c Mon Sep 17 00:00:00 2001 From: mo khan Date: Wed, 25 Jun 2025 14:20:33 -0600 Subject: test: move cedar_authorizer tests to integration test suite --- src/authorization/cedar_authorizer.rs | 88 ---------------------------- tests/authorization/cedar_authorizer_test.rs | 78 ++++++++++++++++++++++++ tests/authorization/mod.rs | 1 + tests/integration_tests.rs | 1 + 4 files changed, 80 insertions(+), 88 deletions(-) create mode 100644 tests/authorization/cedar_authorizer_test.rs create mode 100644 tests/authorization/mod.rs (limited to 'src/authorization') diff --git a/src/authorization/cedar_authorizer.rs b/src/authorization/cedar_authorizer.rs index 19886222..fb85012e 100644 --- a/src/authorization/cedar_authorizer.rs +++ b/src/authorization/cedar_authorizer.rs @@ -113,91 +113,3 @@ impl CedarAuthorizer { .map_err(|e| Box::new(e) as Box) } } - -#[cfg(test)] -mod tests { - use super::*; - use envoy_types::pb::envoy::service::auth::v3::AttributeContext; - use envoy_types::pb::envoy::service::auth::v3::attribute_context::{HttpRequest, Request}; - use std::collections::HashMap; - - fn create_request(f: impl std::ops::FnOnce(&mut HttpRequest)) -> CheckRequest { - please::build_with(|item: &mut CheckRequest| { - item.attributes = Some(please::build_with(|item: &mut AttributeContext| { - item.request = Some(please::build_with(|item: &mut Request| { - item.http = Some(please::build_with(|item: &mut HttpRequest| f(item))); - })); - })); - }) - } - - #[test] - fn test_cedar_authorizer_allows_valid_token() { - let authorizer = CedarAuthorizer::new(); - let mut headers = HashMap::new(); - headers.insert( - "authorization".to_string(), - "Bearer valid-token".to_string(), - ); - let request = create_request(|item: &mut HttpRequest| { - item.headers = headers; - }); - - let result = authorizer.authorize(request); - assert!(result); - } - - #[test] - fn test_cedar_authorizer_denies_invalid_token() { - let authorizer = CedarAuthorizer::new(); - let mut headers = HashMap::new(); - headers.insert( - "authorization".to_string(), - "Bearer invalid-token".to_string(), - ); - let request = create_request(|item: &mut HttpRequest| { - item.headers = headers; - }); - - let result = authorizer.authorize(request); - assert!(!result); - } - - #[test] - fn test_cedar_authorizer_denies_missing_header() { - let authorizer = CedarAuthorizer::new(); - let headers = HashMap::new(); - let request = create_request(|item: &mut HttpRequest| { - item.headers = headers; - }); - - let result = authorizer.authorize(request); - assert!(!result); - } - - #[test] - fn test_cedar_authorizer_allows_static_assets() { - let authorizer = CedarAuthorizer::new(); - let mut headers = HashMap::new(); - headers.insert(":path".to_string(), "/public/style.css".to_string()); - let request = create_request(|item: &mut HttpRequest| { - item.headers = headers; - }); - - let result = authorizer.authorize(request); - assert!(result); - } - - #[test] - fn test_cedar_authorizer_allows_js_assets() { - let authorizer = CedarAuthorizer::new(); - let mut headers = HashMap::new(); - headers.insert(":path".to_string(), "/app.js".to_string()); - let request = create_request(|item: &mut HttpRequest| { - item.headers = headers; - }); - - let result = authorizer.authorize(request); - assert!(result); - } -} diff --git a/tests/authorization/cedar_authorizer_test.rs b/tests/authorization/cedar_authorizer_test.rs new file mode 100644 index 00000000..2ed3dd68 --- /dev/null +++ b/tests/authorization/cedar_authorizer_test.rs @@ -0,0 +1,78 @@ +#[cfg(test)] +mod tests { + use crate::common::create_request; + use authzd::Authorizer; + use authzd::CedarAuthorizer; + use envoy_types::pb::envoy::service::auth::v3::attribute_context::HttpRequest; + use std::collections::HashMap; + + #[test] + fn test_cedar_authorizer_allows_valid_token() { + let authorizer = CedarAuthorizer::new(); + let mut headers = HashMap::new(); + headers.insert( + "authorization".to_string(), + "Bearer valid-token".to_string(), + ); + let request = create_request(|item: &mut HttpRequest| { + item.headers = headers; + }); + + let result = authorizer.authorize(request); + assert!(result); + } + + #[test] + fn test_cedar_authorizer_denies_invalid_token() { + let authorizer = CedarAuthorizer::new(); + let mut headers = HashMap::new(); + headers.insert( + "authorization".to_string(), + "Bearer invalid-token".to_string(), + ); + let request = create_request(|item: &mut HttpRequest| { + item.headers = headers; + }); + + let result = authorizer.authorize(request); + assert!(!result); + } + + #[test] + fn test_cedar_authorizer_denies_missing_header() { + let authorizer = CedarAuthorizer::new(); + let headers = HashMap::new(); + let request = create_request(|item: &mut HttpRequest| { + item.headers = headers; + }); + + let result = authorizer.authorize(request); + assert!(!result); + } + + #[test] + fn test_cedar_authorizer_allows_static_assets() { + let authorizer = CedarAuthorizer::new(); + let mut headers = HashMap::new(); + headers.insert(":path".to_string(), "/public/style.css".to_string()); + let request = create_request(|item: &mut HttpRequest| { + item.headers = headers; + }); + + let result = authorizer.authorize(request); + assert!(result); + } + + #[test] + fn test_cedar_authorizer_allows_js_assets() { + let authorizer = CedarAuthorizer::new(); + let mut headers = HashMap::new(); + headers.insert(":path".to_string(), "/app.js".to_string()); + let request = create_request(|item: &mut HttpRequest| { + item.headers = headers; + }); + + let result = authorizer.authorize(request); + assert!(result); + } +} diff --git a/tests/authorization/mod.rs b/tests/authorization/mod.rs new file mode 100644 index 00000000..a8aab73a --- /dev/null +++ b/tests/authorization/mod.rs @@ -0,0 +1 @@ +mod cedar_authorizer_test; diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index 9bbeaea5..2269c7f7 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -2,6 +2,7 @@ use authzd::{CedarAuthorizer, CheckService}; use envoy_types::ext_authz::v3::pb::Authorization; use std::sync::Arc; +mod authorization; mod common; #[tokio::test] -- cgit v1.2.3 From 86c9564a82f56b7c5ee60f4bff9fb07ca3e4a6eb Mon Sep 17 00:00:00 2001 From: mo khan Date: Wed, 25 Jun 2025 14:24:19 -0600 Subject: test: move unit tests to integration test suite to share code --- src/authorization/check_service.rs | 62 ------------------------------- tests/authorization/check_service_test.rs | 48 ++++++++++++++++++++++++ tests/authorization/mod.rs | 1 + tests/common/mod.rs | 4 ++ 4 files changed, 53 insertions(+), 62 deletions(-) create mode 100644 tests/authorization/check_service_test.rs (limited to 'src/authorization') diff --git a/src/authorization/check_service.rs b/src/authorization/check_service.rs index c0a05e21..6c6bd9c6 100644 --- a/src/authorization/check_service.rs +++ b/src/authorization/check_service.rs @@ -33,65 +33,3 @@ impl envoy_types::ext_authz::v3::pb::Authorization for CheckService { } } } - -#[cfg(test)] -mod tests { - use super::super::cedar_authorizer::CedarAuthorizer; - use super::*; - use envoy_types::ext_authz::v3::pb::{Authorization, CheckRequest}; - use envoy_types::pb::envoy::service::auth::v3::AttributeContext; - use envoy_types::pb::envoy::service::auth::v3::attribute_context::{HttpRequest, Request}; - use std::collections::HashMap; - use std::sync::Arc; - - pub fn create_request(f: impl std::ops::FnOnce(&mut HttpRequest)) -> CheckRequest { - please::build_with(|item: &mut CheckRequest| { - item.attributes = Some(please::build_with(|item: &mut AttributeContext| { - item.request = Some(please::build_with(|item: &mut Request| { - item.http = Some(please::build_with(|item: &mut HttpRequest| f(item))); - })); - })); - }) - } - - pub fn create_token() -> String { - return String::from("valid-token"); - } - - #[tokio::test] - async fn test_check_allows_valid_bearer_token() { - let token = create_token(); - let server = CheckService::new(Arc::new(CedarAuthorizer::new())); - - let mut headers = HashMap::new(); - headers.insert("authorization".to_string(), format!("Bearer {}", token)); - let request = tonic::Request::new(create_request(|item: &mut HttpRequest| { - item.headers = headers; - })); - - let response = server.check(request).await; - - assert!(response.is_ok()); - let check_response = response.unwrap().into_inner(); - assert!(check_response.status.is_some()); - let status = check_response.status.unwrap(); - assert_eq!(status.code, tonic::Code::Ok as i32); - } - - #[tokio::test] - async fn test_check_denies_invalid_bearer_token() { - let authorizer = Arc::new(CedarAuthorizer::new()); - let server = CheckService::new(authorizer); - let request = tonic::Request::new(create_request(|item: &mut HttpRequest| { - item.headers = HashMap::new(); - })); - - let response = server.check(request).await; - - assert!(response.is_ok()); - let check_response = response.unwrap().into_inner(); - assert!(check_response.status.is_some()); - let status = check_response.status.unwrap(); - assert_eq!(status.code, tonic::Code::Unauthenticated as i32); - } -} diff --git a/tests/authorization/check_service_test.rs b/tests/authorization/check_service_test.rs new file mode 100644 index 00000000..23655ffb --- /dev/null +++ b/tests/authorization/check_service_test.rs @@ -0,0 +1,48 @@ +#[cfg(test)] +mod tests { + use crate::common::create_request; + use crate::common::create_token; + use authzd::CedarAuthorizer; + use authzd::CheckService; + use envoy_types::ext_authz::v3::pb::Authorization; + use envoy_types::pb::envoy::service::auth::v3::attribute_context::HttpRequest; + use std::collections::HashMap; + use std::sync::Arc; + + #[tokio::test] + async fn test_check_allows_valid_bearer_token() { + let token = create_token(); + let server = CheckService::new(Arc::new(CedarAuthorizer::new())); + + let mut headers = HashMap::new(); + headers.insert("authorization".to_string(), format!("Bearer {}", token)); + let request = tonic::Request::new(create_request(|item: &mut HttpRequest| { + item.headers = headers; + })); + + let response = server.check(request).await; + + assert!(response.is_ok()); + let check_response = response.unwrap().into_inner(); + assert!(check_response.status.is_some()); + let status = check_response.status.unwrap(); + assert_eq!(status.code, tonic::Code::Ok as i32); + } + + #[tokio::test] + async fn test_check_denies_invalid_bearer_token() { + let authorizer = Arc::new(CedarAuthorizer::new()); + let server = CheckService::new(authorizer); + let request = tonic::Request::new(create_request(|item: &mut HttpRequest| { + item.headers = HashMap::new(); + })); + + let response = server.check(request).await; + + assert!(response.is_ok()); + let check_response = response.unwrap().into_inner(); + assert!(check_response.status.is_some()); + let status = check_response.status.unwrap(); + assert_eq!(status.code, tonic::Code::Unauthenticated as i32); + } +} diff --git a/tests/authorization/mod.rs b/tests/authorization/mod.rs index a8aab73a..a4ece924 100644 --- a/tests/authorization/mod.rs +++ b/tests/authorization/mod.rs @@ -1 +1,2 @@ mod cedar_authorizer_test; +mod check_service_test; diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 9b2370cb..4e879b6f 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -26,3 +26,7 @@ pub fn create_headers_with_auth(auth_value: &str) -> HashMap { headers.insert("authorization".to_string(), auth_value.to_string()); headers } + +pub fn create_token() -> String { + return String::from("valid-token"); +} -- cgit v1.2.3 From 031d4ba92e69966ae91bbebd9ec797e6c115c2f0 Mon Sep 17 00:00:00 2001 From: mo khan Date: Thu, 26 Jun 2025 14:04:57 -0600 Subject: feat: add some debug logging --- src/authorization/check_service.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/authorization') diff --git a/src/authorization/check_service.rs b/src/authorization/check_service.rs index 6c6bd9c6..a65d8d95 100644 --- a/src/authorization/check_service.rs +++ b/src/authorization/check_service.rs @@ -24,7 +24,7 @@ impl envoy_types::ext_authz::v3::pb::Authorization for CheckService { ) -> Result, Status> { let request = request.into_inner(); - if self.authorizer.authorize(request) { + if dbg!(self.authorizer.authorize(dbg!(request))) { Ok(Response::new(CheckResponse::with_status(Status::ok("OK")))) } else { Ok(Response::new(CheckResponse::with_status( -- cgit v1.2.3 From 91a989b761f97a70e76031988cf570ad5d209f47 Mon Sep 17 00:00:00 2001 From: mo khan Date: Thu, 26 Jun 2025 15:00:07 -0600 Subject: chore: add minimal basic logging --- Cargo.lock | 104 +++++++++++++++++++++++++++++++++++++ Cargo.toml | 3 ++ src/authorization/check_service.rs | 2 + src/main.rs | 4 +- 4 files changed, 112 insertions(+), 1 deletion(-) (limited to 'src/authorization') diff --git a/Cargo.lock b/Cargo.lock index 45af23e3..a1c069e6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -107,6 +107,7 @@ version = "0.1.0" dependencies = [ "cedar-policy", "envoy-types", + "log", "please", "tokio", "tokio-test", @@ -114,6 +115,8 @@ dependencies = [ "tonic-build", "tonic-health", "tonic-reflection", + "tracing", + "tracing-subscriber", ] [[package]] @@ -1049,6 +1052,16 @@ dependencies = [ "serde", ] +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num-conv" version = "0.1.0" @@ -1079,6 +1092,12 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "parking_lot" version = "0.12.4" @@ -1545,6 +1564,15 @@ dependencies = [ "keccak", ] +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + [[package]] name = "shlex" version = "1.3.0" @@ -1680,6 +1708,15 @@ dependencies = [ "syn", ] +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + [[package]] name = "time" version = "0.3.41" @@ -1918,6 +1955,45 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-serde" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1" +dependencies = [ + "serde", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" +dependencies = [ + "nu-ansi-term", + "serde", + "serde_json", + "sharded-slab", + "smallvec", + "thread_local", + "tracing-core", + "tracing-log", + "tracing-serde", ] [[package]] @@ -1981,6 +2057,12 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + [[package]] name = "version_check" version = "0.9.5" @@ -2079,6 +2161,22 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + [[package]] name = "winapi-util" version = "0.1.9" @@ -2088,6 +2186,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + [[package]] name = "windows-core" version = "0.61.2" diff --git a/Cargo.toml b/Cargo.toml index 415f3806..2ac42209 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,11 +14,14 @@ path = "src/lib.rs" [dependencies] cedar-policy = "4.4.1" envoy-types = "0.6.0" +log = "0.4.27" please = { git = "https://github.com/xlgmokha/please.git", version = "0.1.0" } tokio = { version = "1.0.0", features = ["macros", "rt-multi-thread"] } tonic = "0.13.1" tonic-health = "0.13.1" tonic-reflection = "0.13.1" +tracing = "0.1" +tracing-subscriber = { version = "0.3", features = ["json"] } [dev-dependencies] tokio-test = "0.4.0" diff --git a/src/authorization/check_service.rs b/src/authorization/check_service.rs index a65d8d95..d2dd1e17 100644 --- a/src/authorization/check_service.rs +++ b/src/authorization/check_service.rs @@ -25,8 +25,10 @@ impl envoy_types::ext_authz::v3::pb::Authorization for CheckService { let request = request.into_inner(); if dbg!(self.authorizer.authorize(dbg!(request))) { + log::info!("OK"); Ok(Response::new(CheckResponse::with_status(Status::ok("OK")))) } else { + log::info!("Unoauthorized"); Ok(Response::new(CheckResponse::with_status( Status::unauthenticated("Unauthorized"), ))) diff --git a/src/main.rs b/src/main.rs index 0a1cd5a5..d847a2ee 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,6 +6,8 @@ async fn main() -> Result<(), Box> { use std::sync::Arc; use tonic::transport::Server; + tracing_subscriber::fmt().json().init(); + let addr = std::env::var("BIND_ADDR") .unwrap_or_else(|_| "[::1]:50051".to_string()) .parse()?; @@ -25,7 +27,7 @@ async fn main() -> Result<(), Box> { .unwrap(), ); - println!("Listening on... {addr}"); + log::info!("Listening on... {addr}"); server.serve(addr).await?; Ok(()) -- cgit v1.2.3 From 187c02e9bf32f152cbca9fd5790f4a6070dbb37d Mon Sep 17 00:00:00 2001 From: mo khan Date: Thu, 26 Jun 2025 15:30:41 -0600 Subject: refactor: try to move policy files to /etc/authzd/ --- Dockerfile | 2 +- etc/authzd/policy0.cedar | 19 +++++++++++++++++++ policies/auth_policy.cedar | 23 ----------------------- src/authorization/cedar_authorizer.rs | 11 +++-------- src/main.rs | 2 +- tests/authorization/cedar_authorizer_test.rs | 10 +++++----- tests/authorization/check_service_test.rs | 4 ++-- tests/integration_tests.rs | 4 ++-- 8 files changed, 33 insertions(+), 42 deletions(-) create mode 100644 etc/authzd/policy0.cedar delete mode 100644 policies/auth_policy.cedar (limited to 'src/authorization') diff --git a/Dockerfile b/Dockerfile index 0faffb8e..744b4f3d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,5 +10,5 @@ FROM gcr.io/distroless/static-debian12:nonroot EXPOSE 50051 WORKDIR /var/www COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/authzd /bin/authzd -COPY --from=builder /app/policies /etc/authzd/policies +COPY --from=builder /app/etc/authzd /etc/authzd ENTRYPOINT ["/bin/authzd"] diff --git a/etc/authzd/policy0.cedar b/etc/authzd/policy0.cedar new file mode 100644 index 00000000..e01182c5 --- /dev/null +++ b/etc/authzd/policy0.cedar @@ -0,0 +1,19 @@ +permit(principal, action == Action::"check", resource) +when { + context has bearer_token && + context.bearer_token == "valid-token" +}; + +permit(principal, action == Action::"check", resource) +when { + context has path && + (context.path like "*.css" || + context.path like "*.js" || + context.path like "*.ico" || + context.path like "*.png" || + context.path like "*.jpg" || + context.path like "*.jpeg" || + context.path like "*.gif" || + context.path like "*.bmp" || + context.path like "*.html") +}; diff --git a/policies/auth_policy.cedar b/policies/auth_policy.cedar deleted file mode 100644 index c7eb6ce5..00000000 --- a/policies/auth_policy.cedar +++ /dev/null @@ -1,23 +0,0 @@ -// Authorization policies for the authzd service - -// Allow requests with valid Bearer tokens -permit(principal, action == Action::"check", resource) -when { - context has bearer_token && - context.bearer_token == "valid-token" -}; - -// Allow static assets to pass through without authentication -permit(principal, action == Action::"check", resource) -when { - context has path && - (context.path like "*.css" || - context.path like "*.js" || - context.path like "*.ico" || - context.path like "*.png" || - context.path like "*.jpg" || - context.path like "*.jpeg" || - context.path like "*.gif" || - context.path like "*.bmp" || - context.path like "*.html") -}; diff --git a/src/authorization/cedar_authorizer.rs b/src/authorization/cedar_authorizer.rs index fb85012e..568bafbc 100644 --- a/src/authorization/cedar_authorizer.rs +++ b/src/authorization/cedar_authorizer.rs @@ -14,21 +14,16 @@ pub struct CedarAuthorizer { } impl CedarAuthorizer { - pub fn new() -> CedarAuthorizer { - let policy_src = include_str!("../../policies/auth_policy.cedar"); - let policies = policy_src.parse().expect("Failed to parse Cedar policies"); - let authorizer = CedarAuth::new(); - + pub fn new(policies: cedar_policy::PolicySet) -> CedarAuthorizer { CedarAuthorizer { policies, - authorizer, + authorizer: CedarAuth::new(), } } } - impl Default for CedarAuthorizer { fn default() -> Self { - Self::new() + Self::new(PolicySet::default()) } } diff --git a/src/main.rs b/src/main.rs index d847a2ee..1a3ff00c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,7 +14,7 @@ async fn main() -> Result<(), Box> { let (_health_reporter, health_service) = tonic_health::server::health_reporter(); - let authorizer = Arc::new(authorization::CedarAuthorizer::new()); + let authorizer = Arc::new(authorization::CedarAuthorizer::default()); let check_service = authorization::CheckService::new(authorizer); let server = Server::builder() diff --git a/tests/authorization/cedar_authorizer_test.rs b/tests/authorization/cedar_authorizer_test.rs index b13f48ad..6e1591eb 100644 --- a/tests/authorization/cedar_authorizer_test.rs +++ b/tests/authorization/cedar_authorizer_test.rs @@ -8,7 +8,7 @@ mod tests { #[test] fn test_cedar_authorizer_allows_valid_token() { - let authorizer = CedarAuthorizer::new(); + let authorizer = CedarAuthorizer::default(); let request = create_request(|item: &mut HttpRequest| { item.headers = build_with(|item: &mut HashMap| { item.insert( @@ -23,7 +23,7 @@ mod tests { #[test] fn test_cedar_authorizer_denies_invalid_token() { - let authorizer = CedarAuthorizer::new(); + let authorizer = CedarAuthorizer::default(); let mut headers = HashMap::new(); headers.insert( "authorization".to_string(), @@ -39,7 +39,7 @@ mod tests { #[test] fn test_cedar_authorizer_denies_missing_header() { - let authorizer = CedarAuthorizer::new(); + let authorizer = CedarAuthorizer::default(); let headers = HashMap::new(); let request = create_request(|item: &mut HttpRequest| { item.headers = headers; @@ -51,7 +51,7 @@ mod tests { #[test] fn test_cedar_authorizer_allows_static_assets() { - let authorizer = CedarAuthorizer::new(); + let authorizer = CedarAuthorizer::default(); let mut headers = HashMap::new(); headers.insert(":path".to_string(), "/public/style.css".to_string()); let request = create_request(|item: &mut HttpRequest| { @@ -64,7 +64,7 @@ mod tests { #[test] fn test_cedar_authorizer_allows_js_assets() { - let authorizer = CedarAuthorizer::new(); + let authorizer = CedarAuthorizer::default(); let mut headers = HashMap::new(); headers.insert(":path".to_string(), "/app.js".to_string()); let request = create_request(|item: &mut HttpRequest| { diff --git a/tests/authorization/check_service_test.rs b/tests/authorization/check_service_test.rs index 0582417e..a739b16a 100644 --- a/tests/authorization/check_service_test.rs +++ b/tests/authorization/check_service_test.rs @@ -11,7 +11,7 @@ mod tests { #[tokio::test] async fn test_check_allows_valid_bearer_token() { let token = create_token(); - let server = CheckService::new(Arc::new(CedarAuthorizer::new())); + let server = CheckService::new(Arc::new(CedarAuthorizer::default())); let mut headers = HashMap::new(); headers.insert("authorization".to_string(), format!("Bearer {}", token)); @@ -30,7 +30,7 @@ mod tests { #[tokio::test] async fn test_check_denies_invalid_bearer_token() { - let authorizer = Arc::new(CedarAuthorizer::new()); + let authorizer = Arc::new(CedarAuthorizer::default()); let server = CheckService::new(authorizer); let request = tonic::Request::new(create_request(|item: &mut HttpRequest| { item.headers = HashMap::new(); diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index 56321acb..a265c2be 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -9,7 +9,7 @@ mod common; #[tokio::test] async fn test_success_response() { - let authorizer = Arc::new(CedarAuthorizer::new()); + let authorizer = Arc::new(CedarAuthorizer::default()); let server = CheckService::new(authorizer); let request = tonic::Request::new(factory_bot::create_request(|item: &mut HttpRequest| { item.headers = factory_bot::build_headers(vec![( @@ -30,7 +30,7 @@ async fn test_success_response() { #[tokio::test] async fn test_multiple() { - let authorizer = Arc::new(CedarAuthorizer::new()); + let authorizer = Arc::new(CedarAuthorizer::default()); let server = CheckService::new(authorizer); let test_cases = vec![ -- cgit v1.2.3 From 9f4bf84825c5a725b0ea36d4474d4fa2cec916fd Mon Sep 17 00:00:00 2001 From: mo khan Date: Thu, 26 Jun 2025 15:46:00 -0600 Subject: test: tidy up the tests --- src/authorization/check_service.rs | 2 +- tests/authorization/cedar_authorizer_test.rs | 33 ++++++++++++---------------- 2 files changed, 15 insertions(+), 20 deletions(-) (limited to 'src/authorization') diff --git a/src/authorization/check_service.rs b/src/authorization/check_service.rs index d2dd1e17..b6809339 100644 --- a/src/authorization/check_service.rs +++ b/src/authorization/check_service.rs @@ -24,7 +24,7 @@ impl envoy_types::ext_authz::v3::pb::Authorization for CheckService { ) -> Result, Status> { let request = request.into_inner(); - if dbg!(self.authorizer.authorize(dbg!(request))) { + if self.authorizer.authorize(request) { log::info!("OK"); Ok(Response::new(CheckResponse::with_status(Status::ok("OK")))) } else { diff --git a/tests/authorization/cedar_authorizer_test.rs b/tests/authorization/cedar_authorizer_test.rs index 6e1591eb..d6742995 100644 --- a/tests/authorization/cedar_authorizer_test.rs +++ b/tests/authorization/cedar_authorizer_test.rs @@ -24,42 +24,38 @@ mod tests { #[test] fn test_cedar_authorizer_denies_invalid_token() { let authorizer = CedarAuthorizer::default(); - let mut headers = HashMap::new(); - headers.insert( - "authorization".to_string(), - "Bearer invalid-token".to_string(), - ); let request = create_request(|item: &mut HttpRequest| { - item.headers = headers; + item.headers = build_with(|item: &mut HashMap| { + item.insert( + String::from("authorization"), + String::from("Bearer invalid-token"), + ); + }); }); - let result = authorizer.authorize(request); - assert!(!result); + assert!(!authorizer.authorize(request)); } #[test] fn test_cedar_authorizer_denies_missing_header() { let authorizer = CedarAuthorizer::default(); - let headers = HashMap::new(); let request = create_request(|item: &mut HttpRequest| { - item.headers = headers; + item.headers = HashMap::new(); }); - let result = authorizer.authorize(request); - assert!(!result); + assert!(!authorizer.authorize(request)); } #[test] fn test_cedar_authorizer_allows_static_assets() { let authorizer = CedarAuthorizer::default(); - let mut headers = HashMap::new(); - headers.insert(":path".to_string(), "/public/style.css".to_string()); let request = create_request(|item: &mut HttpRequest| { - item.headers = headers; + item.headers = build_with(|item: &mut HashMap| { + item.insert(String::from(":path"), String::from("/public/style.css")); + }); }); - let result = authorizer.authorize(request); - assert!(result); + assert!(authorizer.authorize(request)); } #[test] @@ -71,7 +67,6 @@ mod tests { item.headers = headers; }); - let result = authorizer.authorize(request); - assert!(result); + assert!(authorizer.authorize(request)); } } -- cgit v1.2.3 From afd9729146a7e90bd97bf36f9d2081e29de9da35 Mon Sep 17 00:00:00 2001 From: mo khan Date: Fri, 27 Jun 2025 10:40:44 -0600 Subject: feat: scan directory for all policy files --- src/authorization/cedar_authorizer.rs | 34 +++++++++++++++++++++++++++- tests/authorization/cedar_authorizer_test.rs | 21 +++++++++-------- tests/authorization/check_service_test.rs | 11 ++++++--- tests/integration_tests.rs | 12 ++++++---- 4 files changed, 60 insertions(+), 18 deletions(-) (limited to 'src/authorization') diff --git a/src/authorization/cedar_authorizer.rs b/src/authorization/cedar_authorizer.rs index 568bafbc..4ec3b34d 100644 --- a/src/authorization/cedar_authorizer.rs +++ b/src/authorization/cedar_authorizer.rs @@ -5,6 +5,8 @@ use cedar_policy::{ }; use envoy_types::ext_authz::v3::pb::CheckRequest; use std::collections::HashMap; +use std::fs; +use std::path::Path; use std::str::FromStr; #[derive(Debug)] @@ -20,10 +22,40 @@ impl CedarAuthorizer { authorizer: CedarAuth::new(), } } + + pub fn new_from(dir_path: &str) -> CedarAuthorizer { + Self::new(Self::load_from(dir_path).unwrap_or_else(|_| PolicySet::default())) + } + + fn load_from(dir_path: &str) -> Result> { + let path = Path::new(dir_path); + if !path.exists() || !path.is_dir() { + return Ok(PolicySet::default()); + } + + let mut policies = PolicySet::new(); + + for entry in fs::read_dir(path)? { + let file_path = entry?.path(); + + if let Some(extension) = file_path.extension() { + if extension == "cedar" { + let content = fs::read_to_string(&file_path)?; + let file_policies = PolicySet::from_str(&content)?; + + for policy in file_policies.policies() { + policies.add(policy.clone())?; + } + } + } + } + + Ok(policies) + } } impl Default for CedarAuthorizer { fn default() -> Self { - Self::new(PolicySet::default()) + Self::new_from("/etc/authzd") } } diff --git a/tests/authorization/cedar_authorizer_test.rs b/tests/authorization/cedar_authorizer_test.rs index d6742995..3073417d 100644 --- a/tests/authorization/cedar_authorizer_test.rs +++ b/tests/authorization/cedar_authorizer_test.rs @@ -6,9 +6,14 @@ mod tests { use envoy_types::pb::envoy::service::auth::v3::attribute_context::HttpRequest; use std::collections::HashMap; + fn authorizer() -> CedarAuthorizer { + CedarAuthorizer::new_from( + "/home/mokhax/src/gitlab.com/gitlab-org/software-supply-chain-security/authorization/authzd/etc/authzd", + ) + } + #[test] fn test_cedar_authorizer_allows_valid_token() { - let authorizer = CedarAuthorizer::default(); let request = create_request(|item: &mut HttpRequest| { item.headers = build_with(|item: &mut HashMap| { item.insert( @@ -18,12 +23,11 @@ mod tests { }); }); - assert!(authorizer.authorize(request)); + assert!(authorizer().authorize(request)); } #[test] fn test_cedar_authorizer_denies_invalid_token() { - let authorizer = CedarAuthorizer::default(); let request = create_request(|item: &mut HttpRequest| { item.headers = build_with(|item: &mut HashMap| { item.insert( @@ -33,40 +37,37 @@ mod tests { }); }); - assert!(!authorizer.authorize(request)); + assert!(!authorizer().authorize(request)); } #[test] fn test_cedar_authorizer_denies_missing_header() { - let authorizer = CedarAuthorizer::default(); let request = create_request(|item: &mut HttpRequest| { item.headers = HashMap::new(); }); - assert!(!authorizer.authorize(request)); + assert!(!authorizer().authorize(request)); } #[test] fn test_cedar_authorizer_allows_static_assets() { - let authorizer = CedarAuthorizer::default(); let request = create_request(|item: &mut HttpRequest| { item.headers = build_with(|item: &mut HashMap| { item.insert(String::from(":path"), String::from("/public/style.css")); }); }); - assert!(authorizer.authorize(request)); + assert!(authorizer().authorize(request)); } #[test] fn test_cedar_authorizer_allows_js_assets() { - let authorizer = CedarAuthorizer::default(); let mut headers = HashMap::new(); headers.insert(":path".to_string(), "/app.js".to_string()); let request = create_request(|item: &mut HttpRequest| { item.headers = headers; }); - assert!(authorizer.authorize(request)); + assert!(authorizer().authorize(request)); } } diff --git a/tests/authorization/check_service_test.rs b/tests/authorization/check_service_test.rs index a739b16a..c101850c 100644 --- a/tests/authorization/check_service_test.rs +++ b/tests/authorization/check_service_test.rs @@ -8,10 +8,16 @@ mod tests { use std::collections::HashMap; use std::sync::Arc; + fn authorizer() -> Arc { + Arc::new(CedarAuthorizer::new_from( + "/home/mokhax/src/gitlab.com/gitlab-org/software-supply-chain-security/authorization/authzd/etc/authzd", + )) + } + #[tokio::test] async fn test_check_allows_valid_bearer_token() { let token = create_token(); - let server = CheckService::new(Arc::new(CedarAuthorizer::default())); + let server = CheckService::new(authorizer()); let mut headers = HashMap::new(); headers.insert("authorization".to_string(), format!("Bearer {}", token)); @@ -30,8 +36,7 @@ mod tests { #[tokio::test] async fn test_check_denies_invalid_bearer_token() { - let authorizer = Arc::new(CedarAuthorizer::default()); - let server = CheckService::new(authorizer); + let server = CheckService::new(authorizer()); let request = tonic::Request::new(create_request(|item: &mut HttpRequest| { item.headers = HashMap::new(); })); diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index a265c2be..8bf433d1 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -7,10 +7,15 @@ use std::sync::Arc; mod authorization; mod common; +fn authorizer() -> Arc { + Arc::new(CedarAuthorizer::new_from( + "/home/mokhax/src/gitlab.com/gitlab-org/software-supply-chain-security/authorization/authzd/etc/authzd", + )) +} + #[tokio::test] async fn test_success_response() { - let authorizer = Arc::new(CedarAuthorizer::default()); - let server = CheckService::new(authorizer); + let server = CheckService::new(authorizer()); let request = tonic::Request::new(factory_bot::create_request(|item: &mut HttpRequest| { item.headers = factory_bot::build_headers(vec![( "authorization".to_string(), @@ -30,8 +35,7 @@ async fn test_success_response() { #[tokio::test] async fn test_multiple() { - let authorizer = Arc::new(CedarAuthorizer::default()); - let server = CheckService::new(authorizer); + let server = CheckService::new(authorizer()); let test_cases = vec![ ("Bearer valid-token", true), -- cgit v1.2.3 From c87d86d6e32d58070756883e4e0381d66b9fa1ab Mon Sep 17 00:00:00 2001 From: mo khan Date: Fri, 27 Jun 2025 13:06:08 -0600 Subject: test: replace hardcoded path with relative path --- src/authorization/cedar_authorizer.rs | 10 ++++------ tests/common/factory_bot.rs | 6 +++--- tests/integration_tests.rs | 2 +- 3 files changed, 8 insertions(+), 10 deletions(-) (limited to 'src/authorization') diff --git a/src/authorization/cedar_authorizer.rs b/src/authorization/cedar_authorizer.rs index 4ec3b34d..c2c594fe 100644 --- a/src/authorization/cedar_authorizer.rs +++ b/src/authorization/cedar_authorizer.rs @@ -6,7 +6,6 @@ use cedar_policy::{ use envoy_types::ext_authz::v3::pb::CheckRequest; use std::collections::HashMap; use std::fs; -use std::path::Path; use std::str::FromStr; #[derive(Debug)] @@ -23,12 +22,11 @@ impl CedarAuthorizer { } } - pub fn new_from(dir_path: &str) -> CedarAuthorizer { - Self::new(Self::load_from(dir_path).unwrap_or_else(|_| PolicySet::default())) + pub fn new_from(path: &std::path::Path) -> CedarAuthorizer { + Self::new(Self::load_from(path).unwrap_or_else(|_| PolicySet::default())) } - fn load_from(dir_path: &str) -> Result> { - let path = Path::new(dir_path); + fn load_from(path: &std::path::Path) -> Result> { if !path.exists() || !path.is_dir() { return Ok(PolicySet::default()); } @@ -55,7 +53,7 @@ impl CedarAuthorizer { } impl Default for CedarAuthorizer { fn default() -> Self { - Self::new_from("/etc/authzd") + Self::new_from(fs::canonicalize("/etc/authzd").unwrap().as_path()) } } diff --git a/tests/common/factory_bot.rs b/tests/common/factory_bot.rs index 3c3810a7..6e45a01a 100644 --- a/tests/common/factory_bot.rs +++ b/tests/common/factory_bot.rs @@ -39,7 +39,7 @@ pub fn create_token() -> String { } pub fn build_cedar_authorizer() -> authzd::CedarAuthorizer { - authzd::CedarAuthorizer::new_from( - "/home/mokhax/src/gitlab.com/gitlab-org/software-supply-chain-security/authorization/authzd/etc/authzd", - ) + let realpath = std::fs::canonicalize("./etc/authzd").unwrap(); + let path = realpath.as_path(); + authzd::CedarAuthorizer::new_from(path) } diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index 63aaaadc..6e181f26 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -1,4 +1,4 @@ -use authzd::{CedarAuthorizer, CheckService}; +use authzd::CheckService; use common::*; use envoy_types::ext_authz::v3::pb::Authorization; use envoy_types::pb::envoy::service::auth::v3::attribute_context::HttpRequest; -- cgit v1.2.3 From 84420606035fd62bbdcacb6231b9181f197d068f Mon Sep 17 00:00:00 2001 From: mo khan Date: Fri, 27 Jun 2025 13:24:40 -0600 Subject: refactor: extract create_server function to test it directly --- src/authorization/cedar_authorizer.rs | 2 +- src/lib.rs | 20 ++++++++++++++++++++ src/main.rs | 21 ++------------------- tests/main_test.rs | 8 +++++++- 4 files changed, 30 insertions(+), 21 deletions(-) (limited to 'src/authorization') diff --git a/src/authorization/cedar_authorizer.rs b/src/authorization/cedar_authorizer.rs index c2c594fe..658de7a6 100644 --- a/src/authorization/cedar_authorizer.rs +++ b/src/authorization/cedar_authorizer.rs @@ -53,7 +53,7 @@ impl CedarAuthorizer { } impl Default for CedarAuthorizer { fn default() -> Self { - Self::new_from(fs::canonicalize("/etc/authzd").unwrap().as_path()) + Self::new_from(std::path::Path::new("/etc/authzd")) } } diff --git a/src/lib.rs b/src/lib.rs index 210699b5..a82c2ace 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,2 +1,22 @@ pub mod authorization; pub use authorization::{Authorizer, CedarAuthorizer, CheckService}; + +use envoy_types::ext_authz::v3::pb::AuthorizationServer; +use std::sync::Arc; +use tonic::transport::Server; + +pub fn create_server() -> Result> { + let (_health_reporter, health_service) = tonic_health::server::health_reporter(); + let authorizer = Arc::new(authorization::CedarAuthorizer::default()); + let check_service = authorization::CheckService::new(authorizer); + let server = Server::builder() + .add_service(AuthorizationServer::new(check_service)) + .add_service(health_service) + .add_service( + tonic_reflection::server::Builder::configure() + .register_encoded_file_descriptor_set(tonic_health::pb::FILE_DESCRIPTOR_SET) + .build_v1() + .unwrap(), + ); + Ok(server) +} diff --git a/src/main.rs b/src/main.rs index 1a3ff00c..13d313d7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,31 +1,14 @@ -pub mod authorization; +use authzd::create_server; #[tokio::main] async fn main() -> Result<(), Box> { - use envoy_types::ext_authz::v3::pb::AuthorizationServer; - use std::sync::Arc; - use tonic::transport::Server; - tracing_subscriber::fmt().json().init(); let addr = std::env::var("BIND_ADDR") .unwrap_or_else(|_| "[::1]:50051".to_string()) .parse()?; - let (_health_reporter, health_service) = tonic_health::server::health_reporter(); - - let authorizer = Arc::new(authorization::CedarAuthorizer::default()); - let check_service = authorization::CheckService::new(authorizer); - - let server = Server::builder() - .add_service(AuthorizationServer::new(check_service)) - .add_service(health_service) - .add_service( - tonic_reflection::server::Builder::configure() - .register_encoded_file_descriptor_set(tonic_health::pb::FILE_DESCRIPTOR_SET) - .build_v1() - .unwrap(), - ); + let server = create_server()?; log::info!("Listening on... {addr}"); server.serve(addr).await?; diff --git a/tests/main_test.rs b/tests/main_test.rs index 5c6016f6..69c6eda1 100644 --- a/tests/main_test.rs +++ b/tests/main_test.rs @@ -1,2 +1,8 @@ #[cfg(test)] -mod tests {} +mod tests { + #[test] + fn test_create_server() { + let result = authzd::create_server(); + assert!(result.is_ok()); + } +} -- cgit v1.2.3 From cce3e0f170dfacb6b626a8777255c3183c5c5eb3 Mon Sep 17 00:00:00 2001 From: mo khan Date: Fri, 27 Jun 2025 16:45:17 -0600 Subject: refactor: extract authorization::Server type --- src/authorization/cedar_authorizer.rs | 1 + src/authorization/mod.rs | 2 ++ src/authorization/server.rs | 41 +++++++++++++++++++++++++++++++++++ src/lib.rs | 22 +------------------ src/main.rs | 5 +---- tests/authorization/server_test.rs | 2 +- 6 files changed, 47 insertions(+), 26 deletions(-) create mode 100644 src/authorization/server.rs (limited to 'src/authorization') diff --git a/src/authorization/cedar_authorizer.rs b/src/authorization/cedar_authorizer.rs index 658de7a6..a877cf87 100644 --- a/src/authorization/cedar_authorizer.rs +++ b/src/authorization/cedar_authorizer.rs @@ -51,6 +51,7 @@ impl CedarAuthorizer { Ok(policies) } } + impl Default for CedarAuthorizer { fn default() -> Self { Self::new_from(std::path::Path::new("/etc/authzd")) diff --git a/src/authorization/mod.rs b/src/authorization/mod.rs index 7d3856a5..d664815b 100644 --- a/src/authorization/mod.rs +++ b/src/authorization/mod.rs @@ -1,7 +1,9 @@ pub mod authorizer; pub mod cedar_authorizer; pub mod check_service; +pub mod server; pub use authorizer::Authorizer; pub use cedar_authorizer::CedarAuthorizer; pub use check_service::CheckService; +pub use server::Server; diff --git a/src/authorization/server.rs b/src/authorization/server.rs new file mode 100644 index 00000000..f11d0465 --- /dev/null +++ b/src/authorization/server.rs @@ -0,0 +1,41 @@ +use super::cedar_authorizer::CedarAuthorizer; +use super::check_service::CheckService; +use envoy_types::ext_authz::v3::pb::AuthorizationServer; +use std::sync::Arc; + +pub fn create_router() -> Result> { + let (_health_reporter, health_service) = tonic_health::server::health_reporter(); + let authorizer = Arc::new(CedarAuthorizer::default()); + let check_service = CheckService::new(authorizer); + let server = tonic::transport::Server::builder() + .add_service(AuthorizationServer::new(check_service)) + .add_service(health_service) + .add_service( + tonic_reflection::server::Builder::configure() + .register_encoded_file_descriptor_set(tonic_health::pb::FILE_DESCRIPTOR_SET) + .build_v1() + .unwrap(), + ); + Ok(server) +} + +pub struct Server { + router: tonic::transport::server::Router, +} + +impl Server { + pub fn new() -> Result> { + let router = create_router()?; + Ok(Server { router: router }) + } + + pub async fn serve(self, addr: std::net::SocketAddr) -> Result<(), tonic::transport::Error> { + self.router.serve(addr).await + } +} + +impl Default for Server { + fn default() -> Self { + Self::new().unwrap() + } +} diff --git a/src/lib.rs b/src/lib.rs index a82c2ace..3bd8fbd1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,22 +1,2 @@ pub mod authorization; -pub use authorization::{Authorizer, CedarAuthorizer, CheckService}; - -use envoy_types::ext_authz::v3::pb::AuthorizationServer; -use std::sync::Arc; -use tonic::transport::Server; - -pub fn create_server() -> Result> { - let (_health_reporter, health_service) = tonic_health::server::health_reporter(); - let authorizer = Arc::new(authorization::CedarAuthorizer::default()); - let check_service = authorization::CheckService::new(authorizer); - let server = Server::builder() - .add_service(AuthorizationServer::new(check_service)) - .add_service(health_service) - .add_service( - tonic_reflection::server::Builder::configure() - .register_encoded_file_descriptor_set(tonic_health::pb::FILE_DESCRIPTOR_SET) - .build_v1() - .unwrap(), - ); - Ok(server) -} +pub use authorization::{Authorizer, CedarAuthorizer, CheckService, Server}; diff --git a/src/main.rs b/src/main.rs index 13d313d7..8638e14b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,3 @@ -use authzd::create_server; - #[tokio::main] async fn main() -> Result<(), Box> { tracing_subscriber::fmt().json().init(); @@ -8,9 +6,8 @@ async fn main() -> Result<(), Box> { .unwrap_or_else(|_| "[::1]:50051".to_string()) .parse()?; - let server = create_server()?; - log::info!("Listening on... {addr}"); + let server = authzd::authorization::Server::new()?; server.serve(addr).await?; Ok(()) diff --git a/tests/authorization/server_test.rs b/tests/authorization/server_test.rs index 55645dd4..fe8c8a73 100644 --- a/tests/authorization/server_test.rs +++ b/tests/authorization/server_test.rs @@ -15,7 +15,7 @@ mod tests { async fn start_server() -> (SocketAddr, tokio::task::JoinHandle<()>) { let addr = available_port().await; - let server = authzd::create_server().expect("Failed to create server"); + let server = authzd::authorization::Server::default(); let handle = tokio::spawn(async move { server.serve(addr).await.expect("Failed to start server"); -- cgit v1.2.3 From 9d950395315cef169fcb5e99d7109ea34af5b542 Mon Sep 17 00:00:00 2001 From: mo khan Date: Fri, 27 Jun 2025 17:26:37 -0600 Subject: refactor: attempt to create constructor that allows passing in services --- src/authorization/server.rs | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) (limited to 'src/authorization') diff --git a/src/authorization/server.rs b/src/authorization/server.rs index f11d0465..7c39b51c 100644 --- a/src/authorization/server.rs +++ b/src/authorization/server.rs @@ -3,30 +3,34 @@ use super::check_service::CheckService; use envoy_types::ext_authz::v3::pb::AuthorizationServer; use std::sync::Arc; -pub fn create_router() -> Result> { - let (_health_reporter, health_service) = tonic_health::server::health_reporter(); - let authorizer = Arc::new(CedarAuthorizer::default()); - let check_service = CheckService::new(authorizer); - let server = tonic::transport::Server::builder() - .add_service(AuthorizationServer::new(check_service)) - .add_service(health_service) - .add_service( - tonic_reflection::server::Builder::configure() - .register_encoded_file_descriptor_set(tonic_health::pb::FILE_DESCRIPTOR_SET) - .build_v1() - .unwrap(), - ); - Ok(server) -} - pub struct Server { router: tonic::transport::server::Router, } impl Server { pub fn new() -> Result> { - let router = create_router()?; - Ok(Server { router: router }) + Ok(Self::new_with(|mut builder| { + let (_health_reporter, health_service) = tonic_health::server::health_reporter(); + let authorizer = Arc::new(CedarAuthorizer::default()); + let check_service = CheckService::new(authorizer); + builder + .add_service(AuthorizationServer::new(check_service)) + .add_service(health_service) + .add_service( + tonic_reflection::server::Builder::configure() + .register_encoded_file_descriptor_set(tonic_health::pb::FILE_DESCRIPTOR_SET) + .build_v1() + .unwrap(), + ) + })) + } + + pub fn new_with(f: F) -> Server + where + F: FnOnce(tonic::transport::Server) -> tonic::transport::server::Router, + { + let router = f(tonic::transport::Server::builder()); + Server { router } } pub async fn serve(self, addr: std::net::SocketAddr) -> Result<(), tonic::transport::Error> { -- cgit v1.2.3 From f86aa3653c5b88586aa51e218865e62b030c045b Mon Sep 17 00:00:00 2001 From: mo khan Date: Fri, 27 Jun 2025 18:01:59 -0600 Subject: refactor: remove the reflection service --- Makefile | 3 --- src/authorization/server.rs | 6 ------ 2 files changed, 9 deletions(-) (limited to 'src/authorization') diff --git a/Makefile b/Makefile index decb9a05..a134ae64 100644 --- a/Makefile +++ b/Makefile @@ -40,6 +40,3 @@ run-image: build-image # gRPC testing targets health-check: @grpcurl -plaintext localhost:50051 grpc.health.v1.Health/Check - -list-services: - @grpcurl -plaintext localhost:50051 list diff --git a/src/authorization/server.rs b/src/authorization/server.rs index 7c39b51c..2605bd54 100644 --- a/src/authorization/server.rs +++ b/src/authorization/server.rs @@ -16,12 +16,6 @@ impl Server { builder .add_service(AuthorizationServer::new(check_service)) .add_service(health_service) - .add_service( - tonic_reflection::server::Builder::configure() - .register_encoded_file_descriptor_set(tonic_health::pb::FILE_DESCRIPTOR_SET) - .build_v1() - .unwrap(), - ) })) } -- cgit v1.2.3 From eb3914a616cda9e2a777a47be7ad4387319df94e Mon Sep 17 00:00:00 2001 From: mo khan Date: Fri, 27 Jun 2025 18:05:38 -0600 Subject: refactor: fix typo in log message --- src/authorization/check_service.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/authorization') diff --git a/src/authorization/check_service.rs b/src/authorization/check_service.rs index b6809339..e66a0e7b 100644 --- a/src/authorization/check_service.rs +++ b/src/authorization/check_service.rs @@ -28,7 +28,7 @@ impl envoy_types::ext_authz::v3::pb::Authorization for CheckService { log::info!("OK"); Ok(Response::new(CheckResponse::with_status(Status::ok("OK")))) } else { - log::info!("Unoauthorized"); + log::info!("Unauthorized"); Ok(Response::new(CheckResponse::with_status( Status::unauthenticated("Unauthorized"), ))) -- cgit v1.2.3 From 12550869b5f9c50a6ce6c9ab54eee456b32057da Mon Sep 17 00:00:00 2001 From: mo khan Date: Fri, 27 Jun 2025 18:08:42 -0600 Subject: chore: add a logging interceptor to log request --- src/authorization/server.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'src/authorization') diff --git a/src/authorization/server.rs b/src/authorization/server.rs index 2605bd54..de7df580 100644 --- a/src/authorization/server.rs +++ b/src/authorization/server.rs @@ -9,12 +9,15 @@ pub struct Server { impl Server { pub fn new() -> Result> { + let (_health_reporter, health_service) = tonic_health::server::health_reporter(); + let authorization_service = AuthorizationServer::with_interceptor( + CheckService::new(Arc::new(CedarAuthorizer::default())), + logging_interceptor, + ); + Ok(Self::new_with(|mut builder| { - let (_health_reporter, health_service) = tonic_health::server::health_reporter(); - let authorizer = Arc::new(CedarAuthorizer::default()); - let check_service = CheckService::new(authorizer); builder - .add_service(AuthorizationServer::new(check_service)) + .add_service(authorization_service) .add_service(health_service) })) } @@ -37,3 +40,8 @@ impl Default for Server { Self::new().unwrap() } } + +fn logging_interceptor(request: tonic::Request) -> Result, tonic::Status> { + log::info!("gRPC request received"); + Ok(request) +} -- cgit v1.2.3 From dbb213d385314e1f135d57e174ae8e41ff4b5329 Mon Sep 17 00:00:00 2001 From: mo khan Date: Wed, 2 Jul 2025 11:05:04 -0600 Subject: chore: remove logging interceptor --- src/authorization/check_service.rs | 6 +----- src/authorization/server.rs | 11 ++--------- 2 files changed, 3 insertions(+), 14 deletions(-) (limited to 'src/authorization') diff --git a/src/authorization/check_service.rs b/src/authorization/check_service.rs index e66a0e7b..f8c7577f 100644 --- a/src/authorization/check_service.rs +++ b/src/authorization/check_service.rs @@ -22,13 +22,9 @@ impl envoy_types::ext_authz::v3::pb::Authorization for CheckService { &self, request: Request, ) -> Result, Status> { - let request = request.into_inner(); - - if self.authorizer.authorize(request) { - log::info!("OK"); + if self.authorizer.authorize(request.into_inner()) { Ok(Response::new(CheckResponse::with_status(Status::ok("OK")))) } else { - log::info!("Unauthorized"); Ok(Response::new(CheckResponse::with_status( Status::unauthenticated("Unauthorized"), ))) diff --git a/src/authorization/server.rs b/src/authorization/server.rs index de7df580..57712848 100644 --- a/src/authorization/server.rs +++ b/src/authorization/server.rs @@ -10,10 +10,8 @@ pub struct Server { impl Server { pub fn new() -> Result> { let (_health_reporter, health_service) = tonic_health::server::health_reporter(); - let authorization_service = AuthorizationServer::with_interceptor( - CheckService::new(Arc::new(CedarAuthorizer::default())), - logging_interceptor, - ); + let authorization_service = + AuthorizationServer::new(CheckService::new(Arc::new(CedarAuthorizer::default()))); Ok(Self::new_with(|mut builder| { builder @@ -40,8 +38,3 @@ impl Default for Server { Self::new().unwrap() } } - -fn logging_interceptor(request: tonic::Request) -> Result, tonic::Status> { - log::info!("gRPC request received"); - Ok(request) -} -- cgit v1.2.3 From 105b4b2c4af3716e128af84142f2ff0a3442855d Mon Sep 17 00:00:00 2001 From: mo khan Date: Wed, 2 Jul 2025 11:11:45 -0600 Subject: chore: add requst timeout of 30 seconds --- src/authorization/server.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/authorization') diff --git a/src/authorization/server.rs b/src/authorization/server.rs index 57712848..6ae9361f 100644 --- a/src/authorization/server.rs +++ b/src/authorization/server.rs @@ -24,7 +24,9 @@ impl Server { where F: FnOnce(tonic::transport::Server) -> tonic::transport::server::Router, { - let router = f(tonic::transport::Server::builder()); + let builder = + tonic::transport::Server::builder().timeout(std::time::Duration::from_secs(30)); + let router = f(builder); Server { router } } -- cgit v1.2.3 From 6e25870046586fea54ba74ae1e673d2ad22eaeae Mon Sep 17 00:00:00 2001 From: mo khan Date: Wed, 2 Jul 2025 12:09:45 -0600 Subject: chore: add minimal logging --- src/authorization/check_service.rs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/authorization') diff --git a/src/authorization/check_service.rs b/src/authorization/check_service.rs index f8c7577f..57f7b5d5 100644 --- a/src/authorization/check_service.rs +++ b/src/authorization/check_service.rs @@ -23,8 +23,10 @@ impl envoy_types::ext_authz::v3::pb::Authorization for CheckService { request: Request, ) -> Result, Status> { if self.authorizer.authorize(request.into_inner()) { + log::info!("OK"); Ok(Response::new(CheckResponse::with_status(Status::ok("OK")))) } else { + log::info!("Unauthorized"); Ok(Response::new(CheckResponse::with_status( Status::unauthenticated("Unauthorized"), ))) -- cgit v1.2.3 From bc673b0de36342ef4fca8d0ae4f8bd029b4054b8 Mon Sep 17 00:00:00 2001 From: mo khan Date: Wed, 2 Jul 2025 12:16:29 -0600 Subject: chore: request method, path and headers in tracing --- src/authorization/server.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'src/authorization') diff --git a/src/authorization/server.rs b/src/authorization/server.rs index 6ae9361f..da686350 100644 --- a/src/authorization/server.rs +++ b/src/authorization/server.rs @@ -24,8 +24,16 @@ impl Server { where F: FnOnce(tonic::transport::Server) -> tonic::transport::server::Router, { - let builder = - tonic::transport::Server::builder().timeout(std::time::Duration::from_secs(30)); + let builder = tonic::transport::Server::builder() + .trace_fn(|req| { + tracing::info_span!( + "grpc_request", + method = %req.method(), + path = %req.uri().path(), + headers = ?req.headers(), + ) + }) + .timeout(std::time::Duration::from_secs(30)); let router = f(builder); Server { router } } -- cgit v1.2.3 From 0b610d061e45811130d8cf3919037fdc9513e340 Mon Sep 17 00:00:00 2001 From: mo khan Date: Wed, 2 Jul 2025 12:17:31 -0600 Subject: chore: rename log message --- src/authorization/server.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/authorization') diff --git a/src/authorization/server.rs b/src/authorization/server.rs index da686350..2ad270df 100644 --- a/src/authorization/server.rs +++ b/src/authorization/server.rs @@ -27,7 +27,7 @@ impl Server { let builder = tonic::transport::Server::builder() .trace_fn(|req| { tracing::info_span!( - "grpc_request", + "request", method = %req.method(), path = %req.uri().path(), headers = ?req.headers(), -- cgit v1.2.3