diff --git a/como_auth/Cargo.toml b/como_auth/Cargo.toml index 94becac..c6ef12c 100644 --- a/como_auth/Cargo.toml +++ b/como_auth/Cargo.toml @@ -35,3 +35,4 @@ openidconnect = "3.0.0" [dev-dependencies] pretty_assertions.workspace = true +sealed_test.workspace = true diff --git a/como_auth/src/oauth.rs b/como_auth/src/oauth.rs index d4dafc9..6b23a4e 100644 --- a/como_auth/src/oauth.rs +++ b/como_auth/src/oauth.rs @@ -3,7 +3,7 @@ use oauth2::{basic::BasicClient, AuthUrl, ClientId, ClientSecret, RedirectUrl, T use std::ops::Deref; use std::sync::Arc; -#[derive(Clone, clap::Args, Debug)] +#[derive(Clone, clap::Args, Debug, PartialEq, Eq)] pub struct OAuthClientClap { #[clap(flatten)] zitadel: ZitadelClap, @@ -12,40 +12,28 @@ pub struct OAuthClientClap { noop: NoopConfig, } -#[derive(Clone, clap::Args, Debug)] +#[derive(Clone, clap::Args, Debug, PartialEq, Eq)] pub struct NoopConfig { #[arg(env = "OAUTH_NOOP", long = "oauth-noop", group = "auth", global = true)] pub oauth_noop: Option, } #[derive(clap::Args, Clone, Debug, PartialEq, Eq)] +#[group(requires_all = ["auth_url", "client_id", "client_secret", "redirect_url", "token_url"])] pub struct ZitadelClap { - #[arg( - env = "ZITADEL_AUTH_URL", - long = "zitadel-auth-url", - group = "auth", - global = true - )] + #[arg(env = "ZITADEL_AUTH_URL", long = "zitadel-auth-url", group = "auth")] pub auth_url: Option, - #[arg(env = "ZITADEL_CLIENT_ID", long = "zitadel-client-id", global = true)] + #[arg(env = "ZITADEL_CLIENT_ID", long = "zitadel-client-id")] pub client_id: Option, - #[arg( - env = "ZITADEL_CLIENT_SECRET", - long = "zitadel-client-secret", - global = true - )] + #[arg(env = "ZITADEL_CLIENT_SECRET", long = "zitadel-client-secret")] pub client_secret: Option, - #[arg( - env = "ZITADEL_REDIRECT_URL", - long = "zitadel-redirect-url", - global = true - )] + #[arg(env = "ZITADEL_REDIRECT_URL", long = "zitadel-redirect-url")] pub redirect_url: Option, - #[arg(env = "ZITADEL_TOKEN_URL", long = "zitadel-token-url", global = true)] + #[arg(env = "ZITADEL_TOKEN_URL", long = "zitadel-token-url")] pub token_url: Option, } @@ -176,22 +164,32 @@ impl OAuthClient for ZitadelOAuthClient { #[cfg(test)] mod tests { - use crate::oauth::{OAuth, OAuthClientClap, OAuthConfig, ZitadelClap, ZitadelConfig}; + use crate::oauth::{ + NoopConfig, OAuth, OAuthClientClap, OAuthConfig, ZitadelClap, ZitadelConfig, + }; use clap::Parser; + use sealed_test::prelude::*; #[derive(Parser)] #[command(author, version, about, long_about = None)] pub struct Cli { #[clap(flatten)] options: OAuthClientClap, + } + #[derive(Parser, Debug)] + #[command(author, version, about, long_about = None)] + pub struct CliSubCommand { #[command(subcommand)] command: Commands, } - #[derive(clap::Subcommand, Clone)] + #[derive(clap::Subcommand, Clone, Debug, Eq, PartialEq)] pub enum Commands { - One, + One { + #[clap(flatten)] + options: OAuthClientClap, + }, } #[tokio::test] @@ -215,7 +213,7 @@ mod tests { #[tokio::test] async fn test_parse_clap_noop() { - let cli: Cli = Cli::parse_from(&["base", "one", "--oauth-noop=true"]); + let cli: Cli = Cli::parse_from(&["base", "--oauth-noop=true"]); assert_eq!(cli.options.noop.oauth_noop, Some(true)); @@ -226,13 +224,13 @@ mod tests { async fn test_parse_clap_zitadel() { let cli: Cli = Cli::parse_from(&[ "base", - "one", "--zitadel-client-id=something", "--zitadel-client-secret=something", "--zitadel-auth-url=https://something", "--zitadel-redirect-url=https://something", "--zitadel-token-url=https://something", ]); + println!("{:?}", cli.options); pretty_assertions::assert_eq!( cli.options.zitadel, @@ -244,7 +242,67 @@ mod tests { token_url: Some("https://something".into()) } ); + } - println!("{:?}", cli.options); + #[test] + fn test_parse_clap_zitadel_fails_require_all() { + let cli = CliSubCommand::try_parse_from(&[ + "base", + "one", + // "--zitadel-client-id=something", // We want to trigger missing variable + "--zitadel-client-secret=something", + "--zitadel-auth-url=https://something", + "--zitadel-redirect-url=https://something", + "--zitadel-token-url=https://something", + ]); + + pretty_assertions::assert_eq!(cli.is_err(), true); + } + + #[sealed_test] + fn test_parse_clap_env_zitadel() { + std::env::set_var("ZITADEL_CLIENT_ID", "something"); + std::env::set_var("ZITADEL_CLIENT_SECRET", "something"); + std::env::set_var("ZITADEL_AUTH_URL", "https://something"); + std::env::set_var("ZITADEL_REDIRECT_URL", "https://something"); + std::env::set_var("ZITADEL_TOKEN_URL", "https://something"); + + let cli = CliSubCommand::parse_from(&["base", "one"]); + + pretty_assertions::assert_eq!( + cli.command, + Commands::One { + options: OAuthClientClap { + zitadel: ZitadelClap { + auth_url: Some("https://something".into()), + client_id: Some("something".into()), + client_secret: Some("something".into()), + redirect_url: Some("https://something".into()), + token_url: Some("https://something".into()) + }, + noop: NoopConfig { oauth_noop: None } + } + } + ); + } + #[test] + fn test_parse_clap_defaults_to_noop() { + let cli = CliSubCommand::parse_from(&["base", "one"]); + + pretty_assertions::assert_eq!( + cli.command, + Commands::One { + options: OAuthClientClap { + zitadel: ZitadelClap { + auth_url: None, + client_id: None, + client_secret: None, + redirect_url: None, + token_url: None + }, + noop: NoopConfig { oauth_noop: None } + } + } + ); } }