Enforce managed residency for model providers (#39645)

## Why

Model provider configuration could override the residency header required by
`enforce_residency`, so provider-backed requests did not reliably honor the
managed setting.

## What changed

- Apply the managed residency header after building a provider, making it
  authoritative for model requests and model discovery.
- Warn when a provider configures the residency header through
  `http_headers` or `env_http_headers`, while preserving the original provider
  configuration and unrelated headers.
- Cover HTTP and WebSocket requests, model discovery, and case-insensitive
  header detection with targeted tests.

GitOrigin-RevId: 461ef8989d5bd06ffdea694aee4265e392e07590
This commit is contained in:
Anton Panasenko authored and copyberry committed 2026-08-20 07:33:27 +00:00
1 parent 663da53823
commit af0e82c562
7 files changed
+371 -3

No files matched your search

+18 -2
View File
@@ -11,6 +11,9 @@ use codex_api::TransportError;
use codex_api::is_azure_responses_provider;
use codex_login::AuthManager;
use codex_login::CodexAuth;
use codex_login::default_client::RESIDENCY_HEADER_NAME;
use codex_login::default_client::ResidencyRequirement;
use codex_login::default_client::read_default_client_residency_requirement;
use codex_model_provider_info::ModelProviderInfo;
use codex_models_manager::cache::ModelsCache;
use codex_models_manager::manager::OpenAiModelsManager;
@@ -19,6 +22,7 @@ use codex_models_manager::manager::StaticModelsManager;
use codex_protocol::account::ProviderAccount;
use codex_protocol::error::CodexErr;
use codex_protocol::openai_models::ModelsResponse;
use http::HeaderValue;
use crate::amazon_bedrock::AmazonBedrockModelProvider;
use crate::auth::ProviderAuthScope;
@@ -28,6 +32,15 @@ use crate::auth::resolve_provider_auth;
use crate::auth::resolve_provider_auth_for_scope;
use crate::models_endpoint::OpenAiModelsEndpoint;
pub(crate) fn enforce_managed_residency(provider: &mut Provider) {
if let Some(requirement) = read_default_client_residency_requirement() {
let value = match requirement {
ResidencyRequirement::Us => HeaderValue::from_static("us"),
};
provider.headers.insert(RESIDENCY_HEADER_NAME, value);
}
}
/// Remote context-compaction protocols supported by a model provider.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RemoteCompactionSupport {
@@ -203,8 +216,11 @@ pub trait ModelProvider: fmt::Debug + Send + Sync {
fn api_provider(&self) -> ModelProviderFuture<'_, codex_protocol::error::Result<Provider>> {
Box::pin(async move {
let auth = self.auth().await;
self.info()
.to_api_provider(auth.as_ref().map(CodexAuth::auth_mode))
let mut provider = self
.info()
.to_api_provider(auth.as_ref().map(CodexAuth::auth_mode))?;
enforce_managed_residency(&mut provider);
Ok(provider)
})
}