Files
codex/codex-rs/core/src/cyber_access_program.rs
T
jamy-OAI 708e3e2c70 Allow providers to opt into Cyber access programs (#58190)
## Why

Cyber access program selection was restricted to the `openai` provider ID, preventing custom providers from accepting explicit program selections.

## What changed

- Add `capabilities.cyber_access_programs` to provider configuration and preserve it through remote thread configuration. Default to enabled for `openai` and disabled for other provider IDs, with explicit overrides taking precedence.
- Use the capability when forwarding `access_programs.cyber` and determining Daybreak availability in exec and the TUI. Refresh TUI eligibility when the server changes the selected provider.
- Preserve authentication, API-key feature gates, and catalog access checks; the capability does not grant program access.

## Testing

Add coverage for capability defaults and overrides, configuration round trips, custom-provider requests with both authentication types, API-key feature gating, compaction, WebSocket response reuse, exec selection, and TUI provider changes.

GitOrigin-RevId: 579f7c33c9e857ff5fedd08311aa8e3129740c1f
2026-10-29 23:24:52 +00:00

71 lines
2.1 KiB
Rust

//! Forward explicit programs while leaving entitlement and model policy to the server.
use codex_api::AccessPrograms;
use codex_features::Feature;
use codex_login::CodexAuth;
use codex_protocol::error::CodexErr;
use codex_protocol::error::Result;
use codex_protocol::turn_input::CyberAccessProgram;
/// Configured support for explicit Cyber programs on API-key requests.
#[derive(Clone, Copy, Debug)]
pub enum ApiKeyCyberAccessPrograms {
UnsupportedProvider,
Disabled,
Enabled,
}
impl ApiKeyCyberAccessPrograms {
/// Captures the same provider and feature policy used by ordinary model requests.
pub fn from_config(config: &crate::config::Config) -> Self {
if !config
.model_provider
.supports_cyber_access_programs(&config.model_provider_id)
{
Self::UnsupportedProvider
} else if config.features.enabled(Feature::ApiKeyCyberAccessPrograms) {
Self::Enabled
} else {
Self::Disabled
}
}
}
pub(crate) fn for_provider(
config: &crate::config::Config,
program: Option<CyberAccessProgram>,
) -> Option<CyberAccessProgram> {
program.filter(|_| {
config
.model_provider
.supports_cyber_access_programs(&config.model_provider_id)
})
}
/// Resolves an explicit program using the request's current authentication.
pub fn for_auth(
auth: Option<&CodexAuth>,
program: Option<CyberAccessProgram>,
policy: ApiKeyCyberAccessPrograms,
) -> Result<Option<AccessPrograms>> {
let Some(program) = program else {
return Ok(None);
};
let Some(auth) = auth else {
return Ok(None);
};
if auth.is_chatgpt_auth() {
return Ok(Some(program.into()));
}
if !auth.is_api_key_auth() {
return Ok(None);
}
match policy {
ApiKeyCyberAccessPrograms::UnsupportedProvider => Ok(None),
ApiKeyCyberAccessPrograms::Disabled => Err(CodexErr::InvalidRequest(
"Cyber access programs are disabled for this API-key session.".to_owned(),
)),
ApiKeyCyberAccessPrograms::Enabled => Ok(Some(program.into())),
}
}