mirror of
https://github.com/openai/codex.git
synced 2026-11-10 08:43:33 +00:00
Standardize shell execution on unified exec (#39757)
## What changed - Remove the legacy `shell_command` handler and runtime, leaving `exec_command` and `write_stdin` as the shell execution tools. - Treat legacy `shell_command` model metadata as `unified_exec`, and normalize legacy user opt-outs so they do not disable command execution. Managed feature requirements and `shell_tool` can still disable it. - Preserve shell approvals, sandboxing, zsh-fork support, and output truncation through the unified execution path. ## Testing - Cover legacy configuration and model-metadata compatibility. - Exercise unified shell execution, approvals, truncation, and `apply_patch` serialization across the app-server and core test suites. GitOrigin-RevId: 5c2fd6164fc3519cdae4944cb9db276b8467311c
This commit is contained in:
1 parent
d0cc662b8c
commit
8a40095ea3
116 files changed
+1338
-4711
No files matched your search
@@ -6445,6 +6445,50 @@ async fn legacy_toggles_map_to_features() -> std::io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn legacy_unified_exec_disable_flags_do_not_disable_command_execution() -> std::io::Result<()>
|
||||
{
|
||||
for cfg in [
|
||||
ConfigToml {
|
||||
features: Some(FeaturesToml::from(BTreeMap::from([(
|
||||
"unified_exec".to_string(),
|
||||
false,
|
||||
)]))),
|
||||
..Default::default()
|
||||
},
|
||||
ConfigToml {
|
||||
experimental_use_unified_exec_tool: Some(false),
|
||||
..Default::default()
|
||||
},
|
||||
] {
|
||||
let codex_home = TempDir::new()?;
|
||||
let mut config = Config::load_from_base_config_with_overrides(
|
||||
cfg,
|
||||
ConfigOverrides::default(),
|
||||
codex_home.abs(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
assert!(config.features.enabled(Feature::UnifiedExec));
|
||||
assert!(config.features.enabled(Feature::ShellTool));
|
||||
|
||||
config
|
||||
.features
|
||||
.disable(Feature::UnifiedExec)
|
||||
.expect("legacy unified-exec toggle should normalize successfully");
|
||||
assert!(config.features.enabled(Feature::UnifiedExec));
|
||||
|
||||
config
|
||||
.features
|
||||
.disable(Feature::ShellTool)
|
||||
.expect("shell tool should remain independently configurable");
|
||||
assert!(!config.features.enabled(Feature::ShellTool));
|
||||
assert!(config.features.enabled(Feature::UnifiedExec));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn responses_websocket_features_do_not_change_wire_api() -> std::io::Result<()> {
|
||||
for feature_key in ["responses_websockets", "responses_websockets_v2"] {
|
||||
@@ -10977,6 +11021,38 @@ shell_tool = false
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn feature_requirements_can_still_disable_unified_exec() -> std::io::Result<()> {
|
||||
let codex_home = TempDir::new()?;
|
||||
|
||||
let mut config = ConfigBuilder::without_managed_config_for_tests()
|
||||
.codex_home(codex_home.path().to_path_buf())
|
||||
.cloud_config_bundle(
|
||||
CloudConfigBundleFixture::loader_with_enterprise_requirement(
|
||||
r#"
|
||||
[features]
|
||||
unified_exec = false
|
||||
shell_tool = true
|
||||
"#,
|
||||
),
|
||||
)
|
||||
.build()
|
||||
.await?;
|
||||
|
||||
assert!(!config.features.enabled(Feature::UnifiedExec));
|
||||
assert!(config.features.enabled(Feature::ShellTool));
|
||||
|
||||
config
|
||||
.features
|
||||
.enable(Feature::UnifiedExec)
|
||||
.expect("managed feature mutations should normalize successfully");
|
||||
|
||||
assert!(!config.features.enabled(Feature::UnifiedExec));
|
||||
assert!(config.features.enabled(Feature::ShellTool));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn feature_requirements_auto_review_disables_guardian_approval() -> std::io::Result<()> {
|
||||
let codex_home = TempDir::new()?;
|
||||
|
||||
@@ -152,6 +152,12 @@ fn normalize_candidate(
|
||||
mut candidate: Features,
|
||||
pinned_features: &BTreeMap<Feature, bool>,
|
||||
) -> Features {
|
||||
// Legacy user opt-outs selected the removed shell backend. Only managed
|
||||
// requirements may disable the remaining unified-exec implementation.
|
||||
if !pinned_features.contains_key(&Feature::UnifiedExec) {
|
||||
candidate.enable(Feature::UnifiedExec);
|
||||
}
|
||||
|
||||
for (feature, enabled) in pinned_features {
|
||||
candidate.set_enabled(*feature, *enabled);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user