mirror of
https://github.com/openai/codex.git
synced 2026-10-19 17:28:46 +00:00
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:
committed by
copyberry
parent
348f49b292
commit
8444cf63b5
@@ -147,6 +147,8 @@ pub struct McpConfig {
|
||||
/// Optional path to `codex-linux-sandbox` for sandboxed MCP tool execution.
|
||||
pub codex_linux_sandbox_exe: Option<PathBuf>,
|
||||
/// Whether to use legacy Landlock behavior in the MCP sandbox state.
|
||||
// TODO(anp): Reconcile this runtime-wide copy with TurnEnvironment::sandbox_context
|
||||
// for the environment that owns each MCP server.
|
||||
pub use_legacy_landlock: bool,
|
||||
/// Whether the app MCP integration is enabled by config.
|
||||
///
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
use crate::config::Config;
|
||||
use crate::context::UserInstructions as ContextUserInstructions;
|
||||
use crate::environment_selection::TurnEnvironmentSnapshot;
|
||||
use crate::tools::sandboxing::executor_windows_sandbox_level;
|
||||
use codex_config::ConfigLayerSource;
|
||||
use codex_config::default_project_root_markers;
|
||||
use codex_config::merge_toml_values;
|
||||
@@ -30,7 +29,6 @@ use codex_extension_api::UserInstructions;
|
||||
use codex_file_system::FileSystemSandboxContext;
|
||||
use codex_file_system::FindUpErrorPolicy;
|
||||
use codex_file_system::find_nearest_ancestor_with_markers;
|
||||
use codex_protocol::config_types::WindowsSandboxLevel;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use codex_utils_path_uri::PathUri;
|
||||
use futures::StreamExt;
|
||||
@@ -58,7 +56,6 @@ pub(crate) async fn load_project_instructions(
|
||||
config: &Config,
|
||||
user_instructions: Option<UserInstructions>,
|
||||
environments: &TurnEnvironmentSnapshot,
|
||||
windows_sandbox_level: WindowsSandboxLevel,
|
||||
) -> io::Result<Option<LoadedAgentsMd>> {
|
||||
let mut loaded = LoadedAgentsMd::from_user_instructions(user_instructions);
|
||||
if config.active_project.is_untrusted() {
|
||||
@@ -76,20 +73,7 @@ pub(crate) async fn load_project_instructions(
|
||||
.permission_profile()
|
||||
.file_system_sandbox_policy()
|
||||
.has_full_disk_read_access())
|
||||
.then(|| {
|
||||
// TODO(anp): Move sandbox context construction to a method on TurnEnvironment.
|
||||
let mut sandbox = FileSystemSandboxContext::from_permission_profile_with_cwd(
|
||||
turn_environment.permission_profile().clone(),
|
||||
turn_environment.cwd().clone(),
|
||||
);
|
||||
sandbox.workspace_roots = turn_environment.workspace_roots().to_vec();
|
||||
sandbox.windows_sandbox_level =
|
||||
executor_windows_sandbox_level(windows_sandbox_level, turn_environment.cwd());
|
||||
sandbox.windows_sandbox_private_desktop =
|
||||
config.permissions.windows_sandbox_private_desktop;
|
||||
sandbox.use_legacy_landlock = config.features.use_legacy_landlock();
|
||||
sandbox
|
||||
});
|
||||
.then(|| turn_environment.sandbox_context(/*additional_permissions*/ None));
|
||||
match read_agents_md(
|
||||
config,
|
||||
filesystem.as_ref(),
|
||||
|
||||
@@ -4,7 +4,6 @@ use crate::config::Config;
|
||||
use crate::environment_selection::TurnEnvironmentSnapshot;
|
||||
use codex_extension_api::UserInstructions;
|
||||
use codex_protocol::config_types::TrustLevel;
|
||||
use codex_protocol::config_types::WindowsSandboxLevel;
|
||||
use codex_protocol::protocol::TurnEnvironmentSelection;
|
||||
use std::io;
|
||||
use std::sync::Arc;
|
||||
@@ -20,7 +19,6 @@ pub(crate) struct AgentsMdManager {
|
||||
struct AgentsMdCache {
|
||||
selections: Option<Vec<TurnEnvironmentSelection>>,
|
||||
active_project_trust_level: Option<TrustLevel>,
|
||||
windows_sandbox_level: Option<WindowsSandboxLevel>,
|
||||
loaded: Option<Arc<LoadedAgentsMd>>,
|
||||
}
|
||||
|
||||
@@ -38,7 +36,6 @@ impl AgentsMdManager {
|
||||
&self,
|
||||
config: &Config,
|
||||
environments: &TurnEnvironmentSnapshot,
|
||||
windows_sandbox_level: WindowsSandboxLevel,
|
||||
) -> io::Result<()> {
|
||||
let selections = environments
|
||||
.turn_environments()
|
||||
@@ -49,28 +46,21 @@ impl AgentsMdManager {
|
||||
let mut cache = self.cache.lock().await;
|
||||
if cache.selections.as_ref() == Some(&selections)
|
||||
&& cache.active_project_trust_level == active_project_trust_level
|
||||
&& cache.windows_sandbox_level == Some(windows_sandbox_level)
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
cache.selections = None;
|
||||
cache.active_project_trust_level = None;
|
||||
cache.windows_sandbox_level = None;
|
||||
cache.loaded = None;
|
||||
}
|
||||
|
||||
let loaded = load_project_instructions(
|
||||
config,
|
||||
self.user_instructions.clone(),
|
||||
environments,
|
||||
windows_sandbox_level,
|
||||
)
|
||||
.await?
|
||||
.map(Arc::new);
|
||||
let loaded =
|
||||
load_project_instructions(config, self.user_instructions.clone(), environments)
|
||||
.await?
|
||||
.map(Arc::new);
|
||||
let mut cache = self.cache.lock().await;
|
||||
cache.selections = Some(selections);
|
||||
cache.active_project_trust_level = active_project_trust_level;
|
||||
cache.windows_sandbox_level = Some(windows_sandbox_level);
|
||||
cache.loaded = loaded;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -339,7 +339,6 @@ async fn load_agents_md(config: &TestConfig) -> Option<LoadedAgentsMd> {
|
||||
&config.config,
|
||||
config.user_instructions.clone(),
|
||||
&environments,
|
||||
WindowsSandboxLevel::Disabled,
|
||||
)
|
||||
.await
|
||||
.expect("project instructions should load")
|
||||
@@ -369,6 +368,9 @@ fn resolved_local_environments<const N: usize>(
|
||||
workspace_roots: Vec::new(),
|
||||
config: EnvironmentConfigState::Ready(EnvironmentConfig {
|
||||
allow_login_shell: true,
|
||||
windows_sandbox_level: WindowsSandboxLevel::Disabled,
|
||||
windows_sandbox_private_desktop: true,
|
||||
use_legacy_landlock: false,
|
||||
permission_profile: PermissionProfileSnapshot::legacy(
|
||||
PermissionProfile::read_only(),
|
||||
),
|
||||
@@ -1133,15 +1135,10 @@ async fn multiple_environment_docs_use_labeled_layout_and_preserve_source_order(
|
||||
]);
|
||||
let user_instructions = config.user_instructions.clone();
|
||||
|
||||
let loaded = load_project_instructions(
|
||||
&config.config,
|
||||
user_instructions,
|
||||
&environments,
|
||||
WindowsSandboxLevel::Disabled,
|
||||
)
|
||||
.await
|
||||
.expect("project instructions should load")
|
||||
.expect("instructions expected");
|
||||
let loaded = load_project_instructions(&config.config, user_instructions, &environments)
|
||||
.await
|
||||
.expect("project instructions should load")
|
||||
.expect("instructions expected");
|
||||
let inner = format!(
|
||||
r#"global instructions
|
||||
|
||||
@@ -1200,15 +1197,10 @@ async fn secondary_only_project_doc_uses_single_contributor_layout() {
|
||||
]);
|
||||
let user_instructions = config.user_instructions.clone();
|
||||
|
||||
let loaded = load_project_instructions(
|
||||
&config.config,
|
||||
user_instructions,
|
||||
&environments,
|
||||
WindowsSandboxLevel::Disabled,
|
||||
)
|
||||
.await
|
||||
.expect("project instructions should load")
|
||||
.expect("instructions expected");
|
||||
let loaded = load_project_instructions(&config.config, user_instructions, &environments)
|
||||
.await
|
||||
.expect("project instructions should load")
|
||||
.expect("instructions expected");
|
||||
let inner = format!("global instructions{AGENTS_MD_SEPARATOR}secondary doc");
|
||||
|
||||
assert_eq!(loaded.legacy_text(), inner);
|
||||
@@ -1235,15 +1227,10 @@ async fn primary_only_project_doc_preserves_legacy_layout_with_multiple_bound_en
|
||||
]);
|
||||
let user_instructions = config.user_instructions.clone();
|
||||
|
||||
let loaded = load_project_instructions(
|
||||
&config.config,
|
||||
user_instructions,
|
||||
&environments,
|
||||
WindowsSandboxLevel::Disabled,
|
||||
)
|
||||
.await
|
||||
.expect("project instructions should load")
|
||||
.expect("instructions expected");
|
||||
let loaded = load_project_instructions(&config.config, user_instructions, &environments)
|
||||
.await
|
||||
.expect("project instructions should load")
|
||||
.expect("instructions expected");
|
||||
let inner = format!("global instructions{AGENTS_MD_SEPARATOR}primary doc");
|
||||
|
||||
assert_eq!(loaded.legacy_text(), inner);
|
||||
@@ -1271,15 +1258,10 @@ async fn project_doc_byte_limit_is_shared_across_environments() {
|
||||
]);
|
||||
let user_instructions = config.user_instructions.clone();
|
||||
|
||||
let loaded = load_project_instructions(
|
||||
&config.config,
|
||||
user_instructions,
|
||||
&environments,
|
||||
WindowsSandboxLevel::Disabled,
|
||||
)
|
||||
.await
|
||||
.expect("project instructions should load")
|
||||
.expect("instructions expected");
|
||||
let loaded = load_project_instructions(&config.config, user_instructions, &environments)
|
||||
.await
|
||||
.expect("project instructions should load")
|
||||
.expect("instructions expected");
|
||||
|
||||
assert_eq!(
|
||||
loaded.text(),
|
||||
@@ -1310,7 +1292,6 @@ async fn full_primary_environment_budget_excludes_later_environment_docs() {
|
||||
&config.config,
|
||||
/*user_instructions*/ None,
|
||||
&environments,
|
||||
WindowsSandboxLevel::Disabled,
|
||||
)
|
||||
.await
|
||||
.expect("project instructions should load")
|
||||
@@ -1343,7 +1324,6 @@ async fn secondary_environment_invalid_utf8_does_not_suppress_other_docs() {
|
||||
&config.config,
|
||||
/*user_instructions*/ None,
|
||||
&environments,
|
||||
WindowsSandboxLevel::Disabled,
|
||||
)
|
||||
.await
|
||||
.expect("project instructions should load")
|
||||
|
||||
@@ -25,6 +25,8 @@ pub(crate) fn prepare_apply_patch(
|
||||
file_system_sandbox_policy: &FileSystemSandboxPolicy,
|
||||
action: ApplyPatchAction,
|
||||
) -> Result<ApplyPatchRuntimeInvocation, FunctionCallError> {
|
||||
// TODO(anp): Reconcile patch approval with TurnEnvironment::sandbox_context
|
||||
// so the Windows backend matches the environment that will apply the patch.
|
||||
match assess_patch_safety(
|
||||
&action,
|
||||
turn_context.approval_policy(),
|
||||
|
||||
@@ -878,6 +878,7 @@ mod tests {
|
||||
use codex_exec_server_test_support::environment_manager_without_environments;
|
||||
use codex_http_client::HttpClientFactory;
|
||||
use codex_http_client::OutboundProxyPolicy;
|
||||
use codex_protocol::config_types::WindowsSandboxLevel;
|
||||
use codex_protocol::models::ActivePermissionProfile;
|
||||
use codex_protocol::models::PermissionProfile;
|
||||
use codex_protocol::protocol::TurnEnvironmentSelection;
|
||||
@@ -902,6 +903,9 @@ mod tests {
|
||||
fn test_environment_config() -> EnvironmentConfig {
|
||||
EnvironmentConfig {
|
||||
allow_login_shell: true,
|
||||
windows_sandbox_level: WindowsSandboxLevel::Disabled,
|
||||
windows_sandbox_private_desktop: true,
|
||||
use_legacy_landlock: false,
|
||||
permission_profile: PermissionProfileSnapshot::legacy(PermissionProfile::read_only()),
|
||||
shell_environment_policy: Default::default(),
|
||||
exec_policy: None,
|
||||
@@ -1073,6 +1077,9 @@ url = "ws://127.0.0.1:8765"
|
||||
};
|
||||
let expected_config = EnvironmentConfig {
|
||||
allow_login_shell: false,
|
||||
windows_sandbox_level: WindowsSandboxLevel::Disabled,
|
||||
windows_sandbox_private_desktop: true,
|
||||
use_legacy_landlock: false,
|
||||
permission_profile: PermissionProfileSnapshot::active_with_profile_workspace_roots(
|
||||
PermissionProfile::read_only(),
|
||||
ActivePermissionProfile::read_only(),
|
||||
@@ -1309,6 +1316,9 @@ url = "ws://127.0.0.1:8765"
|
||||
let cwd = AbsolutePathBuf::current_dir().expect("cwd");
|
||||
let expected_config = EnvironmentConfig {
|
||||
allow_login_shell: false,
|
||||
windows_sandbox_level: WindowsSandboxLevel::Disabled,
|
||||
windows_sandbox_private_desktop: true,
|
||||
use_legacy_landlock: false,
|
||||
permission_profile: PermissionProfileSnapshot::active_with_profile_workspace_roots(
|
||||
PermissionProfile::read_only(),
|
||||
ActivePermissionProfile::read_only(),
|
||||
@@ -1646,6 +1656,9 @@ url = "ws://127.0.0.1:8765"
|
||||
.expect("replacement environment");
|
||||
let child_config = EnvironmentConfig {
|
||||
allow_login_shell: false,
|
||||
windows_sandbox_level: WindowsSandboxLevel::Disabled,
|
||||
windows_sandbox_private_desktop: true,
|
||||
use_legacy_landlock: false,
|
||||
permission_profile: PermissionProfileSnapshot::active_with_profile_workspace_roots(
|
||||
PermissionProfile::read_only(),
|
||||
ActivePermissionProfile::read_only(),
|
||||
@@ -1697,6 +1710,9 @@ url = "ws://127.0.0.1:8765"
|
||||
resolve_turn_environments(Arc::clone(&manager), std::slice::from_ref(&selection)).await;
|
||||
let parent_owner_config = EnvironmentConfig {
|
||||
allow_login_shell: false,
|
||||
windows_sandbox_level: WindowsSandboxLevel::Disabled,
|
||||
windows_sandbox_private_desktop: true,
|
||||
use_legacy_landlock: false,
|
||||
permission_profile: PermissionProfileSnapshot::legacy(PermissionProfile::read_only()),
|
||||
shell_environment_policy: Default::default(),
|
||||
exec_policy: None,
|
||||
|
||||
@@ -101,6 +101,8 @@ pub struct ExecParams {
|
||||
pub network: Option<NetworkProxy>,
|
||||
pub network_environment_id: Option<String>,
|
||||
pub sandbox_permissions: SandboxPermissions,
|
||||
// TODO(anp): Reconcile these launch settings with TurnEnvironment::sandbox_context
|
||||
// so turn-scoped execution uses the selected environment's backend.
|
||||
pub windows_sandbox_level: codex_protocol::config_types::WindowsSandboxLevel,
|
||||
pub windows_sandbox_private_desktop: bool,
|
||||
pub justification: Option<String>,
|
||||
|
||||
@@ -167,6 +167,8 @@ pub(crate) enum ExecPolicyCommandOrigin {
|
||||
pub(crate) struct UnmatchedCommandContext<'a> {
|
||||
pub(crate) approval_policy: AskForApproval,
|
||||
pub(crate) permission_profile: &'a PermissionProfile,
|
||||
// TODO(anp): Reconcile this decision input with TurnEnvironment::sandbox_context
|
||||
// so approval heuristics match the selected environment's Windows backend.
|
||||
pub(crate) windows_sandbox_level: WindowsSandboxLevel,
|
||||
pub(crate) sandbox_permissions: SandboxPermissions,
|
||||
pub(crate) command_origin: ExecPolicyCommandOrigin,
|
||||
@@ -281,6 +283,8 @@ pub(crate) struct ExecApprovalRequest<'a> {
|
||||
pub(crate) approval_policy: AskForApproval,
|
||||
pub(crate) permission_profile: PermissionProfile,
|
||||
pub(crate) environment_policy: Option<&'a RequirementsExecPolicy>,
|
||||
// TODO(anp): Reconcile this approval snapshot with TurnEnvironment::sandbox_context
|
||||
// rather than taking the Windows backend from the turn-wide default.
|
||||
pub(crate) windows_sandbox_level: WindowsSandboxLevel,
|
||||
pub(crate) sandbox_permissions: SandboxPermissions,
|
||||
pub(crate) prefix_rule: Option<Vec<String>>,
|
||||
|
||||
@@ -180,9 +180,8 @@ async fn build_uploaded_argument_value(
|
||||
.entries
|
||||
.iter()
|
||||
.any(|entry| entry.access == FileSystemAccessMode::Deny);
|
||||
let sandbox = requires_sandbox.then(|| {
|
||||
turn_context.file_system_sandbox_context(additional_permissions, turn_environment)
|
||||
});
|
||||
let sandbox =
|
||||
requires_sandbox.then(|| turn_environment.sandbox_context(additional_permissions));
|
||||
if sandbox.is_some() {
|
||||
let environment_info = turn_environment
|
||||
.environment
|
||||
|
||||
@@ -773,6 +773,8 @@ async fn augment_mcp_tool_request_meta_with_sandbox_state(
|
||||
else {
|
||||
return Ok(meta);
|
||||
};
|
||||
// TODO(anp): Build this metadata from the server's captured
|
||||
// TurnEnvironment::sandbox_context instead of the runtime-wide Landlock value.
|
||||
let permission_profile = prepared_call.config().permission_profile.clone();
|
||||
let sandbox_state = serde_json::to_value(SandboxState {
|
||||
permission_profile,
|
||||
|
||||
@@ -1113,6 +1113,12 @@ async fn mcp_sandbox_cwd_uses_matching_server_environment_uri() -> anyhow::Resul
|
||||
workspace_roots: Vec::new(),
|
||||
config: EnvironmentConfigState::Ready(EnvironmentConfig {
|
||||
allow_login_shell: true,
|
||||
windows_sandbox_level: turn_context.windows_sandbox_level,
|
||||
windows_sandbox_private_desktop: turn_context
|
||||
.config
|
||||
.permissions
|
||||
.windows_sandbox_private_desktop,
|
||||
use_legacy_landlock: turn_context.config.features.use_legacy_landlock(),
|
||||
permission_profile: turn_context
|
||||
.config
|
||||
.permissions
|
||||
|
||||
@@ -60,6 +60,8 @@ pub struct ExecRequest {
|
||||
pub sandbox: SandboxType,
|
||||
pub windows_sandbox_policy_cwd: PathUri,
|
||||
pub windows_sandbox_workspace_roots: Vec<AbsolutePathBuf>,
|
||||
// TODO(anp): Reconcile these backend copies with TurnEnvironment::sandbox_context
|
||||
// and exec_server_sandbox so local and remote launches use the same settings.
|
||||
pub windows_sandbox_level: WindowsSandboxLevel,
|
||||
pub windows_sandbox_private_desktop: bool,
|
||||
pub permission_profile: PermissionProfile,
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
use super::mcp_refresh::McpRefreshInvalidationGuard;
|
||||
use super::*;
|
||||
use crate::environment_selection::combine_selected_capability_roots;
|
||||
use crate::tools::sandboxing::executor_windows_sandbox_level;
|
||||
use codex_exec_server::ExecutorCapabilityDiscoveryCache;
|
||||
use codex_exec_server::ExecutorCapabilityDiscoverySnapshot;
|
||||
use codex_exec_server::FileSystemSandboxContext;
|
||||
use codex_exec_server::MAX_SELECTED_CAPABILITY_ROOTS;
|
||||
use codex_exec_server::ResolvedSelectedCapabilityRoot;
|
||||
use codex_mcp::CODEX_APPS_MCP_SERVER_NAME;
|
||||
@@ -98,10 +96,9 @@ impl Session {
|
||||
config: &Config,
|
||||
) -> (McpConfig, McpRuntimeContext) {
|
||||
let originator = self.originator().await;
|
||||
let (windows_sandbox_level, session_source, host_fallback_cwd) = {
|
||||
let (session_source, host_fallback_cwd) = {
|
||||
let state = self.state.lock().await;
|
||||
(
|
||||
state.session_configuration.windows_sandbox_level,
|
||||
state.session_configuration.session_source.clone(),
|
||||
state.session_configuration.cwd().clone(),
|
||||
)
|
||||
@@ -117,7 +114,6 @@ impl Session {
|
||||
config,
|
||||
&ready_selected_capability_roots,
|
||||
&environments,
|
||||
windows_sandbox_level,
|
||||
)
|
||||
.await;
|
||||
let mcp_projection = self
|
||||
@@ -210,7 +206,6 @@ impl Session {
|
||||
&desired.config,
|
||||
&ready_selected_capability_roots,
|
||||
&desired.environments,
|
||||
desired.windows_sandbox_level,
|
||||
)
|
||||
.await;
|
||||
let mcp_projection = self
|
||||
@@ -265,7 +260,6 @@ impl Session {
|
||||
&desired.config,
|
||||
&ready_selected_capability_roots,
|
||||
&desired.environments,
|
||||
desired.windows_sandbox_level,
|
||||
)
|
||||
.await;
|
||||
let mcp_projection = self
|
||||
@@ -373,7 +367,6 @@ impl Session {
|
||||
config: &Config,
|
||||
ready_selected_capability_roots: &[SelectedCapabilityRoot],
|
||||
environments: &TurnEnvironmentSnapshot,
|
||||
windows_sandbox_level: WindowsSandboxLevel,
|
||||
) -> Option<Arc<ExecutorCapabilityDiscoverySnapshot>> {
|
||||
// Capability roots can currently be selected independently of turn environments, so a
|
||||
// root may be ready when there is no primary `TurnEnvironment`. Keep using the thread
|
||||
@@ -408,17 +401,10 @@ impl Session {
|
||||
environments
|
||||
.turn_environments()
|
||||
.map(|environment| {
|
||||
let mut sandbox = FileSystemSandboxContext::from_permission_profile_with_cwd(
|
||||
environment.permission_profile().clone(),
|
||||
environment.cwd().clone(),
|
||||
);
|
||||
sandbox.workspace_roots = environment.workspace_roots().to_vec();
|
||||
sandbox.windows_sandbox_level =
|
||||
executor_windows_sandbox_level(windows_sandbox_level, environment.cwd());
|
||||
sandbox.windows_sandbox_private_desktop =
|
||||
config.permissions.windows_sandbox_private_desktop;
|
||||
sandbox.use_legacy_landlock = config.features.use_legacy_landlock();
|
||||
(environment.selection.environment_id.clone(), sandbox)
|
||||
(
|
||||
environment.selection.environment_id.clone(),
|
||||
environment.sandbox_context(/*additional_permissions*/ None),
|
||||
)
|
||||
})
|
||||
.collect::<HashMap<_, _>>()
|
||||
} else {
|
||||
@@ -665,7 +651,6 @@ impl Session {
|
||||
refresh_config,
|
||||
&ready_selected_capability_roots,
|
||||
&environments,
|
||||
turn_context.windows_sandbox_level,
|
||||
)
|
||||
.await;
|
||||
let mcp_projection = self
|
||||
|
||||
@@ -28,7 +28,6 @@ pub(super) struct McpDesiredState {
|
||||
pub(super) session_source: SessionSource,
|
||||
pub(super) environments: TurnEnvironmentSnapshot,
|
||||
pub(super) local_process_cwd: PathBuf,
|
||||
pub(super) windows_sandbox_level: WindowsSandboxLevel,
|
||||
}
|
||||
|
||||
impl Session {
|
||||
@@ -38,6 +37,9 @@ impl Session {
|
||||
next: &SessionConfiguration,
|
||||
updates: &SessionSettingsUpdate,
|
||||
) -> bool {
|
||||
// TODO(anp): Reconcile invalidation with TurnEnvironment::sandbox_context.
|
||||
// This gap predates that API: an internal Windows-level-only settings update
|
||||
// can leave the published MCP configuration stale.
|
||||
current.cwd() != next.cwd()
|
||||
|| current.approval_policy.value() != next.approval_policy.value()
|
||||
|| current.approvals_reviewer != next.approvals_reviewer
|
||||
@@ -97,7 +99,6 @@ impl Session {
|
||||
session_source: session_configuration.session_source.clone(),
|
||||
environments,
|
||||
local_process_cwd,
|
||||
windows_sandbox_level: session_configuration.windows_sandbox_level,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,7 +125,6 @@ impl Session {
|
||||
session_source: session_configuration.session_source.clone(),
|
||||
environments: resolved_environments.clone(),
|
||||
local_process_cwd,
|
||||
windows_sandbox_level: session_configuration.windows_sandbox_level,
|
||||
};
|
||||
self.publish_mcp_runtime(
|
||||
&desired,
|
||||
|
||||
@@ -716,6 +716,8 @@ impl Session {
|
||||
allow_login_shell: config.permissions.allow_login_shell,
|
||||
shell_environment_policy: config.permissions.shell_environment_policy.clone(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&config),
|
||||
windows_sandbox_private_desktop: config.permissions.windows_sandbox_private_desktop,
|
||||
use_legacy_landlock: config.features.use_legacy_landlock(),
|
||||
legacy_fallback_cwd: config.cwd.clone(),
|
||||
codex_home: config.codex_home.clone(),
|
||||
thread_name: None,
|
||||
@@ -3254,11 +3256,7 @@ impl Session {
|
||||
let environments = turn_context.environments.refresh_readiness();
|
||||
self.services
|
||||
.agents_md_manager
|
||||
.refresh(
|
||||
&turn_context.config,
|
||||
&environments,
|
||||
turn_context.windows_sandbox_level,
|
||||
)
|
||||
.refresh(&turn_context.config, &environments)
|
||||
.await?;
|
||||
let loaded_agents_md = self.services.agents_md_manager.get_loaded().await;
|
||||
let selected_capability_roots = self
|
||||
@@ -3271,7 +3269,6 @@ impl Session {
|
||||
&turn_context.config,
|
||||
&ready_selected_capability_roots,
|
||||
&environments,
|
||||
turn_context.windows_sandbox_level,
|
||||
)
|
||||
.or_cancel(cancellation_token)
|
||||
.await?;
|
||||
@@ -3292,10 +3289,7 @@ impl Session {
|
||||
.map(|environment| {
|
||||
(
|
||||
environment.selection.environment_id.clone(),
|
||||
turn_context.file_system_sandbox_context(
|
||||
/*additional_permissions*/ None,
|
||||
environment,
|
||||
),
|
||||
environment.sandbox_context(/*additional_permissions*/ None),
|
||||
)
|
||||
})
|
||||
.collect::<HashMap<_, _>>();
|
||||
|
||||
@@ -97,7 +97,11 @@ pub(crate) struct SessionConfiguration {
|
||||
pub(super) permission_profile_state: PermissionProfileState,
|
||||
pub(super) allow_login_shell: bool,
|
||||
pub(super) shell_environment_policy: ShellEnvironmentPolicy,
|
||||
// TODO(anp): Reconcile these legacy thread defaults with TurnEnvironment::sandbox_context;
|
||||
// internal sandbox decisions should use the selected environment's configuration.
|
||||
pub(super) windows_sandbox_level: WindowsSandboxLevel,
|
||||
pub(super) windows_sandbox_private_desktop: bool,
|
||||
pub(super) use_legacy_landlock: bool,
|
||||
|
||||
/// Legacy thread cwd used when a turn does not select an environment.
|
||||
pub(super) legacy_fallback_cwd: AbsolutePathBuf,
|
||||
@@ -144,6 +148,9 @@ impl SessionConfiguration {
|
||||
allow_login_shell: self.allow_login_shell,
|
||||
permission_profile: self.permission_profile_state.snapshot(),
|
||||
shell_environment_policy: self.shell_environment_policy.clone(),
|
||||
windows_sandbox_level: self.windows_sandbox_level,
|
||||
windows_sandbox_private_desktop: self.windows_sandbox_private_desktop,
|
||||
use_legacy_landlock: self.use_legacy_landlock,
|
||||
exec_policy: None,
|
||||
mcp_policy: None,
|
||||
network_policy: None,
|
||||
@@ -293,6 +300,9 @@ impl SessionConfiguration {
|
||||
service_tier: Some(self.service_tier.clone()),
|
||||
collaboration_mode: Some(self.collaboration_mode.clone()),
|
||||
personality: self.personality,
|
||||
// TODO(anp): Include the runtime Windows sandbox override in restored settings.
|
||||
// This omission predates TurnEnvironment::sandbox_context; rebuilding FromThread
|
||||
// environments falls back to Config instead of retaining that override.
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
@@ -1219,11 +1229,7 @@ impl Session {
|
||||
otel.name = "session_init.thread_name_lookup",
|
||||
));
|
||||
let (agents_md_result, plugin_skill_errors, thread_name) = tokio::join!(
|
||||
agents_md_manager.refresh(
|
||||
config.as_ref(),
|
||||
&resolved_environments,
|
||||
session_configuration.windows_sandbox_level,
|
||||
),
|
||||
agents_md_manager.refresh(config.as_ref(), &resolved_environments),
|
||||
plugin_skill_warmup,
|
||||
thread_name_lookup,
|
||||
);
|
||||
|
||||
@@ -32,9 +32,11 @@ use codex_config::loader::project_trust_key;
|
||||
use codex_config::types::McpServerConfig;
|
||||
use codex_config::types::McpServerTransportConfig;
|
||||
use codex_config::types::ToolSuggestDisabledTool;
|
||||
use codex_config::types::WindowsSandboxModeToml;
|
||||
use core_test_support::test_codex::TurnInputRequest as ExternalTurnInputRequest;
|
||||
|
||||
use codex_features::Feature;
|
||||
use codex_file_system::FileSystemSandboxContext;
|
||||
use codex_http_client::ClientRouteClass;
|
||||
use codex_http_client::HttpClientFactory;
|
||||
use codex_http_client::OutboundProxyPolicy;
|
||||
@@ -4340,6 +4342,8 @@ async fn set_rate_limits_retains_previous_credits() {
|
||||
allow_login_shell: config.permissions.allow_login_shell,
|
||||
shell_environment_policy: config.permissions.shell_environment_policy.clone(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&config),
|
||||
windows_sandbox_private_desktop: config.permissions.windows_sandbox_private_desktop,
|
||||
use_legacy_landlock: config.features.use_legacy_landlock(),
|
||||
legacy_fallback_cwd: config.cwd.clone(),
|
||||
codex_home: config.codex_home.clone(),
|
||||
thread_name: None,
|
||||
@@ -4451,6 +4455,8 @@ async fn set_rate_limits_updates_plan_type_when_present() {
|
||||
allow_login_shell: config.permissions.allow_login_shell,
|
||||
shell_environment_policy: config.permissions.shell_environment_policy.clone(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&config),
|
||||
windows_sandbox_private_desktop: config.permissions.windows_sandbox_private_desktop,
|
||||
use_legacy_landlock: config.features.use_legacy_landlock(),
|
||||
legacy_fallback_cwd: config.cwd.clone(),
|
||||
codex_home: config.codex_home.clone(),
|
||||
thread_name: None,
|
||||
@@ -5007,6 +5013,8 @@ pub(crate) async fn make_session_configuration_for_tests() -> SessionConfigurati
|
||||
allow_login_shell: config.permissions.allow_login_shell,
|
||||
shell_environment_policy: config.permissions.shell_environment_policy.clone(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&config),
|
||||
windows_sandbox_private_desktop: config.permissions.windows_sandbox_private_desktop,
|
||||
use_legacy_landlock: config.features.use_legacy_landlock(),
|
||||
legacy_fallback_cwd: config.cwd.clone(),
|
||||
codex_home: config.codex_home.clone(),
|
||||
thread_name: None,
|
||||
@@ -5794,6 +5802,8 @@ async fn session_new_fails_when_zsh_fork_enabled_without_packaged_zsh() {
|
||||
allow_login_shell: config.permissions.allow_login_shell,
|
||||
shell_environment_policy: config.permissions.shell_environment_policy.clone(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&config),
|
||||
windows_sandbox_private_desktop: config.permissions.windows_sandbox_private_desktop,
|
||||
use_legacy_landlock: config.features.use_legacy_landlock(),
|
||||
legacy_fallback_cwd: config.cwd.clone(),
|
||||
codex_home: config.codex_home.clone(),
|
||||
thread_name: None,
|
||||
@@ -5942,6 +5952,8 @@ pub(crate) async fn make_session_and_context() -> (Session, TurnContext) {
|
||||
allow_login_shell: config.permissions.allow_login_shell,
|
||||
shell_environment_policy: config.permissions.shell_environment_policy.clone(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&config),
|
||||
windows_sandbox_private_desktop: config.permissions.windows_sandbox_private_desktop,
|
||||
use_legacy_landlock: config.features.use_legacy_landlock(),
|
||||
legacy_fallback_cwd: config.cwd.clone(),
|
||||
codex_home: config.codex_home.clone(),
|
||||
thread_name: None,
|
||||
@@ -6230,6 +6242,8 @@ async fn make_session_with_config_and_rx(
|
||||
allow_login_shell: config.permissions.allow_login_shell,
|
||||
shell_environment_policy: config.permissions.shell_environment_policy.clone(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&config),
|
||||
windows_sandbox_private_desktop: config.permissions.windows_sandbox_private_desktop,
|
||||
use_legacy_landlock: config.features.use_legacy_landlock(),
|
||||
legacy_fallback_cwd: config.cwd.clone(),
|
||||
codex_home: config.codex_home.clone(),
|
||||
thread_name: None,
|
||||
@@ -6351,6 +6365,8 @@ async fn make_session_with_history_source_and_agent_control_and_rx(
|
||||
allow_login_shell: config.permissions.allow_login_shell,
|
||||
shell_environment_policy: config.permissions.shell_environment_policy.clone(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&config),
|
||||
windows_sandbox_private_desktop: config.permissions.windows_sandbox_private_desktop,
|
||||
use_legacy_landlock: config.features.use_legacy_landlock(),
|
||||
legacy_fallback_cwd: config.cwd.clone(),
|
||||
codex_home: config.codex_home.clone(),
|
||||
thread_name: None,
|
||||
@@ -8153,6 +8169,8 @@ where
|
||||
allow_login_shell: config.permissions.allow_login_shell,
|
||||
shell_environment_policy: config.permissions.shell_environment_policy.clone(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&config),
|
||||
windows_sandbox_private_desktop: config.permissions.windows_sandbox_private_desktop,
|
||||
use_legacy_landlock: config.features.use_legacy_landlock(),
|
||||
legacy_fallback_cwd: config.cwd.clone(),
|
||||
codex_home: config.codex_home.clone(),
|
||||
thread_name: None,
|
||||
@@ -8844,13 +8862,23 @@ async fn conflicting_ready_environment_root_ids_keep_first_location() {
|
||||
});
|
||||
}
|
||||
|
||||
/// Capability discovery must use environment-owned permissions and sandbox backends,
|
||||
/// even when the thread defaults differ.
|
||||
#[tokio::test]
|
||||
async fn capability_discovery_uses_environment_permission_profile() {
|
||||
let (session, mut turn_context) = make_session_and_context().await;
|
||||
Arc::make_mut(&mut turn_context.config)
|
||||
let config = Arc::make_mut(&mut turn_context.config);
|
||||
config
|
||||
.permissions
|
||||
.set_permission_profile(PermissionProfile::Disabled)
|
||||
.expect("unrestricted permission profile should be allowed");
|
||||
config.permissions.windows_sandbox_mode = Some(WindowsSandboxModeToml::Unelevated);
|
||||
config.permissions.windows_sandbox_private_desktop = true;
|
||||
config
|
||||
.features
|
||||
.disable(Feature::UseLegacyLandlock)
|
||||
.expect("disable legacy Landlock");
|
||||
turn_context.windows_sandbox_level = WindowsSandboxLevel::RestrictedToken;
|
||||
let mut environment = turn_context
|
||||
.environments
|
||||
.primary()
|
||||
@@ -8864,13 +8892,24 @@ async fn capability_discovery_uses_environment_permission_profile() {
|
||||
access: FileSystemAccessMode::Deny,
|
||||
missing_path_behavior: None,
|
||||
});
|
||||
environment.config_mut().permission_profile =
|
||||
let environment_config = environment.config_mut();
|
||||
environment_config.permission_profile =
|
||||
PermissionProfileSnapshot::legacy(PermissionProfile::from_runtime_permissions(
|
||||
&file_system_policy,
|
||||
NetworkSandboxPolicy::Restricted,
|
||||
));
|
||||
let expected_sandbox = turn_context
|
||||
.file_system_sandbox_context(/*additional_permissions*/ None, &environment);
|
||||
environment_config.windows_sandbox_level = WindowsSandboxLevel::Elevated;
|
||||
environment_config.windows_sandbox_private_desktop = false;
|
||||
environment_config.use_legacy_landlock = true;
|
||||
let expected_sandbox = FileSystemSandboxContext {
|
||||
permissions: environment.permission_profile().clone().into(),
|
||||
cwd: Some(environment.cwd().clone()),
|
||||
workspace_roots: environment.workspace_roots().to_vec(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::Elevated,
|
||||
windows_sandbox_private_desktop: false,
|
||||
windows_sandbox_proxy_settings_mode: None,
|
||||
use_legacy_landlock: true,
|
||||
};
|
||||
let environment_id = environment.selection.environment_id.clone();
|
||||
turn_context.environments.environments[0] = TurnEnvironmentState::Ready(environment);
|
||||
|
||||
@@ -8879,7 +8918,6 @@ async fn capability_discovery_uses_environment_permission_profile() {
|
||||
&turn_context.config,
|
||||
/*ready_selected_capability_roots*/ &[],
|
||||
&turn_context.environments,
|
||||
turn_context.windows_sandbox_level,
|
||||
)
|
||||
.await
|
||||
.expect("restricted environment should trigger capability discovery");
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -11,6 +11,7 @@ use crate::session::tests::build_world_state_from_turn_context;
|
||||
use crate::session::tests::make_session_and_context;
|
||||
use crate::tasks::InterruptedTurnHistoryMarker;
|
||||
use crate::tasks::interrupted_turn_history_marker;
|
||||
use crate::windows_sandbox::WindowsSandboxLevelExt;
|
||||
use codex_extension_api::empty_extension_registry;
|
||||
use codex_history::InitialHistory;
|
||||
use codex_history::ResumedHistory;
|
||||
@@ -18,6 +19,7 @@ use codex_models_manager::manager::RefreshStrategy;
|
||||
use codex_protocol::ResponseItemId;
|
||||
use codex_protocol::capabilities::CapabilityRootLocation;
|
||||
use codex_protocol::capabilities::SelectedCapabilityRoot;
|
||||
use codex_protocol::config_types::WindowsSandboxLevel;
|
||||
use codex_protocol::mcp::ClientMcpExtensions;
|
||||
use codex_protocol::mcp::MCP_APP_UI_EXTENSION_ID;
|
||||
use codex_protocol::mcp::OPENAI_FORM_EXTENSION_ID;
|
||||
@@ -1017,6 +1019,9 @@ async fn spawn_internal_session_preserves_parent_lineage_without_forking_history
|
||||
allow_login_shell: true,
|
||||
permission_profile: config.permissions.permission_profile_state().snapshot(),
|
||||
shell_environment_policy: Default::default(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&config),
|
||||
windows_sandbox_private_desktop: config.permissions.windows_sandbox_private_desktop,
|
||||
use_legacy_landlock: config.features.use_legacy_landlock(),
|
||||
exec_policy: Some(codex_execpolicy::RequirementsExecPolicy::new(
|
||||
codex_execpolicy::Policy::empty(),
|
||||
)),
|
||||
|
||||
@@ -406,8 +406,7 @@ impl ApplyPatchHandler {
|
||||
));
|
||||
};
|
||||
let fs = turn_environment.environment.get_filesystem();
|
||||
let sandbox = turn
|
||||
.file_system_sandbox_context(/*additional_permissions*/ None, turn_environment);
|
||||
let sandbox = turn_environment.sandbox_context(/*additional_permissions*/ None);
|
||||
match codex_apply_patch::verify_apply_patch_args_with_mode(
|
||||
args,
|
||||
turn_environment.cwd(),
|
||||
@@ -518,8 +517,7 @@ pub(crate) async fn intercept_apply_patch(
|
||||
tool_name: &str,
|
||||
) -> Result<Option<FunctionToolOutput>, FunctionCallError> {
|
||||
let turn = &step_context.turn;
|
||||
let sandbox =
|
||||
turn.file_system_sandbox_context(/*additional_permissions*/ None, &turn_environment);
|
||||
let sandbox = turn_environment.sandbox_context(/*additional_permissions*/ None);
|
||||
match codex_apply_patch::maybe_parse_apply_patch_verified_with_mode(
|
||||
command,
|
||||
cwd,
|
||||
|
||||
@@ -182,9 +182,7 @@ async fn to_extension_call(invocation: &ToolInvocation) -> ExtensionToolCall {
|
||||
)
|
||||
.await
|
||||
.additional_permissions;
|
||||
let file_system_sandbox_context = invocation
|
||||
.turn
|
||||
.file_system_sandbox_context(additional_permissions, environment);
|
||||
let file_system_sandbox_context = environment.sandbox_context(additional_permissions);
|
||||
environments.push(ToolEnvironment {
|
||||
environment_id: environment.selection.environment_id.clone(),
|
||||
cwd: native_cwd,
|
||||
|
||||
@@ -161,6 +161,8 @@ impl ExecCommandHandler {
|
||||
|
||||
// Remote executors enforce URI-native sandbox policy themselves. Only a host-local
|
||||
// sandbox needs a native cwd for resolving paths nested in the permissions config.
|
||||
// TODO(anp): Reconcile this backend choice with TurnEnvironment::sandbox_context
|
||||
// so the native-cwd requirement follows the selected environment's sandbox.
|
||||
let requires_host_native_cwd = !environment.is_remote()
|
||||
&& SandboxManager::new().select_initial(
|
||||
turn_environment.permission_profile(),
|
||||
|
||||
@@ -151,8 +151,7 @@ impl ViewImageHandler {
|
||||
))
|
||||
})?;
|
||||
let model_visible_path = path_uri.inferred_native_path_string();
|
||||
let sandbox = turn
|
||||
.file_system_sandbox_context(/*additional_permissions*/ None, turn_environment);
|
||||
let sandbox = turn_environment.sandbox_context(/*additional_permissions*/ None);
|
||||
let fs = turn_environment.environment.get_filesystem();
|
||||
|
||||
let metadata = fs
|
||||
|
||||
@@ -269,6 +269,8 @@ impl ToolOrchestrator {
|
||||
managed_network_active,
|
||||
),
|
||||
};
|
||||
// TODO(anp): Reconcile backend selection and both attempts with
|
||||
// TurnEnvironment::sandbox_context; turn-wide inputs can differ from owner config.
|
||||
let initial_sandbox = if sandbox_requested && !executor_managed_process_sandbox {
|
||||
self.sandbox.select_initial(
|
||||
&permissions,
|
||||
|
||||
@@ -485,6 +485,8 @@ impl ToolRegistry {
|
||||
let call_id_owned = invocation.call_id.clone();
|
||||
let otel = invocation.turn.session_telemetry.clone();
|
||||
let permission_profile = invocation.turn.permission_profile();
|
||||
// TODO(anp): Reconcile these tags with TurnEnvironment::sandbox_context
|
||||
// instead of reporting the thread-wide backend for environment-scoped tools.
|
||||
let base_tool_result_tags = [
|
||||
(
|
||||
"sandbox",
|
||||
|
||||
@@ -27,6 +27,9 @@ fn test_turn_environment(environment_id: &str) -> crate::session::turn_context::
|
||||
workspace_roots: Vec::new(),
|
||||
config: EnvironmentConfigState::Ready(EnvironmentConfig {
|
||||
allow_login_shell: true,
|
||||
windows_sandbox_level: WindowsSandboxLevel::Disabled,
|
||||
windows_sandbox_private_desktop: true,
|
||||
use_legacy_landlock: false,
|
||||
permission_profile: PermissionProfileSnapshot::legacy(
|
||||
PermissionProfile::read_only(),
|
||||
),
|
||||
|
||||
@@ -530,6 +530,7 @@ mod tests {
|
||||
use crate::tools::sandboxing::ToolRuntime;
|
||||
use codex_exec_server::Environment;
|
||||
use codex_exec_server::LOCAL_ENVIRONMENT_ID;
|
||||
use codex_protocol::config_types::WindowsSandboxLevel;
|
||||
use codex_protocol::models::PermissionProfile;
|
||||
use codex_protocol::protocol::EnvironmentConfig;
|
||||
use codex_protocol::protocol::EnvironmentConfigState;
|
||||
@@ -550,6 +551,9 @@ mod tests {
|
||||
workspace_roots: Vec::new(),
|
||||
config: EnvironmentConfigState::Ready(EnvironmentConfig {
|
||||
allow_login_shell: true,
|
||||
windows_sandbox_level: WindowsSandboxLevel::Disabled,
|
||||
windows_sandbox_private_desktop: true,
|
||||
use_legacy_landlock: false,
|
||||
permission_profile: PermissionProfileSnapshot::legacy(
|
||||
PermissionProfile::read_only(),
|
||||
),
|
||||
|
||||
@@ -532,6 +532,8 @@ fn evaluate_intercepted_exec_policy(
|
||||
struct InterceptedExecPolicyContext {
|
||||
approval_policy: AskForApproval,
|
||||
permission_profile: PermissionProfile,
|
||||
// TODO(anp): Reconcile this policy input with TurnEnvironment::sandbox_context
|
||||
// so intercepted commands use the selected environment's Windows backend.
|
||||
windows_sandbox_level: WindowsSandboxLevel,
|
||||
sandbox_permissions: SandboxPermissions,
|
||||
enable_shell_wrapper_parsing: bool,
|
||||
@@ -557,6 +559,8 @@ fn commands_for_intercepted_exec_policy(
|
||||
vec![join_program_and_argv(program, argv)]
|
||||
}
|
||||
|
||||
// TODO(anp): Capture these Windows and Landlock settings from
|
||||
// TurnEnvironment::sandbox_context when preparing this executor, preserving its snapshot.
|
||||
struct CoreShellCommandExecutor {
|
||||
command: Vec<String>,
|
||||
cwd: AbsolutePathBuf,
|
||||
|
||||
@@ -395,6 +395,8 @@ pub(crate) struct SandboxAttempt<'a> {
|
||||
pub(crate) sandbox_cwd: &'a PathUri,
|
||||
pub(crate) workspace_roots: &'a [PathUri],
|
||||
pub codex_linux_sandbox_exe: Option<&'a std::path::PathBuf>,
|
||||
// TODO(anp): Reconcile these attempt settings with TurnEnvironment::sandbox_context
|
||||
// so process execution and patch writes honor the selected environment's backend.
|
||||
pub use_legacy_landlock: bool,
|
||||
pub windows_sandbox_level: codex_protocol::config_types::WindowsSandboxLevel,
|
||||
pub windows_sandbox_private_desktop: bool,
|
||||
|
||||
@@ -1070,6 +1070,12 @@ async fn zsh_fork_unified_exec_keeps_shell_parameter_when_remote_environment_ava
|
||||
config: EnvironmentConfigState::Ready(
|
||||
codex_protocol::protocol::EnvironmentConfig {
|
||||
allow_login_shell: true,
|
||||
windows_sandbox_level: turn.windows_sandbox_level,
|
||||
windows_sandbox_private_desktop: turn
|
||||
.config
|
||||
.permissions
|
||||
.windows_sandbox_private_desktop,
|
||||
use_legacy_landlock: turn.config.features.use_legacy_landlock(),
|
||||
permission_profile: turn
|
||||
.config
|
||||
.permissions
|
||||
|
||||
@@ -114,6 +114,8 @@ pub(crate) struct TurnMetadataState {
|
||||
subagent_kind: Option<String>,
|
||||
thread_source: Option<ThreadSource>,
|
||||
turn_id: String,
|
||||
// TODO(anp): Derive this cached tag from TurnEnvironment::sandbox_context
|
||||
// so metadata reflects the selected environment's backend.
|
||||
sandbox: Option<String>,
|
||||
sandbox_mode: Option<String>,
|
||||
auto_review_enabled: bool,
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
use anyhow::Result;
|
||||
use codex_core::windows_sandbox::WindowsSandboxLevelExt;
|
||||
use codex_exec_server::CreateDirectoryOptions;
|
||||
use codex_features::Feature;
|
||||
use codex_protocol::config_types::WindowsSandboxLevel;
|
||||
use codex_protocol::models::PermissionProfile;
|
||||
use codex_protocol::models::PermissionProfileSnapshot;
|
||||
use codex_protocol::protocol::EnvironmentConfig;
|
||||
@@ -312,6 +314,12 @@ async fn v2_residency_reload_preserves_inherited_environment_and_tools(
|
||||
allow_login_shell: test.config.permissions.allow_login_shell,
|
||||
permission_profile: PermissionProfileSnapshot::legacy(child_permissions),
|
||||
shell_environment_policy: Default::default(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&test.config),
|
||||
windows_sandbox_private_desktop: test
|
||||
.config
|
||||
.permissions
|
||||
.windows_sandbox_private_desktop,
|
||||
use_legacy_landlock: test.config.features.use_legacy_landlock(),
|
||||
exec_policy: None,
|
||||
mcp_policy: None,
|
||||
network_policy: None,
|
||||
|
||||
@@ -5,6 +5,7 @@ use codex_config::test_support::CloudConfigBundleFixture;
|
||||
use codex_core::EnvironmentConfig;
|
||||
use codex_core::TurnInputRequest;
|
||||
use codex_core::config::Constrained;
|
||||
use codex_core::windows_sandbox::WindowsSandboxLevelExt;
|
||||
use codex_execpolicy::Decision;
|
||||
use codex_execpolicy::Policy;
|
||||
use codex_execpolicy::RequirementsExecPolicy;
|
||||
@@ -13,6 +14,7 @@ use codex_protocol::config_types::ApprovalsReviewer;
|
||||
use codex_protocol::config_types::CollaborationMode;
|
||||
use codex_protocol::config_types::ModeKind;
|
||||
use codex_protocol::config_types::Settings;
|
||||
use codex_protocol::config_types::WindowsSandboxLevel;
|
||||
use codex_protocol::error::CodexErrorDetails;
|
||||
use codex_protocol::models::PermissionProfile;
|
||||
use codex_protocol::models::PermissionProfileSnapshot;
|
||||
@@ -716,6 +718,12 @@ async fn environment_command_restrictions_override_saved_prefix_approvals() -> R
|
||||
allow_login_shell: true,
|
||||
permission_profile: PermissionProfileSnapshot::legacy(PermissionProfile::Disabled),
|
||||
shell_environment_policy: Default::default(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&test.config),
|
||||
windows_sandbox_private_desktop: test
|
||||
.config
|
||||
.permissions
|
||||
.windows_sandbox_private_desktop,
|
||||
use_legacy_landlock: test.config.features.use_legacy_landlock(),
|
||||
exec_policy: Some(RequirementsExecPolicy::new(invalid_policy)),
|
||||
mcp_policy: None,
|
||||
network_policy: None,
|
||||
@@ -739,6 +747,12 @@ async fn environment_command_restrictions_override_saved_prefix_approvals() -> R
|
||||
allow_login_shell: true,
|
||||
permission_profile: PermissionProfileSnapshot::legacy(PermissionProfile::Disabled),
|
||||
shell_environment_policy: Default::default(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&test.config),
|
||||
windows_sandbox_private_desktop: test
|
||||
.config
|
||||
.permissions
|
||||
.windows_sandbox_private_desktop,
|
||||
use_legacy_landlock: test.config.features.use_legacy_landlock(),
|
||||
exec_policy: Some(RequirementsExecPolicy::new(environment_policy)),
|
||||
mcp_policy: None,
|
||||
network_policy: None,
|
||||
@@ -843,6 +857,12 @@ async fn environment_command_policy_changes_invalidate_session_approvals() -> Re
|
||||
PermissionProfile::Disabled,
|
||||
),
|
||||
shell_environment_policy: Default::default(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&test.config),
|
||||
windows_sandbox_private_desktop: test
|
||||
.config
|
||||
.permissions
|
||||
.windows_sandbox_private_desktop,
|
||||
use_legacy_landlock: test.config.features.use_legacy_landlock(),
|
||||
exec_policy: Some(RequirementsExecPolicy::new(policy)),
|
||||
mcp_policy: None,
|
||||
network_policy: None,
|
||||
|
||||
@@ -14,6 +14,7 @@ use codex_core::config::Config;
|
||||
use codex_core::config::Constrained;
|
||||
use codex_core::config::CurrentTimeReminderConfig;
|
||||
use codex_core::sandboxing::SandboxPermissions;
|
||||
use codex_core::windows_sandbox::WindowsSandboxLevelExt;
|
||||
use codex_extension_api::ExtensionRegistryBuilder;
|
||||
use codex_extension_api::ToolLifecycleContributor;
|
||||
use codex_extension_api::ToolLifecycleFuture;
|
||||
@@ -25,6 +26,7 @@ use codex_history::RolloutLine;
|
||||
use codex_login::CodexAuth;
|
||||
use codex_protocol::ThreadId;
|
||||
use codex_protocol::config_types::ApprovalsReviewer;
|
||||
use codex_protocol::config_types::WindowsSandboxLevel;
|
||||
use codex_protocol::models::PermissionProfile;
|
||||
use codex_protocol::models::PermissionProfileSnapshot;
|
||||
use codex_protocol::openai_models::AutoReviewMessages;
|
||||
@@ -768,6 +770,9 @@ async fn guardian_session_is_reused_for_consecutive_tool_reviews_without_prewarm
|
||||
test.config.permissions.permission_profile().clone(),
|
||||
),
|
||||
shell_environment_policy: Default::default(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&test.config),
|
||||
windows_sandbox_private_desktop: test.config.permissions.windows_sandbox_private_desktop,
|
||||
use_legacy_landlock: test.config.features.use_legacy_landlock(),
|
||||
exec_policy: None,
|
||||
mcp_policy: None,
|
||||
network_policy: None,
|
||||
|
||||
@@ -2,11 +2,13 @@ use anyhow::Context;
|
||||
use anyhow::Result;
|
||||
use codex_config::McpServerConfig;
|
||||
use codex_core::EnvironmentConfig;
|
||||
use codex_core::windows_sandbox::WindowsSandboxLevelExt;
|
||||
use codex_exec_server::CreateDirectoryOptions;
|
||||
use codex_exec_server::ExecServerRuntimePaths;
|
||||
use codex_features::Feature;
|
||||
use codex_protocol::capabilities::CapabilityRootLocation;
|
||||
use codex_protocol::capabilities::SelectedCapabilityRoot;
|
||||
use codex_protocol::config_types::WindowsSandboxLevel;
|
||||
use codex_protocol::models::PermissionProfileSnapshot;
|
||||
use codex_protocol::protocol::EnvironmentConfigState;
|
||||
use codex_protocol::protocol::ThreadSettingsOverrides;
|
||||
@@ -400,6 +402,13 @@ impl ExecutorStopHookFixture {
|
||||
self.test.config.permissions.permission_profile().clone(),
|
||||
),
|
||||
shell_environment_policy: Default::default(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&self.test.config),
|
||||
windows_sandbox_private_desktop: self
|
||||
.test
|
||||
.config
|
||||
.permissions
|
||||
.windows_sandbox_private_desktop,
|
||||
use_legacy_landlock: self.test.config.features.use_legacy_landlock(),
|
||||
exec_policy: None,
|
||||
mcp_policy: None,
|
||||
network_policy: None,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use codex_core::EnvironmentConfig;
|
||||
use codex_core::EnvironmentMcpPolicy;
|
||||
use codex_core::TurnInputRequest;
|
||||
use codex_core::windows_sandbox::WindowsSandboxLevelExt;
|
||||
use std::collections::BTreeMap;
|
||||
use std::collections::HashMap;
|
||||
use std::time::Duration;
|
||||
@@ -12,6 +13,7 @@ use codex_config::McpServerOAuthConfig;
|
||||
use codex_config::McpServerTransportConfig;
|
||||
use codex_exec_server::CreateDirectoryOptions;
|
||||
use codex_features::Feature;
|
||||
use codex_protocol::config_types::WindowsSandboxLevel;
|
||||
use codex_protocol::mcp_policy::McpServerIdentity;
|
||||
use codex_protocol::mcp_policy::McpServerRequirement;
|
||||
use codex_protocol::models::PermissionProfile;
|
||||
@@ -362,6 +364,9 @@ async fn skill_mcp_dependency_oauth_uses_configured_http_client() -> Result<()>
|
||||
allow_login_shell: fixture.config.permissions.allow_login_shell,
|
||||
permission_profile: PermissionProfileSnapshot::legacy(PermissionProfile::Disabled),
|
||||
shell_environment_policy: Default::default(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&fixture.config),
|
||||
windows_sandbox_private_desktop: fixture.config.permissions.windows_sandbox_private_desktop,
|
||||
use_legacy_landlock: fixture.config.features.use_legacy_landlock(),
|
||||
exec_policy: None,
|
||||
mcp_policy: Some(EnvironmentMcpPolicy {
|
||||
servers: Some(BTreeMap::from([(
|
||||
|
||||
@@ -3,6 +3,7 @@ use codex_config::Constrained;
|
||||
use codex_core::EnvironmentConfig;
|
||||
use codex_core::TurnInputRequest;
|
||||
use codex_core::config::Config;
|
||||
use codex_core::windows_sandbox::WindowsSandboxLevelExt;
|
||||
use codex_extension_api::ExtensionFuture;
|
||||
use codex_extension_api::ExtensionRegistryBuilder;
|
||||
use codex_extension_api::McpServerContribution;
|
||||
@@ -17,6 +18,7 @@ use codex_mcp::CODEX_APPS_MCP_SERVER_NAME;
|
||||
use codex_mcp::McpResourceClient;
|
||||
use codex_protocol::capabilities::CapabilityRootLocation;
|
||||
use codex_protocol::capabilities::SelectedCapabilityRoot;
|
||||
use codex_protocol::config_types::WindowsSandboxLevel;
|
||||
use codex_protocol::models::PermissionProfile;
|
||||
use codex_protocol::models::PermissionProfileSnapshot;
|
||||
use codex_protocol::protocol::AskForApproval;
|
||||
@@ -491,6 +493,12 @@ async fn root_reconciliation_reuses_pending_apps_startup() -> Result<()> {
|
||||
test.config.permissions.permission_profile().clone(),
|
||||
),
|
||||
shell_environment_policy: Default::default(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&test.config),
|
||||
windows_sandbox_private_desktop: test
|
||||
.config
|
||||
.permissions
|
||||
.windows_sandbox_private_desktop,
|
||||
use_legacy_landlock: test.config.features.use_legacy_landlock(),
|
||||
exec_policy: None,
|
||||
mcp_policy: None,
|
||||
network_policy: None,
|
||||
|
||||
@@ -8,6 +8,7 @@ use codex_core::config::Constrained;
|
||||
use codex_core::config::NetworkProxySpec;
|
||||
use codex_core::shell::ShellType;
|
||||
use codex_core::shell::get_shell;
|
||||
use codex_core::windows_sandbox::WindowsSandboxLevelExt;
|
||||
use codex_exec_server::CreateDirectoryOptions;
|
||||
use codex_exec_server::LOCAL_ENVIRONMENT_ID;
|
||||
use codex_exec_server::REMOTE_ENVIRONMENT_ID;
|
||||
@@ -21,6 +22,7 @@ use codex_protocol::approvals::NetworkPolicyRuleAction;
|
||||
use codex_protocol::config_types::CollaborationMode;
|
||||
use codex_protocol::config_types::ModeKind;
|
||||
use codex_protocol::config_types::Settings;
|
||||
use codex_protocol::config_types::WindowsSandboxLevel;
|
||||
use codex_protocol::models::NetworkPermissions;
|
||||
use codex_protocol::models::PermissionProfile;
|
||||
use codex_protocol::models::PermissionProfileSnapshot;
|
||||
@@ -2024,6 +2026,12 @@ async fn owner_network_policy_follows_the_selected_remote_command() -> Result<()
|
||||
test.config.permissions.permission_profile().clone()
|
||||
}),
|
||||
shell_environment_policy: test.config.permissions.shell_environment_policy.clone(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&test.config),
|
||||
windows_sandbox_private_desktop: test
|
||||
.config
|
||||
.permissions
|
||||
.windows_sandbox_private_desktop,
|
||||
use_legacy_landlock: test.config.features.use_legacy_landlock(),
|
||||
exec_policy: None,
|
||||
mcp_policy: None,
|
||||
network_policy: Some(EnvironmentNetworkPolicy::from_config(
|
||||
|
||||
@@ -13,6 +13,7 @@ use codex_core::WaitForEnvironmentToolConfig;
|
||||
use codex_core::compact::SUMMARIZATION_PROMPT;
|
||||
use codex_core::config::Config;
|
||||
use codex_core::config::Constrained;
|
||||
use codex_core::windows_sandbox::WindowsSandboxLevelExt;
|
||||
use codex_exec_server::CopyOptions;
|
||||
use codex_exec_server::CreateDirectoryOptions;
|
||||
use codex_exec_server::EnvironmentReadyInfo;
|
||||
@@ -46,6 +47,7 @@ use codex_protocol::capabilities::SelectedCapabilityRoot;
|
||||
use codex_protocol::config_types::CollaborationMode;
|
||||
use codex_protocol::config_types::ModeKind;
|
||||
use codex_protocol::config_types::Settings;
|
||||
use codex_protocol::config_types::WindowsSandboxLevel;
|
||||
use codex_protocol::models::ActivePermissionProfile;
|
||||
use codex_protocol::models::FileSystemPermissions;
|
||||
use codex_protocol::models::PermissionProfile;
|
||||
@@ -557,6 +559,12 @@ async fn environment_permissions_follow_configuration_ownership() -> Result<()>
|
||||
allow_login_shell: test.config.permissions.allow_login_shell,
|
||||
permission_profile: owner_permission_profile,
|
||||
shell_environment_policy: Default::default(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&test.config),
|
||||
windows_sandbox_private_desktop: test
|
||||
.config
|
||||
.permissions
|
||||
.windows_sandbox_private_desktop,
|
||||
use_legacy_landlock: test.config.features.use_legacy_landlock(),
|
||||
exec_policy: None,
|
||||
mcp_policy: None,
|
||||
network_policy: None,
|
||||
@@ -1246,6 +1254,12 @@ async fn shared_executor_keeps_ready_capability_roots_scoped_to_each_attachment(
|
||||
allow_login_shell: false,
|
||||
permission_profile: permission_profile.clone(),
|
||||
shell_environment_policy: Default::default(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&test.config),
|
||||
windows_sandbox_private_desktop: test
|
||||
.config
|
||||
.permissions
|
||||
.windows_sandbox_private_desktop,
|
||||
use_legacy_landlock: test.config.features.use_legacy_landlock(),
|
||||
exec_policy: None,
|
||||
mcp_policy: None,
|
||||
network_policy: None,
|
||||
@@ -1284,6 +1298,12 @@ async fn shared_executor_keeps_ready_capability_roots_scoped_to_each_attachment(
|
||||
allow_login_shell: true,
|
||||
permission_profile: permission_profile.clone(),
|
||||
shell_environment_policy: Default::default(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&test.config),
|
||||
windows_sandbox_private_desktop: test
|
||||
.config
|
||||
.permissions
|
||||
.windows_sandbox_private_desktop,
|
||||
use_legacy_landlock: test.config.features.use_legacy_landlock(),
|
||||
exec_policy: None,
|
||||
mcp_policy: None,
|
||||
network_policy: None,
|
||||
@@ -1306,6 +1326,12 @@ async fn shared_executor_keeps_ready_capability_roots_scoped_to_each_attachment(
|
||||
allow_login_shell: false,
|
||||
permission_profile: permission_profile.clone(),
|
||||
shell_environment_policy: Default::default(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&test.config),
|
||||
windows_sandbox_private_desktop: test
|
||||
.config
|
||||
.permissions
|
||||
.windows_sandbox_private_desktop,
|
||||
use_legacy_landlock: test.config.features.use_legacy_landlock(),
|
||||
exec_policy: None,
|
||||
mcp_policy: None,
|
||||
network_policy: None,
|
||||
@@ -1367,6 +1393,12 @@ async fn shared_executor_keeps_ready_capability_roots_scoped_to_each_attachment(
|
||||
allow_login_shell: false,
|
||||
permission_profile: permission_profile.clone(),
|
||||
shell_environment_policy: Default::default(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&test.config),
|
||||
windows_sandbox_private_desktop: test
|
||||
.config
|
||||
.permissions
|
||||
.windows_sandbox_private_desktop,
|
||||
use_legacy_landlock: test.config.features.use_legacy_landlock(),
|
||||
exec_policy: None,
|
||||
mcp_policy: None,
|
||||
network_policy: None,
|
||||
@@ -1436,6 +1468,9 @@ async fn owner_network_policy_rejects_unsupported_environment_authority() -> Res
|
||||
allow_login_shell: test.config.permissions.allow_login_shell,
|
||||
permission_profile: PermissionProfileSnapshot::legacy(PermissionProfile::Disabled),
|
||||
shell_environment_policy: test.config.permissions.shell_environment_policy.clone(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&test.config),
|
||||
windows_sandbox_private_desktop: test.config.permissions.windows_sandbox_private_desktop,
|
||||
use_legacy_landlock: test.config.features.use_legacy_landlock(),
|
||||
exec_policy: None,
|
||||
mcp_policy: None,
|
||||
network_policy: Some(EnvironmentNetworkPolicy::from_config(
|
||||
@@ -1520,6 +1555,9 @@ async fn pending_attachment_installs_configuration_before_waiting_turn_resumes()
|
||||
allow_login_shell,
|
||||
permission_profile: PermissionProfileSnapshot::legacy(PermissionProfile::read_only()),
|
||||
shell_environment_policy: Default::default(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&test.config),
|
||||
windows_sandbox_private_desktop: test.config.permissions.windows_sandbox_private_desktop,
|
||||
use_legacy_landlock: test.config.features.use_legacy_landlock(),
|
||||
exec_policy: None,
|
||||
mcp_policy: None,
|
||||
network_policy: None,
|
||||
@@ -2174,6 +2212,12 @@ async fn deferred_executor_spawn_agent_inherits_ready_step_environments(
|
||||
vec![owner_profile_workspace_root.clone()],
|
||||
),
|
||||
shell_environment_policy: Default::default(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&test.config),
|
||||
windows_sandbox_private_desktop: test
|
||||
.config
|
||||
.permissions
|
||||
.windows_sandbox_private_desktop,
|
||||
use_legacy_landlock: test.config.features.use_legacy_landlock(),
|
||||
exec_policy: None,
|
||||
mcp_policy: None,
|
||||
network_policy: None,
|
||||
|
||||
@@ -27,6 +27,7 @@ use codex_core::EnvironmentConfig;
|
||||
use codex_core::EnvironmentMcpPolicy;
|
||||
use codex_core::TurnInputRequest;
|
||||
use codex_core::config::Config;
|
||||
use codex_core::windows_sandbox::WindowsSandboxLevelExt;
|
||||
use codex_exec_server::CreateDirectoryOptions;
|
||||
use codex_exec_server::Environment;
|
||||
use codex_exec_server::HttpRedirectPolicy;
|
||||
@@ -45,6 +46,7 @@ use codex_protocol::config_types::CollaborationMode;
|
||||
use codex_protocol::config_types::ModeKind;
|
||||
use codex_protocol::config_types::ReasoningSummary;
|
||||
use codex_protocol::config_types::Settings;
|
||||
use codex_protocol::config_types::WindowsSandboxLevel;
|
||||
use codex_protocol::mcp_policy::McpServerIdentity;
|
||||
use codex_protocol::mcp_policy::McpServerRequirement;
|
||||
use codex_protocol::mcp_policy::PluginMcpRequirements;
|
||||
@@ -712,6 +714,12 @@ async fn environment_mcp_policy_filters_runtime_config_and_model_tools(
|
||||
fixture.config.permissions.permission_profile().clone(),
|
||||
),
|
||||
shell_environment_policy: Default::default(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&fixture.config),
|
||||
windows_sandbox_private_desktop: fixture
|
||||
.config
|
||||
.permissions
|
||||
.windows_sandbox_private_desktop,
|
||||
use_legacy_landlock: fixture.config.features.use_legacy_landlock(),
|
||||
exec_policy: None,
|
||||
mcp_policy: Some(mcp_policy),
|
||||
network_policy: None,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use codex_core::EnvironmentConfig;
|
||||
use codex_core::TurnInputRequest;
|
||||
use codex_core::windows_sandbox::WindowsSandboxLevelExt;
|
||||
use core_test_support::test_codex::local_selections;
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::OsStr;
|
||||
@@ -15,6 +16,7 @@ use codex_protocol::config_types::ModeKind;
|
||||
use codex_protocol::config_types::Settings;
|
||||
use codex_protocol::config_types::ShellEnvironmentPolicy;
|
||||
use codex_protocol::config_types::ShellEnvironmentPolicyInherit;
|
||||
use codex_protocol::config_types::WindowsSandboxLevel;
|
||||
use codex_protocol::models::PermissionProfile;
|
||||
use codex_protocol::models::PermissionProfileSnapshot;
|
||||
use codex_protocol::models::ResponseItem;
|
||||
@@ -402,6 +404,13 @@ async fn exec_command_uses_installed_environment_shell_policy_with_explicit_over
|
||||
.clone(),
|
||||
..Default::default()
|
||||
},
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&harness.test().config),
|
||||
windows_sandbox_private_desktop: harness
|
||||
.test()
|
||||
.config
|
||||
.permissions
|
||||
.windows_sandbox_private_desktop,
|
||||
use_legacy_landlock: harness.test().config.features.use_legacy_landlock(),
|
||||
exec_policy: None,
|
||||
mcp_policy: None,
|
||||
network_policy: None,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::capabilities::SelectedCapabilityRoot;
|
||||
use crate::config_types::ShellEnvironmentPolicy;
|
||||
use crate::config_types::WindowsSandboxLevel;
|
||||
use crate::mcp_policy::EnvironmentMcpPolicy;
|
||||
use crate::models::PermissionProfileSnapshot;
|
||||
use codex_execpolicy::RequirementsExecPolicy;
|
||||
@@ -28,6 +29,12 @@ pub struct EnvironmentConfig {
|
||||
pub permission_profile: PermissionProfileSnapshot,
|
||||
/// Controls which environment variables shell commands may inherit.
|
||||
pub shell_environment_policy: ShellEnvironmentPolicy,
|
||||
/// Windows sandbox implementation for this environment attachment.
|
||||
pub windows_sandbox_level: WindowsSandboxLevel,
|
||||
/// Whether Windows sandbox processes use a private desktop.
|
||||
pub windows_sandbox_private_desktop: bool,
|
||||
/// Whether Linux sandbox processes use the legacy Landlock backend.
|
||||
pub use_legacy_landlock: bool,
|
||||
/// Additional managed command restrictions for this environment attachment.
|
||||
pub exec_policy: Option<RequirementsExecPolicy>,
|
||||
/// Additional managed MCP restrictions for this environment attachment.
|
||||
@@ -45,6 +52,12 @@ impl std::fmt::Debug for EnvironmentConfig {
|
||||
.field("allow_login_shell", &self.allow_login_shell)
|
||||
.field("permission_profile", &self.permission_profile)
|
||||
.field("shell_environment_policy", &"<redacted>")
|
||||
.field("windows_sandbox_level", &self.windows_sandbox_level)
|
||||
.field(
|
||||
"windows_sandbox_private_desktop",
|
||||
&self.windows_sandbox_private_desktop,
|
||||
)
|
||||
.field("use_legacy_landlock", &self.use_legacy_landlock)
|
||||
.field("exec_policy", &self.exec_policy)
|
||||
.field("mcp_policy", &self.mcp_policy)
|
||||
.field("network_policy", &self.network_policy)
|
||||
|
||||
@@ -119,6 +119,8 @@ pub struct SandboxExecRequest {
|
||||
pub network: Option<NetworkProxy>,
|
||||
pub network_environment_id: Option<String>,
|
||||
pub sandbox: SandboxType,
|
||||
// TODO(anp): Reconcile these backend copies with the supplied sandbox context
|
||||
// (TurnEnvironment::sandbox_context for turns), preserving this launch snapshot.
|
||||
pub windows_sandbox_level: WindowsSandboxLevel,
|
||||
pub windows_sandbox_private_desktop: bool,
|
||||
pub permission_profile: PermissionProfile,
|
||||
@@ -139,6 +141,8 @@ pub struct SandboxTransformRequest<'a> {
|
||||
pub network: Option<&'a NetworkProxy>,
|
||||
pub sandbox_policy_cwd: &'a PathUri,
|
||||
pub codex_linux_sandbox_exe: Option<&'a Path>,
|
||||
// TODO(anp): Reconcile these backend inputs with the supplied sandbox context
|
||||
// (TurnEnvironment::sandbox_context for turns) so selection shares its authority.
|
||||
pub use_legacy_landlock: bool,
|
||||
pub windows_sandbox_level: WindowsSandboxLevel,
|
||||
pub windows_sandbox_private_desktop: bool,
|
||||
|
||||
@@ -14,6 +14,8 @@ use crate::WindowsSandboxFilesystemOverrides;
|
||||
use crate::WindowsSandboxProxySettingsMode;
|
||||
|
||||
/// Windows-specific inputs for an executor-native process spawn.
|
||||
// TODO(anp): Reconcile Windows backend and desktop copies with the supplied sandbox
|
||||
// context (TurnEnvironment::sandbox_context for turns), preserving this launch snapshot.
|
||||
pub struct WindowsSandboxSpawnRequest<'a> {
|
||||
pub permission_profile: &'a PermissionProfile,
|
||||
pub workspace_roots: &'a [AbsolutePathBuf],
|
||||
|
||||
@@ -153,6 +153,8 @@ impl App {
|
||||
approvals_reviewer,
|
||||
permission_profile: _,
|
||||
active_permission_profile,
|
||||
// TODO(anp): Support Windows sandbox updates through environment configuration;
|
||||
// thread/settings/update cannot currently represent this override.
|
||||
windows_sandbox_level: _,
|
||||
model,
|
||||
effort,
|
||||
|
||||
@@ -13,6 +13,8 @@ pub struct ElevatedSandboxProfileCaptureRequest<'a> {
|
||||
pub env_map: HashMap<String, String>,
|
||||
pub timeout_ms: Option<u64>,
|
||||
pub cancellation: Option<crate::WindowsSandboxCancellationToken>,
|
||||
// TODO(anp): Reconcile this private-desktop copy with the supplied sandbox context
|
||||
// (TurnEnvironment::sandbox_context for turns), preserving this launch snapshot.
|
||||
pub use_private_desktop: bool,
|
||||
pub proxy_enforced: bool,
|
||||
pub network_proxy_restricting_sid: Option<String>,
|
||||
|
||||
@@ -23,6 +23,8 @@ use std::path::PathBuf;
|
||||
///
|
||||
/// Callers should parse their own input shape first, then use this request to
|
||||
/// share the elevated-vs-legacy backend selection and session launch path.
|
||||
// TODO(anp): Reconcile Windows backend and desktop copies with the supplied sandbox
|
||||
// context (TurnEnvironment::sandbox_context for turns), preserving this launch snapshot.
|
||||
pub struct WindowsSandboxSessionRequest<'a> {
|
||||
pub permission_profile: &'a PermissionProfile,
|
||||
pub workspace_roots: &'a [AbsolutePathBuf],
|
||||
|
||||
Reference in New Issue
Block a user