Files
codex/codex-rs/core/src/cyber_access_program.rs
T
Dane Schneider 10da569252 Forward per-turn Cyber access programs to Guardian (#52689)
## What changed

Pass the parent turn's `cyber_access_program` to Guardian reviewers and asynchronous classifiers. Use `daybreak_blue` for either Daybreak selection, preserve `standard`, and omit `access_programs` when no program is selected.

Capture the selection with the owning turn so asynchronous observations retain it across later turns. Resolve classifier programs using current authentication and the same provider and API-key feature policy as ordinary model requests.

## Testing

Add regression tests for program changes across reused reviewer sessions with API-key and ChatGPT authentication, snapshot and conversation classifiers at low and high risk, and enabled, disabled, and unsupported-provider API-key policies. Verify parent requests retain their selected program.

GitOrigin-RevId: 447f306df3a6bd6805464b819950690c751b04b4
2026-10-09 20:14:04 +00:00

65 lines
2.0 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_model_provider_info::OPENAI_PROVIDER_ID;
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_id != OPENAI_PROVIDER_ID {
Self::UnsupportedProvider
} else if config.features.enabled(Feature::ApiKeyCyberAccessPrograms) {
Self::Enabled
} else {
Self::Disabled
}
}
}
pub(crate) fn for_provider(
provider_id: &str,
program: Option<CyberAccessProgram>,
) -> Option<CyberAccessProgram> {
program.filter(|_| provider_id == OPENAI_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())),
}
}