feat: add AWS SigV4 auth for OpenAI-compatible model providers (#17820)

## Summary

Add first-class Amazon Bedrock Mantle provider support so Codex can keep
using its existing Responses API transport with OpenAI-compatible
AWS-hosted endpoints such as AOA/Mantle.

This is needed for the AWS launch path, where provider traffic should
authenticate with AWS credentials instead of OpenAI bearer credentials.
Requests are authenticated immediately before transport send, so SigV4
signs the final method, URL, headers, and body bytes that `reqwest` will
send.

## What Changed

- Added a new `codex-aws-auth` crate for loading AWS SDK config,
resolving credentials, and signing finalized HTTP requests with AWS
SigV4.
- Added a built-in `amazon-bedrock` provider that targets Bedrock Mantle
Responses endpoints, defaults to `us-east-1`, supports region/profile
overrides, disables WebSockets, and does not require OpenAI auth.
- Added Amazon Bedrock auth resolution in `codex-model-provider`: prefer
`AWS_BEARER_TOKEN_BEDROCK` when set, otherwise use AWS SDK credentials
and SigV4 signing.
- Added `AuthProvider::apply_auth` and `Request::prepare_body_for_send`
so request-signing providers can sign the exact outbound request after
JSON serialization/compression.
- Determine the region by taking the `aws.region` config first (required
for bearer token codepath), and fallback to SDK default region.

## Testing
Amazon Bedrock Mantle Responses paths:

- Built the local Codex binary with `cargo build`.
- Verified the custom proxy-backed `aws` provider using `env_key =
"AWS_BEARER_TOKEN_BEDROCK"` streamed raw `responses` output with
`response.output_text.delta`, `response.completed`, and `mantle-env-ok`.
- Verified a full `codex exec --profile aws` turn returned
`mantle-env-ok`.
- Confirmed the custom provider used the bearer env var, not AWS profile
auth: bogus `AWS_PROFILE` still passed, empty env var failed locally,
and malformed env var reached Mantle and failed with `401
invalid_api_key`.
- Verified built-in `amazon-bedrock` with `AWS_BEARER_TOKEN_BEDROCK` set
passed despite bogus AWS profiles, returning `amazon-bedrock-env-ok`.
- Verified built-in `amazon-bedrock` SDK/SigV4 auth passed with
`AWS_BEARER_TOKEN_BEDROCK` unset and temporary AWS session env
credentials, returning `amazon-bedrock-sdk-env-ok`.
This commit is contained in:
Celia Chen authored and GitHub committed 2026-04-22 01:11:17 +00:00
1 parent e18fe7a07f
commit 1cd3ad1f49
25 files changed
+1676 -94

No files matched your search

@@ -0,0 +1,73 @@
mod auth;
mod mantle;
use std::sync::Arc;
use codex_api::Provider;
use codex_api::SharedAuthProvider;
use codex_login::AuthManager;
use codex_login::CodexAuth;
use codex_model_provider_info::ModelProviderAwsAuthInfo;
use codex_model_provider_info::ModelProviderInfo;
use codex_protocol::error::Result;
use crate::provider::ModelProvider;
use auth::resolve_provider_auth;
use auth::resolve_region;
use mantle::base_url;
/// Runtime provider for Amazon Bedrock's OpenAI-compatible Mantle endpoint.
#[derive(Clone, Debug)]
pub(crate) struct AmazonBedrockModelProvider {
pub(crate) info: ModelProviderInfo,
pub(crate) aws: ModelProviderAwsAuthInfo,
}
#[async_trait::async_trait]
impl ModelProvider for AmazonBedrockModelProvider {
fn info(&self) -> &ModelProviderInfo {
&self.info
}
fn auth_manager(&self) -> Option<Arc<AuthManager>> {
None
}
async fn auth(&self) -> Option<CodexAuth> {
None
}
async fn api_provider(&self) -> Result<Provider> {
let region = resolve_region(&self.aws).await?;
let mut api_provider_info = self.info.clone();
api_provider_info.base_url = Some(base_url(&region)?);
api_provider_info.to_api_provider(/*auth_mode*/ None)
}
async fn api_auth(&self) -> Result<SharedAuthProvider> {
resolve_provider_auth(&self.aws).await
}
}
#[cfg(test)]
mod tests {
use pretty_assertions::assert_eq;
use super::*;
#[test]
fn api_provider_for_bedrock_bearer_token_uses_configured_region_endpoint() {
let region = "eu-central-1";
let mut api_provider_info =
ModelProviderInfo::create_amazon_bedrock_provider(/*aws*/ None);
api_provider_info.base_url = Some(base_url(region).expect("supported region"));
let api_provider = api_provider_info
.to_api_provider(/*auth_mode*/ None)
.expect("api provider should build");
assert_eq!(
api_provider.base_url,
"https://bedrock-mantle.eu-central-1.api.aws/v1"
);
}
}