Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

This file was deleted.

1 change: 0 additions & 1 deletion codex-rs/app-server-protocol/schema/typescript/index.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions codex-rs/app-server-protocol/schema/typescript/v2/Account.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 8 additions & 9 deletions codex-rs/app-server-protocol/src/protocol/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1755,7 +1755,6 @@ mod tests {
use super::*;
use anyhow::Result;
use codex_protocol::ThreadId;
use codex_protocol::account::AmazonBedrockCredentialSource;
use codex_protocol::account::PlanType;
use codex_protocol::config_types::MultiAgentMode;
use codex_protocol::models::BUILT_IN_PERMISSION_PROFILE_READ_ONLY;
Expand Down Expand Up @@ -2995,35 +2994,35 @@ mod tests {
);

let codex_managed_bedrock = v2::Account::AmazonBedrock {
credential_source: AmazonBedrockCredentialSource::CodexManaged,
uses_codex_managed_credentials: true,
};
assert_eq!(
json!({
"type": "amazonBedrock",
"credentialSource": "codexManaged",
"usesCodexManagedCredentials": true,
}),
serde_json::to_value(&codex_managed_bedrock)?,
);

let aws_managed_bedrock = v2::Account::AmazonBedrock {
credential_source: AmazonBedrockCredentialSource::AwsManaged,
let externally_managed_bedrock = v2::Account::AmazonBedrock {
uses_codex_managed_credentials: false,
};
assert_eq!(
json!({
"type": "amazonBedrock",
"credentialSource": "awsManaged",
"usesCodexManagedCredentials": false,
}),
serde_json::to_value(&aws_managed_bedrock)?,
serde_json::to_value(&externally_managed_bedrock)?,
);

Ok(())
}

#[test]
fn account_defaults_legacy_bedrock_credential_source() -> Result<()> {
fn account_defaults_legacy_bedrock_managed_credentials_flag() -> Result<()> {
assert_eq!(
v2::Account::AmazonBedrock {
credential_source: AmazonBedrockCredentialSource::AwsManaged,
uses_codex_managed_credentials: false,
},
serde_json::from_value(json!({
"type": "amazonBedrock",
Expand Down
17 changes: 7 additions & 10 deletions codex-rs/app-server-protocol/src/protocol/v2/account.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use crate::protocol::common::AuthMode;
use codex_experimental_api_macros::ExperimentalApi;
use codex_protocol::account::AmazonBedrockCredentialSource;
use codex_protocol::account::PlanType;
use codex_protocol::account::ProviderAccount;
use codex_protocol::protocol::CreditsSnapshot as CoreCreditsSnapshot;
Expand Down Expand Up @@ -34,8 +33,8 @@ pub enum Account {
#[serde(rename = "amazonBedrock", rename_all = "camelCase")]
#[ts(rename = "amazonBedrock", rename_all = "camelCase")]
AmazonBedrock {
#[serde(default = "default_bedrock_credential_source")]
credential_source: AmazonBedrockCredentialSource,
#[serde(default)]
uses_codex_managed_credentials: bool,
},
}

Expand All @@ -45,18 +44,16 @@ fn nullable_string_schema(
generator.subschema_for::<Option<String>>()
}

fn default_bedrock_credential_source() -> AmazonBedrockCredentialSource {
AmazonBedrockCredentialSource::AwsManaged
}

impl From<ProviderAccount> for Account {
fn from(account: ProviderAccount) -> Self {
match account {
ProviderAccount::ApiKey => Self::ApiKey {},
ProviderAccount::Chatgpt { email, plan_type } => Self::Chatgpt { email, plan_type },
ProviderAccount::AmazonBedrock { credential_source } => {
Self::AmazonBedrock { credential_source }
}
ProviderAccount::AmazonBedrock {
uses_codex_managed_credentials,
} => Self::AmazonBedrock {
uses_codex_managed_credentials,
},
}
}
}
Expand Down
9 changes: 2 additions & 7 deletions codex-rs/app-server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2010,21 +2010,16 @@ Request:
Response examples:

```json
{ "id": 1, "result": { "account": null, "requiresOpenaiAuth": false } } // No OpenAI auth needed (e.g., OSS/local models)
{ "id": 1, "result": { "account": null, "requiresOpenaiAuth": true } } // OpenAI auth required (typical for OpenAI-hosted models)
{ "id": 1, "result": { "account": { "type": "apiKey" }, "requiresOpenaiAuth": true } }
{ "id": 1, "result": { "account": { "type": "chatgpt", "email": "user@example.com", "planType": "pro" }, "requiresOpenaiAuth": true } }
{ "id": 1, "result": { "account": { "type": "chatgpt", "email": null, "planType": "enterprise" }, "requiresOpenaiAuth": true } }
{ "id": 1, "result": { "account": { "type": "amazonBedrock", "credentialSource": "codexManaged" }, "requiresOpenaiAuth": false } }
{ "id": 1, "result": { "account": { "type": "amazonBedrock", "credentialSource": "awsManaged" }, "requiresOpenaiAuth": false } }
{ "id": 1, "result": { "account": { "type": "amazonBedrock", "usesCodexManagedCredentials": false }, "requiresOpenaiAuth": false } }
```

Field notes:

- `refreshToken` (bool): set `true` to force a token refresh.
- `email` is `null` when the ChatGPT account does not have an email address.
- `requiresOpenaiAuth` reflects the active provider; when `false`, Codex can run without OpenAI credentials.
- Amazon Bedrock reports `credentialSource: "codexManaged"` when it uses a Bedrock API key managed by Codex. Otherwise it reports `credentialSource: "awsManaged"` for the external AWS credential path. This identifies the selected credential source; it does not validate that the AWS credential chain can resolve credentials.
- Amazon Bedrock reports `usesCodexManagedCredentials: true` when it uses a Bedrock API key managed by Codex. It reports `false` for external credential paths, including the AWS credential chain and configured command auth. This identifies whether Codex-managed credentials are selected; it does not validate that the credential source can resolve credentials.

### 2) Log in with an API key

Expand Down
48 changes: 43 additions & 5 deletions codex-rs/app-server/tests/suite/v2/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ use codex_login::auth::BedrockApiKeyAuth;
use codex_login::load_auth_dot_json;
use codex_login::login_with_api_key;
use codex_login::login_with_bedrock_api_key;
use codex_protocol::account::AmazonBedrockCredentialSource;
use codex_protocol::account::PlanType as AccountPlanType;
use codex_protocol::auth::AuthMode as DomainAuthMode;
use core_test_support::responses;
Expand Down Expand Up @@ -1555,7 +1554,7 @@ async fn login_managed_bedrock_updates_active_bedrock_account() -> Result<()> {
read_account(&mut mcp).await?,
GetAccountResponse {
account: Some(Account::AmazonBedrock {
credential_source: AmazonBedrockCredentialSource::CodexManaged,
uses_codex_managed_credentials: true,
}),
requires_openai_auth: false,
}
Expand Down Expand Up @@ -2583,14 +2582,53 @@ region = "us-west-2"

let expected = GetAccountResponse {
account: Some(Account::AmazonBedrock {
credential_source: AmazonBedrockCredentialSource::AwsManaged,
uses_codex_managed_credentials: false,
}),
requires_openai_auth: false,
};
assert_eq!(received, expected);
Ok(())
}

#[tokio::test]
async fn get_account_with_user_managed_bedrock_provider() -> Result<()> {
let codex_home = TempDir::new()?;
create_config_toml(
codex_home.path(),
CreateConfigTomlParams {
model_provider_id: Some("amazon-bedrock".to_string()),
extra_provider_config: Some(
r#"[model_providers.amazon-bedrock]
base_url = "https://bedrock.example.com/v1"

[model_providers.amazon-bedrock.auth]
command = "print-token"
"#
.to_string(),
),
..Default::default()
},
)?;

let mut mcp = TestAppServer::builder()
.with_codex_home(codex_home.path())
.without_auto_env()
.build()
.await?;
timeout(DEFAULT_READ_TIMEOUT, mcp.initialize()).await??;

assert_eq!(
read_account(&mut mcp).await?,
GetAccountResponse {
account: Some(Account::AmazonBedrock {
uses_codex_managed_credentials: false,
}),
requires_openai_auth: false,
}
);
Ok(())
}

#[tokio::test]
async fn account_reads_use_startup_config_when_config_reload_fails() -> Result<()> {
let codex_home = TempDir::new()?;
Expand Down Expand Up @@ -2622,7 +2660,7 @@ region = "us-west-2"
read_account(&mut mcp).await?,
GetAccountResponse {
account: Some(Account::AmazonBedrock {
credential_source: AmazonBedrockCredentialSource::AwsManaged,
uses_codex_managed_credentials: false,
}),
requires_openai_auth: false,
}
Expand Down Expand Up @@ -2692,7 +2730,7 @@ async fn get_account_with_managed_bedrock_provider() -> Result<()> {
received,
GetAccountResponse {
account: Some(Account::AmazonBedrock {
credential_source: AmazonBedrockCredentialSource::CodexManaged,
uses_codex_managed_credentials: true,
}),
requires_openai_auth: false,
}
Expand Down
40 changes: 28 additions & 12 deletions codex-rs/config/src/config_toml.rs
Original file line number Diff line number Diff line change
Expand Up @@ -923,18 +923,17 @@ pub fn validate_model_providers(
) -> Result<(), String> {
validate_reserved_model_provider_ids(model_providers)?;
for (key, provider) in model_providers {
if key == AMAZON_BEDROCK_PROVIDER_ID {
continue;
}
if provider.aws.is_some() {
return Err(format!(
"model_providers.{key}: provider aws is only supported for `{AMAZON_BEDROCK_PROVIDER_ID}`"
));
}
if provider.name.trim().is_empty() {
return Err(format!(
"model_providers.{key}: provider name must not be empty"
));
if key != AMAZON_BEDROCK_PROVIDER_ID {
if provider.aws.is_some() {
return Err(format!(
"model_providers.{key}: provider aws is only supported for `{AMAZON_BEDROCK_PROVIDER_ID}`"
));
}
if provider.name.trim().is_empty() {
return Err(format!(
"model_providers.{key}: provider name must not be empty"
));
}
}
provider
.validate()
Expand Down Expand Up @@ -1021,4 +1020,21 @@ mod tests {
assert!(message.contains("TOML list of strings"));
assert!(message.contains("comma-separated strings are not supported"));
}

#[test]
fn amazon_bedrock_auth_command_must_not_be_empty() {
let err = toml::from_str::<ConfigToml>(
r#"
[model_providers.amazon-bedrock.auth]
command = " "
"#,
)
.expect_err("empty Amazon Bedrock auth command should be rejected");

assert!(
err.to_string().contains(
"model_providers.amazon-bedrock: provider auth.command must not be empty"
)
);
}
}
Loading
Loading