use anyhow::{Context, Result};
pub fn required_secret(name: &str) -> Result<String> {
std::env::var(name).with_context(|| format!("{name} env var (from auth Secret) required"))
}
#[cfg(test)]
mod tests {
use super::*;
fn required_secret_via<F>(name: &str, lookup: F) -> Result<String>
where
F: FnOnce(&str) -> std::result::Result<String, std::env::VarError>,
{
lookup(name).with_context(|| format!("{name} env var (from auth Secret) required"))
}
#[test]
fn required_secret_error_wording_is_canonical() {
let e = required_secret_via("ACCESS_ID", |_| Err(std::env::VarError::NotPresent))
.expect_err("must error when the env var is absent");
assert_eq!(
format!("{e}"),
"ACCESS_ID env var (from auth Secret) required",
);
let e = required_secret_via("ACCESS_KEY", |_| Err(std::env::VarError::NotPresent))
.expect_err("must error when the env var is absent");
assert_eq!(
format!("{e}"),
"ACCESS_KEY env var (from auth Secret) required",
);
}
#[test]
fn required_secret_preserves_underlying_var_error_in_chain() {
let e = required_secret_via("MISSING_VAR", |_| Err(std::env::VarError::NotPresent))
.expect_err("must error");
let dbg = format!("{e:?}");
assert!(
dbg.contains("MISSING_VAR env var (from auth Secret) required"),
"chain must carry the canonical head; got: {dbg}"
);
assert!(
dbg.contains("environment variable not found"),
"chain must preserve the underlying env::VarError cause; got: {dbg}"
);
}
#[test]
fn required_secret_interpolates_arbitrary_var_names_verbatim() {
for name in [
"ACCESS_ID",
"ACCESS_KEY",
"MIXED_Case_123",
"a",
"TATARA_PROCESS_REF",
] {
let e = required_secret_via(name, |_| Err(std::env::VarError::NotPresent))
.expect_err("must error");
assert_eq!(
format!("{e}"),
format!("{name} env var (from auth Secret) required"),
"diagnostic must interpolate {name:?} verbatim at the head",
);
}
}
#[test]
fn required_secret_returns_owned_string_on_happy_path() {
let v = required_secret_via("PROBE_TOKEN", |_| Ok("abc-123-token".to_string()))
.expect("happy path");
assert_eq!(v, "abc-123-token");
}
#[test]
fn required_secret_matches_pre_lift_chain_shape() {
fn pre_lift(
name: &str,
val: std::result::Result<String, std::env::VarError>,
) -> Result<String> {
val.with_context(|| format!("{name} env var (from auth Secret) required"))
}
for name in ["ACCESS_ID", "ACCESS_KEY"] {
let via_primitive =
required_secret_via(name, |_| Ok("fixture-value".to_string())).unwrap();
let via_pre_lift = pre_lift(name, Ok("fixture-value".to_string())).unwrap();
assert_eq!(via_primitive, via_pre_lift);
let via_primitive_err =
required_secret_via(name, |_| Err(std::env::VarError::NotPresent))
.unwrap_err()
.to_string();
let via_pre_lift_err = pre_lift(name, Err(std::env::VarError::NotPresent))
.unwrap_err()
.to_string();
assert_eq!(via_primitive_err, via_pre_lift_err);
}
}
#[test]
fn required_secret_reads_live_env_var_when_set() {
let name = "TATARA_SECRET_ENV_TEST_VAR_ABSENT_XYZ_12345";
assert!(
std::env::var(name).is_err(),
"fixture env var {name} must not be set in this test environment"
);
let e = required_secret(name).expect_err("must error on absent var");
assert_eq!(
format!("{e}"),
format!("{name} env var (from auth Secret) required"),
);
}
}