mirror of
https://github.com/openai/codex.git
synced 2026-08-23 13:09:46 +00:00
Preserve owner-provided environment configuration (#39278)
## Why Thread settings could replace an owner-provided environment configuration with `FromThread`, allowing the thread to take ownership of that configuration. ## What changed Reject environment settings updates that change an existing owner-provided configuration to `FromThread`. ## Testing Cover preview and turn settings updates for pending, ready, and failed owner-provided environments. GitOrigin-RevId: c516954819447ceb29e2ff9f29fe781ca101ae54
This commit is contained in:
@@ -9,6 +9,7 @@ use codex_protocol::protocol::EnvironmentConfig;
|
||||
use codex_protocol::protocol::EnvironmentConfigState;
|
||||
use codex_protocol::protocol::TurnEnvironmentSelection;
|
||||
|
||||
use crate::config::ConstraintError;
|
||||
use crate::config::ConstraintResult;
|
||||
use crate::session::session::Session;
|
||||
use crate::session::session::SessionConfiguration;
|
||||
@@ -78,7 +79,25 @@ impl Session {
|
||||
current: &SessionConfiguration,
|
||||
updates: &SessionSettingsUpdate,
|
||||
) -> ConstraintResult<SessionConfiguration> {
|
||||
current.apply(updates, &self.services.turn_environments.selections())
|
||||
let current_environments = self.services.turn_environments.selections();
|
||||
if let Some(environments) = &updates.environments
|
||||
&& let Some(environment) = environments.environments.iter().find(|environment| {
|
||||
environment.config == EnvironmentConfigState::FromThread
|
||||
&& current_environments.iter().any(|current| {
|
||||
current.environment_id == environment.environment_id
|
||||
&& current.config != EnvironmentConfigState::FromThread
|
||||
})
|
||||
})
|
||||
{
|
||||
return Err(ConstraintError::InvalidValue {
|
||||
field_name: "environments",
|
||||
candidate: environment.environment_id.clone(),
|
||||
allowed: "owner-provided environment configuration".to_string(),
|
||||
requirement_source: codex_config::RequirementSource::Unknown,
|
||||
});
|
||||
}
|
||||
|
||||
current.apply(updates, ¤t_environments)
|
||||
}
|
||||
|
||||
pub(crate) async fn environment_ready(
|
||||
|
||||
@@ -1516,6 +1516,39 @@ async fn pending_attachment_installs_configuration_before_waiting_turn_resumes()
|
||||
..pending_selection.clone()
|
||||
}]
|
||||
);
|
||||
let downgraded_environments = TurnEnvironmentSelections::new(
|
||||
test.config.cwd.clone(),
|
||||
vec![TurnEnvironmentSelection {
|
||||
config: EnvironmentConfigState::FromThread,
|
||||
workspace_roots: Vec::new(),
|
||||
..pending_selection.clone()
|
||||
}],
|
||||
);
|
||||
for thread in [&waiting.thread, &independent.thread, &failed.thread] {
|
||||
let error = thread
|
||||
.preview_thread_settings_overrides(CodexThreadSettingsOverrides {
|
||||
environments: Some(downgraded_environments.clone()),
|
||||
..Default::default()
|
||||
})
|
||||
.await
|
||||
.expect_err("owner-controlled environment must not become thread-owned");
|
||||
assert!(error.to_string().contains("owner-provided"));
|
||||
}
|
||||
let error = independent
|
||||
.thread
|
||||
.start_or_steer_turn(
|
||||
TurnInputRequest::user_input(vec![UserInput::Text {
|
||||
text: "attempt to clear owner configuration".into(),
|
||||
text_elements: Vec::new(),
|
||||
}])
|
||||
.with_thread_settings(ThreadSettingsOverrides {
|
||||
environments: Some(downgraded_environments),
|
||||
..Default::default()
|
||||
}),
|
||||
)
|
||||
.await
|
||||
.expect_err("turn settings must not clear owner configuration");
|
||||
assert!(error.to_string().contains("owner-provided"));
|
||||
assert!(
|
||||
waiting
|
||||
.thread
|
||||
|
||||
Reference in New Issue
Block a user