Derive sandbox contexts from turn environments (#40551)

## What changed

- Add Windows sandbox mode, private-desktop behavior, and legacy Landlock selection to each `EnvironmentConfig`.
- Centralize sandbox context construction on `TurnEnvironment`, preserving environment-owned permissions, paths, and backend settings while applying additional permission grants.
- Use the environment-derived context for project instructions, capability discovery, file uploads, and filesystem-oriented tools.

## Testing

- Verify capability discovery uses the selected environment's permission profile and sandbox backends when they differ from the thread defaults.

GitOrigin-RevId: 7ae2fed90c8ada950f2e8431e571e9b2c793c291
This commit is contained in:
Adam Perry @ OpenAI authored and copyberry committed 2026-08-25 05:16:45 +00:00
1 parent 348f49b292
commit 8444cf63b5
47 files changed
+341 -151

No files matched your search

+28 -26
View File
@@ -104,6 +104,32 @@ impl TurnEnvironment {
self.config().permission_profile.permission_profile()
}
/// Sandbox context for this environment, including any additional permission grants.
pub(crate) fn sandbox_context(
&self,
additional_permissions: Option<AdditionalPermissionProfile>,
) -> FileSystemSandboxContext {
let config = self.config();
// Grant-adjusted permissions take precedence over the environment's baseline;
// paths and sandbox backend settings remain environment-owned.
let permissions = effective_permission_profile(
self.permission_profile(),
additional_permissions.as_ref(),
);
FileSystemSandboxContext {
permissions: permissions.into(),
cwd: Some(self.cwd().clone()),
workspace_roots: self.workspace_roots().to_vec(),
windows_sandbox_level: executor_windows_sandbox_level(
config.windows_sandbox_level,
self.cwd(),
),
windows_sandbox_private_desktop: config.windows_sandbox_private_desktop,
windows_sandbox_proxy_settings_mode: None,
use_legacy_landlock: config.use_legacy_landlock,
}
}
pub(crate) fn active_permission_profile(&self) -> Option<ActivePermissionProfile> {
self.config().permission_profile.active_permission_profile()
}
@@ -178,6 +204,8 @@ pub struct TurnContext {
pub(crate) multi_agent_version: MultiAgentVersion,
pub(crate) personality: Option<Personality>,
pub(crate) network: Option<NetworkProxy>,
// TODO(anp): Reconcile this parallel turn snapshot with TurnEnvironment::sandbox_context
// so owner-provided environment settings govern the remaining sandbox decisions.
pub(crate) windows_sandbox_level: WindowsSandboxLevel,
pub(crate) available_models: Vec<ModelPreset>,
pub(crate) unified_exec_shell_mode: UnifiedExecShellMode,
@@ -449,32 +477,6 @@ impl TurnContext {
}
}
pub(crate) fn file_system_sandbox_context(
&self,
additional_permissions: Option<AdditionalPermissionProfile>,
environment: &TurnEnvironment,
) -> FileSystemSandboxContext {
let permissions = effective_permission_profile(
environment.permission_profile(),
additional_permissions.as_ref(),
);
FileSystemSandboxContext {
permissions: permissions.into(),
cwd: Some(environment.cwd().clone()),
workspace_roots: environment.workspace_roots().to_vec(),
windows_sandbox_level: executor_windows_sandbox_level(
self.windows_sandbox_level,
environment.cwd(),
),
windows_sandbox_private_desktop: self
.config
.permissions
.windows_sandbox_private_desktop,
windows_sandbox_proxy_settings_mode: None,
use_legacy_landlock: self.config.features.use_legacy_landlock(),
}
}
fn non_legacy_file_system_sandbox_policy(&self) -> Option<RawFileSystemSandboxPolicy> {
// Omit the derived split filesystem policy when it is equivalent to
// the legacy sandbox policy. This keeps turn-context payloads stable