Support configured credential providers in remote execution (#56049)

## Why

Remote credential masking previously fell back to unmasked execution whenever custom credential providers were configured.

## What changed

- Transport configured provider rules to the executor-local network proxy, where credential values and destination context are resolved.
- Advertise `credentialMaskingCustomProviders` and negotiate masking support. Keep the warning and unmasked fallback for executors that support only built-in providers.
- Discard provider rules when masking is disabled and omit their contents from debug output.

## Testing

Extend coverage for capability compatibility, provider configuration round trips, and fallback on older executors. Exercise configured-provider masking in remote request history and verify that masked placeholders are restored to real credentials in upstream request headers.

GitOrigin-RevId: b036f56900b343ddccc17b5293c82bc1f3426237
This commit is contained in:
viyatb-oai
2026-10-22 01:54:51 +00:00
committed by copyberry
parent 0769c6aeeb
commit 2a77e82f09
14 changed files with 479 additions and 81 deletions
+117 -2
View File
@@ -8,6 +8,7 @@ pub use codex_file_system::WalkOutcome;
use codex_file_system::WireFileSystemSandboxContext;
use codex_install_context::InstallContext;
use codex_network_proxy::ManagedNetworkSandboxContext;
use codex_network_proxy::RemoteCredentialMasking;
use codex_network_proxy::RemoteNetworkProxyLaunchConfig;
use codex_protocol::ThreadId;
use codex_protocol::capabilities::SelectedCapabilityRoot;
@@ -151,10 +152,13 @@ fn unknown_executor_version() -> String {
pub struct EnvironmentCapabilities {
/// Whether `exec` accepts instructions for launching an executor-local network proxy.
#[serde(default)]
pub network_proxy_launch: bool,
network_proxy_launch: bool,
/// Whether the selected shell can mask executor environment credentials.
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
pub credential_masking: bool,
credential_masking: bool,
/// Whether credential masking also supports configured providers.
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
credential_masking_custom_providers: bool,
/// Whether capability discovery applies the filesystem sandbox sent with each root.
#[serde(default)]
pub capability_discovery_sandbox: bool,
@@ -187,6 +191,31 @@ pub struct EnvironmentCapabilities {
pub linux_approved_root_write_preserves_restrictions: bool,
}
impl EnvironmentCapabilities {
/// Network proxy features available through this executor.
pub fn network_proxy(&self) -> NetworkProxyCapabilities {
NetworkProxyCapabilities {
launch: self.network_proxy_launch,
credential_masking: if !self.credential_masking {
RemoteCredentialMasking::Disabled
} else if self.credential_masking_custom_providers {
RemoteCredentialMasking::WithConfiguredProviders
} else {
RemoteCredentialMasking::BuiltInOnly
},
}
}
}
/// Features supported by an executor-local network proxy.
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct NetworkProxyCapabilities {
/// Whether `exec` accepts instructions for launching an executor-local network proxy.
pub launch: bool,
/// Credential masking support available through the selected shell.
pub credential_masking: RemoteCredentialMasking,
}
/// Status returned by an initialized exec-server connection.
///
/// The response is intentionally small today. New status details can be added
@@ -286,6 +315,7 @@ impl EnvironmentInfo {
capabilities: EnvironmentCapabilities {
network_proxy_launch: true,
credential_masking,
credential_masking_custom_providers: credential_masking,
capability_discovery_sandbox: true,
capability_discovery_v2: true,
environment_config_read: true,
@@ -1260,6 +1290,7 @@ mod tests {
use super::FsOpenParams;
use super::FsReadFileParams;
use super::HttpRequestParams;
use super::NetworkProxyCapabilities;
use super::ProcessId;
use super::ProcessSandboxType;
use super::ShellInfo;
@@ -1270,6 +1301,7 @@ mod tests {
use codex_network_proxy::ManagedNetworkSandboxContext;
use codex_network_proxy::NetworkProxyAuditMetadata;
use codex_network_proxy::NetworkProxyConfig;
use codex_network_proxy::RemoteCredentialMasking;
use codex_network_proxy::RemoteNetworkProxyConfig;
use codex_network_proxy::RemoteNetworkProxyLaunchConfig;
use codex_protocol::config_types::WindowsSandboxProxySettingsMode;
@@ -1508,6 +1540,7 @@ mod tests {
EnvironmentCapabilities {
network_proxy_launch: true,
credential_masking: false,
credential_masking_custom_providers: false,
capability_discovery_sandbox: true,
capability_discovery_v2: false,
environment_config_read: false,
@@ -1520,6 +1553,88 @@ mod tests {
linux_approved_root_write_preserves_restrictions: false,
}
);
for (input_masking, expected_masking, output_masking) in [
(
serde_json::json!({}),
RemoteCredentialMasking::Disabled,
serde_json::json!({}),
),
(
serde_json::json!({ "credentialMasking": true }),
RemoteCredentialMasking::BuiltInOnly,
serde_json::json!({ "credentialMasking": true }),
),
(
serde_json::json!({
"credentialMasking": true,
"credentialMaskingCustomProviders": false,
}),
RemoteCredentialMasking::BuiltInOnly,
serde_json::json!({ "credentialMasking": true }),
),
(
serde_json::json!({
"credentialMasking": true,
"credentialMaskingCustomProviders": true,
}),
RemoteCredentialMasking::WithConfiguredProviders,
serde_json::json!({
"credentialMasking": true,
"credentialMaskingCustomProviders": true,
}),
),
(
serde_json::json!({ "credentialMaskingCustomProviders": true }),
RemoteCredentialMasking::Disabled,
serde_json::json!({ "credentialMaskingCustomProviders": true }),
),
(
serde_json::json!({
"credentialMasking": false,
"credentialMaskingCustomProviders": true,
}),
RemoteCredentialMasking::Disabled,
serde_json::json!({ "credentialMaskingCustomProviders": true }),
),
] {
for launch in [None, Some(false), Some(true)] {
let mut input = serde_json::json!({
"capabilityDiscoverySandbox": true,
});
if let Some(launch) = launch {
input["networkProxyLaunch"] = launch.into();
}
input
.as_object_mut()
.unwrap()
.extend(input_masking.as_object().unwrap().clone());
let decoded: EnvironmentCapabilities = serde_json::from_value(input).unwrap();
assert_eq!(
decoded.network_proxy(),
NetworkProxyCapabilities {
launch: launch.unwrap_or_default(),
credential_masking: expected_masking,
}
);
let mut expected_wire = serde_json::json!({
"networkProxyLaunch": launch.unwrap_or_default(),
"capabilityDiscoverySandbox": true,
"capabilityDiscoveryV2": false,
"environmentConfigRead": false,
"httpHeaderEnvVars": false,
"sandboxedFileStreaming": false,
"fileWriteStreaming": false,
"shellSnapshotV2": false,
"windowsMxc": false,
});
expected_wire
.as_object_mut()
.unwrap()
.extend(output_masking.as_object().unwrap().clone());
assert_eq!(serde_json::to_value(decoded).unwrap(), expected_wire);
}
}
}
#[test]