From f151a0f5c20e50055957b79d50e16834e00e32e1 Mon Sep 17 00:00:00 2001 From: Brian Lee Date: Wed, 30 Sep 2026 18:59:59 +0000 Subject: [PATCH] Decouple API-key cyber access programs from model discovery (#49714) ## What changed Allow API-key sessions using the OpenAI provider to forward explicit cyber access programs when `features.api_key_cyber_access_programs` is enabled, regardless of `features.api_key_model_discovery`. ## Testing Expand the app-server test to cover all four combinations of the two feature flags, checking forwarded programs and failures when forwarding is disabled. Default the API-key test helper to model discovery disabled. GitOrigin-RevId: f9cf1d2bd7c231645d50178cc6721b55a8d63268 --- .../tests/suite/v2/cyber_access_program.rs | 30 ++++++++++++------- codex-rs/core/src/cyber_access_program.rs | 4 +-- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/codex-rs/app-server/tests/suite/v2/cyber_access_program.rs b/codex-rs/app-server/tests/suite/v2/cyber_access_program.rs index 6cfedf7706..cae8a6bced 100644 --- a/codex-rs/app-server/tests/suite/v2/cyber_access_program.rs +++ b/codex-rs/app-server/tests/suite/v2/cyber_access_program.rs @@ -201,7 +201,7 @@ async fn turn_start_forwards_explicit_cyber_access_program() -> Result<()> { } #[tokio::test] -async fn api_key_cyber_access_program_requires_both_features() -> Result<()> { +async fn api_key_cyber_access_program_requires_only_forwarding_feature() -> Result<()> { core_test_support::skip_if_no_network!(Ok(())); let server = responses::start_mock_server().await; let expected_programs = [ @@ -211,6 +211,10 @@ async fn api_key_cyber_access_program_requires_both_features() -> Result<()> { Some(json!({"cyber": "daybreak_blue"})), Some(json!({"cyber": "daybreak_red"})), Some(json!({"cyber": "standard"})), + None, + Some(json!({"cyber": "daybreak_blue"})), + Some(json!({"cyber": "daybreak_red"})), + Some(json!({"cyber": "standard"})), ]; let requests = responses::mount_sse_sequence( &server, @@ -224,15 +228,21 @@ async fn api_key_cyber_access_program_requires_both_features() -> Result<()> { let home = TempDir::new()?; let mut app = start_api_key_app(home.path(), &server).await?; set_api_key_cyber_access_programs(&mut app, /*enabled*/ true).await?; - for disabled_feature in [ - Some("api_key_cyber_access_programs"), - Some("api_key_model_discovery"), - None, - ] { + for (forwarding_enabled, discovery_enabled) in + [(false, false), (false, true), (true, false), (true, true)] + { let thread = app .start_thread(ThreadStartParams { - config: disabled_feature - .map(|feature| HashMap::from([(format!("features.{feature}"), json!(false))])), + config: Some(HashMap::from([ + ( + "features.api_key_cyber_access_programs".to_owned(), + json!(forwarding_enabled), + ), + ( + "features.api_key_model_discovery".to_owned(), + json!(discovery_enabled), + ), + ])), ..Default::default() }) .await? @@ -254,7 +264,7 @@ async fn api_key_cyber_access_program_requires_both_features() -> Result<()> { ..Default::default() }) .await?; - if program.is_some() && disabled_feature.is_some() { + if program.is_some() && !forwarding_enabled { assert_eq!(completed.turn.status, TurnStatus::Failed); assert_eq!( completed.turn.error, @@ -642,7 +652,7 @@ async fn start_api_key_app(home: &Path, server: &MockServer) -> Result Self { if config.model_provider_id != codex_model_provider_info::OPENAI_PROVIDER_ID { Self::UnsupportedProvider - } else if config.features.enabled(Feature::ApiKeyCyberAccessPrograms) - && config.features.enabled(Feature::ApiKeyModelDiscovery) - { + } else if config.features.enabled(Feature::ApiKeyCyberAccessPrograms) { Self::Enabled } else { Self::Disabled