chore: merge origin/main into symlink hardening

Co-authored-by: Codex noreply@openai.com
This commit is contained in:
viyatb-oai
2026-06-01 16:23:20 -07:00
co-authored by Codex noreply@openai.com
2047 changed files with 208407 additions and 75082 deletions
+1
View File
@@ -18,6 +18,7 @@ workspace = true
[target.'cfg(target_os = "linux")'.dependencies]
clap = { workspace = true, features = ["derive"] }
codex-install-context = { workspace = true }
codex-process-hardening = { workspace = true }
codex-protocol = { workspace = true }
codex-sandboxing = { workspace = true }
+2 -2
View File
@@ -74,7 +74,7 @@ commands that would enter the bubblewrap path.
[permissions.workspace.filesystem]
glob_scan_max_depth = 2
[permissions.workspace.filesystem.":project_roots"]
[permissions.workspace.filesystem.":workspace_roots"]
"**/*.env" = "none"
```
@@ -94,4 +94,4 @@ commands that would enter the bubblewrap path.
you can skip this in restrictive container environments with `--no-proc`.
**Notes**
- The CLI surface still uses legacy names like `codex debug landlock`.
- The CLI surface is `codex sandbox`; the host OS selects the sandbox backend.
+48 -8
View File
@@ -12,6 +12,7 @@ use std::sync::OnceLock;
use crate::bazel_bwrap;
use crate::exec_util::argv_to_cstrings;
use crate::exec_util::make_files_inheritable;
use codex_install_context::InstallContext;
use codex_utils_absolute_path::AbsolutePathBuf;
use sha2::Digest as _;
use sha2::Sha256;
@@ -26,7 +27,9 @@ pub(crate) struct BundledBwrapLauncher {
pub(crate) fn launcher() -> Option<BundledBwrapLauncher> {
let current_exe = std::env::current_exe().ok()?;
find_for_exe(&current_exe).map(|program| BundledBwrapLauncher { program })
find_for_install_context(InstallContext::current())
.or_else(|| find_legacy_for_exe(&current_exe))
.map(|program| BundledBwrapLauncher { program })
}
impl BundledBwrapLauncher {
@@ -66,8 +69,14 @@ impl BundledBwrapLauncher {
}
}
fn find_for_exe(exe: &Path) -> Option<AbsolutePathBuf> {
candidates_for_exe(exe)
fn find_for_install_context(context: &InstallContext) -> Option<AbsolutePathBuf> {
context
.bundled_resource("bwrap")
.filter(|path| is_executable_file(path))
}
fn find_legacy_for_exe(exe: &Path) -> Option<AbsolutePathBuf> {
legacy_candidates_for_exe(exe)
.into_iter()
.find(|candidate| is_executable_file(candidate))
.map(|path| {
@@ -80,7 +89,7 @@ fn find_for_exe(exe: &Path) -> Option<AbsolutePathBuf> {
})
}
fn candidates_for_exe(exe: &Path) -> Vec<PathBuf> {
fn legacy_candidates_for_exe(exe: &Path) -> Vec<PathBuf> {
let Some(exe_dir) = exe.parent() else {
return Vec::new();
};
@@ -180,13 +189,44 @@ fn bytes_to_hex(bytes: &[u8; 32]) -> String {
#[cfg(test)]
mod tests {
use super::*;
use codex_install_context::CodexPackageLayout;
use codex_install_context::InstallContext;
use codex_install_context::InstallMethod;
use pretty_assertions::assert_eq;
use std::fs;
use tempfile::NamedTempFile;
use tempfile::tempdir;
#[test]
fn finds_standalone_bundled_bwrap_next_to_exe_resources() {
fn finds_package_layout_bwrap_from_install_context() {
let temp_dir = tempdir().expect("temp dir");
let package_dir = temp_dir.path();
let bin_dir = package_dir.join("bin");
let resources_dir = package_dir.join("codex-resources");
let expected_bwrap = resources_dir.join("bwrap");
fs::create_dir_all(&bin_dir).expect("create bin dir");
write_executable(&expected_bwrap);
let context = InstallContext {
method: InstallMethod::Other,
package_layout: Some(CodexPackageLayout {
package_dir: AbsolutePathBuf::from_absolute_path(package_dir).expect("absolute"),
bin_dir: AbsolutePathBuf::from_absolute_path(&bin_dir).expect("absolute"),
resources_dir: Some(
AbsolutePathBuf::from_absolute_path(&resources_dir).expect("absolute"),
),
path_dir: None,
}),
};
assert_eq!(
find_for_install_context(&context),
Some(AbsolutePathBuf::from_absolute_path(&expected_bwrap).expect("absolute"))
);
}
#[test]
fn finds_legacy_standalone_bundled_bwrap_next_to_exe_resources() {
let temp_dir = tempdir().expect("temp dir");
let exe = temp_dir.path().join("codex");
let expected_bwrap = temp_dir.path().join("codex-resources").join("bwrap");
@@ -194,7 +234,7 @@ mod tests {
write_executable(&expected_bwrap);
assert_eq!(
find_for_exe(&exe),
find_legacy_for_exe(&exe),
Some(AbsolutePathBuf::from_absolute_path(&expected_bwrap).expect("absolute"))
);
}
@@ -209,7 +249,7 @@ mod tests {
write_executable(&expected_bwrap);
assert_eq!(
find_for_exe(&exe),
find_legacy_for_exe(&exe),
Some(AbsolutePathBuf::from_absolute_path(&expected_bwrap).expect("absolute"))
);
}
@@ -223,7 +263,7 @@ mod tests {
write_executable(&expected_bwrap);
assert_eq!(
find_for_exe(&exe),
find_legacy_for_exe(&exe),
Some(AbsolutePathBuf::from_absolute_path(&expected_bwrap).expect("absolute"))
);
}
+10 -10
View File
@@ -1347,7 +1347,7 @@ mod tests {
fn unreadable_glob_entry(pattern: String) -> FileSystemSandboxEntry {
FileSystemSandboxEntry {
path: FileSystemPath::GlobPattern { pattern },
access: FileSystemAccessMode::None,
access: FileSystemAccessMode::Deny,
}
}
@@ -1547,7 +1547,7 @@ mod tests {
},
FileSystemSandboxEntry {
path: FileSystemPath::Path { path: link_blocked },
access: FileSystemAccessMode::None,
access: FileSystemAccessMode::Deny,
},
]);
@@ -1672,7 +1672,7 @@ mod tests {
},
FileSystemSandboxEntry {
path: FileSystemPath::Path { path: link_private },
access: FileSystemAccessMode::None,
access: FileSystemAccessMode::Deny,
},
]);
@@ -1989,7 +1989,7 @@ mod tests {
path: FileSystemPath::Special {
value: FileSystemSpecialPath::project_roots(Some(".secrets".into())),
},
access: FileSystemAccessMode::None,
access: FileSystemAccessMode::Deny,
},
]);
@@ -2172,7 +2172,7 @@ mod tests {
},
FileSystemSandboxEntry {
path: FileSystemPath::Path { path: blocked },
access: FileSystemAccessMode::None,
access: FileSystemAccessMode::Deny,
},
]);
@@ -2332,7 +2332,7 @@ mod tests {
path: FileSystemPath::Path {
path: blocked.clone(),
},
access: FileSystemAccessMode::None,
access: FileSystemAccessMode::Deny,
},
FileSystemSandboxEntry {
path: FileSystemPath::Path {
@@ -2401,7 +2401,7 @@ mod tests {
path: FileSystemPath::Path {
path: blocked.clone(),
},
access: FileSystemAccessMode::None,
access: FileSystemAccessMode::Deny,
},
FileSystemSandboxEntry {
path: FileSystemPath::Path {
@@ -2480,7 +2480,7 @@ mod tests {
},
FileSystemSandboxEntry {
path: FileSystemPath::Path { path: blocked },
access: FileSystemAccessMode::None,
access: FileSystemAccessMode::Deny,
},
FileSystemSandboxEntry {
path: FileSystemPath::Path { path: allowed },
@@ -2531,7 +2531,7 @@ mod tests {
path: FileSystemPath::Path {
path: blocked.clone(),
},
access: FileSystemAccessMode::None,
access: FileSystemAccessMode::Deny,
},
]);
@@ -2575,7 +2575,7 @@ mod tests {
path: FileSystemPath::Path {
path: blocked_file.clone(),
},
access: FileSystemAccessMode::None,
access: FileSystemAccessMode::Deny,
},
]);
@@ -190,6 +190,7 @@ async fn run_cmd_result_with_permission_profile_for_cwd(
params,
&permission_profile,
&sandbox_cwd,
std::slice::from_ref(&sandbox_cwd),
&codex_linux_sandbox_exe,
use_legacy_landlock,
/*stdout_stream*/ None,
@@ -448,6 +449,7 @@ async fn assert_network_blocked(cmd: &[&str]) {
params,
&permission_profile,
&sandbox_cwd,
std::slice::from_ref(&sandbox_cwd),
&codex_linux_sandbox_exe,
/*use_legacy_landlock*/ false,
/*stdout_stream*/ None,
@@ -805,7 +807,7 @@ async fn sandbox_blocks_explicit_split_policy_carveouts_under_bwrap() {
path: FileSystemPath::Path {
path: AbsolutePathBuf::try_from(blocked.as_path()).expect("absolute blocked dir"),
},
access: FileSystemAccessMode::None,
access: FileSystemAccessMode::Deny,
},
]);
let permission_profile = PermissionProfile::from_runtime_permissions(
@@ -873,7 +875,7 @@ async fn sandbox_reenables_writable_subpaths_under_unreadable_parents() {
path: FileSystemPath::Path {
path: AbsolutePathBuf::try_from(blocked.as_path()).expect("absolute blocked dir"),
},
access: FileSystemAccessMode::None,
access: FileSystemAccessMode::Deny,
},
FileSystemSandboxEntry {
path: FileSystemPath::Path {
@@ -931,7 +933,7 @@ async fn sandbox_blocks_root_read_carveouts_under_bwrap() {
path: FileSystemPath::Path {
path: AbsolutePathBuf::try_from(blocked.as_path()).expect("absolute blocked dir"),
},
access: FileSystemAccessMode::None,
access: FileSystemAccessMode::Deny,
},
]);
let permission_profile = PermissionProfile::from_runtime_permissions(