Mercury/src/config.rs
Matthew L McPeak 2d95265e7d
Some checks failed
ci / build-ui (pull_request) Successful in 21s
ci / test (pull_request) Failing after 34s
ci / publish (pull_request) Has been skipped
fix: cleanup
2026-08-09 14:34:28 -04:00

107 lines
4 KiB
Rust

use anyhow::Result;
#[derive(Clone, Debug)]
pub struct Config {
pub database_url: String,
pub jwt_secret: String,
pub jwt_expiry_secs: u64,
pub cache_max_capacity: usize,
pub cache_idle_timeout_secs: u64,
pub cache_sweep_interval_secs: u64,
/// Comma-separated allowed CORS origins, or "*" for permissive. Empty = no CORS headers.
pub cors_origins: Vec<String>,
/// Base URL of the MinIO/S3 endpoint (no trailing slash).
pub cdn_endpoint: String,
/// Bucket name used for CDN object storage.
pub cdn_bucket: String,
/// Dev-only: when true, all auth/permission checks are bypassed and every
/// request is treated as a super-admin. NEVER enable in production.
pub disable_auth: bool,
}
impl Config {
pub fn from_env() -> Result<Self> {
Ok(Self {
database_url: std::env::var("DATABASE_URL")?,
jwt_secret: std::env::var("JWT_SECRET")?,
jwt_expiry_secs: std::env::var("JWT_EXPIRY_SECS")
.unwrap_or_else(|_| "3600".into())
.parse()?,
cache_max_capacity: std::env::var("CACHE_MAX_CAPACITY")
.unwrap_or_else(|_| "10000".into())
.parse()?,
cache_idle_timeout_secs: std::env::var("CACHE_IDLE_TIMEOUT_SECS")
.unwrap_or_else(|_| "300".into())
.parse()?,
cache_sweep_interval_secs: std::env::var("CACHE_SWEEP_INTERVAL_SECS")
.unwrap_or_else(|_| "60".into())
.parse()?,
cors_origins: std::env::var("CORS_ORIGINS")
.unwrap_or_default()
.split(',')
.map(|s| s.trim().to_string())
.filter(|s| !s.is_empty())
.collect(),
cdn_endpoint: std::env::var("CDN_ENDPOINT")
.unwrap_or_else(|_| "http://localhost:9000".into()),
cdn_bucket: std::env::var("CDN_BUCKET").unwrap_or_else(|_| "mercury".into()),
disable_auth: std::env::var("DISABLE_AUTH")
.map(|v| matches!(v.trim().to_lowercase().as_str(), "1" | "true"))
.unwrap_or(false),
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::sync::Mutex;
// Serializes tests that mutate the process-global DISABLE_AUTH env var,
// since cargo runs tests in parallel by default.
static DISABLE_AUTH_ENV_LOCK: Mutex<()> = Mutex::new(());
#[test]
fn test_config_defaults() {
std::env::set_var("DATABASE_URL", "postgres://test");
std::env::set_var("JWT_SECRET", "secret");
let cfg = Config::from_env().unwrap();
assert_eq!(cfg.jwt_expiry_secs, 3600);
assert_eq!(cfg.cache_max_capacity, 10_000);
assert_eq!(cfg.cache_idle_timeout_secs, 300);
assert_eq!(cfg.cache_sweep_interval_secs, 60);
assert!(cfg.cors_origins.is_empty());
}
#[test]
fn test_config_disable_auth_default_false() {
let _guard = DISABLE_AUTH_ENV_LOCK.lock().unwrap();
std::env::set_var("DATABASE_URL", "postgres://test");
std::env::set_var("JWT_SECRET", "secret");
std::env::remove_var("DISABLE_AUTH");
let cfg = Config::from_env().unwrap();
assert!(!cfg.disable_auth);
}
#[test]
fn test_config_disable_auth_true() {
let _guard = DISABLE_AUTH_ENV_LOCK.lock().unwrap();
std::env::set_var("DATABASE_URL", "postgres://test");
std::env::set_var("JWT_SECRET", "secret");
std::env::set_var("DISABLE_AUTH", "true");
let cfg = Config::from_env().unwrap();
assert!(cfg.disable_auth);
std::env::remove_var("DISABLE_AUTH");
}
#[test]
fn test_config_disable_auth_numeric_true() {
let _guard = DISABLE_AUTH_ENV_LOCK.lock().unwrap();
std::env::set_var("DATABASE_URL", "postgres://test");
std::env::set_var("JWT_SECRET", "secret");
std::env::set_var("DISABLE_AUTH", "1");
let cfg = Config::from_env().unwrap();
assert!(cfg.disable_auth);
std::env::remove_var("DISABLE_AUTH");
}
}