tests: cover macOS capability propagation through turns

This commit is contained in:
Greg
2026-06-03 10:12:40 -07:00
parent af1b977d7e
commit 60cf6de0ba
2 changed files with 134 additions and 2 deletions

View File

@@ -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"))]

View File

@@ -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(()));