Files
codex/codex-rs/model-provider-info/src/gateway_oauth_tests.rs
T
smurching-oai 9526f8d0d0 Default gateway OAuth delivery to Authorization bearer tokens (#57313)
## What changed

Allow omitting `gateway_oauth.delivery` to send the gateway token as `Authorization: Bearer …`. Custom headers and cookies remain available when a provider also needs its own credentials.

Reject conflicting provider authentication and duplicate delivery headers with actionable errors. For gateway bearer delivery, require `model_catalog_url` to share the scheme, host, and port of `base_url`. Consistently reject request header collisions across auth application methods.

## Testing

Add coverage for omitted delivery, provider credential conflicts, and model catalog origin validation. Update inference tests to verify gateway-only authentication while signed in and combined ChatGPT and gateway credentials in separate headers.

GitOrigin-RevId: 8564d3998511b3f6c55f3b65a01ed9056a90417e
2026-10-27 00:08:07 +00:00

121 lines
3.8 KiB
Rust

use super::*;
use pretty_assertions::assert_eq;
fn provider(extra: &str) -> ModelProviderInfo {
toml::from_str(&format!(
r#"
base_url = "https://gateway.example.test/v1"
[gateway_oauth]
authorization_url = "https://login.example.test/authorize"
token_url = "https://login.example.test/token"
client_id = "codex"
{extra}
"#
))
.unwrap()
}
#[test]
fn parses_header_and_cookie_delivery() {
let header = provider("delivery = { kind = 'header', name = 'x-gateway-auth' }");
assert_eq!(header.validate(), Ok(()));
assert_eq!(
header.gateway_oauth.as_ref().unwrap().delivery,
GatewayOAuthDelivery::Header {
name: "x-gateway-auth".into(),
scheme: "Bearer".into(),
}
);
let cookie = provider("delivery = { kind = 'cookie', name = 'gateway_session' }");
assert_eq!(cookie.validate(), Ok(()));
assert_eq!(
toml::from_str::<ModelProviderInfo>(&toml::to_string(&cookie).unwrap()).unwrap(),
cookie
);
}
#[test]
fn rejects_unsafe_endpoints_and_delivery_collisions() {
let valid = provider("delivery = { kind = 'header', name = 'x-gateway-auth' }");
for url in [
"http://remote.example.test",
"https://user:secret@gateway.example.test",
"https://gateway.example.test/#secret",
"file:///token",
] {
let mut invalid = valid.clone();
invalid.base_url = Some(url.into());
assert!(invalid.validate().is_err());
invalid = valid.clone();
invalid.gateway_oauth.as_mut().unwrap().token_url = url.into();
let error = invalid.validate().unwrap_err();
assert!(!error.contains(url));
}
for name in [
"HOST",
"x-openai-actor-authorization",
"content-length",
"sec-websocket-key",
"bad name",
] {
let invalid = provider(&format!(
"delivery = {{ kind = 'header', name = '{name}' }}"
));
assert!(invalid.validate().is_err(), "{name}");
}
let mut collision = valid;
collision.http_headers = Some(std::collections::HashMap::from([(
"X-Gateway-Auth".into(),
"static".into(),
)]));
assert!(collision.validate().is_err());
let mut cookie = provider("delivery = { kind = 'cookie', name = 'gateway' }");
cookie.env_http_headers = Some(std::collections::HashMap::from([(
"COOKIE".into(),
"COOKIE_ENV".into(),
)]));
assert!(cookie.validate().is_err());
}
#[test]
fn gateway_bearer_requires_the_model_catalog_to_share_its_origin() {
let other = "https://gateway.example.test:8443/catalog";
let mut info = provider("");
info.model_catalog_url = Some(other.into());
assert!(
info.validate()
.unwrap_err()
.contains("same scheme, host, and port as base_url")
);
info.model_catalog_url = Some("https://gateway.example.test:443/custom/catalog".into());
assert_eq!(info.validate(), Ok(()));
let mut legacy = provider("delivery = { kind = 'header', name = 'x-gateway-auth' }");
legacy.model_catalog_url = Some(other.into());
assert_eq!(legacy.validate(), Ok(()));
}
#[test]
fn omitted_delivery_rejects_an_existing_provider_bearer() {
let mut info = provider("");
assert_eq!(info.validate(), Ok(()));
info.requires_openai_auth = true;
assert!(
info.validate()
.unwrap_err()
.contains("gateway_oauth.delivery")
);
info.requires_openai_auth = false;
info.env_key = Some("PROVIDER_API_KEY".into());
assert!(
info.validate()
.unwrap_err()
.contains("gateway_oauth.delivery")
);
let mut explicit = provider("delivery = { kind = 'header', name = 'x-gateway-auth' }");
explicit.env_key = info.env_key;
assert_eq!(explicit.validate(), Ok(()));
}