Broker credential aliases in child environments (#40484)

## What changed

- Discover supported credentials inherited from the parent even when their canonical provider variable is filtered from the child environment.
- Replace matching values and credentials embedded in longer child environment values with broker dummies, then restore only aliases that the broker virtualized.
- Preserve provider and host bindings when selecting credentials for outbound requests, including GitHub Enterprise and custom OpenAI hosts.
- Expose helpers for identifying provider and binding variables, plus an API for virtualizing credential-bearing text before it is persisted.

## Testing

- Extend credential broker tests for filtered parent variables, exact and embedded aliases, text virtualization, user overrides, and host-bound GitHub and OpenAI credentials.

GitOrigin-RevId: 55d673911900470aab4e206d0f4f5e62ed3611ae
This commit is contained in:
Winston Howes authored and copyberry committed 2026-08-24 22:10:44 +00:00
1 parent 4f6d43c267
commit 0280d73c1e
8 files changed
+566 -42

No files matched your search

@@ -51,10 +51,13 @@ fn virtualize_child_env_replaces_supported_credentials() {
let broker = CredentialBroker::new(/*enabled*/ true);
let github_token = "github_pat_11AA0bbCC_abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGH";
let openai_api_key = "sk-proj-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_";
let authorization = format!("Bearer {github_token}");
let mut env = env_map([
("GH_TOKEN", github_token),
("HOMEBREW_GITHUB_API_TOKEN", github_token),
("AUTH_HEADER", authorization.as_str()),
("OPENAI_API_KEY", openai_api_key),
("GH_ENTERPRISE_TOKEN", "ghp-enterprise-real"),
("GH_ENTERPRISE_TOKEN", github_token),
]);
broker.virtualize_child_env(&mut env);
@@ -63,12 +66,37 @@ fn virtualize_child_env_replaces_supported_credentials() {
let openai_dummy = env.get("OPENAI_API_KEY").expect("dummy OpenAI API key");
assert_credential_shape(github_token, github_dummy, "github_pat_");
assert_credential_shape(openai_api_key, openai_dummy, "sk-proj-");
assert_eq!(env.get("HOMEBREW_GITHUB_API_TOKEN"), Some(github_dummy));
assert_eq!(env.get("GH_ENTERPRISE_TOKEN"), Some(github_dummy));
assert_eq!(
env.get("AUTH_HEADER"),
Some(&format!("Bearer {github_dummy}"))
);
let mut persisted_credentials = format!("{github_token}\n{openai_api_key}");
assert!(broker.virtualize_text(&mut persisted_credentials, &env));
assert_eq!(
persisted_credentials,
format!("{github_dummy}\n{openai_dummy}")
);
let mut filtered_env = env.clone();
filtered_env.remove("OPENAI_API_KEY");
let mut excluded_credentials = format!("{github_token}\n{openai_api_key}");
assert!(!broker.virtualize_text(&mut excluded_credentials, &filtered_env));
assert_eq!(excluded_credentials, format!("{github_dummy}\n"));
let mut excluded_dummies = format!("{github_dummy}\n{openai_dummy}");
assert!(!broker.virtualize_text(&mut excluded_dummies, &filtered_env));
assert_eq!(excluded_dummies, format!("{github_dummy}\n"));
let mut command = vec![
format!("Authorization: Bearer {github_dummy}"),
format!("Authorization: Bearer {openai_dummy}"),
];
let github_dummy = github_dummy.clone();
let openai_dummy = openai_dummy.clone();
env.insert("OPENAI_API_KEY".to_string(), "sk-user-override".to_string());
env.insert(
"GIT_CONFIG_VALUE_0".to_string(),
format!("Authorization: Bearer {github_dummy}"),
);
assert_eq!(
brokered_credential_dummy_env_keys(&env),
vec!["GH_TOKEN".to_string()]
@@ -76,17 +104,36 @@ fn virtualize_child_env_replaces_supported_credentials() {
broker.restore_child_env(&mut env, &mut command);
assert_eq!(env.get("GH_TOKEN").map(String::as_str), Some(github_token));
assert_eq!(
env.get("HOMEBREW_GITHUB_API_TOKEN").map(String::as_str),
Some(github_token)
);
assert_eq!(
env.get("GH_ENTERPRISE_TOKEN").map(String::as_str),
Some(github_token)
);
assert_eq!(env.get("AUTH_HEADER"), Some(&authorization));
assert_eq!(
env.get("OPENAI_API_KEY").map(String::as_str),
Some("sk-user-override")
);
assert_eq!(
env.get("GIT_CONFIG_VALUE_0"),
Some(&format!("Authorization: Bearer {github_dummy}"))
);
assert_eq!(
command,
vec![
format!("Authorization: Bearer {github_token}"),
format!("Authorization: Bearer {github_dummy}"),
format!("Authorization: Bearer {openai_dummy}"),
]
);
env.insert("GH_TOKEN".to_string(), openai_dummy.clone());
env.insert("OPENAI_API_KEY".to_string(), github_dummy.clone());
broker.restore_child_env(&mut env, &mut []);
assert_eq!(env.get("GH_TOKEN"), Some(&openai_dummy));
assert_eq!(env.get("OPENAI_API_KEY"), Some(&github_dummy));
}
#[cfg(windows)]
@@ -130,6 +177,119 @@ fn virtualize_child_env_preserves_live_dummy_mappings() {
assert_eq!(authorization(&first_headers), Some("Bearer ghp-real-one"));
assert_eq!(authorization(&second_headers), Some("Bearer ghp-real-two"));
let mut alias_only = env_map([("HOMEBREW_GITHUB_API_TOKEN", "ghp-real-one")]);
broker.virtualize_child_env(&mut alias_only);
assert_eq!(
alias_only.get("HOMEBREW_GITHUB_API_TOKEN"),
Some(first_dummy)
);
broker.restore_child_env(&mut alias_only, &mut []);
assert_eq!(alias_only["HOMEBREW_GITHUB_API_TOKEN"], "ghp-real-one");
let mut overridden = env_map([
("GH_TOKEN", "ghp-real-two"),
("HOMEBREW_GITHUB_API_TOKEN", "ghp-real-one"),
]);
broker.virtualize_child_env(&mut overridden);
assert_eq!(overridden.get("GH_TOKEN"), Some(second_dummy));
assert_eq!(
overridden.get("HOMEBREW_GITHUB_API_TOKEN"),
Some(first_dummy)
);
let mut cloud_alias = env_map([
("GH_TOKEN", "ghp-real-one"),
("GITHUB_TOKEN", "ghp-real-one"),
]);
broker.virtualize_child_env(&mut cloud_alias);
cloud_alias.insert("GITHUB_TOKEN".to_string(), first_dummy.clone());
broker.restore_child_env(&mut cloud_alias, &mut []);
assert_eq!(cloud_alias["GITHUB_TOKEN"], "ghp-real-one");
let mut distinct_credentials = env_map([
("GH_TOKEN", "ghp-primary-secret"),
("GITHUB_TOKEN", "ghp-secondary-secret"),
]);
broker.virtualize_child_env(&mut distinct_credentials);
let secondary_dummy = distinct_credentials["GITHUB_TOKEN"].clone();
distinct_credentials.remove("GITHUB_TOKEN");
distinct_credentials.insert("GH_TOKEN".to_string(), secondary_dummy.clone());
broker.virtualize_child_env(&mut distinct_credentials);
broker.restore_child_env(&mut distinct_credentials, &mut []);
assert_eq!(distinct_credentials["GH_TOKEN"], secondary_dummy);
}
#[test]
fn virtualize_child_env_replaces_aliases_of_filtered_parent_credentials() {
let broker = CredentialBroker::new(/*enabled*/ true);
let github_token = "ghp_abcdefghijklmnopqrstuvwxyz1234567890";
let authorization_header = format!("Bearer {github_token}");
let parent_env = env_map([
("GH_TOKEN", github_token),
("HOMEBREW_GITHUB_API_TOKEN", github_token),
]);
let mut child_env = env_map([
("HOMEBREW_GITHUB_API_TOKEN", github_token),
("AUTH_HEADER", authorization_header.as_str()),
]);
broker.discover_parent_credentials(&parent_env, &child_env);
broker.virtualize_child_env(&mut child_env);
let dummy = child_env["HOMEBREW_GITHUB_API_TOKEN"].clone();
assert_ne!(dummy, github_token);
assert_eq!(child_env["AUTH_HEADER"], format!("Bearer {dummy}"));
assert!(!child_env.contains_key("GH_TOKEN"));
let mut headers = headers_with_bearer(&dummy);
broker.inject_request_headers("api.github.com", &mut headers);
assert_eq!(authorization(&headers), Some(authorization_header.as_str()));
broker.restore_child_env(&mut child_env, &mut []);
assert_eq!(child_env["HOMEBREW_GITHUB_API_TOKEN"], github_token);
assert_eq!(child_env["AUTH_HEADER"], authorization_header);
assert!(!child_env.contains_key("GH_TOKEN"));
}
#[test]
fn virtualize_child_env_binds_filtered_enterprise_credentials_to_child_host() {
let github_token = "ghp_abcdefghijklmnopqrstuvwxyz1234567890";
let authorization_header = format!("Bearer {github_token}");
for (parent_host, include_cloud_token) in [
(None, false),
(Some("github.previous.example"), false),
(None, true),
] {
let broker = CredentialBroker::new(/*enabled*/ true);
let mut parent_env = env_map([("GH_ENTERPRISE_TOKEN", github_token)]);
if let Some(parent_host) = parent_host {
parent_env.insert("GH_HOST".to_string(), parent_host.to_string());
}
if include_cloud_token {
parent_env.insert("GH_TOKEN".to_string(), github_token.to_string());
}
let mut child_env = env_map([
("GH_HOST", "github.current.example"),
("AUTH_HEADER", authorization_header.as_str()),
]);
broker.discover_parent_credentials(&parent_env, &child_env);
broker.virtualize_child_env(&mut child_env);
assert_ne!(child_env["AUTH_HEADER"], authorization_header);
let mut headers = headers_with_authorization(&child_env["AUTH_HEADER"]);
broker.inject_request_headers("github.current.example", &mut headers);
assert_eq!(authorization(&headers), Some(authorization_header.as_str()));
let mut previous_headers = headers_with_authorization(&child_env["AUTH_HEADER"]);
broker.inject_request_headers("github.previous.example", &mut previous_headers);
assert_eq!(
authorization(&previous_headers),
Some(child_env["AUTH_HEADER"].as_str())
);
}
}
#[test]
@@ -192,6 +352,12 @@ fn virtualize_child_env_preserves_unbound_enterprise_token() {
assert_eq!(env["GH_ENTERPRISE_TOKEN"], "ghp-enterprise-real");
assert_eq!(headers, headers_with_bearer(inert_token));
assert!(!broker.host_requires_mitm("attacker.example"));
env.insert("GH_HOST".to_string(), "github.example.com".to_string());
broker.virtualize_child_env(&mut env);
let mut headers = headers_with_bearer(&env["GH_ENTERPRISE_TOKEN"]);
broker.inject_request_headers("github.example.com", &mut headers);
assert_eq!(authorization(&headers), Some("Bearer ghp-enterprise-real"));
}
#[test]
@@ -294,6 +460,7 @@ fn openai_credentials_bind_only_to_default_and_configured_trusted_hosts() {
]);
broker.virtualize_child_env(&mut env);
assert!(brokered_credential_env_keys(&env).any(|key| key == "OPENAI_BASE_URL"));
assert!(brokered_credential_binding_env_keys(&env).any(|key| key == "OPENAI_BASE_URL"));
let dummy = &env["OPENAI_API_KEY"];
for (host, expected_credential) in [
@@ -330,6 +497,7 @@ fn github_cloud_credentials_match_ghe_com_host_hint() {
let broker = CredentialBroker::new(/*enabled*/ true);
let mut env = env_map([("GH_HOST", "astemu.ghe.com"), ("GH_TOKEN", "ghp-real")]);
broker.virtualize_child_env(&mut env);
assert!(!brokered_credential_binding_env_keys(&env).any(|key| key == "GH_HOST"));
let github_token = env.get("GH_TOKEN").expect("dummy GitHub token");
let mut headers = headers_with_bearer(github_token);
@@ -362,18 +530,77 @@ fn github_enterprise_credentials_bind_to_gh_host() {
let broker = CredentialBroker::new(/*enabled*/ true);
let mut env = env_map([
("GH_HOST", "github.example.com"),
("GH_TOKEN", "ghp-enterprise-real"),
("GH_ENTERPRISE_TOKEN", "ghp-enterprise-real"),
("AUTH_HEADER", "Bearer ghp-enterprise-real"),
]);
broker.virtualize_child_env(&mut env);
let github_dummy = env["GH_TOKEN"].clone();
assert!(brokered_credential_env_keys(&env).any(|key| key == "GH_HOST"));
assert!(brokered_credential_binding_env_keys(&env).any(|key| key == "GH_HOST"));
let github_token = env
.get("GH_ENTERPRISE_TOKEN")
.expect("dummy GitHub enterprise token");
assert_ne!(github_token, &github_dummy);
let mut headers = headers_with_bearer(github_token);
broker.inject_request_headers("github.example.com", &mut headers);
assert_eq!(authorization(&headers), Some("Bearer ghp-enterprise-real"));
assert_eq!(env["AUTH_HEADER"], format!("Bearer {github_token}"));
let mut alias_headers = headers_with_authorization(&env["AUTH_HEADER"]);
broker.inject_request_headers("github.example.com", &mut alias_headers);
assert_eq!(
authorization(&alias_headers),
Some("Bearer ghp-enterprise-real")
);
let mut persisted_alias = "Bearer ghp-enterprise-real".to_string();
assert!(broker.virtualize_text(&mut persisted_alias, &env));
assert_eq!(persisted_alias, format!("Bearer {github_token}"));
assert_eq!(
brokered_credential_dummy_env_keys(&env).first(),
Some(&"GH_ENTERPRISE_TOKEN".to_string())
);
let mut cloud_headers = headers_with_bearer(&github_dummy);
broker.inject_request_headers("github.example.com", &mut cloud_headers);
assert_eq!(cloud_headers, headers_with_bearer(&github_dummy));
let mut enterprise_headers = headers_with_bearer(github_token);
broker.inject_request_headers("api.github.com", &mut enterprise_headers);
assert_eq!(enterprise_headers, headers_with_bearer(github_token));
let mut cloud_only = env_map([
("GH_HOST", "github.example.com"),
("GH_TOKEN", "ghp-enterprise-real"),
("AUTH_HEADER", "Bearer ghp-enterprise-real"),
]);
broker.virtualize_child_env(&mut cloud_only);
assert_eq!(cloud_only["AUTH_HEADER"], format!("Bearer {github_dummy}"));
assert!(broker.host_requires_mitm("github.example.com"));
assert!(!broker.host_requires_mitm("api.github.com"));
assert!(broker.host_requires_mitm("api.github.com"));
env.insert("GH_HOST".to_string(), "attacker.example".to_string());
env.insert("GH_ENTERPRISE_TOKEN".to_string(), github_dummy.clone());
broker.virtualize_child_env(&mut env);
let mut attacker_headers = headers_with_bearer(&github_dummy);
broker.inject_request_headers("attacker.example", &mut attacker_headers);
assert_eq!(attacker_headers, headers_with_bearer(&github_dummy));
assert!(!broker.host_requires_mitm("attacker.example"));
let mut alternate_enterprise_key = env_map([
("GH_HOST", "github.alternate.example"),
("GH_TOKEN", "ghp-alternate-real"),
("GITHUB_ENTERPRISE_TOKEN", "ghp-alternate-real"),
("AUTH_HEADER", "Bearer ghp-alternate-real"),
]);
broker.virtualize_child_env(&mut alternate_enterprise_key);
assert_eq!(
alternate_enterprise_key["AUTH_HEADER"],
format!(
"Bearer {}",
alternate_enterprise_key["GITHUB_ENTERPRISE_TOKEN"]
)
);
assert_eq!(
brokered_credential_dummy_env_keys(&alternate_enterprise_key).first(),
Some(&"GITHUB_ENTERPRISE_TOKEN".to_string())
);
}