mirror of
https://github.com/openai/codex.git
synced 2026-11-05 20:10:33 +00:00
fix Windows deny-read for shell runtimes
This commit is contained in:
@@ -385,7 +385,7 @@ pub fn build_exec_request(
|
||||
expiration,
|
||||
capture_policy,
|
||||
};
|
||||
let mut exec_req = manager
|
||||
let exec_req = manager
|
||||
.transform(SandboxTransformRequest {
|
||||
command,
|
||||
permissions: permission_profile,
|
||||
@@ -414,6 +414,12 @@ pub fn build_exec_request(
|
||||
)
|
||||
})
|
||||
.map_err(CodexErr::from)?;
|
||||
apply_windows_sandbox_filesystem_overrides(exec_req)
|
||||
}
|
||||
|
||||
pub(crate) fn apply_windows_sandbox_filesystem_overrides(
|
||||
mut exec_req: ExecRequest,
|
||||
) -> Result<ExecRequest> {
|
||||
let use_windows_elevated_backend = windows_sandbox_uses_elevated_backend(
|
||||
exec_req.windows_sandbox_level,
|
||||
exec_req.network.is_some(),
|
||||
@@ -422,14 +428,14 @@ pub fn build_exec_request(
|
||||
resolve_windows_elevated_filesystem_overrides(
|
||||
exec_req.sandbox,
|
||||
&exec_req.permission_profile,
|
||||
sandbox_cwd,
|
||||
&exec_req.windows_sandbox_policy_cwd,
|
||||
use_windows_elevated_backend,
|
||||
)
|
||||
} else {
|
||||
resolve_windows_restricted_token_filesystem_overrides(
|
||||
exec_req.sandbox,
|
||||
&exec_req.permission_profile,
|
||||
sandbox_cwd,
|
||||
&exec_req.windows_sandbox_policy_cwd,
|
||||
exec_req.windows_sandbox_level,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -310,7 +310,7 @@ impl ToolRuntime<ShellRequest, ExecToolCallOutput> for ShellRuntime {
|
||||
};
|
||||
let env = attempt
|
||||
.env_for(command, options, managed_network)
|
||||
.map_err(|err| ToolError::Codex(err.into()))?;
|
||||
.map_err(ToolError::Codex)?;
|
||||
let out = execute_env(env, Self::stdout_stream(ctx))
|
||||
.await
|
||||
.map_err(ToolError::Codex)?;
|
||||
|
||||
@@ -141,7 +141,7 @@ pub(super) async fn try_run_zsh_fork(
|
||||
options,
|
||||
managed_network_for_sandbox_permissions(req.network.as_ref(), req.sandbox_permissions),
|
||||
)
|
||||
.map_err(|err| ToolError::Codex(err.into()))?;
|
||||
.map_err(ToolError::Codex)?;
|
||||
let crate::sandboxing::ExecRequest {
|
||||
command,
|
||||
cwd: sandbox_cwd,
|
||||
|
||||
@@ -330,7 +330,7 @@ impl<'a> ToolRuntime<UnifiedExecRequest, UnifiedExecProcess> for UnifiedExecRunt
|
||||
let options = unified_exec_options(attempt.network_denial_cancellation_token.clone());
|
||||
let mut exec_env = attempt
|
||||
.env_for(command, options, managed_network)
|
||||
.map_err(|err| ToolError::Codex(err.into()))?;
|
||||
.map_err(ToolError::Codex)?;
|
||||
exec_env.exec_server_env_config = req.exec_server_env_config.clone();
|
||||
match zsh_fork_backend::maybe_prepare_unified_exec(
|
||||
req,
|
||||
@@ -381,7 +381,7 @@ impl<'a> ToolRuntime<UnifiedExecRequest, UnifiedExecProcess> for UnifiedExecRunt
|
||||
let options = unified_exec_options(attempt.network_denial_cancellation_token.clone());
|
||||
let mut exec_env = attempt
|
||||
.env_for(command, options, managed_network)
|
||||
.map_err(|err| ToolError::Codex(err.into()))?;
|
||||
.map_err(ToolError::Codex)?;
|
||||
exec_env.exec_server_env_config = req.exec_server_env_config.clone();
|
||||
self.manager
|
||||
.open_session_with_exec_env(
|
||||
|
||||
@@ -21,7 +21,6 @@ use codex_protocol::protocol::AskForApproval;
|
||||
use codex_protocol::protocol::ReviewDecision;
|
||||
use codex_sandboxing::SandboxCommand;
|
||||
use codex_sandboxing::SandboxManager;
|
||||
use codex_sandboxing::SandboxTransformError;
|
||||
use codex_sandboxing::SandboxTransformRequest;
|
||||
use codex_sandboxing::SandboxType;
|
||||
use codex_sandboxing::SandboxablePreference;
|
||||
@@ -426,8 +425,9 @@ impl<'a> SandboxAttempt<'a> {
|
||||
command: SandboxCommand,
|
||||
options: ExecOptions,
|
||||
network: Option<&NetworkProxy>,
|
||||
) -> Result<crate::sandboxing::ExecRequest, SandboxTransformError> {
|
||||
self.manager
|
||||
) -> codex_protocol::error::Result<crate::sandboxing::ExecRequest> {
|
||||
let exec_request = self
|
||||
.manager
|
||||
.transform(SandboxTransformRequest {
|
||||
command,
|
||||
permissions: self.permissions,
|
||||
@@ -455,6 +455,8 @@ impl<'a> SandboxAttempt<'a> {
|
||||
self.workspace_roots.to_vec(),
|
||||
)
|
||||
})
|
||||
.map_err(CodexErr::from)?;
|
||||
crate::exec::apply_windows_sandbox_filesystem_overrides(exec_request)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,101 @@
|
||||
use super::*;
|
||||
use crate::exec::ExecCapturePolicy;
|
||||
use crate::exec::ExecExpiration;
|
||||
use crate::exec::WindowsSandboxFilesystemOverrides;
|
||||
use crate::sandboxing::ExecOptions;
|
||||
use crate::sandboxing::SandboxPermissions;
|
||||
use crate::tools::hook_names::HookToolName;
|
||||
use codex_protocol::config_types::WindowsSandboxLevel;
|
||||
use codex_protocol::models::PermissionProfile;
|
||||
use codex_protocol::permissions::FileSystemAccessMode;
|
||||
use codex_protocol::permissions::FileSystemPath;
|
||||
use codex_protocol::permissions::FileSystemSandboxEntry;
|
||||
use codex_protocol::permissions::FileSystemSpecialPath;
|
||||
use codex_protocol::permissions::NetworkSandboxPolicy;
|
||||
use codex_protocol::protocol::GranularApprovalConfig;
|
||||
use codex_sandboxing::SandboxCommand;
|
||||
use codex_sandboxing::SandboxManager;
|
||||
use codex_sandboxing::SandboxType;
|
||||
use codex_utils_absolute_path::test_support::PathBufExt;
|
||||
use codex_utils_absolute_path::test_support::PathExt;
|
||||
use pretty_assertions::assert_eq;
|
||||
use serde_json::json;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[test]
|
||||
fn shell_sandbox_attempt_applies_windows_deny_read_overrides() {
|
||||
let temp_dir = tempfile::TempDir::new().expect("tempdir");
|
||||
let blocked = temp_dir.path().join(".env");
|
||||
std::fs::write(&blocked, "secret").expect("write blocked file");
|
||||
let expected_blocked = dunce::canonicalize(&blocked)
|
||||
.expect("canonical blocked file")
|
||||
.abs();
|
||||
let file_system_policy = FileSystemSandboxPolicy::restricted(vec![
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Special {
|
||||
value: FileSystemSpecialPath::Root,
|
||||
},
|
||||
access: FileSystemAccessMode::Read,
|
||||
},
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Special {
|
||||
value: FileSystemSpecialPath::project_roots(/*subpath*/ None),
|
||||
},
|
||||
access: FileSystemAccessMode::Write,
|
||||
},
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Path {
|
||||
path: blocked.abs(),
|
||||
},
|
||||
access: FileSystemAccessMode::Deny,
|
||||
},
|
||||
]);
|
||||
let permissions = PermissionProfile::from_runtime_permissions(
|
||||
&file_system_policy,
|
||||
NetworkSandboxPolicy::Restricted,
|
||||
);
|
||||
let sandbox_cwd = temp_dir.path().abs();
|
||||
let manager = SandboxManager::new();
|
||||
let attempt = SandboxAttempt {
|
||||
sandbox: SandboxType::WindowsRestrictedToken,
|
||||
permissions: &permissions,
|
||||
enforce_managed_network: false,
|
||||
manager: &manager,
|
||||
sandbox_cwd: &sandbox_cwd,
|
||||
workspace_roots: std::slice::from_ref(&sandbox_cwd),
|
||||
codex_linux_sandbox_exe: None,
|
||||
use_legacy_landlock: false,
|
||||
windows_sandbox_level: WindowsSandboxLevel::Elevated,
|
||||
windows_sandbox_private_desktop: false,
|
||||
network_denial_cancellation_token: None,
|
||||
};
|
||||
let command = SandboxCommand {
|
||||
program: "echo".into(),
|
||||
args: vec!["ok".to_string()],
|
||||
cwd: sandbox_cwd.clone(),
|
||||
env: HashMap::new(),
|
||||
additional_permissions: None,
|
||||
};
|
||||
let options = ExecOptions {
|
||||
expiration: ExecExpiration::DefaultTimeout,
|
||||
capture_policy: ExecCapturePolicy::ShellTool,
|
||||
};
|
||||
|
||||
let exec_request = attempt
|
||||
.env_for(command, options, /*network*/ None)
|
||||
.expect("prepare shell exec request");
|
||||
|
||||
assert_eq!(
|
||||
exec_request.windows_sandbox_filesystem_overrides,
|
||||
Some(WindowsSandboxFilesystemOverrides {
|
||||
read_roots_override: None,
|
||||
read_roots_include_platform_defaults: false,
|
||||
write_roots_override: None,
|
||||
additional_deny_read_paths: vec![expected_blocked.clone()],
|
||||
additional_deny_write_paths: vec![expected_blocked],
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bash_permission_request_payload_omits_missing_description() {
|
||||
|
||||
Reference in New Issue
Block a user