use serde::Deserialize;
use tracing::warn;
const ENV_VERIFICATION_ENABLED: &str = "TRUSTY_REVIEW_VERIFICATION_ENABLED";
const ENV_LIVENESS_CHECK: &str = "TRUSTY_REVIEW_VERIFIER_LIVENESS_CHECK";
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct VerificationConfig {
pub enabled: bool,
pub liveness_check: bool,
}
impl Default for VerificationConfig {
fn default() -> Self {
Self {
enabled: true,
liveness_check: true,
}
}
}
impl VerificationConfig {
pub fn from_env_and_file(file: Option<&VerificationFileConfig>) -> Self {
let mut cfg = VerificationConfig {
enabled: file.and_then(|f| f.enabled).unwrap_or(true),
liveness_check: file.and_then(|f| f.liveness_check).unwrap_or(true),
};
if let Some(v) = parse_bool_env(ENV_VERIFICATION_ENABLED) {
cfg.enabled = v;
}
if let Some(v) = parse_bool_env(ENV_LIVENESS_CHECK) {
cfg.liveness_check = v;
}
cfg
}
}
#[derive(Debug, Clone, Default, Deserialize)]
pub struct VerificationFileConfig {
pub enabled: Option<bool>,
pub liveness_check: Option<bool>,
}
fn parse_bool_env(var: &str) -> Option<bool> {
let raw = std::env::var(var).ok()?;
let v = raw.trim().to_lowercase();
if v.is_empty() {
return None;
}
match v.as_str() {
"false" | "0" | "no" | "off" => Some(false),
"true" | "1" | "yes" | "on" => Some(true),
other => {
warn!("unrecognised boolean for {var}: {other:?} — ignoring");
None
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use serial_test::serial;
fn clear_env() {
unsafe {
std::env::remove_var(ENV_VERIFICATION_ENABLED);
std::env::remove_var(ENV_LIVENESS_CHECK);
}
}
#[test]
fn verification_defaults_enabled() {
let cfg = VerificationConfig::default();
assert!(cfg.enabled, "verification must default ON");
assert!(cfg.liveness_check, "liveness gate must default ON");
}
#[test]
#[serial]
fn verification_env_disables() {
clear_env();
unsafe {
std::env::set_var(ENV_VERIFICATION_ENABLED, "false");
}
let cfg = VerificationConfig::from_env_and_file(None);
assert!(!cfg.enabled, "env false must disable verification");
assert!(cfg.liveness_check, "liveness untouched by enabled var");
clear_env();
}
#[test]
#[serial]
fn verification_file_disables() {
clear_env();
let file = VerificationFileConfig {
enabled: Some(false),
liveness_check: Some(false),
};
let cfg = VerificationConfig::from_env_and_file(Some(&file));
assert!(!cfg.enabled, "file false must disable verification");
assert!(!cfg.liveness_check, "file false must disable liveness gate");
clear_env();
}
#[test]
#[serial]
fn verification_env_beats_file() {
clear_env();
unsafe {
std::env::set_var(ENV_VERIFICATION_ENABLED, "true");
}
let file = VerificationFileConfig {
enabled: Some(false),
liveness_check: None,
};
let cfg = VerificationConfig::from_env_and_file(Some(&file));
assert!(cfg.enabled, "env true must override file false");
clear_env();
}
#[test]
#[serial]
fn verification_unrecognised_env_keeps_file_value() {
clear_env();
unsafe {
std::env::set_var(ENV_VERIFICATION_ENABLED, "maybe");
}
let file = VerificationFileConfig {
enabled: Some(false),
liveness_check: None,
};
let cfg = VerificationConfig::from_env_and_file(Some(&file));
assert!(
!cfg.enabled,
"unrecognised env must fall through to file value"
);
clear_env();
}
}