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}"
);
}
#[test]
fn an_audit_entry_keeps_the_approval_token_it_is_about() {
let mut detail = serde_json::json!({ "token": "apv_1f67575ecb24b5fe" });
aethershell::safety::redact_json(&mut detail);
assert_eq!(
detail["token"], "apv_1f67575ecb24b5fe",
"the audit trail must stay correlatable: {detail}"
);
}
#[test]
fn an_audit_entry_still_hides_a_real_credential() {
let mut detail = serde_json::json!({
"auth_token": "ghp_realcredentialvalue",
"password": "hunter2",
});
aethershell::safety::redact_json(&mut detail);
let text = detail.to_string();
assert!(!text.contains("ghp_real"), "credential leaked: {text}");
assert!(!text.contains("hunter2"), "password leaked: {text}");
}
#[test]
fn an_audit_entry_keeps_numeric_counts() {
let mut detail = serde_json::json!({ "page_tokens": 81, "tokens_in": 12 });
aethershell::safety::redact_json(&mut detail);
assert_eq!(detail["page_tokens"], 81);
assert_eq!(detail["tokens_in"], 12);
}
#[test]
fn both_redaction_layers_agree_on_what_a_capability_is() {
use aethershell::safety::is_capability_token;
assert!(is_capability_token("apv_deadbeef"));
assert!(is_capability_token("apl_deadbeef"));
assert!(!is_capability_token("ghp_realcredentialvalue"));
assert!(!is_capability_token("sk-live-abc"));
}