use serde::Deserialize;
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum KernelMode {
#[default]
Shadow,
Enforce,
Explain,
}
#[derive(Debug, Default, Deserialize)]
struct KernelModeConfig {
kernel_mode: Option<KernelMode>,
}
const KERNEL_MODE_ENV: &str = "LEAN_CTX_KERNEL_MODE";
const LEGACY_KERNEL_MODE_ENV: &str = "LEANCTX_KERNEL_MODE";
static LEGACY_ENV_WARNED: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false);
pub fn resolve_mode(_project_root: &str) -> KernelMode {
let legacy = std::env::var(LEGACY_KERNEL_MODE_ENV).ok();
if legacy.is_some() && !LEGACY_ENV_WARNED.swap(true, std::sync::atomic::Ordering::Relaxed) {
tracing::warn!(
"{LEGACY_KERNEL_MODE_ENV} is deprecated and will be removed in 3.15.0; set {KERNEL_MODE_ENV} instead"
);
}
if let Some(mode) = mode_from_env(
std::env::var(KERNEL_MODE_ENV).ok().as_deref(),
legacy.as_deref(),
) {
return mode;
}
crate::core::paths::config_dir_member("config.toml")
.ok()
.and_then(|path| std::fs::read_to_string(path).ok())
.and_then(|raw| toml::from_str::<KernelModeConfig>(&raw).ok())
.and_then(|config| config.kernel_mode)
.unwrap_or_default()
}
fn mode_from_env(current: Option<&str>, legacy: Option<&str>) -> Option<KernelMode> {
current
.and_then(parse_mode)
.or_else(|| legacy.and_then(parse_mode))
}
fn parse_mode(value: &str) -> Option<KernelMode> {
match value.trim().to_ascii_lowercase().as_str() {
"shadow" => Some(KernelMode::Shadow),
"enforce" => Some(KernelMode::Enforce),
"explain" => Some(KernelMode::Explain),
_ => None,
}
}
#[derive(Debug, Clone)]
pub struct BlockedEntry {
pub object_id: String,
pub reason: String,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn current_env_name_wins_over_the_legacy_one() {
assert_eq!(
mode_from_env(Some("enforce"), None),
Some(KernelMode::Enforce)
);
assert_eq!(
mode_from_env(None, Some("explain")),
Some(KernelMode::Explain)
);
assert_eq!(
mode_from_env(Some("Shadow"), Some("enforce")),
Some(KernelMode::Shadow)
);
assert_eq!(
mode_from_env(Some("bogus"), Some("enforce")),
Some(KernelMode::Enforce)
);
assert_eq!(mode_from_env(None, None), None);
}
}