mirror of
https://github.com/openai/codex.git
synced 2026-05-16 17:23:57 +00:00
## Why The split filesystem policy stack already supports exact and glob `access = none` read restrictions on macOS and Linux. Windows still needed subprocess handling for those deny-read policies without claiming enforcement from a backend that cannot provide it. ## Key finding The unelevated restricted-token backend cannot safely enforce deny-read overlays. Its `WRITE_RESTRICTED` token model is authoritative for write checks, not read denials, so this PR intentionally fails that backend closed when deny-read overrides are present instead of claiming unsupported enforcement. ## What changed This PR adds the Windows deny-read enforcement layer and makes the backend split explicit: - Resolves Windows deny-read filesystem policy entries into concrete ACL targets. - Preserves exact missing paths so they can be materialized and denied before an enforceable sandboxed process starts. - Snapshot-expands existing glob matches into ACL targets for Windows subprocess enforcement. - Honors `glob_scan_max_depth` when expanding Windows deny-read globs. - Plans both the configured lexical path and the canonical target for existing paths so reparse-point aliases are covered. - Threads deny-read overrides through the elevated/logon-user Windows sandbox backend and unified exec. - Applies elevated deny-read ACLs synchronously before command launch rather than delegating them to the background read-grant helper. - Reconciles persistent deny-read ACEs per sandbox principal so policy changes do not leave stale deny-read ACLs behind. - Fails closed on the unelevated restricted-token backend when deny-read overrides are present, because its `WRITE_RESTRICTED` token model is not authoritative for read denials. ## Landed prerequisites These prerequisite PRs are already on `main`: 1. #15979 `feat(permissions): add glob deny-read policy support` 2. #18096 `feat(sandbox): add glob deny-read platform enforcement` 3. #17740 `feat(config): support managed deny-read requirements` This PR targets `main` directly and contains only the Windows deny-read enforcement layer. ## Implementation notes - Exact deny-read paths remain enforceable on the elevated path even when they do not exist yet: Windows materializes the missing path before applying the deny ACE, so the sandboxed command cannot create and read it during the same run. - Existing exact deny paths are preserved lexically until the ACL planner, which then adds the canonical target as a second ACL target when needed. That keeps both the configured alias and the resolved object covered. - Windows ACLs do not consume Codex glob syntax directly, so glob deny-read entries are expanded to the concrete matches that exist before process launch. - Glob traversal deduplicates directory visits within each pattern walk to avoid cycles, without collapsing distinct lexical roots that happen to resolve to the same target. - Persistent deny-read ACL state is keyed by sandbox principal SID, so cleanup only removes ACEs owned by the same backend principal. - Deny-read ACEs are fail-closed on the elevated path: setup aborts if mandatory deny-read ACL application fails. - Unelevated restricted-token sessions reject deny-read overrides early instead of running with a silently unenforceable read policy. ## Verification - `cargo test -p codex-core windows_restricted_token_rejects_unreadable_split_carveouts` - `just fmt` - `just fix -p codex-core` - `just fix -p codex-windows-sandbox` - GitHub Actions rerun is in progress on the pushed head. --------- Co-authored-by: Codex <noreply@openai.com>
119 lines
3.0 KiB
Rust
119 lines
3.0 KiB
Rust
// Aggregates all former standalone integration tests as modules.
|
|
use codex_apply_patch::CODEX_CORE_APPLY_PATCH_ARG1;
|
|
use codex_exec_server::CODEX_FS_HELPER_ARG1;
|
|
use codex_sandboxing::landlock::CODEX_LINUX_SANDBOX_ARG0;
|
|
use codex_test_binary_support::TestBinaryDispatchGuard;
|
|
use codex_test_binary_support::TestBinaryDispatchMode;
|
|
use codex_test_binary_support::configure_test_binary_dispatch;
|
|
use ctor::ctor;
|
|
|
|
// 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| {
|
|
if argv1 == Some(CODEX_CORE_APPLY_PATCH_ARG1) {
|
|
return TestBinaryDispatchMode::DispatchArg0Only;
|
|
}
|
|
if argv1 == Some(CODEX_FS_HELPER_ARG1) {
|
|
return TestBinaryDispatchMode::DispatchArg0Only;
|
|
}
|
|
if exe_name == CODEX_LINUX_SANDBOX_ARG0 {
|
|
return TestBinaryDispatchMode::DispatchArg0Only;
|
|
}
|
|
TestBinaryDispatchMode::InstallAliases
|
|
})
|
|
};
|
|
|
|
#[cfg(not(target_os = "windows"))]
|
|
mod abort_tasks;
|
|
mod agent_jobs;
|
|
mod agent_websocket;
|
|
mod agents_md;
|
|
mod apply_patch_cli;
|
|
#[cfg(not(target_os = "windows"))]
|
|
mod approvals;
|
|
mod cli_stream;
|
|
mod client;
|
|
mod client_websockets;
|
|
mod code_mode;
|
|
mod codex_delegate;
|
|
mod collaboration_instructions;
|
|
mod compact;
|
|
mod compact_remote;
|
|
mod compact_resume_fork;
|
|
mod deprecation_notice;
|
|
mod exec;
|
|
mod exec_policy;
|
|
mod fork_thread;
|
|
mod hierarchical_agents;
|
|
#[cfg(not(target_os = "windows"))]
|
|
mod hooks;
|
|
#[cfg(not(target_os = "windows"))]
|
|
mod hooks_mcp;
|
|
mod image_rollout;
|
|
mod items;
|
|
mod json_result;
|
|
mod live_cli;
|
|
mod model_overrides;
|
|
mod model_switching;
|
|
mod model_visible_layout;
|
|
mod models_cache_ttl;
|
|
mod models_etag_responses;
|
|
mod openai_file_mcp;
|
|
mod otel;
|
|
mod override_updates;
|
|
mod pending_input;
|
|
mod permissions_messages;
|
|
mod personality;
|
|
mod personality_migration;
|
|
mod plugins;
|
|
mod prompt_caching;
|
|
mod prompt_debug_tests;
|
|
mod quota_exceeded;
|
|
mod realtime_conversation;
|
|
mod remote_env;
|
|
mod remote_models;
|
|
mod request_compression;
|
|
#[cfg(not(target_os = "windows"))]
|
|
mod request_permissions;
|
|
#[cfg(not(target_os = "windows"))]
|
|
mod request_permissions_tool;
|
|
mod request_plugin_install;
|
|
mod request_user_input;
|
|
mod responses_api_proxy_headers;
|
|
mod resume;
|
|
mod resume_warning;
|
|
mod review;
|
|
mod rmcp_client;
|
|
mod rollout_list_find;
|
|
mod safety_check_downgrade;
|
|
mod search_tool;
|
|
mod shell_command;
|
|
mod shell_serialization;
|
|
mod shell_snapshot;
|
|
mod skill_approval;
|
|
mod skills;
|
|
mod spawn_agent_description;
|
|
mod sqlite_state;
|
|
mod stream_error_allows_next_turn;
|
|
mod stream_no_completed;
|
|
mod subagent_notifications;
|
|
mod tool_harness;
|
|
mod tool_parallelism;
|
|
mod tools;
|
|
mod truncation;
|
|
mod turn_state;
|
|
mod unified_exec;
|
|
mod unstable_features_warning;
|
|
mod user_notification;
|
|
mod user_shell_cmd;
|
|
mod view_image;
|
|
mod web_search;
|
|
mod websocket_fallback;
|
|
mod window_headers;
|
|
#[cfg(target_os = "windows")]
|
|
mod windows_sandbox;
|