Protect first-time project .codex creation across sandboxes#15067
Protect first-time project .codex creation across sandboxes#15067rreichel3-oai wants to merge 6 commits intomainfrom
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: dd61525cf7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
codex-rs/protocol/src/permissions.rs
Outdated
| let cwd_root = AbsolutePathBuf::from_absolute_path(cwd) | ||
| .expect("workspace-write cwd should already be absolute"); |
There was a problem hiding this comment.
Handle relative cwd without panicking in legacy conversion
FileSystemSandboxPolicy::from_legacy_sandbox_policy now calls AbsolutePathBuf::from_absolute_path(cwd).expect(...). A relative cwd (still accepted by the &Path API) now crashes the process instead of degrading gracefully. This is a behavior regression from the prior non-panicking path handling and can turn bad caller input into a hard failure.
Useful? React with 👍 / 👎.
| args.iter().any(|arg| { | ||
| arg.starts_with("-DWRITABLE_ROOT_0_RO_") | ||
| && arg.ends_with(&format!("={}", unreadable_root.display())) | ||
| }), |
There was a problem hiding this comment.
This isn't a huge deal, but while we're here, we could create the suffix once:
| args.iter().any(|arg| { | |
| arg.starts_with("-DWRITABLE_ROOT_0_RO_") | |
| && arg.ends_with(&format!("={}", unreadable_root.display())) | |
| }), | |
| let expected_suffix = format!("={}", unreadable_root.display()); | |
| assert!( | |
| args.iter().any(|arg| { | |
| arg.starts_with("-DWRITABLE_ROOT_0_RO_") | |
| && arg.ends_with(&expected_suffix) | |
| }), |
Though taking a step back, the unreadable_root is supposed to be associated with WRITABLE_ROOT_0_RO_?
| .map(std::string::ToString::to_string) | ||
| .collect(); | ||
| let args = create_seatbelt_command_args(shell_command.clone(), &policy, &cwd, false, None); | ||
|
|
There was a problem hiding this comment.
Can we get back to this? It's much clearer to have one assert_eq!().
| assert!( | ||
| args.iter() | ||
| .any(|arg| arg == &format!("-DWRITABLE_ROOT_0_RO_0={}", unreadable_root.display())), | ||
| args.iter().any(|arg| { |
There was a problem hiding this comment.
Is there any reason the arg list is unstable? Shouldn't we be able to match arg exactly instead of using prefix/suffix checks?
| @@ -388,6 +388,12 @@ fn build_seatbelt_access_policy( | |||
| normalize_path_for_sandbox(excluded_subpath.as_path()).unwrap_or(excluded_subpath); | |||
| let excluded_param = format!("{param_prefix}_{index}_RO_{excluded_index}"); | |||
There was a problem hiding this comment.
Hmm, so _RO_ means "read-only," but are we also using it for "unreadable" subpaths here?
| .map(std::string::ToString::to_string) | ||
| .collect(); | ||
| let args = | ||
| create_seatbelt_command_args(shell_command, &policy, repo_root.as_path(), false, None); |
There was a problem hiding this comment.
This is a reminder to myself that we really need to get away from SandboxPolicy in favor of FileSystemPermissions.
| } | ||
|
|
||
| #[test] | ||
| fn create_seatbelt_args_block_first_time_dot_codex_creation() { |
There was a problem hiding this comment.
I really like this test, though I feel it should ideally live in codex-rs/exec/tests/suite/sandbox.rs because both our Mac and Linux sandboxing should be enforcing this, right?
| if top_level_codex.as_path().is_dir() { | ||
| subpaths.push(top_level_codex); | ||
| } | ||
| #[allow(clippy::expect_used)] |
There was a problem hiding this comment.
For these, we should check to see if the user has an existing rule.
Though I'll be honest: I think I need to go back and change FileSystemPermissions to use a map like we do in the config file.
Reserve missing top-level project .codex paths in the protocol layer so first-time creation still goes through protected-path approval. Update macOS Seatbelt to deny both the exact protected path and descendants, and add regression coverage for protocol, seatbelt, and apply_patch safety behavior.
dd61525 to
6b36994
Compare
Update codex-rs/app-server/src/fs_api.rs to instantiate Environment before requesting the default filesystem so codex-app-server compiles again.
Update codex-rs/protocol/src/permissions.rs to skip proactive cwd-root protection when legacy workspace-write conversion receives a relative cwd and add regression coverage for the relative-path case.
Update protocol path protection so a missing top-level project .codex still requires approval before writes.
Fix the macOS seatbelt sandbox to deny both the exact protected path and descendants, which closes the first-creation gap for .codex/config.toml.
Fix the Windows sandbox to reserve missing writable-root .codex directories before applying deny ACLs, while keeping .agents and .git behavior unchanged.
Add regressions for protocol path protection, seatbelt policy generation, apply-patch safety checks, and Windows writable-root/.codex reservation.
External (non-OpenAI) Pull Request Requirements
Before opening this Pull Request, please read the dedicated "Contributing" markdown file or your PR may be closed:
https://github.com/openai/codex/blob/main/docs/contributing.md
If your PR conforms to our contribution guidelines, replace this text with a detailed and high quality description of your changes.
Include a link to a bug report or enhancement request.