kych

OAuth 2.0 API for Swiyu to enable Taler integration of Swiyu for KYC (experimental)
Log | Files | Refs | README

commit 933cde3ff2aee1e275d1e777aad2ccf221a6b553
parent 441b37187fed12cadc53f3579d156083e94a8215
Author: Henrique Chan Carvalho Machado <henriqueccmachado@tecnico.ulisboa.pt>
Date:   Mon, 19 Jan 2026 19:25:11 +0100

Update kych-client-management to use unified config

The kych-client-management CLI is aligned with the unified configuration by
requiring a global -c/--config flag and reading the database URL and client
definitions from it. The sync command no longer takes a config argument, manual
INI parsing has been removed, and client synchronization now uses pre-parsed
ClientConfig entries from Config::from_file().

Diffstat:
Mkych_oauth2_gateway/src/bin/client_management_cli.rs | 110++++++++++++++++++++++++++++++-------------------------------------------------
1 file changed, 41 insertions(+), 69 deletions(-)

diff --git a/kych_oauth2_gateway/src/bin/client_management_cli.rs b/kych_oauth2_gateway/src/bin/client_management_cli.rs @@ -2,29 +2,28 @@ //! //! Command-line tool for managing OAuth2 Gateway clients. //! -//! Set DATABASE_URL environment variable to connect to the database. //! Usage: -//! kych-client-management list -//! kych-client-management show <client_id> -//! kych-client-management create --client-id <id> --secret <secret> ... -//! kych-client-management update <client_id> --webhook-url <url> -//! kych-client-management sync kych.conf -//! kych-client-management delete <client_id> +//! kych-client-management --config kych.conf list +//! kych-client-management --config kych.conf show <client_id> +//! kych-client-management --config kych.conf create --client-id <id> --secret <secret> ... +//! kych-client-management --config kych.conf update <client_id> --webhook-url <url> +//! kych-client-management --config kych.conf sync +//! kych-client-management --config kych.conf delete <client_id> use anyhow::{Context, Result}; use clap::{Parser, Subcommand}; -use ini::Ini; -use kych_oauth2_gateway_lib::db; -use std::env; +use kych_oauth2_gateway_lib::{config::Config, db}; use std::collections::HashSet; #[derive(Parser, Debug)] #[command(name = "client-mgmt")] - #[command(version)] #[command(about = "OAuth2 Gateway client management CLI")] -#[command(after_help = "Environment variables:\n DATABASE_URL PostgreSQL connection string (required)")] struct Args { + /// Path to kych.conf configuration file + #[arg(long, short = 'c', required = true)] + config: String, + #[command(subcommand)] command: Commands, } @@ -88,9 +87,6 @@ enum Commands { /// Sync clients from configuration file (reads [client_*] sections) Sync { - /// Path to kych.conf file - config_file: String, - /// Remove clients not in config file #[arg(long)] prune: bool, @@ -107,21 +103,18 @@ enum Commands { #[tokio::main] async fn main() -> Result<()> { - // Load .env (ignore if missing) - let _ = dotenvy::dotenv(); - let args = Args::parse(); - let database_url = env::var("DATABASE_URL") - .context("DATABASE_URL environment variable not set")?; + let config = Config::from_file(&args.config) + .context(format!("Failed to load config from '{}'", args.config))?; - let pool = db::create_pool(&database_url) + let pool = db::create_pool(&config.database.url) .await .context("Failed to connect to database")?; match args.command { Commands::List => cmd_list_clients(&pool).await?, - Commands::Show { client_id } => cmd_show_client(&pool,&client_id).await?, + Commands::Show { client_id } => cmd_show_client(&pool, &client_id).await?, Commands::Create { client_id, secret, @@ -162,8 +155,8 @@ async fn main() -> Result<()> { ) .await? } - Commands::Sync { config_file, prune } => { - cmd_sync_clients(&pool, &config_file, prune).await? + Commands::Sync { prune } => { + cmd_sync_clients(&pool, &config, prune).await? } Commands::Delete { client_id, yes } => { cmd_delete_client(&pool, &client_id, yes).await? @@ -326,74 +319,53 @@ async fn cmd_delete_client(pool: &sqlx::PgPool, client_id: &str, skip_confirm: b Ok(()) } -async fn cmd_sync_clients(pool: &sqlx::PgPool, config_file: &str, prune: bool) -> Result<()> { - println!("Loading clients from: {}", config_file); - - let ini = Ini::load_from_file(config_file) - .context("Failed to load configuration file")?; +async fn cmd_sync_clients(pool: &sqlx::PgPool, config: &Config, prune: bool) -> Result<()> { + println!("Syncing {} client(s) from configuration...", config.clients.len()); let mut synced_client_ids = HashSet::new(); let mut created_count = 0; let mut updated_count = 0; - for (section_name, properties) in ini.iter() { - let section_name = match section_name { - Some(name) if name.starts_with("client_") => name, - _ => continue, - }; - - println!("\nProcessing section: [{}]", section_name); - - let client_id = properties.get("CLIENT_ID") - .ok_or_else(|| anyhow::anyhow!("Missing CLIENT_ID in section [{}]", section_name))?; - let client_secret = properties.get("CLIENT_SECRET") - .ok_or_else(|| anyhow::anyhow!("Missing CLIENT_SECRET in section [{}]", section_name))?; - let webhook_url = properties.get("WEBHOOK_URL") - .ok_or_else(|| anyhow::anyhow!("Missing WEBHOOK_URL in section [{}]", section_name))?; - let verifier_url = properties.get("VERIFIER_URL") - .ok_or_else(|| anyhow::anyhow!("Missing VERIFIER_URL in section [{}]", section_name))?; - - let verifier_api_path = properties.get("VERIFIER_MANAGEMENT_API_PATH"); - let redirect_uri = properties.get("REDIRECT_URI"); - let accepted_issuer_dids = properties.get("ACCEPTED_ISSUER_DIDS"); + for client_config in &config.clients { + println!("\nProcessing section: [{}]", client_config.section_name); - synced_client_ids.insert(client_id.to_string()); + synced_client_ids.insert(client_config.client_id.clone()); - let existing_client = db::clients::get_client_by_id(pool, client_id).await?; + let existing_client = db::clients::get_client_by_id(pool, &client_config.client_id).await?; match existing_client { Some(existing) => { - println!(" Client '{}' already exists, updating...", client_id); + println!(" Client '{}' already exists, updating...", client_config.client_id); db::clients::update_client( pool, existing.id, - Some(webhook_url), - Some(verifier_url), - verifier_api_path, - redirect_uri, - accepted_issuer_dids, + Some(&client_config.webhook_url), + Some(&client_config.verifier_url), + Some(&client_config.verifier_management_api_path), + client_config.redirect_uri.as_deref(), + client_config.accepted_issuer_dids.as_deref(), ) .await - .context(format!("Failed to update client '{}'", client_id))?; + .context(format!("Failed to update client '{}'", client_config.client_id))?; updated_count += 1; - println!(" Updated client '{}'", client_id); + println!(" Updated client '{}'", client_config.client_id); } None => { - println!(" Creating new client '{}'...", client_id); + println!(" Creating new client '{}'...", client_config.client_id); db::clients::register_client( pool, - client_id, - client_secret, - webhook_url, - verifier_url, - verifier_api_path, - redirect_uri, - accepted_issuer_dids, + &client_config.client_id, + &client_config.client_secret, + &client_config.webhook_url, + &client_config.verifier_url, + Some(&client_config.verifier_management_api_path), + client_config.redirect_uri.as_deref(), + client_config.accepted_issuer_dids.as_deref(), ) .await - .context(format!("Failed to create client '{}'", client_id))?; + .context(format!("Failed to create client '{}'", client_config.client_id))?; created_count += 1; - println!(" Created client '{}'", client_id); + println!(" Created client '{}'", client_config.client_id); } } }