From 645d440b4a9795fb96c355bb10bb3a4708e0aee6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandra=20Theresa=20Ke=C3=9Fler?= Date: Fri, 15 May 2026 13:05:09 +0200 Subject: [PATCH] fix(ws-bridged): apply --topic/--auth-token/--tls/--metrics to config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bisher mergte run() in bin/zerodds-ws-bridged.rs nur --listen, --domain und --log-level in die DaemonConfig. Alle anderen CLI-Flags wurden via cli::parse() korrekt geparst, dann aber ignoriert. Resultat: ein User der --topic Foo --auth-token secret startet, bekommt eine Bridge mit topics=0, auth-mode=none. Fix: apply_cli_overrides() extrahiert, mit allen Feldern. --topic ist additiv (an cfg.topics angehängt) mit default_ws_path-Mapping; alle anderen Flags sind Replace-Operationen. --auth-token impliziert auth_mode=bearer, --tls-cert/--tls-key impliziert tls_enabled=true, --metrics impliziert metrics_enabled=true (CLI-Setzen-bedeutet-Aktiv). Plus 8 Unit-Tests in einem cfg(test)-Module direkt im bin-Crate. Signed-off-by: Sandra Theresa Keßler --- .../src/bin/zerodds-ws-bridged.rs | 152 ++++++++++++++++-- 1 file changed, 143 insertions(+), 9 deletions(-) diff --git a/crates/websocket-bridge/src/bin/zerodds-ws-bridged.rs b/crates/websocket-bridge/src/bin/zerodds-ws-bridged.rs index a35ce05b..92229d17 100644 --- a/crates/websocket-bridge/src/bin/zerodds-ws-bridged.rs +++ b/crates/websocket-bridge/src/bin/zerodds-ws-bridged.rs @@ -76,15 +76,7 @@ fn run(args: CliArgs) -> Result<(), ServerError> { } else { DaemonConfig::default_for_dev() }; - if let Some(l) = args.listen { - cfg.listen = l; - } - if let Some(d) = args.domain { - cfg.domain = d; - } - if let Some(lvl) = args.log_level { - cfg.log_level = lvl; - } + apply_cli_overrides(&mut cfg, args); let handle = server::start(cfg)?; eprintln!("[zerodds-ws-bridged] running on {}", handle.local_addr); @@ -102,3 +94,145 @@ fn run(args: CliArgs) -> Result<(), ServerError> { Ok(()) } } + +/// Wendet CLI-Overrides auf die geladene Config an. Public-in-Crate fuer Tests. +/// +/// Spec §2: CLI ueberschreibt File-Werte. `--topic` ist additiv (kann mehrfach +/// vorkommen), alle anderen Flags sind Replace-Operationen. +fn apply_cli_overrides(cfg: &mut DaemonConfig, args: CliArgs) { + if let Some(l) = args.listen { + cfg.listen = l; + } + if let Some(d) = args.domain { + cfg.domain = d; + } + if let Some(lvl) = args.log_level { + cfg.log_level = lvl; + } + if let Some(token) = args.auth_token { + cfg.auth_mode = "bearer".to_string(); + cfg.auth_bearer_token = Some(token); + } + if let Some(cert) = args.tls_cert { + cfg.tls_cert_file = cert; + cfg.tls_enabled = true; + } + if let Some(key) = args.tls_key { + cfg.tls_key_file = key; + cfg.tls_enabled = true; + } + if let Some(addr) = args.metrics { + cfg.metrics_addr = addr; + cfg.metrics_enabled = true; + } + if !args.topics.is_empty() { + for name in args.topics { + // Default: bidir, ws_path via default_ws_path, type_name == name. + let topic = zerodds_websocket_bridge::daemon::config::TopicConfig { + name: name.clone(), + type_name: name.clone(), + direction: "bidir".to_string(), + ws_path: + zerodds_websocket_bridge::daemon::config::default_ws_path(&name), + ..Default::default() + }; + cfg.topics.push(topic); + } + } +} + +#[cfg(test)] +mod tests { + use super::apply_cli_overrides; + use zerodds_websocket_bridge::daemon::cli::CliArgs; + use zerodds_websocket_bridge::daemon::config::DaemonConfig; + + fn cfg() -> DaemonConfig { + DaemonConfig::default_for_dev() + } + + #[test] + fn listen_override_replaces_default() { + let mut c = cfg(); + let mut a = CliArgs::default(); + a.listen = Some("0.0.0.0:9000".into()); + apply_cli_overrides(&mut c, a); + assert_eq!(c.listen, "0.0.0.0:9000"); + } + + #[test] + fn domain_override_replaces_default() { + let mut c = cfg(); + let mut a = CliArgs::default(); + a.domain = Some(42); + apply_cli_overrides(&mut c, a); + assert_eq!(c.domain, 42); + } + + #[test] + fn log_level_override_replaces_default() { + let mut c = cfg(); + let mut a = CliArgs::default(); + a.log_level = Some("debug".into()); + apply_cli_overrides(&mut c, a); + assert_eq!(c.log_level, "debug"); + } + + #[test] + fn auth_token_sets_bearer_mode_and_token() { + let mut c = cfg(); + let mut a = CliArgs::default(); + a.auth_token = Some("secret-32-bytes".into()); + apply_cli_overrides(&mut c, a); + assert_eq!(c.auth_mode, "bearer"); + assert_eq!(c.auth_bearer_token.as_deref(), Some("secret-32-bytes")); + } + + #[test] + fn tls_cert_and_key_enable_tls() { + let mut c = cfg(); + let mut a = CliArgs::default(); + a.tls_cert = Some("/etc/tls/cert.pem".into()); + a.tls_key = Some("/etc/tls/key.pem".into()); + apply_cli_overrides(&mut c, a); + assert!(c.tls_enabled); + assert_eq!(c.tls_cert_file, "/etc/tls/cert.pem"); + assert_eq!(c.tls_key_file, "/etc/tls/key.pem"); + } + + #[test] + fn metrics_addr_enables_metrics() { + let mut c = cfg(); + let mut a = CliArgs::default(); + a.metrics = Some("0.0.0.0:9091".into()); + apply_cli_overrides(&mut c, a); + assert!(c.metrics_enabled); + assert_eq!(c.metrics_addr, "0.0.0.0:9091"); + } + + #[test] + fn topics_cli_appends_to_existing() { + let mut c = cfg(); + let mut a = CliArgs::default(); + a.topics = vec!["Card".into(), "Thread".into()]; + apply_cli_overrides(&mut c, a); + assert_eq!(c.topics.len(), 2); + assert_eq!(c.topics[0].name, "Card"); + assert_eq!(c.topics[0].direction, "bidir"); + assert_eq!(c.topics[0].ws_path, "/topics/card"); + assert_eq!(c.topics[1].name, "Thread"); + } + + #[test] + fn empty_args_leaves_config_unchanged() { + let mut c = cfg(); + let baseline = c.clone(); + apply_cli_overrides(&mut c, CliArgs::default()); + assert_eq!(c.listen, baseline.listen); + assert_eq!(c.domain, baseline.domain); + assert!(!c.tls_enabled); + assert!(!c.metrics_enabled); + assert_eq!(c.auth_mode, "none"); + assert!(c.topics.is_empty()); + } +}