mirror of
https://github.com/openai/codex.git
synced 2026-10-21 17:48:44 +00:00
Add runtime assertion authentication modes and an auth provider (#55636)
## What changed Add `RuntimeAuthProvider` to resolve request authentication through the runtime auth manager. Support `dual_header` mode, which sends a bearer credential alongside `x-openai-agent-assertion`, and `assertion_only` mode, which uses `Authorization: AgentAssertion …`. Replace stale authentication headers and sign a fresh assertion for each request attempt. Propagate registration failures without falling back to credential-only authentication, preserving policy errors and classifying transport failures, rate limits, and server errors as transient. Add the disabled-by-default `features.runtime_agent_instances` configuration with independent `enabled` and `mode` settings, schema support, and structured override merging. Selecting a mode alone does not enable the feature. ## Testing Add coverage for both modes with API key and ChatGPT credentials, stale header replacement, fresh assertions, credential refresh without runtime replacement, registration failures, and configuration parsing and merging. GitOrigin-RevId: 9e93d25762600f0ff592c5248fe4c8c2c8182c8d
This commit is contained in:
@@ -16,6 +16,7 @@ use toml::Table;
|
||||
|
||||
mod feature_configs;
|
||||
mod legacy;
|
||||
mod runtime_auth;
|
||||
pub use feature_configs::AsyncCompactionConfigToml;
|
||||
pub use feature_configs::CodeModeConfigToml;
|
||||
pub use feature_configs::CodeModeHostConfigToml;
|
||||
@@ -42,6 +43,8 @@ pub use feature_configs::TokenBudgetConfigToml;
|
||||
pub use feature_configs::ToolRegistryConfigToml;
|
||||
use legacy::LegacyFeatureToggles;
|
||||
pub use legacy::legacy_feature_keys;
|
||||
pub use runtime_auth::RuntimeAgentInstancesConfigToml;
|
||||
pub use runtime_auth::RuntimeAuthMode;
|
||||
|
||||
/// High-level lifecycle stage for a feature.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
@@ -442,6 +445,8 @@ pub enum Feature {
|
||||
RetainClientToolOutputs,
|
||||
/// Use Agent Identity for ChatGPT-authenticated sessions.
|
||||
UseAgentIdentity,
|
||||
/// Register an ephemeral runtime for OpenAI request authentication.
|
||||
RuntimeAgentInstances,
|
||||
/// Enable workspace dependency support.
|
||||
WorkspaceDependencies,
|
||||
|
||||
@@ -904,6 +909,8 @@ pub struct FeaturesToml {
|
||||
pub current_time_reminder: Option<FeatureToml<CurrentTimeReminderConfigToml>>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub sleep_tool: Option<FeatureToml<SleepToolConfigToml>>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub runtime_agent_instances: Option<FeatureToml<RuntimeAgentInstancesConfigToml>>,
|
||||
#[serde(default, rename = "apps_mcp_path_override", skip_serializing)]
|
||||
#[schemars(skip)]
|
||||
removed_apps_mcp_path_override: Option<FeatureToml<RemovedAppsMcpPathOverrideConfigToml>>,
|
||||
@@ -980,6 +987,13 @@ impl FeaturesToml {
|
||||
if let Some(enabled) = self.sleep_tool.as_ref().and_then(FeatureToml::enabled) {
|
||||
entries.insert(Feature::SleepTool.key().to_string(), enabled);
|
||||
}
|
||||
if let Some(enabled) = self
|
||||
.runtime_agent_instances
|
||||
.as_ref()
|
||||
.and_then(FeatureToml::enabled)
|
||||
{
|
||||
entries.insert(Feature::RuntimeAgentInstances.key().to_string(), enabled);
|
||||
}
|
||||
entries
|
||||
}
|
||||
}
|
||||
@@ -2132,6 +2146,12 @@ pub const FEATURES: &[FeatureSpec] = &[
|
||||
stage: Stage::UnderDevelopment,
|
||||
default_enabled: false,
|
||||
},
|
||||
FeatureSpec {
|
||||
id: Feature::RuntimeAgentInstances,
|
||||
key: "runtime_agent_instances",
|
||||
stage: Stage::UnderDevelopment,
|
||||
default_enabled: false,
|
||||
},
|
||||
FeatureSpec {
|
||||
id: Feature::WorkspaceDependencies,
|
||||
key: "workspace_dependencies",
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
//! Configuration for runtime assertions; enabling the feature is separate from selecting its mode.
|
||||
|
||||
use crate::FeatureConfig;
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy, Default, PartialEq, Eq, JsonSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum RuntimeAuthMode {
|
||||
/// Send the actor credential and a runtime assertion together during migration.
|
||||
#[default]
|
||||
DualHeader,
|
||||
/// Send only the runtime assertion as the request credential.
|
||||
AssertionOnly,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, JsonSchema)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct RuntimeAgentInstancesConfigToml {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub enabled: Option<bool>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub mode: Option<RuntimeAuthMode>,
|
||||
}
|
||||
|
||||
impl FeatureConfig for RuntimeAgentInstancesConfigToml {
|
||||
fn enabled(&self) -> Option<bool> {
|
||||
self.enabled
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,28 @@ fn sleep_tool_config_rejects_unknown_mode() {
|
||||
assert!(toml::from_str::<FeaturesToml>("[sleep_tool]\nmode = 'off'").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn runtime_auth_config_accepts_modes_without_implicitly_enabling_the_feature() {
|
||||
for mode in ["dual_header", "assertion_only"] {
|
||||
let config: FeaturesToml =
|
||||
toml::from_str(&format!("[runtime_agent_instances]\nmode = '{mode}'")).unwrap();
|
||||
let mut features = Features::with_defaults();
|
||||
features.apply_toml(&config);
|
||||
assert!(!features.enabled(Feature::RuntimeAgentInstances));
|
||||
|
||||
let config: FeaturesToml = toml::from_str(&format!(
|
||||
"[runtime_agent_instances]\nenabled = true\nmode = '{mode}'"
|
||||
))
|
||||
.unwrap();
|
||||
features.apply_toml(&config);
|
||||
assert!(features.enabled(Feature::RuntimeAgentInstances));
|
||||
}
|
||||
assert!(
|
||||
toml::from_str::<FeaturesToml>("[runtime_agent_instances]\nmode = 'credential_only'")
|
||||
.is_err()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn under_development_features_are_disabled_by_default() {
|
||||
for spec in crate::FEATURES {
|
||||
|
||||
Reference in New Issue
Block a user