diff --git a/src/cli.rs b/src/cli.rs index bcf46fd..4c9d665 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -12,6 +12,7 @@ //! no flags. Each flag has a matching `ANWESEN_` environment variable //! and CLI wins over env per the manual. +use std::net::SocketAddr; use std::path::PathBuf; use clap::{Parser, Subcommand, ValueEnum}; @@ -41,7 +42,7 @@ pub struct ServeArgs { /// Listen address for the HTTP server. #[arg(long, env = "ANWESEN_BIND", default_value = "127.0.0.1:8080")] - pub bind: String, + pub bind: SocketAddr, /// Log verbosity. #[arg(long, env = "ANWESEN_LOG_LEVEL", default_value = "info")] @@ -109,13 +110,19 @@ mod tests { match cli.command { Command::Serve(a) => { assert_eq!(a.vault, PathBuf::from("/tmp/v")); - assert_eq!(a.bind, "0.0.0.0:9000"); + assert_eq!(a.bind, "0.0.0.0:9000".parse::().unwrap()); assert!(matches!(a.log_level, LogLevel::Debug)); } _ => panic!("expected serve"), } } + #[test] + fn serve_rejects_malformed_bind_at_parse_time() { + let err = parse(&["serve", "--vault", "/tmp/v", "--bind", "not-an-addr"]).unwrap_err(); + assert_eq!(err.kind(), clap::error::ErrorKind::ValueValidation); + } + #[test] fn doctor_rejects_bind() { // --bind is serve-only; doctor must not accept it. diff --git a/src/main.rs b/src/main.rs index 0f18275..cf41e1f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -40,8 +40,11 @@ fn main() -> Result<()> { } fn init_logging(level: cli::LogLevel) { - let filter = tracing_subscriber::EnvFilter::try_from_env("ANWESEN_LOG") - .unwrap_or_else(|_| tracing_subscriber::EnvFilter::new(level.as_filter_directive())); + // The User Manual lists --log-level / ANWESEN_LOG_LEVEL as the only knobs + // for verbosity, and pins "CLI flags win over environment variables". + // Resolution happens in clap; this function only builds the filter from + // the already-resolved level. + let filter = tracing_subscriber::EnvFilter::new(level.as_filter_directive()); let _ = tracing_subscriber::fmt() .with_env_filter(filter) .with_writer(std::io::stderr)