use std::ffi::OsStr;
pub const FED_IDENTITY_ENV: &str = "AI_MEMORY_FED_IDENTITY";
pub const HOSTNAME_IDENTITY_PREFIX: &str = "host:";
pub const UNKNOWN_HOSTNAME_FALLBACK: &str = "unknown-host";
#[must_use]
pub fn resolve_federation_identity(configured: Option<&str>) -> String {
if let Some(id) = env_identity() {
return id;
}
if let Some(id) = non_empty(configured) {
return id.to_string();
}
default_hostname_identity()
}
#[must_use]
pub fn default_hostname_identity() -> String {
let raw = gethostname::gethostname();
format!("{HOSTNAME_IDENTITY_PREFIX}{}", hostname_component(&raw))
}
fn env_identity() -> Option<String> {
let raw = std::env::var(FED_IDENTITY_ENV).ok()?;
non_empty(Some(&raw)).map(str::to_string)
}
fn hostname_component(host: &OsStr) -> String {
let lossy = host.to_string_lossy();
match non_empty(Some(&lossy)) {
Some(name) => name.to_string(),
None => UNKNOWN_HOSTNAME_FALLBACK.to_string(),
}
}
fn non_empty(s: Option<&str>) -> Option<&str> {
s.map(str::trim).filter(|t| !t.is_empty())
}
#[cfg(test)]
mod tests {
use super::*;
fn fed_identity_env_lock() -> &'static std::sync::Mutex<()> {
static M: std::sync::OnceLock<std::sync::Mutex<()>> = std::sync::OnceLock::new();
M.get_or_init(|| std::sync::Mutex::new(()))
}
struct EnvGuard {
prior: Option<String>,
}
impl EnvGuard {
fn set(value: &str) -> Self {
let prior = std::env::var(FED_IDENTITY_ENV).ok();
unsafe { std::env::set_var(FED_IDENTITY_ENV, value) };
Self { prior }
}
fn cleared() -> Self {
let prior = std::env::var(FED_IDENTITY_ENV).ok();
unsafe { std::env::remove_var(FED_IDENTITY_ENV) };
Self { prior }
}
}
impl Drop for EnvGuard {
fn drop(&mut self) {
match &self.prior {
Some(v) => unsafe { std::env::set_var(FED_IDENTITY_ENV, v) },
None => unsafe { std::env::remove_var(FED_IDENTITY_ENV) },
}
}
}
#[test]
fn default_matches_legacy_hostname_expression() {
let _g = fed_identity_env_lock()
.lock()
.unwrap_or_else(|e| e.into_inner());
let _env = EnvGuard::cleared();
let legacy = format!("host:{}", gethostname::gethostname().to_string_lossy());
assert_eq!(resolve_federation_identity(None), legacy);
assert_eq!(default_hostname_identity(), legacy);
}
#[test]
fn env_override_takes_precedence_over_config_and_default() {
let _g = fed_identity_env_lock()
.lock()
.unwrap_or_else(|e| e.into_inner());
let _env = EnvGuard::set("spiffe://fleet/region/nyc/node-7");
assert_eq!(
resolve_federation_identity(Some("config-identity")),
"spiffe://fleet/region/nyc/node-7"
);
}
#[test]
fn blank_env_is_skipped_in_favour_of_config() {
let _g = fed_identity_env_lock()
.lock()
.unwrap_or_else(|e| e.into_inner());
let _env = EnvGuard::set(" ");
assert_eq!(
resolve_federation_identity(Some("config-identity")),
"config-identity"
);
}
#[test]
fn config_used_when_env_absent() {
let _g = fed_identity_env_lock()
.lock()
.unwrap_or_else(|e| e.into_inner());
let _env = EnvGuard::cleared();
assert_eq!(
resolve_federation_identity(Some(" region/sfo/node-3 ")),
"region/sfo/node-3"
);
}
#[test]
fn blank_config_falls_through_to_hostname_default() {
let _g = fed_identity_env_lock()
.lock()
.unwrap_or_else(|e| e.into_inner());
let _env = EnvGuard::cleared();
let resolved = resolve_federation_identity(Some(" "));
assert!(resolved.starts_with(HOSTNAME_IDENTITY_PREFIX));
assert_eq!(resolved, default_hostname_identity());
}
#[test]
fn env_value_is_trimmed() {
let _g = fed_identity_env_lock()
.lock()
.unwrap_or_else(|e| e.into_inner());
let _env = EnvGuard::set(" trimmed-id ");
assert_eq!(resolve_federation_identity(None), "trimmed-id");
}
#[test]
fn hostname_component_falls_back_when_empty() {
assert_eq!(
hostname_component(OsStr::new(" ")),
UNKNOWN_HOSTNAME_FALLBACK
);
assert_eq!(hostname_component(OsStr::new("host-a")), "host-a");
}
}