diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index be4ee54d..fc82fb66 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,10 +18,7 @@ jobs: - uses: extractions/setup-just@v3 with: github-token: ${{ secrets.GITHUB_TOKEN }} - - uses: arduino/setup-protoc@v1 - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - - run: cargo install protoc-gen-prost protoc-gen-prost-crate protoc-gen-tonic + - run: cargo install protoc-gen-prost-crate - name: generated grpc code run: just - name: Semantic Release diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml index 093b7868..d7ee13a7 100644 --- a/.github/workflows/testing.yml +++ b/.github/workflows/testing.yml @@ -20,10 +20,7 @@ jobs: - uses: extractions/setup-just@v3 with: github-token: ${{ secrets.GITHUB_TOKEN }} - - uses: arduino/setup-protoc@v1 - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - - run: cargo install protoc-gen-prost protoc-gen-prost-crate protoc-gen-tonic + - run: cargo install protoc-gen-prost-crate - name: generated grpc code run: just - run: cargo clippy --all-features --no-deps diff --git a/README.md b/README.md index 4526ae23..63884261 100644 --- a/README.md +++ b/README.md @@ -35,9 +35,6 @@ Required tooling: - [just](https://just.systems) - [buf](https://buf.build) -- [protoc](https://grpc.io/docs/protoc-installation/) -- `protoc-gen-prost`: `cargo install protoc-gen-prost` -- `protoc-gen-tonic`: `cargo install protoc-gen-tonic` - `protoc-gen-prost-crate`: `cargo install protoc-gen-prost-crate` Installing the tools is also partially available via `just install-tools`. diff --git a/buf.gen.yaml b/buf.gen.yaml index a104bb93..8e616cc0 100644 --- a/buf.gen.yaml +++ b/buf.gen.yaml @@ -1,20 +1,20 @@ # buf.gen.yaml -version: v1 +version: v2 managed: enabled: true plugins: - - plugin: prost + - remote: buf.build/community/neoeinstein-prost:v0.5.0 out: crates/zitadel-gen/src/api/ opt: - compile_well_known_types - extern_path=.google.protobuf=::pbjson_types - - plugin: tonic + - remote: buf.build/community/neoeinstein-tonic:v0.5.0 out: crates/zitadel-gen/src/api/ opt: - compile_well_known_types - extern_path=.google.protobuf=::pbjson_types - no_server - - name: prost-crate + - local: protoc-gen-prost-crate out: ./crates/zitadel-gen strategy: all opt: diff --git a/crates/zitadel-gen/Cargo.toml b/crates/zitadel-gen/Cargo.toml index 4ade53fe..20142fe5 100644 --- a/crates/zitadel-gen/Cargo.toml +++ b/crates/zitadel-gen/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "zitadel-gen" -version = "2.69.1" +version = "2.71.19" edition = "2021" @@ -62,13 +62,9 @@ proto_full = ["zitadel-action-v1","zitadel-admin-v1","zitadel-app-v1","zitadel-a [dependencies] anyhow = "1.0" -pbjson-types = { version = "0.7.0"} -prost = { version = "0.13.1", default-features = false, features = ["std"] } -prost-types = { version = "0.13.1", default-features = false } +pbjson-types = { version = "0.8.0"} +prost = { version = "0.14.1", default-features = false, features = ["std"] } +prost-types = { version = "0.14.1", default-features = false } regex = { version = "1.5.5", default-features = false } -tonic = "0.12.0" - -[build-dependencies] -tonic-build = "0.12.0" -prost-build = { version = "0.13.1", default-features = false } -pbjson-build = "0.7.0" \ No newline at end of file +tonic = "0.14.2" +tonic-prost = "0.14.2" \ No newline at end of file diff --git a/crates/zitadel-gen/src/lib.rs b/crates/zitadel-gen/src/lib.rs index df514a63..a880cd62 100644 --- a/crates/zitadel-gen/src/lib.rs +++ b/crates/zitadel-gen/src/lib.rs @@ -1,8 +1,7 @@ - #[allow(clippy::all)] pub mod api; #[allow(clippy::all)] pub mod zitadel { pub use crate::api::zitadel::*; -} \ No newline at end of file +} diff --git a/crates/zitadel/Cargo.toml b/crates/zitadel/Cargo.toml index 7e9e3e8f..42f02c5d 100644 --- a/crates/zitadel/Cargo.toml +++ b/crates/zitadel/Cargo.toml @@ -21,7 +21,7 @@ default = ["tls-roots"] ## Feature that enables support for the [actix framework](https://actix.rs/). actix = ["credentials", "oidc", "dep:actix-web"] -api-common = ["dep:prost", "dep:prost-types", "dep:tonic", "dep:tonic-types", "dep:pbjson-types", "dep:zitadel-gen" ] +api-common = ["dep:tonic", "dep:zitadel-gen"] ## The API feature enables all gRPC service clients to access the ZITADEL API. api = [ @@ -55,7 +55,7 @@ api-settings-v2 = ["api-common", "zitadel-gen/zitadel-settings-v2" ] api-user-v2 = ["api-common", "zitadel-gen/zitadel-user-v2" ] -tls-roots = ["tonic/tls-roots"] +tls-roots = ["tonic/tls-native-roots"] tls-webpki-roots = ["tonic/tls-webpki-roots"] @@ -105,9 +105,6 @@ document-features = { version = "0.2.8", optional = true } jsonwebtoken = { version = "9.3.0", optional = true } moka = { version = "0.12.8", features = ["future"], optional = true } openidconnect = { version = "4.0.0", optional = true } -pbjson-types = { version = "0.7.0", optional = true } -prost = { version = "0.13.1", optional = true } -prost-types = { version = "0.13.1", optional = true } reqwest = { version = "0.12.12", features = ["json", "rustls-tls"], default-features = false, optional = true } rocket = { version = "0.5.0", optional = true } serde = { version = "1.0.200", features = ["derive"], optional = true } @@ -118,14 +115,13 @@ tokio = { version = "1.37.0", optional = true, features = [ "macros", "rt-multi-thread", ] } -tonic = { version = "0.12.1", features = [ - "tls", +tonic = { version = "0.14.2", features = [ + "tls-ring", ], optional = true } rocket_okapi = { version = "0.9.0", optional = true, default-features = false } schemars = {version = "0.8.21", optional = true} -tonic-types = { version = "0.12.1", optional = true } -zitadel-gen = { path = "../zitadel-gen", version = "2.69", optional = true } +zitadel-gen = { path = "../zitadel-gen", version = "2.71", optional = true } [dev-dependencies] chrono = "0.4.38" diff --git a/crates/zitadel/src/api/clients.rs b/crates/zitadel/src/api/clients.rs index c314aa33..89e8b380 100644 --- a/crates/zitadel/src/api/clients.rs +++ b/crates/zitadel/src/api/clients.rs @@ -132,10 +132,10 @@ impl ClientBuilder { impl ClientBuilder where T: BuildInterceptedService, - T::Target: tonic::client::GrpcService, - >::ResponseBody: + T::Target: tonic::client::GrpcService, + >::ResponseBody: Body + Send + 'static, - <>::ResponseBody as Body>::Error: + <>::ResponseBody as Body>::Error: Into + Send, { /// Create a new [`AdminServiceClient`]. @@ -306,7 +306,6 @@ async fn get_channel(api_endpoint: &str) -> Result { .map_err(|_| ClientError::ConnectionError) } - #[cfg(test)] mod tests { use super::*; diff --git a/crates/zitadel/src/api/mod.rs b/crates/zitadel/src/api/mod.rs index 9e58098c..ec220df4 100644 --- a/crates/zitadel/src/api/mod.rs +++ b/crates/zitadel/src/api/mod.rs @@ -5,7 +5,6 @@ //! Further contains interceptors that may be used to //! authenticate the clients to ZITADEL with credentials. - pub mod clients; #[allow(clippy::all)] #[cfg(feature = "api")] diff --git a/crates/zitadel/src/credentials/service_account.rs b/crates/zitadel/src/credentials/service_account.rs index ea818408..e37033f5 100644 --- a/crates/zitadel/src/credentials/service_account.rs +++ b/crates/zitadel/src/credentials/service_account.rs @@ -237,7 +237,9 @@ impl ServiceAccount { ) -> Result { let issuer = IssuerUrl::new(audience.to_string()) .map_err(|e| ServiceAccountError::AudienceUrl { source: e })?; - let async_http_client = reqwest::ClientBuilder::new().redirect(reqwest::redirect::Policy::none()).build()?; + let async_http_client = reqwest::ClientBuilder::new() + .redirect(reqwest::redirect::Policy::none()) + .build()?; let metadata = CoreProviderMetadata::discover_async(issuer, &async_http_client) .await .map_err(|e| ServiceAccountError::DiscoveryError { @@ -271,7 +273,12 @@ impl ServiceAccount { // }) // .await // .map_err(|e| ServiceAccountError::HttpError { source: e })?; - let response = async_http_client.post(url).headers(headers).body(body).send().await?; + let response = async_http_client + .post(url) + .headers(headers) + .body(body) + .send() + .await?; serde_json::from_slice(response.bytes().await?.to_vec().as_slice()) .map_err(|e| ServiceAccountError::Json { source: e }) diff --git a/crates/zitadel/src/oidc/discovery.rs b/crates/zitadel/src/oidc/discovery.rs index d4c1ae8f..2265fab0 100644 --- a/crates/zitadel/src/oidc/discovery.rs +++ b/crates/zitadel/src/oidc/discovery.rs @@ -2,9 +2,8 @@ use custom_error::custom_error; use openidconnect::{ core::{ CoreAuthDisplay, CoreClaimName, CoreClaimType, CoreClientAuthMethod, CoreGrantType, - CoreJsonWebKey, CoreJweContentEncryptionAlgorithm, - CoreJweKeyManagementAlgorithm, CoreResponseMode, CoreResponseType, - CoreSubjectIdentifierType, + CoreJsonWebKey, CoreJweContentEncryptionAlgorithm, CoreJweKeyManagementAlgorithm, + CoreResponseMode, CoreResponseType, CoreSubjectIdentifierType, }, url, AdditionalProviderMetadata, IntrospectionUrl, IssuerUrl, ProviderMetadata, RevocationUrl, }; @@ -50,7 +49,9 @@ custom_error! { pub async fn discover(authority: &str) -> Result { let issuer = IssuerUrl::new(authority.to_string()) .map_err(|source| DiscoveryError::IssuerUrl { source })?; - let async_http_client = reqwest::ClientBuilder::new().redirect(reqwest::redirect::Policy::none()).build()?; + let async_http_client = reqwest::ClientBuilder::new() + .redirect(reqwest::redirect::Policy::none()) + .build()?; ZitadelProviderMetadata::discover_async(issuer, &async_http_client) .await .map_err(|_| DiscoveryError::DiscoveryDocument) diff --git a/crates/zitadel/src/oidc/introspection/mod.rs b/crates/zitadel/src/oidc/introspection/mod.rs index 50a4e810..a1c39df1 100644 --- a/crates/zitadel/src/oidc/introspection/mod.rs +++ b/crates/zitadel/src/oidc/introspection/mod.rs @@ -1,21 +1,19 @@ +use crate::credentials::{Application, ApplicationError}; +use crate::oidc::discovery::{discover, DiscoveryError}; use custom_error::custom_error; +use jsonwebtoken::jwk::{AlgorithmParameters, JwkSet}; +use jsonwebtoken::{decode, decode_header, Algorithm, DecodingKey, Header, TokenData, Validation}; use openidconnect::url::{ParseError, Url}; -use openidconnect::{ - core::CoreTokenType, ExtraTokenFields, StandardTokenIntrospectionResponse, -}; +use openidconnect::{core::CoreTokenType, ExtraTokenFields, StandardTokenIntrospectionResponse}; use reqwest::header::{HeaderMap, ACCEPT, AUTHORIZATION, CONTENT_TYPE}; +use reqwest::Client; +use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; +use serde_json::Value as JsonValue; use std::collections::HashMap; use std::error::Error; use std::fmt::{Debug, Display}; -use jsonwebtoken::{decode, decode_header, Algorithm, DecodingKey, Header, TokenData, Validation}; -use jsonwebtoken::jwk::{AlgorithmParameters, JwkSet}; use std::str::FromStr; -use reqwest::{Client}; -use serde::de::DeserializeOwned; -use serde_json::Value as JsonValue; -use crate::credentials::{Application, ApplicationError}; -use crate::oidc::discovery::{discover, DiscoveryError}; #[cfg(feature = "introspection_cache")] pub mod cache; @@ -50,11 +48,11 @@ custom_error! { /// - When scope contains `urn:zitadel:iam:user:resourceowner`, the fields prefixed with /// `resource_owner_` are set. /// - When scope contains `urn:zitadel:iam:user:metadata`, the metadata hashmap will be -/// filled with the user metadata. -/// - When scope contains `urn:zitadel:iam:org:projects:roles`, the project_roles hashmap will be -/// filled with the project roles. -/// - When using custom claims through Zitadel Actions, the custom_claims hashmap will be filled with -/// the custom claims. [custom claims](https://zitadel.com/docs/apis/openidoauth/claims#custom-claims) +/// filled with the user metadata. +/// - When scope contains `urn:zitadel:iam:org:projects:roles`, the project_roles hashmap will be +/// filled with the project roles. +/// - When using custom claims through Zitadel Actions, the custom_claims hashmap will be filled with +/// the custom claims. [custom claims](https://zitadel.com/docs/apis/openidoauth/claims#custom-claims) /// /// It can be used as a basis for further customized authorization checks, for example: /// ``` @@ -140,7 +138,7 @@ pub struct ZitadelIntrospectionExtraTokenFields { #[serde(rename = "urn:zitadel:iam:user:metadata")] pub metadata: Option>, #[serde(flatten)] - custom_claims: Option> + custom_claims: Option>, } impl ExtraTokenFields for ZitadelIntrospectionExtraTokenFields {} @@ -269,17 +267,22 @@ pub async fn introspect( authentication: &AuthorityAuthentication, token: &str, ) -> Result { - let async_http_client = reqwest::ClientBuilder::new().redirect(reqwest::redirect::Policy::none()).build()?; + let async_http_client = reqwest::ClientBuilder::new() + .redirect(reqwest::redirect::Policy::none()) + .build()?; - let url= Url::parse(introspection_uri) - .map_err(|source| IntrospectionError::ParseUrl { source })?; + let url = + Url::parse(introspection_uri).map_err(|source| IntrospectionError::ParseUrl { source })?; let response = async_http_client .post(url) .headers(headers(authentication)) .body(payload(authority, authentication, token)?) .send() .await - .map_err(|source| IntrospectionError::RequestFailed {origin: "The introspection".to_string(), source })?; + .map_err(|source| IntrospectionError::RequestFailed { + origin: "The introspection".to_string(), + source, + })?; if !response.status().is_success() { let status = response.status(); @@ -303,12 +306,12 @@ struct ZitadelResponseError { body: String, } impl ZitadelResponseError { - fn new(status_code: reqwest::StatusCode, body: &[u8]) -> Self { - Self { - status_code: status_code.to_string(), - body: String::from_utf8_lossy(body).to_string(), - } + fn new(status_code: reqwest::StatusCode, body: &[u8]) -> Self { + Self { + status_code: status_code.to_string(), + body: String::from_utf8_lossy(body).to_string(), } + } } impl Display for ZitadelResponseError { @@ -335,32 +338,35 @@ fn decode_metadata(response: &mut ZitadelIntrospectionResponse) -> Result<(), In Ok(()) } - pub async fn fetch_jwks(idm_url: &str) -> Result { let client: Client = Client::new(); - let openid_config = discover(idm_url).await.map_err(|err| { - IntrospectionError::DiscoveryError { source: err } - })?; + let openid_config = discover(idm_url) + .await + .map_err(|err| IntrospectionError::DiscoveryError { source: err })?; let jwks_url = openid_config.jwks_uri().url().as_ref(); - let response = client - .get(jwks_url) - .send() - .await?; - let jwks_keys: JwkSet = response.json::().await.map_err(|err| IntrospectionError::RequestFailed {origin: "Could not fetch jwks keys because ".to_string(), source: err })?; + let response = client.get(jwks_url).send().await?; + let jwks_keys: JwkSet = + response + .json::() + .await + .map_err(|err| IntrospectionError::RequestFailed { + origin: "Could not fetch jwks keys because ".to_string(), + source: err, + })?; Ok(jwks_keys) } - -pub async fn local_jwt_validation(issuers: &[&str], - audiences: &[&str], - jwks_keys: JwkSet, - token: &str, ) -> Result - +pub async fn local_jwt_validation( + issuers: &[&str], + audiences: &[&str], + jwks_keys: JwkSet, + token: &str, +) -> Result where U: DeserializeOwned, { - - let unverified_token_header: Header = decode_header(token).map_err(|source| IntrospectionError::JsonWebTokenErrors { source })?; + let unverified_token_header: Header = + decode_header(token).map_err(|source| IntrospectionError::JsonWebTokenErrors { source })?; let user_kid = match unverified_token_header.kid { Some(k) => k, None => return Err(IntrospectionError::MissingJwksKey), @@ -369,16 +375,21 @@ where match &j.algorithm { AlgorithmParameters::RSA(rsa) => { let decoding_key = DecodingKey::from_rsa_components(&rsa.n, &rsa.e)?; - let algorithm_key = j.common.key_algorithm.ok_or(IntrospectionError::JWTUnsupportedAlgorithm)?; + let algorithm_key = j + .common + .key_algorithm + .ok_or(IntrospectionError::JWTUnsupportedAlgorithm)?; let algorithm_str = format!("{}", algorithm_key); - let algorithm = Algorithm::from_str(&algorithm_str).map_err(|source| IntrospectionError::JsonWebTokenErrors { source })?; + let algorithm = Algorithm::from_str(&algorithm_str) + .map_err(|source| IntrospectionError::JsonWebTokenErrors { source })?; let mut validation = Validation::new(algorithm); validation.set_audience(audiences); validation.leeway = 5; validation.set_issuer(issuers); validation.validate_exp = true; - let decoded_token: TokenData = decode::(token, &decoding_key, &validation).map_err(|source| IntrospectionError::JsonWebTokenErrors { source })?; + let decoded_token: TokenData = decode::(token, &decoding_key, &validation) + .map_err(|source| IntrospectionError::JsonWebTokenErrors { source })?; Ok(decoded_token.claims) } _ => unreachable!("Not yet Implemented or supported by Zitadel"), @@ -388,15 +399,14 @@ where } } - #[cfg(test)] mod tests { #![allow(clippy::all)] + use super::*; + use crate::credentials::{AuthenticationOptions, ServiceAccount}; use crate::oidc::discovery::discover; use openidconnect::TokenIntrospectionResponse; - use crate::credentials::{AuthenticationOptions, ServiceAccount}; - use super::*; const ZITADEL_URL: &str = "https://zitadel-libraries-l8boqa.zitadel.cloud"; const ZITADEL_URL_ALTER: &str = "https://ferris-hk3otq.us1.zitadel.cloud"; @@ -413,7 +423,7 @@ mod tests { const PERSONAL_ACCESS_TOKEN: &str = "dEnGhIFs3VnqcQU5D2zRSeiarB1nwH6goIKY0J8MWZbsnWcTuu1C59lW9DgCq1y096GYdXA"; - const PERSONAL_ACCESS_TOKEN_ALTER : &str = + const PERSONAL_ACCESS_TOKEN_ALTER: &str = "KyX1Pw1bVfYFSE0g6s3Io12I4sC-feEtkaShWstZJ0h34JHfE29q4oIOJFF0PZlfMDvaCvk"; #[derive(Debug, serde::Deserialize, serde::Serialize)] @@ -437,18 +447,18 @@ mod tests { pub taste: Option, #[serde(rename = "year")] pub anum: Option, - } + } - pub trait ExtIntrospectedUser { + pub trait ExtIntrospectedUser { fn custom_claims(&self) -> Result; - } - impl ExtIntrospectedUser for ZitadelIntrospectionResponse { - fn custom_claims(&self) -> Result { + } + impl ExtIntrospectedUser for ZitadelIntrospectionResponse { + fn custom_claims(&self) -> Result { let as_value = serde_json::to_value(self)?; - let custom_claims: CustomClaims = serde_json::from_value(as_value)?; + let custom_claims: CustomClaims = serde_json::from_value(as_value)?; Ok(custom_claims) } - } + } #[tokio::test] async fn introspect_fails_with_invalid_url() { @@ -536,13 +546,30 @@ mod tests { // let sa = ServiceAccount::load_from_json(SERVICE_ACCOUNT).unwrap(); - let access_token = sa.authenticate_with_options(ZITADEL_URL_ALTER, &AuthenticationOptions { - scopes: vec!["profile".to_string(), "email".to_string(), "urn:zitadel:iam:user:resourceowner".to_string()], - ..Default::default() - }).await.unwrap(); + let access_token = sa + .authenticate_with_options( + ZITADEL_URL_ALTER, + &AuthenticationOptions { + scopes: vec![ + "profile".to_string(), + "email".to_string(), + "urn:zitadel:iam:user:resourceowner".to_string(), + ], + ..Default::default() + }, + ) + .await + .unwrap(); // move fetch_jwks after login has jwks can be purged after 30 hours of no login let jwks: JwkSet = fetch_jwks(ZITADEL_URL_ALTER).await.unwrap(); - let result: CustomClaims = local_jwt_validation::(&ZITADEL_ISSUERS, &ZITADEL_AUDIENCES, jwks, &access_token).await.unwrap(); + let result: CustomClaims = local_jwt_validation::( + &ZITADEL_ISSUERS, + &ZITADEL_AUDIENCES, + jwks, + &access_token, + ) + .await + .unwrap(); assert_eq!(result.taste.unwrap(), "funk"); assert_eq!(result.anum.unwrap(), 2025); } @@ -565,8 +592,8 @@ mod tests { }, PERSONAL_ACCESS_TOKEN_ALTER, ) - .await - .unwrap(); + .await + .unwrap(); let custom_claims = result.custom_claims().unwrap(); diff --git a/crates/zitadel/src/rocket/introspection/guard.rs b/crates/zitadel/src/rocket/introspection/guard.rs index 42f23c50..23ae4245 100644 --- a/crates/zitadel/src/rocket/introspection/guard.rs +++ b/crates/zitadel/src/rocket/introspection/guard.rs @@ -7,22 +7,21 @@ use rocket::{async_trait, Request}; use std::collections::BTreeSet; use std::collections::HashMap; +#[cfg(feature = "rocket_okapi")] +use crate::oidc::introspection::{introspect, IntrospectionError, ZitadelIntrospectionResponse}; +use crate::rocket::introspection::IntrospectionConfig; #[cfg(feature = "rocket_okapi")] use rocket_okapi::{ gen::OpenApiGenerator, okapi::openapi3::{ - Object, Responses, SecurityRequirement, SecurityScheme, SecuritySchemeData, MediaType, - RefOr, Response, + MediaType, Object, RefOr, Response, Responses, SecurityRequirement, SecurityScheme, + SecuritySchemeData, }, okapi::Map, request::{OpenApiFromRequest, RequestHeaderInput}, }; #[cfg(feature = "rocket_okapi")] use schemars::schema::{InstanceType, ObjectValidation, Schema, SchemaObject}; -#[cfg(feature = "rocket_okapi")] - -use crate::oidc::introspection::{introspect, IntrospectionError, ZitadelIntrospectionResponse}; -use crate::rocket::introspection::IntrospectionConfig; use super::config::IntrospectionRocketConfig; @@ -235,9 +234,13 @@ impl<'a> OpenApiFromRequest<'a> for &'a IntrospectedUser { ); properties }, - required: vec!["code".to_owned(), "reason".to_owned(), "description".to_owned()] - .into_iter() - .collect::>(), // Convert Vec to BTreeSet + required: vec![ + "code".to_owned(), + "reason".to_owned(), + "description".to_owned(), + ] + .into_iter() + .collect::>(), // Convert Vec to BTreeSet ..Default::default() })), ..Default::default() @@ -251,7 +254,9 @@ impl<'a> OpenApiFromRequest<'a> for &'a IntrospectedUser { properties.insert("error".to_owned(), Schema::Object(error_detail_schema)); properties }, - required: vec!["error".to_owned()].into_iter().collect::>(), // Convert Vec to BTreeSet + required: vec!["error".to_owned()] + .into_iter() + .collect::>(), // Convert Vec to BTreeSet ..Default::default() })), ..Default::default() @@ -273,7 +278,8 @@ impl<'a> OpenApiFromRequest<'a> for &'a IntrospectedUser { content: content.clone(), ..Default::default() }; - res.responses.insert("400".to_owned(), RefOr::Object(bad_request_response)); + res.responses + .insert("400".to_owned(), RefOr::Object(bad_request_response)); // Adding 401 Unauthorized response let unauthorized_response = Response { @@ -281,10 +287,12 @@ impl<'a> OpenApiFromRequest<'a> for &'a IntrospectedUser { content: content.clone(), ..Default::default() }; - res.responses.insert("401".to_owned(), RefOr::Object(unauthorized_response)); + res.responses + .insert("401".to_owned(), RefOr::Object(unauthorized_response)); Ok(res) - }} + } +} #[cfg(test)] mod tests { diff --git a/justfile b/justfile index cabd4ba5..8cfb7ff0 100644 --- a/justfile +++ b/justfile @@ -1,6 +1,6 @@ proto_dir := "./crates/zitadel-gen/src/api/" gen_dir := "./crates/zitadel-gen" -zitadel_proto_version := "v2.69.1" +zitadel_proto_version := "v2.71.19" default: clean generate-grpc @@ -16,7 +16,7 @@ build_zitadel-grpc: cargo build --package zitadel-gen --release install-tools: - cargo install protoc-gen-prost protoc-gen-tonic protoc-gen-prost-crate protoc-gen-prost-serde cargo-edit + cargo install protoc-gen-prost-crate cargo-edit all_examples: # fetch_profile_with_pat