mirror of
https://github.com/openai/codex.git
synced 2026-09-06 15:29:32 +00:00
tests: cover macOS capability propagation through turns
This commit is contained in:
@@ -7,13 +7,56 @@ use codex_test_binary_support::TestBinaryDispatchMode;
|
||||
use codex_test_binary_support::configure_test_binary_dispatch;
|
||||
use ctor::ctor;
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
pub(crate) const MACOS_SANDBOX_CAPABILITY_PROBE_ARG: &str =
|
||||
"--codex-test-macos-sandbox-capability-probe";
|
||||
#[cfg(target_os = "macos")]
|
||||
pub(crate) const MACOS_SANDBOX_CAPABILITY_PROBE_MACH_SERVICE: &str =
|
||||
"com.apple.coreservices.appleevents";
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
unsafe extern "C" {
|
||||
static bootstrap_port: libc::c_uint;
|
||||
fn bootstrap_look_up(
|
||||
bootstrap_port: libc::c_uint,
|
||||
service_name: *const libc::c_char,
|
||||
service_port: *mut libc::c_uint,
|
||||
) -> libc::c_int;
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
fn maybe_run_macos_sandbox_capability_probe() {
|
||||
if std::env::args().nth(1).as_deref() != Some(MACOS_SANDBOX_CAPABILITY_PROBE_ARG) {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut service_port = 0;
|
||||
// SAFETY: the service name and output port pointers remain valid for the duration of the call.
|
||||
let result = unsafe {
|
||||
bootstrap_look_up(
|
||||
bootstrap_port,
|
||||
c"com.apple.coreservices.appleevents".as_ptr(),
|
||||
&mut service_port,
|
||||
)
|
||||
};
|
||||
if result != 0 {
|
||||
eprintln!("Mach lookup failed with result {result}");
|
||||
std::process::exit(1);
|
||||
}
|
||||
std::process::exit(0);
|
||||
}
|
||||
|
||||
// This code runs before any other tests are run.
|
||||
// It allows the test binary to behave like codex and dispatch to apply_patch and codex-linux-sandbox
|
||||
// based on the arg0.
|
||||
// NOTE: this doesn't work on ARM
|
||||
#[ctor]
|
||||
pub static CODEX_ALIASES_TEMP_DIR: Option<TestBinaryDispatchGuard> = {
|
||||
configure_test_binary_dispatch("codex-core-tests", |exe_name, argv1| {
|
||||
let guard = configure_test_binary_dispatch("codex-core-tests", |exe_name, argv1| {
|
||||
#[cfg(target_os = "macos")]
|
||||
if argv1 == Some(MACOS_SANDBOX_CAPABILITY_PROBE_ARG) {
|
||||
return TestBinaryDispatchMode::Skip;
|
||||
}
|
||||
if argv1 == Some(CODEX_CORE_APPLY_PATCH_ARG1) {
|
||||
return TestBinaryDispatchMode::DispatchArg0Only;
|
||||
}
|
||||
@@ -24,7 +67,10 @@ pub static CODEX_ALIASES_TEMP_DIR: Option<TestBinaryDispatchGuard> = {
|
||||
return TestBinaryDispatchMode::DispatchArg0Only;
|
||||
}
|
||||
TestBinaryDispatchMode::InstallAliases
|
||||
})
|
||||
});
|
||||
#[cfg(target_os = "macos")]
|
||||
maybe_run_macos_sandbox_capability_probe();
|
||||
guard
|
||||
};
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
|
||||
@@ -7,6 +7,8 @@ use codex_features::Feature;
|
||||
use codex_protocol::config_types::ApprovalsReviewer;
|
||||
use codex_protocol::models::AdditionalPermissionProfile as PermissionProfile;
|
||||
use codex_protocol::models::FileSystemPermissions;
|
||||
#[cfg(target_os = "macos")]
|
||||
use codex_protocol::models::MacOsSandboxCapabilities;
|
||||
use codex_protocol::models::PermissionProfile as CorePermissionProfile;
|
||||
use codex_protocol::permissions::NetworkSandboxPolicy;
|
||||
use codex_protocol::protocol::AskForApproval;
|
||||
@@ -507,6 +509,90 @@ async fn request_permissions_tool_is_auto_denied_when_granular_request_permissio
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
#[tokio::test(flavor = "current_thread")]
|
||||
async fn managed_macos_capability_survives_additional_permissions_tool_execution() -> Result<()> {
|
||||
skip_if_no_network!(Ok(()));
|
||||
skip_if_sandbox!(Ok(()));
|
||||
|
||||
let server = start_mock_server().await;
|
||||
let approval_policy = AskForApproval::OnRequest;
|
||||
let macos = MacOsSandboxCapabilities {
|
||||
mach_lookup_services: vec![super::MACOS_SANDBOX_CAPABILITY_PROBE_MACH_SERVICE.to_string()],
|
||||
apple_event_destinations: Vec::new(),
|
||||
launch_services_open: false,
|
||||
};
|
||||
let permission_profile =
|
||||
CorePermissionProfile::read_only().with_macos_sandbox_capabilities(Some(macos));
|
||||
let permission_profile_for_config = permission_profile.clone();
|
||||
|
||||
let mut builder = test_codex().with_config(move |config| {
|
||||
config.permissions.approval_policy = Constrained::allow_any(approval_policy);
|
||||
config
|
||||
.permissions
|
||||
.set_permission_profile(permission_profile_for_config)
|
||||
.expect("set permission profile");
|
||||
config
|
||||
.features
|
||||
.enable(Feature::ExecPermissionApprovals)
|
||||
.expect("test config should allow feature update");
|
||||
});
|
||||
let test = builder.build(&server).await?;
|
||||
|
||||
let requested_dir = test.workspace_path("macos-capability-probe-grant");
|
||||
fs::create_dir_all(&requested_dir)?;
|
||||
let requested_permissions = requested_directory_write_permissions(&requested_dir);
|
||||
let normalized_requested_permissions = normalized_directory_write_permissions(&requested_dir)?;
|
||||
let test_exe = std::env::current_exe()?;
|
||||
let probe_arg = super::MACOS_SANDBOX_CAPABILITY_PROBE_ARG;
|
||||
let command = format!("{test_exe:?} {probe_arg}");
|
||||
let call_id = "managed-macos-capability-with-additional-permissions";
|
||||
let event = shell_event_with_request_permissions(call_id, &command, &requested_permissions)?;
|
||||
|
||||
let _ = mount_sse_once(
|
||||
&server,
|
||||
sse(vec![
|
||||
ev_response_created("resp-macos-capability-1"),
|
||||
event,
|
||||
ev_completed("resp-macos-capability-1"),
|
||||
]),
|
||||
)
|
||||
.await;
|
||||
let results = mount_sse_once(
|
||||
&server,
|
||||
sse(vec![
|
||||
ev_assistant_message("msg-macos-capability-1", "done"),
|
||||
ev_completed("resp-macos-capability-2"),
|
||||
]),
|
||||
)
|
||||
.await;
|
||||
|
||||
submit_turn(&test, call_id, approval_policy, permission_profile).await?;
|
||||
let approval = expect_exec_approval(&test, &command).await;
|
||||
assert_eq!(
|
||||
approval.additional_permissions,
|
||||
Some(normalized_requested_permissions.into())
|
||||
);
|
||||
test.codex
|
||||
.submit(Op::ExecApproval {
|
||||
id: approval.effective_approval_id(),
|
||||
turn_id: None,
|
||||
decision: ReviewDecision::Approved,
|
||||
})
|
||||
.await?;
|
||||
wait_for_completion(&test).await;
|
||||
|
||||
let result = parse_result(&results.single_request().function_call_output(call_id));
|
||||
assert_eq!(
|
||||
result.exit_code,
|
||||
Some(0),
|
||||
"capability probe should succeed after applying additional permissions: {}",
|
||||
result.stdout
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "current_thread")]
|
||||
async fn relative_additional_permissions_resolve_against_tool_workdir() -> Result<()> {
|
||||
skip_if_no_network!(Ok(()));
|
||||
|
||||
Reference in New Issue
Block a user