mirror of
https://github.com/openai/codex.git
synced 2026-10-27 18:48:37 +00:00
chore: merge origin/main into symlink hardening
Co-authored-by: Codex noreply@openai.com
This commit is contained in:
@@ -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 }
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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(¤t_exe).map(|program| BundledBwrapLauncher { program })
|
||||
find_for_install_context(InstallContext::current())
|
||||
.or_else(|| find_legacy_for_exe(¤t_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"))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user