use aethershell::value::Value;
use std::collections::BTreeMap;
fn rec(pairs: &[(&str, Value)]) -> Value {
let mut m = BTreeMap::new();
for (k, v) in pairs {
m.insert(k.to_string(), v.clone());
}
Value::Record(m)
}
fn render(v: &Value) -> String {
aethershell::builtins::render_agent(v, None).expect("agent render")
}
#[test]
fn a_real_secret_is_still_hidden() {
let v = rec(&[
("api_key", Value::Str("sk-live-abcdefghijklmnop".into())),
("password", Value::Str("hunter2".into())),
("client_secret", Value::Str("shhh".into())),
]);
let out = render(&v);
assert!(!out.contains("sk-live"), "api_key leaked: {out}");
assert!(!out.contains("hunter2"), "password leaked: {out}");
assert!(!out.contains("shhh"), "client_secret leaked: {out}");
}
#[test]
fn a_token_count_is_not_a_secret() {
let v = rec(&[
("full_tokens", Value::Int(4180)),
("compact_tokens", Value::Int(216)),
("page_tokens", Value::Int(81)),
]);
let out = render(&v);
assert!(out.contains("4180"), "token counts must survive: {out}");
assert!(out.contains("216"), "token counts must survive: {out}");
assert!(!out.contains("REDACTED"), "nothing here is secret: {out}");
}
#[test]
fn an_approval_token_survives_because_the_agent_must_echo_it_back() {
let v = rec(&[
("token", Value::Str("apl_9fa896b743ee6f2f".into())),
("operations", Value::Int(1)),
]);
let out = render(&v);
assert!(
out.contains("apl_9fa896b743ee6f2f"),
"the plan token must reach the agent: {out}"
);
}
#[test]
fn a_secret_string_under_a_token_name_is_still_hidden() {
let v = rec(&[("auth_token", Value::Str("ghp_realcredentialvalue".into()))]);
let out = render(&v);
assert!(
!out.contains("ghp_realcredentialvalue"),
"a genuine credential must stay hidden: {out}"
);
}
#[test]
fn a_secret_nested_inside_a_container_is_still_found() {
let v = Value::Array(vec![rec(&[(
"credentials",
rec(&[("password", Value::Str("nested-secret".into()))]),
)])]);
let out = render(&v);
assert!(
!out.contains("nested-secret"),
"nested secret leaked: {out}"
);
}