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:
sayan-oai authored and copyberry committed 2026-08-18 20:49:36 +00:00
1 parent 884a193b78
commit 392328ed5d
2 files changed
+53 -1

No files matched your search

+20 -1
View File
@@ -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, &current_environments)
}
pub(crate) async fn environment_ready(