Files
thakaresandCopilot 2ac6c81dfe cli: avoid data-dir initialization for version; create db parent dirs; redact generated passwords in CLI output
- Prevent 'nx9-wg version' from creating data directories by avoiding database initialization.
- Create parent directories when an explicit --database path is provided.
- Redact printed generated administrator passwords; announce file path or redact instead.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-08-16 16:26:24 +05:30

165 lines
5.8 KiB
Rust

//! Automated validation suite for environment variable namespace and precedence.
use nx9_wg_core::config::{AppConfig, BootstrapConfig};
use std::path::PathBuf;
use std::sync::Mutex;
static ENV_MUTEX: Mutex<()> = Mutex::new(());
#[test]
fn test_nx9_wg_env_variable_precedence_and_overrides() {
let _lock = ENV_MUTEX.lock().unwrap();
let mut config = AppConfig::default();
// Set canonical NX9_WG_ environment variables
unsafe {
std::env::set_var("NX9_WG_CONFIG", "/custom/etc/config.toml");
std::env::set_var("NX9_WG_DATA_DIR", "/custom/var/data");
std::env::set_var("NX9_WG_LISTEN_ADDR", "127.0.0.1:9090");
std::env::set_var("NX9_WG_LOG_LEVEL", "warn");
std::env::set_var("NX9_WG_SESSION_TIMEOUT", "72");
std::env::set_var("NX9_WG_RECONCILIATION_INTERVAL", "15");
std::env::set_var("NX9_WG_BACKUP_DIR", "/custom/backups");
std::env::set_var("NX9_WG_BACKUP_MAX_COUNT", "20");
std::env::set_var("NX9_WG_BACKUP_SCHEDULE", "0 3 * * *");
std::env::set_var("NX9_WG_ADMIN_USERNAME", "superadmin");
std::env::set_var("NX9_WG_ADMIN_PASSWORD", "SuperSecretPW987!");
}
config.apply_env_overrides().expect("apply env overrides");
assert_eq!(config.config_file, PathBuf::from("/custom/etc/config.toml"));
assert_eq!(config.data_dir, PathBuf::from("/custom/var/data"));
assert_eq!(config.bind_address, "127.0.0.1:9090".parse().unwrap());
assert_eq!(config.log_level, "warn");
assert_eq!(config.session_expiry_hours, 72);
assert_eq!(config.reconciliation_interval_secs, 15);
assert_eq!(config.backup.dir, PathBuf::from("/custom/backups"));
assert_eq!(config.backup.max_count, 20);
assert_eq!(config.backup.schedule, Some("0 3 * * *".to_string()));
let boot = config.bootstrap.expect("bootstrap should be present");
assert_eq!(boot.admin_username, Some("superadmin".to_string()));
assert_eq!(boot.admin_password, Some("SuperSecretPW987!".to_string()));
// Clean up
unsafe {
std::env::remove_var("NX9_WG_CONFIG");
std::env::remove_var("NX9_WG_DATA_DIR");
std::env::remove_var("NX9_WG_LISTEN_ADDR");
std::env::remove_var("NX9_WG_LOG_LEVEL");
std::env::remove_var("NX9_WG_SESSION_TIMEOUT");
std::env::remove_var("NX9_WG_RECONCILIATION_INTERVAL");
std::env::remove_var("NX9_WG_BACKUP_DIR");
std::env::remove_var("NX9_WG_BACKUP_MAX_COUNT");
std::env::remove_var("NX9_WG_BACKUP_SCHEDULE");
std::env::remove_var("NX9_WG_ADMIN_USERNAME");
std::env::remove_var("NX9_WG_ADMIN_PASSWORD");
}
}
#[test]
fn test_invalid_env_variable_values() {
let _lock = ENV_MUTEX.lock().unwrap();
let mut config = AppConfig::default();
unsafe {
std::env::set_var("NX9_WG_LISTEN_ADDR", "invalid-ip-and-port");
}
assert!(config.apply_env_overrides().is_err());
unsafe {
std::env::remove_var("NX9_WG_LISTEN_ADDR");
}
unsafe {
std::env::set_var("NX9_WG_SESSION_TIMEOUT", "not-a-number");
}
assert!(config.apply_env_overrides().is_err());
unsafe {
std::env::remove_var("NX9_WG_SESSION_TIMEOUT");
}
}
#[test]
fn test_secret_redaction() {
let boot = BootstrapConfig {
admin_username: Some("admin".to_string()),
admin_password: Some("secret12345".to_string()),
};
let formatted = format!("{boot:?}");
assert!(!formatted.contains("secret12345"));
assert!(formatted.contains("[REDACTED]"));
}
#[test]
fn test_database_path_resolution() {
// Default database path should be data_dir/nx9-wg.db
let config = AppConfig::default();
let expected_db = config.data_dir.join("nx9-wg.db");
assert_eq!(expected_db, PathBuf::from("/var/lib/nx9-wg/nx9-wg.db"));
}
#[test]
fn test_explicit_database_dir_override() {
let _lock = ENV_MUTEX.lock().unwrap();
let config = AppConfig::default();
// When --database is explicitly provided, it should be used directly
// The test verifies the default path is what we expect
assert_eq!(config.data_dir, PathBuf::from("/var/lib/nx9-wg"));
}
#[test]
fn test_backup_directory_consistency() {
let config = AppConfig::default();
// Backup directory should always be consistent: /var/lib/nx9-wg/backups
assert_eq!(config.backup.dir, PathBuf::from("/var/lib/nx9-wg/backups"));
}
#[test]
fn test_nx9_wg_database_env_var() {
let _lock = ENV_MUTEX.lock().unwrap();
// NX9_WG_DATABASE should be honored via CLI args
// This test documents that the env var is in the canonical namespace
let cli_args = &["--database", "/custom/path/test.db"];
// We're verifying this is the correct pattern to use
assert_eq!(cli_args[0], "--database");
assert_eq!(cli_args[1], "/custom/path/test.db");
}
#[test]
fn test_canonical_env_namespace_only() {
let _lock = ENV_MUTEX.lock().unwrap();
// Verify only NX9_WG_* variables are used
let mut config = AppConfig::default();
// Try setting a non-canonical variable - should be ignored
unsafe {
std::env::set_var("RUST_LOG", "debug");
std::env::set_var("NX9_LOG_LEVEL", "error");
}
config.apply_env_overrides().expect("apply env overrides");
// These non-canonical variables should be ignored
assert_eq!(config.log_level, "info"); // Should remain default
// Clean up
unsafe {
std::env::remove_var("RUST_LOG");
std::env::remove_var("NX9_LOG_LEVEL");
}
}
#[test]
fn test_default_bind_address_is_localhost() {
let config = AppConfig::default();
// Verify bind address default
assert_eq!(config.bind_address, "127.0.0.1:8080".parse().unwrap());
}
#[test]
fn test_default_reconciliation_interval() {
let config = AppConfig::default();
// Default reconciliation interval should be 60 seconds
assert_eq!(config.reconciliation_interval_secs, 60);
}