From 421fb591849715f8d91c9db27e8b9a7a18333424 Mon Sep 17 00:00:00 2001 From: Jose Bovet Derpich Date: Sun, 8 Feb 2026 00:49:58 -0300 Subject: [PATCH] refactor: simplify --exit-code from integer to boolean flag The exit_code option was an integer that behaved as a boolean. Simplify to a true boolean flag: --exit-code enables exit code 1 on certificate issues, omitting it always exits 0. Co-Authored-By: Claude Opus 4.6 --- src/config.rs | 36 ++++++++++++++++++------------------ src/main.rs | 44 +++++++++++++++++++++++--------------------- 2 files changed, 41 insertions(+), 39 deletions(-) diff --git a/src/config.rs b/src/config.rs index fb0571f..0209ef9 100644 --- a/src/config.rs +++ b/src/config.rs @@ -15,7 +15,7 @@ //! ```toml //! hosts = ["example.com", "example.com:8443"] //! output = "summary" -//! exit_code = 1 +//! exit_code = true //! check_revocation = true //! //! [prometheus] @@ -37,8 +37,8 @@ pub struct Config { pub hosts: Option>, /// Output format: json, text, summary pub output: Option, - /// Exit code to use when certificates are expired/revoked - pub exit_code: Option, + /// Enable non-zero exit code when certificate issues are found + pub exit_code: Option, /// Enable certificate revocation checking pub check_revocation: Option, /// Prometheus configuration @@ -95,7 +95,7 @@ impl Config { /// /// - `hosts`: None (must be provided) /// - `output`: "summary" - /// - `exit_code`: 0 (don't fail on expired certificates) + /// - `exit_code`: false (don't fail on certificate issues) /// - `check_revocation`: false /// - `prometheus.enabled`: false /// - `prometheus.address`: "http://localhost:9091" @@ -107,7 +107,7 @@ impl Config { Config { hosts: None, output: Some("summary".to_string()), - exit_code: Some(0), + exit_code: Some(false), check_revocation: Some(false), prometheus: Some(PrometheusConfig { enabled: Some(false), @@ -179,7 +179,7 @@ impl Config { /// /// * `addresses` - List of hosts to check /// * `output` - Output format (json, text, summary) - /// * `exit_code` - Exit code for failures + /// * `exit_code` - Enable exit code on certificate issues /// * `prometheus` - Enable Prometheus metrics /// * `prometheus_address` - Prometheus push gateway address /// * `check_revocation` - Enable certificate revocation checking @@ -190,7 +190,7 @@ impl Config { pub fn from_cli_args( addresses: Option>, output: Option, - exit_code: Option, + exit_code: Option, prometheus: Option, prometheus_address: Option, check_revocation: Option, @@ -235,7 +235,7 @@ impl Config { "expired.badssl.com".to_string(), ]), output: Some("summary".to_string()), - exit_code: Some(1), + exit_code: Some(true), check_revocation: Some(true), prometheus: Some(PrometheusConfig { enabled: Some(true), @@ -283,7 +283,7 @@ mod tests { let toml_content = r#" hosts = ["jpbd.dev", "google.cl"] output = "json" - exit_code = 1 + exit_code = true check_revocation = true [prometheus] @@ -301,7 +301,7 @@ mod tests { Some(vec!["jpbd.dev".to_string(), "google.cl".to_string()]) ); assert_eq!(config.output, Some("json".to_string())); - assert_eq!(config.exit_code, Some(1)); + assert_eq!(config.exit_code, Some(true)); assert_eq!(config.check_revocation, Some(true)); let prometheus = config.prometheus.unwrap(); @@ -317,7 +317,7 @@ mod tests { let base_config = Config { hosts: Some(vec!["base.com".to_string()]), output: Some("text".to_string()), - exit_code: Some(0), + exit_code: Some(false), check_revocation: Some(false), prometheus: Some(PrometheusConfig { enabled: Some(false), @@ -329,7 +329,7 @@ mod tests { let override_config = Config { hosts: Some(vec!["override.com".to_string()]), output: None, - exit_code: Some(1), + exit_code: Some(true), check_revocation: Some(true), prometheus: Some(PrometheusConfig { enabled: Some(true), @@ -343,7 +343,7 @@ mod tests { // Override config should take precedence where specified assert_eq!(merged.hosts, Some(vec!["override.com".to_string()])); assert_eq!(merged.output, Some("text".to_string())); // From base (not overridden) - assert_eq!(merged.exit_code, Some(1)); // Overridden + assert_eq!(merged.exit_code, Some(true)); // Overridden assert_eq!(merged.check_revocation, Some(true)); // Overridden let prometheus = merged.prometheus.unwrap(); @@ -358,7 +358,7 @@ mod tests { assert_eq!(config.hosts, None); assert_eq!(config.output, Some("summary".to_string())); - assert_eq!(config.exit_code, Some(0)); + assert_eq!(config.exit_code, Some(false)); assert_eq!(config.check_revocation, Some(false)); let prometheus = config.prometheus.unwrap(); @@ -374,7 +374,7 @@ mod tests { let config = Config::from_cli_args( Some(vec!["cli.com".to_string()]), Some("json".to_string()), - Some(2), + Some(true), Some(true), Some("http://cli:9091".to_string()), Some(true), @@ -383,7 +383,7 @@ mod tests { assert_eq!(config.hosts, Some(vec!["cli.com".to_string()])); assert_eq!(config.output, Some("json".to_string())); - assert_eq!(config.exit_code, Some(2)); + assert_eq!(config.exit_code, Some(true)); assert_eq!(config.check_revocation, Some(true)); assert_eq!(config.grade, Some(true)); @@ -460,7 +460,7 @@ mod tests { let base = Config { hosts: Some(vec!["base.com".to_string()]), output: Some("json".to_string()), - exit_code: Some(1), + exit_code: Some(true), check_revocation: Some(true), prometheus: Some(PrometheusConfig { enabled: Some(true), @@ -479,7 +479,7 @@ mod tests { let merged = base.merge_with(empty_override); assert_eq!(merged.hosts, Some(vec!["base.com".to_string()])); assert_eq!(merged.output, Some("json".to_string())); - assert_eq!(merged.exit_code, Some(1)); + assert_eq!(merged.exit_code, Some(true)); assert_eq!(merged.check_revocation, Some(true)); assert_eq!(merged.grade, Some(true)); assert!(merged.prometheus.is_some()); diff --git a/src/main.rs b/src/main.rs index cc129b6..2e911b0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -40,12 +40,13 @@ struct Args { #[arg(short, value_enum)] output: Option, - /// Exit with this code when expired or revoked certificates are found. + /// Exit with code 1 when certificate issues are found. /// - /// Defaults to 0 (always succeed). Set to 1 for CI/CD pipelines - /// that should fail on certificate issues. - #[arg(long)] - exit_code: Option, + /// Issues include: expired certificates, revoked certificates, + /// or certificates below the --min-validity threshold. + /// Disabled by default (always exits 0). + #[arg(long, default_value_t = false)] + exit_code: bool, /// Push certificate metrics to a Prometheus Push Gateway #[arg(long)] @@ -462,7 +463,7 @@ struct HostPort { struct FinalConfig { addresses: Vec, output: OutFormat, - exit_code: i32, + exit_code: bool, prometheus: bool, prometheus_address: String, check_revocation: bool, @@ -496,7 +497,7 @@ impl FinalConfig { Ok(FinalConfig { addresses, output, - exit_code: config.exit_code.unwrap_or(0), + exit_code: config.exit_code.unwrap_or(false), prometheus: prometheus_config.enabled.unwrap_or(false), prometheus_address: prometheus_config .address @@ -690,7 +691,7 @@ fn load_config(cli: &Args) -> Result { let cli_config = Config::from_cli_args( cli_addresses, cli.output.as_ref().map(|o| o.to_string()), - cli.exit_code, + if cli.exit_code { Some(true) } else { None }, cli.prometheus, cli.prometheus_address.clone(), cli.check_revocation, @@ -703,24 +704,25 @@ fn load_config(cli: &Args) -> Result { FinalConfig::from_merged_config(config) } -/// Exits the program with the appropriate exit code. +/// Exits the program with code 1 when certificate issues are detected. /// /// This function implements conditional exit behavior based on whether -/// any certificates failed validation (expired or revoked). +/// any certificates failed validation (expired, revoked, or below +/// the minimum validity threshold). /// /// # Arguments /// -/// * `exit_code` - The exit code to use when failures are detected +/// * `exit_code` - Whether to enable non-zero exit codes on failure /// * `failed_result` - Whether any certificate checks failed /// /// # Behavior /// -/// - If `failed_result` is `true` and `exit_code` is non-zero, exits with `exit_code` +/// - If `exit_code` is `true` and `failed_result` is `true`, exits with code 1 /// - Otherwise, exits normally with code 0 /// - Useful for CI/CD pipelines where exit code indicates build success/failure -fn exit(exit_code: i32, failed_result: bool) { - if exit_code != 0 && failed_result { - std::process::exit(exit_code) +fn exit(exit_code: bool, failed_result: bool) { + if exit_code && failed_result { + std::process::exit(1) } } @@ -918,7 +920,7 @@ mod tests { let config = Config { hosts: None, output: Some("summary".to_string()), - exit_code: Some(0), + exit_code: Some(false), check_revocation: Some(false), prometheus: None, grade: Some(false), @@ -932,7 +934,7 @@ mod tests { let config = Config { hosts: Some(vec![]), output: Some("summary".to_string()), - exit_code: Some(0), + exit_code: Some(false), check_revocation: Some(false), prometheus: None, grade: Some(false), @@ -946,7 +948,7 @@ mod tests { let config = Config { hosts: Some(vec!["example.com".to_string()]), output: Some("xml".to_string()), - exit_code: Some(0), + exit_code: Some(false), check_revocation: Some(false), prometheus: None, grade: Some(false), @@ -967,7 +969,7 @@ mod tests { }; let final_config = FinalConfig::from_merged_config(config).unwrap(); assert_eq!(final_config.output, OutFormat::Summary); - assert_eq!(final_config.exit_code, 0); + assert!(!final_config.exit_code); assert!(!final_config.check_revocation); assert!(!final_config.prometheus); assert!(!final_config.grade); @@ -979,7 +981,7 @@ mod tests { let config = Config { hosts: Some(vec!["a.com".to_string(), "b.com".to_string()]), output: Some("json".to_string()), - exit_code: Some(2), + exit_code: Some(true), check_revocation: Some(true), prometheus: Some(config::PrometheusConfig { enabled: Some(true), @@ -990,7 +992,7 @@ mod tests { let final_config = FinalConfig::from_merged_config(config).unwrap(); assert_eq!(final_config.addresses, vec!["a.com", "b.com"]); assert_eq!(final_config.output, OutFormat::Json); - assert_eq!(final_config.exit_code, 2); + assert!(final_config.exit_code); assert!(final_config.check_revocation); assert!(final_config.prometheus); assert_eq!(final_config.prometheus_address, "http://prom:9091");