mirror of
https://github.com/openai/codex.git
synced 2026-11-14 21:40:39 +00:00
Support configured credential providers across shell snapshots (#44072)
## Why Credential brokerage must retain trusted destination hints even when shell environment policy hides them from child processes. Snapshot replay also needs to preserve credential aliases when tokens are short or captured dummy values change. ## What changed - Add `features.network_proxy.credentials` and preserve provider settings when toggling the proxy. Prevent project configuration from overriding providers or their credential and destination environment variables. - Use provider metadata throughout snapshot capture and replay, and pass hidden destination context to the broker without exposing it in the child environment. - Rewrite aliases containing short credentials or previously captured dummies, respecting environment filters and explicit overrides. - Preserve case-distinct `shell_environment_policy.set` keys so Windows credential ambiguity checks survive configuration merging and permission profile changes. - Restore independent MITM settings when credential brokerage is disabled. ## Testing Add regression coverage for custom providers, hidden destination hints, Bash and Zsh alias replay, configuration edits and merging, Windows ambiguity handling, and credential protection during approved execution. GitOrigin-RevId: b2bd935d2d8555be56baf8feb1a8e5b3a0c666bc
This commit is contained in:
@@ -2157,6 +2157,58 @@ mod tests {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn private_credential_context_prepares_spawn_ready_env() -> Result<()> {
|
||||
#[cfg(target_os = "windows")]
|
||||
let _permit = WINDOWS_INGRESS_TEST_LOCK.acquire().await.unwrap();
|
||||
let mut config = NetworkProxyConfig {
|
||||
enabled: true,
|
||||
..NetworkProxyConfig::default()
|
||||
};
|
||||
config.set_credential_broker_enabled(/*enabled*/ true);
|
||||
let state = Arc::new(network_proxy_state_for_policy(config));
|
||||
let proxy = NetworkProxy::builder()
|
||||
.state(Arc::clone(&state))
|
||||
.build()
|
||||
.await?;
|
||||
let handle = proxy.run().await?;
|
||||
let real = "ghp-private-context-test";
|
||||
for previous in [None, Some(""), Some("visible.example")] {
|
||||
let mut env = HashMap::from([("GH_ENTERPRISE_TOKEN".to_string(), real.to_string())]);
|
||||
if let Some(previous) = previous {
|
||||
env.insert("GH_HOST".to_string(), previous.to_string());
|
||||
}
|
||||
let context = crate::CredentialBrokerContext::from(HashMap::from([(
|
||||
"GH_HOST".to_string(),
|
||||
"private.enterprise.example".to_string(),
|
||||
)]));
|
||||
let prepared =
|
||||
context.prepare_child_environment(&proxy, env, Some("snapshot-context"))?;
|
||||
assert_eq!(prepared.env.get("GH_HOST").map(String::as_str), previous);
|
||||
let dummy = &prepared.env["GH_ENTERPRISE_TOKEN"];
|
||||
assert_ne!(dummy, real);
|
||||
for (host, expected) in [
|
||||
("private.enterprise.example", real),
|
||||
("visible.example", dummy.as_str()),
|
||||
] {
|
||||
let mut headers = rama_http::HeaderMap::new();
|
||||
headers.insert(
|
||||
rama_http::header::AUTHORIZATION,
|
||||
format!("Bearer {dummy}").parse()?,
|
||||
);
|
||||
state
|
||||
.for_environment_id(Some("snapshot-context"))
|
||||
.inject_request_credentials(host, &mut headers);
|
||||
assert_eq!(
|
||||
headers[rama_http::header::AUTHORIZATION],
|
||||
format!("Bearer {expected}")
|
||||
);
|
||||
}
|
||||
}
|
||||
handle.shutdown().await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn remote_launch_config_carries_execution_scope() -> Result<()> {
|
||||
#[cfg(target_os = "windows")]
|
||||
|
||||
Reference in New Issue
Block a user