#[derive(Debug, thiserror::Error)]
pub enum SecretError {
#[error("Missing required secret '{name}'. Set with: cargo pmcp secret set <server>/{name} --prompt")]
Missing {
name: String,
},
}
pub fn get(name: &str) -> Option<String> {
std::env::var(name).ok()
}
pub fn require(name: &str) -> Result<String, SecretError> {
std::env::var(name).map_err(|_| SecretError::Missing {
name: name.to_string(),
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn get_returns_some_when_env_var_is_set() {
let key = "__PMCP_TEST_SECRET_GET_EXISTS";
std::env::set_var(key, "test_value_42");
let result = get(key);
std::env::remove_var(key);
assert_eq!(result, Some("test_value_42".to_string()));
}
#[test]
fn get_returns_none_when_env_var_is_not_set() {
let key = "__PMCP_TEST_SECRET_GET_MISSING";
std::env::remove_var(key);
assert_eq!(get(key), None);
}
#[test]
fn require_returns_ok_when_env_var_is_set() {
let key = "__PMCP_TEST_SECRET_REQUIRE_EXISTS";
std::env::set_var(key, "required_value_99");
let result = require(key);
std::env::remove_var(key);
assert_eq!(result.unwrap(), "required_value_99");
}
#[test]
fn require_returns_err_when_env_var_is_not_set() {
let key = "__PMCP_TEST_SECRET_REQUIRE_MISSING";
std::env::remove_var(key);
let result = require(key);
assert!(result.is_err());
assert!(matches!(result.unwrap_err(), SecretError::Missing { .. }));
}
#[test]
fn secret_error_display_contains_secret_name() {
let err = SecretError::Missing {
name: "MY_API_KEY".to_string(),
};
let msg = err.to_string();
assert!(
msg.contains("MY_API_KEY"),
"Error message should contain the secret name, got: {msg}"
);
}
#[test]
fn secret_error_display_contains_cli_command() {
let err = SecretError::Missing {
name: "MY_API_KEY".to_string(),
};
let msg = err.to_string();
assert!(
msg.contains("cargo pmcp secret set"),
"Error message should contain CLI command, got: {msg}"
);
}
}