From ee6b992c8ec999a1d71fbc3ddcdb8821801e8c67 Mon Sep 17 00:00:00 2001 From: Stefan Menner Date: Sun, 22 Jun 2025 16:49:54 +0200 Subject: [PATCH] Update Doc & Fallback improvement --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/config/env.rs | 177 ++++++++++++++++++++++++---------------------- 3 files changed, 96 insertions(+), 85 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7e38b17..f182f91 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,4 +4,4 @@ version = 4 [[package]] name = "merlin_env_helper" -version = "0.3.0" +version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index 59a4a7c..ed8dc95 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "merlin_env_helper" -version = "0.3.0" +version = "0.4.0" edition = "2024" publish = ["merlin"] description = "Utility functions to read environment with fallback and values from a file" diff --git a/src/config/env.rs b/src/config/env.rs index 931533e..2472030 100644 --- a/src/config/env.rs +++ b/src/config/env.rs @@ -30,13 +30,17 @@ //! } //! ``` use core::fmt; -use std::{error::Error, fmt::{Display, Formatter}, io::{self, Read}, path::Path}; +use std::{ + error::Error, + fmt::{Display, Formatter}, + io::{self, Read}, + path::Path, +}; use crate::config::types::EnvKey; pub type Result = std::result::Result; - #[derive(Debug)] #[non_exhaustive] pub struct ConfigError { @@ -60,7 +64,6 @@ impl Error for ConfigError { } } - /// The kind of error that can occur when reading a configuration key. #[derive(Debug)] pub enum ConfigErrorKind { @@ -82,17 +85,26 @@ impl Display for ConfigErrorMessage { } } -impl Error for ConfigErrorMessage { -} +impl Error for ConfigErrorMessage {} - - -pub fn get_env_value(env_key : &EnvKey) -> Result { +/// Retrieves the value of an environment variable or a secure file-based secret. +/// If not specified, a fallback value is returned if one is specified, otherwise an error is returned. +pub fn get_env_value(env_key: &EnvKey) -> Result { if let Some(sec_key) = &env_key.sec_key { let key = std::env::var(&sec_key); if let Ok(path_file) = key { - return read_secure_value(&env_key.key, &path_file); + let result = read_secure_value(&env_key.key, &path_file); + + if let Ok(value) = result { + return Ok(value); + } + + if let Some(fallback) = &env_key.fallback { + return Ok(fallback.to_string()); + } + + return result; } } @@ -102,7 +114,6 @@ pub fn get_env_value(env_key : &EnvKey) -> Result { fn read_key_value(key: &str, fallback: &Option) -> Result { let env_value = std::env::var(key); - println!("env_value: {:?}", env_value); if let Ok(value) = env_value { return Ok(value); } @@ -111,21 +122,16 @@ fn read_key_value(key: &str, fallback: &Option) -> Result { return Ok(fallback.to_string()); } - Err( - ConfigError { - key: key.to_string(), - kind: ConfigErrorKind::NotFound, - } - ) + Err(ConfigError { + key: key.to_string(), + kind: ConfigErrorKind::NotFound, + }) } - fn read_secure_value(key: &str, path_file: &str) -> Result { - let path = Path::new(path_file); let exists = path.try_exists().map_err(|e| -> ConfigError { - println!("path.try_exists(): {:?}", e); ConfigError { key: format!("{}: {} File not found.", key.to_string(), path_file), kind: ConfigErrorKind::IO(e), @@ -133,18 +139,15 @@ fn read_secure_value(key: &str, path_file: &str) -> Result { })?; if !exists { - return Err( - ConfigError { - key: format!("{}: {} File not found.", key.to_string(), path_file), - kind: ConfigErrorKind::FileNotFound(ConfigErrorMessage { - msg: format!("File not found: {}", path_file), - }), - } - ); + return Err(ConfigError { + key: format!("{}: {} File not found.", key.to_string(), path_file), + kind: ConfigErrorKind::FileNotFound(ConfigErrorMessage { + msg: format!("File not found: {}", path_file), + }), + }); } let file = std::fs::File::open(path).map_err(|e| -> ConfigError { - println!("std::fs::File::open(path_file): {:?}", e); ConfigError { key: key.to_string(), kind: ConfigErrorKind::IO(e), @@ -154,17 +157,18 @@ fn read_secure_value(key: &str, path_file: &str) -> Result { let mut reader = std::io::BufReader::new(file); let mut content = String::new(); - reader.read_to_string(&mut content).map_err(|e| -> ConfigError { - ConfigError { - key: key.to_string(), - kind: ConfigErrorKind::IO(e), - } - })?; + reader + .read_to_string(&mut content) + .map_err(|e| -> ConfigError { + ConfigError { + key: key.to_string(), + kind: ConfigErrorKind::IO(e), + } + })?; Ok(content) } - #[cfg(test)] mod tests { use super::*; @@ -172,26 +176,27 @@ mod tests { fn clean_up(reset_value: &Option) { if let Some(value) = reset_value { - unsafe {std::env::set_var("TEST_KEY", value)}; + unsafe { std::env::set_var("TEST_KEY", value) }; } else { - unsafe {std::env::remove_var("TEST_KEY")}; - } + unsafe { std::env::remove_var("TEST_KEY") }; + } } - fn run_test(env_key : &str, test: T, clean_up: U) -> () - where T: FnOnce() -> () + std::panic::UnwindSafe - , U: FnOnce(&Option) -> () + fn run_test(env_key: &str, test: T, clean_up: U) -> () + where + T: FnOnce() -> () + std::panic::UnwindSafe, + U: FnOnce(&Option) -> (), { - let old_value = std::env::var(env_key); - let mut reset_value= None; + let old_value = std::env::var(env_key); + let mut reset_value = None; if let Ok(value) = old_value { reset_value = Some(value.clone()); } - let result = panic::catch_unwind( || { - test(); - }); + let result = panic::catch_unwind(|| { + test(); + }); clean_up(&reset_value); @@ -200,54 +205,60 @@ mod tests { #[test] fn test_get_env_value() { - - run_test("TEST_KEY", || { - let key = "TEST_KEY"; - let value = "test_value"; - unsafe {std::env::set_var(key, value)}; - let env_key = EnvKey::key(key); - let result = get_env_value(&env_key); - assert_eq!(result.is_ok(), true); - assert_eq!(result.unwrap(), value); - - }, - clean_up + run_test( + "TEST_KEY", + || { + let key = "TEST_KEY"; + let value = "test_value"; + unsafe { std::env::set_var(key, value) }; + let env_key = EnvKey::key(key); + let result = get_env_value(&env_key); + assert_eq!(result.is_ok(), true); + assert_eq!(result.unwrap(), value); + }, + clean_up, ); - } #[test] fn test_get_env_value_with_fallback() { - run_test("TEST_KEY", || { - let key = "TEST_KEY"; - let fallback_value = "fallback_value"; + run_test( + "TEST_KEY", + || { + let key = "TEST_KEY"; + let fallback_value = "fallback_value"; - let env_key = EnvKey::key_with_fallback(key, fallback_value); - let result = get_env_value(&env_key); - assert_eq!(result.is_ok(), true); - assert_eq!(result.unwrap(), fallback_value); - }, - clean_up); + let env_key = EnvKey::key_with_fallback(key, fallback_value); + let result = get_env_value(&env_key); + assert_eq!(result.is_ok(), true); + assert_eq!(result.unwrap(), fallback_value); + }, + clean_up, + ); } #[test] fn test_get_env_value_with_secure_key() { - run_test("TEST_KEY", || { - let key = "TEST_KEY"; - let value = "test_value"; - let secure_key = "TEST_KEY_FILE"; - let secure_value = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("resources/test/test_secret.txt"); + run_test( + "TEST_KEY", + || { + let key = "TEST_KEY"; + let value = "test_value"; + let secure_key = "TEST_KEY_FILE"; + let secure_value = PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("resources/test/test_secret.txt"); - unsafe {std::env::set_var(key, value)}; - unsafe {std::env::set_var(secure_key, &secure_value)}; + unsafe { std::env::set_var(key, value) }; + unsafe { std::env::set_var(secure_key, &secure_value) }; - assert_eq!(secure_value.try_exists().unwrap(), true); + assert_eq!(secure_value.try_exists().unwrap(), true); - let env_key = EnvKey::secure_key(key, secure_key); - let result = get_env_value(&env_key); - assert_eq!(result.is_ok(), true); - assert_eq!(result.unwrap(), "my_secret"); - }, - clean_up); + let env_key = EnvKey::secure_key(key, secure_key); + let result = get_env_value(&env_key); + assert_eq!(result.is_ok(), true); + assert_eq!(result.unwrap(), "my_secret"); + }, + clean_up, + ); } -} \ No newline at end of file +}