Preserve credential broker destinations across environment filtering (#44068)

## Why

Filtering destination variables out of a child environment can undo credential registrations. Rotating a provider token and destination must also leave older credential aliases bound to their original destinations.

## What changed

- Add `CredentialBrokerContext` to retain local destination hints for built-in and configured providers without adding them to child environments or serialized configuration. Explicit environment values, including empty values, override these fallbacks.
- Preserve registered destinations when hints are absent, reconcile fallback changes, and keep credential aliases scoped to their source identities and environments during rotation and inheritance.
- Expose provider context and source matching for trusted captured text, including configured provider context keys.
- Disable brokerage on Windows when provider environment overrides contain conflicting case-insensitive keys.

## Testing

Add regression coverage for filtered destinations, token rotation, inherited aliases, fallback updates and clearing, context redaction, trusted text matching, and non-Unicode environment values.

GitOrigin-RevId: 411790ea6339e1d8fa568049cf8160a67b134666
This commit is contained in:
Winston Howes
2026-09-09 05:45:31 +00:00
committed by copyberry
parent b4d42052cd
commit f45115a137
10 changed files with 1188 additions and 66 deletions
+25
View File
@@ -896,6 +896,7 @@ impl NetworkProxy {
enabled: config.enabled,
credential_providers: config.credential_providers.clone(),
credential_broker_openai_host: config.credential_broker_openai_host.clone(),
credential_broker_context: config.credential_broker_context.clone(),
dangerously_allow_plaintext_credential_injection: config
.dangerously_allow_plaintext_credential_injection,
..config::NetworkProxyConfig::default()
@@ -1202,6 +1203,26 @@ impl NetworkProxy {
self.state.credential_broker_environment(env)
}
/// Returns provider context for the dummy credentials contained in trusted text.
pub fn credential_broker_environment_for_text(
&self,
text: &str,
env: &HashMap<String, String>,
) -> crate::CredentialBrokerEnvironment {
self.state.credential_broker_environment_for_text(text, env)
}
/// Checks whether a registered provider source occurs in trusted captured text.
pub fn credential_broker_source_matches_text(
&self,
source: &str,
source_value: &str,
text: &str,
) -> bool {
self.state
.credential_broker_source_matches_text(source, source_value, text)
}
/// Checks whether recognized credentials originate from permitted provider variables.
pub fn credential_broker_sources_allowed(
&self,
@@ -2145,6 +2166,10 @@ mod tests {
..NetworkProxyConfig::default()
};
config.set_credential_broker_enabled(/*enabled*/ true);
config.configure_credential_broker_environment(&HashMap::from([(
"GH_HOST".to_string(),
"local-github.example".to_string(),
)]));
let state = Arc::new(network_proxy_state_for_policy(config));
let proxy = match NetworkProxy::builder().state(state).build().await {
Ok(proxy) => proxy,