Merge 715446387f into sapling-pr-archive-bolinfest

This commit is contained in:
Michael Bolin
2025-08-14 21:23:17 -07:00
committed by GitHub
76 changed files with 131 additions and 196 deletions
+3 -3
View File
@@ -8,6 +8,6 @@ In the codex-rs folder where the rust code lives:
- You operate in a sandbox where `CODEX_SANDBOX_NETWORK_DISABLED=1` will be set whenever you use the `shell` tool. Any existing code that uses `CODEX_SANDBOX_NETWORK_DISABLED_ENV_VAR` was authored with this fact in mind. It is often used to early exit out of tests that the author knew you would not be able to run given your sandbox limitations.
- Similarly, when you spawn a process using Seatbelt (`/usr/bin/sandbox-exec`), `CODEX_SANDBOX=seatbelt` will be set on the child process. Integration tests that want to run Seatbelt themselves cannot be run under Seatbelt, so checks for `CODEX_SANDBOX=seatbelt` are also often used to early exit out of tests, as appropriate.
Before creating a pull request with changes to `codex-rs`, run `just fmt` (in `codex-rs` directory) to format the code and `just fix` (in `codex-rs` directory) to fix any linter issues in the code, ensure the test suite passes by running `cargo test --all-features` in the `codex-rs` directory.
When making individual changes prefer running tests on individual files or projects first.
Before finalizing a change to `codex-rs`, run `just fmt` (in `codex-rs` directory) to format the code and `just fix` (in `codex-rs` directory) to fix any linter issues in the code. Additionally, run the tests:
1. Run the test for the specific project that was changed. For example, if changes were made in `codex-rs/tui`, run `cargo test -p codex-tui`.
2. Once those pass, if any changes were made in common, core, or protocol, run the complete test suite with `cargo test --all-features`.
+2 -4
View File
@@ -166,7 +166,7 @@ impl ApplyPatchAction {
panic!("path must be absolute");
}
#[allow(clippy::expect_used)]
#[expect(clippy::expect_used)]
let filename = path
.file_name()
.expect("path should not be empty")
@@ -179,7 +179,7 @@ impl ApplyPatchAction {
*** End Patch"#,
);
let changes = HashMap::from([(path.to_path_buf(), ApplyPatchFileChange::Add { content })]);
#[allow(clippy::expect_used)]
#[expect(clippy::expect_used)]
Self {
changes,
cwd: path
@@ -682,8 +682,6 @@ pub fn print_summary(
#[cfg(test)]
mod tests {
#![allow(clippy::unwrap_used)]
use super::*;
use pretty_assertions::assert_eq;
use std::fs;
-1
View File
@@ -427,7 +427,6 @@ fn parse_update_file_chunk(
}
#[test]
#[allow(clippy::unwrap_used)]
fn test_parse_patch() {
assert_eq!(
parse_patch_text("bad", ParseMode::Strict),
@@ -1,5 +1,3 @@
#![expect(clippy::expect_used)]
use codex_chatgpt::apply_command::apply_diff_from_task;
use codex_chatgpt::get_task::GetTaskResponse;
use std::path::Path;
+2
View File
@@ -0,0 +1,2 @@
allow-expect-in-tests = true
allow-unwrap-in-tests = true
-1
View File
@@ -142,7 +142,6 @@ fn parse_toml_value(raw: &str) -> Result<Value, toml::de::Error> {
}
#[cfg(all(test, feature = "cli"))]
#[allow(clippy::expect_used, clippy::unwrap_used)]
mod tests {
use super::*;
+1 -31
View File
@@ -8,7 +8,6 @@ use crate::safety::assess_patch_safety;
use codex_apply_patch::ApplyPatchAction;
use codex_apply_patch::ApplyPatchFileChange;
use std::collections::HashMap;
use std::path::Path;
use std::path::PathBuf;
pub const CODEX_APPLY_PATCH_ARG1: &str = "--codex-run-as-apply-patch";
@@ -45,12 +44,10 @@ pub(crate) async fn apply_patch(
call_id: &str,
action: ApplyPatchAction,
) -> InternalApplyPatchInvocation {
let writable_roots_snapshot = sess.get_writable_roots().to_vec();
match assess_patch_safety(
&action,
sess.get_approval_policy(),
&writable_roots_snapshot,
sess.get_sandbox_policy(),
sess.get_cwd(),
) {
SafetyCheck::AutoApprove { .. } => {
@@ -124,30 +121,3 @@ pub(crate) fn convert_apply_patch_to_protocol(
}
result
}
pub(crate) fn get_writable_roots(cwd: &Path) -> Vec<PathBuf> {
let mut writable_roots = Vec::new();
if cfg!(target_os = "macos") {
// On macOS, $TMPDIR is private to the user.
writable_roots.push(std::env::temp_dir());
// Allow pyenv to update its shims directory. Without this, any tool
// that happens to be managed by `pyenv` will fail with an error like:
//
// pyenv: cannot rehash: $HOME/.pyenv/shims isn't writable
//
// which is emitted every time `pyenv` tries to run `rehash` (for
// example, after installing a new Python package that drops an entry
// point). Although the sandbox is intentionally read‑only by default,
// writing to the user's local `pyenv` directory is safe because it
// is already user‑writable and scoped to the current user account.
if let Ok(home_dir) = std::env::var("HOME") {
let pyenv_dir = PathBuf::from(home_dir).join(".pyenv");
writable_roots.push(pyenv_dir);
}
}
writable_roots.push(cwd.to_path_buf());
writable_roots
}
-1
View File
@@ -132,7 +132,6 @@ fn parse_plain_command_from_node(cmd: tree_sitter::Node, src: &str) -> Option<Ve
#[cfg(test)]
mod tests {
#![allow(clippy::unwrap_used)]
use super::*;
fn parse_seq(src: &str) -> Option<Vec<Vec<String>>> {
-2
View File
@@ -609,8 +609,6 @@ fn try_parse_retry_after(err: &Error) -> Option<Duration> {
#[cfg(test)]
mod tests {
#![allow(clippy::expect_used, clippy::unwrap_used)]
use super::*;
use serde_json::json;
use tokio::sync::mpsc;
-1
View File
@@ -187,7 +187,6 @@ impl Stream for ResponseStream {
#[cfg(test)]
mod tests {
#![allow(clippy::expect_used)]
use crate::model_family::find_family_for_model;
use super::*;
+6 -11
View File
@@ -1,5 +1,5 @@
// Poisoned mutex should fail the program
#![allow(clippy::unwrap_used)]
#![expect(clippy::unwrap_used)]
use std::borrow::Cow;
use std::collections::HashMap;
@@ -31,12 +31,11 @@ use tracing::warn;
use uuid::Uuid;
use crate::ModelProviderInfo;
use crate::apply_patch;
use crate::apply_patch::ApplyPatchExec;
use crate::apply_patch::CODEX_APPLY_PATCH_ARG1;
use crate::apply_patch::InternalApplyPatchInvocation;
use crate::apply_patch::convert_apply_patch_to_protocol;
use crate::apply_patch::get_writable_roots;
use crate::apply_patch::{self};
use crate::client::ModelClient;
use crate::client_common::Prompt;
use crate::client_common::ResponseEvent;
@@ -230,7 +229,6 @@ pub(crate) struct Session {
approval_policy: AskForApproval,
sandbox_policy: SandboxPolicy,
shell_environment_policy: ShellEnvironmentPolicy,
writable_roots: Vec<PathBuf>,
disable_response_storage: bool,
tools_config: ToolsConfig,
@@ -409,8 +407,6 @@ impl Session {
state.history.record_items(&restored_items);
}
let writable_roots = get_writable_roots(&cwd);
// Handle MCP manager result and record any startup failures.
let (mcp_connection_manager, failed_clients) = match mcp_res {
Ok((mgr, failures)) => (mgr, failures),
@@ -463,7 +459,6 @@ impl Session {
sandbox_policy,
shell_environment_policy: config.shell_environment_policy.clone(),
cwd,
writable_roots,
mcp_connection_manager,
notify,
state: Mutex::new(state),
@@ -507,14 +502,14 @@ impl Session {
Ok(sess)
}
pub(crate) fn get_writable_roots(&self) -> &[PathBuf] {
&self.writable_roots
}
pub(crate) fn get_approval_policy(&self) -> AskForApproval {
self.approval_policy
}
pub(crate) fn get_sandbox_policy(&self) -> &SandboxPolicy {
&self.sandbox_policy
}
pub(crate) fn get_cwd(&self) -> &Path {
&self.cwd
}
-1
View File
@@ -765,7 +765,6 @@ pub fn log_dir(cfg: &Config) -> std::io::Result<PathBuf> {
#[cfg(test)]
mod tests {
#![allow(clippy::expect_used, clippy::unwrap_used)]
use crate::config_types::HistoryPersistence;
use super::*;
-2
View File
@@ -70,8 +70,6 @@ where
#[cfg(test)]
mod tests {
#![allow(clippy::unwrap_used, clippy::expect_used)]
use super::*;
use crate::config_types::ShellEnvironmentPolicyInherit;
use maplit::hashmap;
-3
View File
@@ -99,9 +99,6 @@ async fn run_git_command_with_timeout(args: &[&str], cwd: &Path) -> Option<std::
#[cfg(test)]
mod tests {
#![allow(clippy::expect_used)]
#![allow(clippy::unwrap_used)]
use super::*;
use std::fs;
-1
View File
@@ -162,7 +162,6 @@ fn is_valid_sed_n_arg(arg: Option<&str>) -> bool {
#[cfg(test)]
mod tests {
#![allow(clippy::unwrap_used)]
use super::*;
fn vec_str(args: &[&str]) -> Vec<String> {
@@ -281,7 +281,6 @@ fn is_valid_mcp_server_name(server_name: &str) -> bool {
}
#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod tests {
use super::*;
use mcp_types::ToolInputSchema;
-1
View File
@@ -322,7 +322,6 @@ pub fn create_oss_provider_with_base_url(base_url: &str) -> ModelProviderInfo {
#[cfg(test)]
mod tests {
#![allow(clippy::unwrap_used)]
use super::*;
use pretty_assertions::assert_eq;
-1
View File
@@ -266,7 +266,6 @@ impl std::ops::Deref for FunctionCallOutputPayload {
#[cfg(test)]
mod tests {
#![allow(clippy::unwrap_used)]
use super::*;
#[test]
-1
View File
@@ -470,7 +470,6 @@ pub(crate) fn get_openai_tools(
}
#[cfg(test)]
#[allow(clippy::expect_used)]
mod tests {
use crate::model_family::find_family_for_model;
use mcp_types::ToolInputSchema;
-2
View File
@@ -134,8 +134,6 @@ async fn load_first_candidate(
#[cfg(test)]
mod tests {
#![allow(clippy::expect_used, clippy::unwrap_used)]
use super::*;
use crate::config::ConfigOverrides;
use crate::config::ConfigToml;
+21 -1
View File
@@ -183,10 +183,31 @@ pub enum SandboxPolicy {
/// not modified by the agent.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct WritableRoot {
/// Absolute path, by construction.
pub root: PathBuf,
/// Also absolute paths, by construction.
pub read_only_subpaths: Vec<PathBuf>,
}
impl WritableRoot {
pub(crate) fn is_path_writable(&self, path: &Path) -> bool {
// Check if the path is under the root.
if !path.starts_with(&self.root) {
return false;
}
// Check if the path is under any of the read-only subpaths.
for subpath in &self.read_only_subpaths {
if path.starts_with(subpath) {
return false;
}
}
true
}
}
impl FromStr for SandboxPolicy {
type Err = serde_json::Error;
@@ -724,7 +745,6 @@ pub struct Chunk {
#[cfg(test)]
mod tests {
#![allow(clippy::unwrap_used)]
use super::*;
/// Serialize Event to verify that its JSON representation has the expected
+44 -26
View File
@@ -21,7 +21,7 @@ pub enum SafetyCheck {
pub fn assess_patch_safety(
action: &ApplyPatchAction,
policy: AskForApproval,
writable_roots: &[PathBuf],
sandbox_policy: &SandboxPolicy,
cwd: &Path,
) -> SafetyCheck {
if action.is_empty() {
@@ -45,7 +45,7 @@ pub fn assess_patch_safety(
// is possible that paths in the patch are hard links to files outside the
// writable roots, so we should still run `apply_patch` in a sandbox in that
// case.
if is_write_patch_constrained_to_writable_paths(action, writable_roots, cwd)
if is_write_patch_constrained_to_writable_paths(action, sandbox_policy, cwd)
|| policy == AskForApproval::OnFailure
{
// Only auto‑approve when we can actually enforce a sandbox. Otherwise
@@ -171,13 +171,19 @@ pub fn get_platform_sandbox() -> Option<SandboxType> {
fn is_write_patch_constrained_to_writable_paths(
action: &ApplyPatchAction,
writable_roots: &[PathBuf],
sandbox_policy: &SandboxPolicy,
cwd: &Path,
) -> bool {
// Early‑exit if there are no declared writable roots.
if writable_roots.is_empty() {
return false;
}
let writable_roots = match sandbox_policy {
SandboxPolicy::ReadOnly => {
return false;
}
SandboxPolicy::DangerFullAccess => {
return true;
}
SandboxPolicy::WorkspaceWrite { .. } => sandbox_policy.get_writable_roots_with_cwd(cwd),
};
// Normalize a path by removing `.` and resolving `..` without touching the
// filesystem (works even if the file does not exist).
@@ -209,15 +215,9 @@ fn is_write_patch_constrained_to_writable_paths(
None => return false,
};
writable_roots.iter().any(|root| {
let root_abs = if root.is_absolute() {
root.clone()
} else {
normalize(&cwd.join(root)).unwrap_or_else(|| cwd.join(root))
};
abs.starts_with(&root_abs)
})
writable_roots
.iter()
.any(|writable_root| writable_root.is_path_writable(&abs))
};
for (path, change) in action.changes() {
@@ -245,40 +245,58 @@ fn is_write_patch_constrained_to_writable_paths(
#[cfg(test)]
mod tests {
#![allow(clippy::unwrap_used)]
use super::*;
#[test]
fn test_writable_roots_constraint() {
let cwd = std::env::current_dir().unwrap();
use tempfile::TempDir;
// Use a temporary directory as our workspace to avoid touching
// the real current working directory.
let tmp = TempDir::new().unwrap();
let cwd = tmp.path().to_path_buf();
let parent = cwd.parent().unwrap().to_path_buf();
// Helper to build a single‑entry map representing a patch that adds a
// file at `p`.
// Helper to build a single‑entry patch that adds a file at `p`.
let make_add_change = |p: PathBuf| ApplyPatchAction::new_add_for_test(&p, "".to_string());
let add_inside = make_add_change(cwd.join("inner.txt"));
let add_outside = make_add_change(parent.join("outside.txt"));
// Policy limited to the workspace only; exclude system temp roots so
// only `cwd` is writable by default.
let policy_workspace_only = SandboxPolicy::WorkspaceWrite {
writable_roots: vec![],
network_access: false,
exclude_tmpdir_env_var: true,
exclude_slash_tmp: true,
};
assert!(is_write_patch_constrained_to_writable_paths(
&add_inside,
&[PathBuf::from(".")],
&policy_workspace_only,
&cwd,
));
let add_outside_2 = make_add_change(parent.join("outside.txt"));
assert!(!is_write_patch_constrained_to_writable_paths(
&add_outside_2,
&[PathBuf::from(".")],
&add_outside,
&policy_workspace_only,
&cwd,
));
// With parent dir added as writable root, it should pass.
// With the parent dir explicitly added as a writable root, the
// outside write should be permitted.
let policy_with_parent = SandboxPolicy::WorkspaceWrite {
writable_roots: vec![parent.clone()],
network_access: false,
exclude_tmpdir_env_var: true,
exclude_slash_tmp: true,
};
assert!(is_write_patch_constrained_to_writable_paths(
&add_outside,
&[PathBuf::from("..")],
&policy_with_parent,
&cwd,
))
));
}
#[test]
-1
View File
@@ -122,7 +122,6 @@ fn create_seatbelt_command_args(
#[cfg(test)]
mod tests {
#![expect(clippy::expect_used)]
use super::MACOS_SEATBELT_BASE_POLICY;
use super::create_seatbelt_command_args;
use crate::protocol::SandboxPolicy;
-2
View File
@@ -98,7 +98,6 @@ mod tests {
use std::process::Command;
#[tokio::test]
#[expect(clippy::unwrap_used)]
async fn test_current_shell_detects_zsh() {
let shell = Command::new("sh")
.arg("-c")
@@ -129,7 +128,6 @@ mod tests {
assert_eq!(actual_cmd, None);
}
#[expect(clippy::unwrap_used)]
#[tokio::test]
async fn test_run_with_profile_escaping_and_execution() {
let shell_path = "/bin/zsh";
-1
View File
@@ -466,7 +466,6 @@ fn is_windows_drive_or_unc_root(p: &std::path::Path) -> bool {
#[cfg(test)]
mod tests {
#![allow(clippy::unwrap_used)]
use super::*;
use pretty_assertions::assert_eq;
use tempfile::tempdir;
-1
View File
@@ -13,7 +13,6 @@ pub fn get_codex_user_agent(originator: Option<&str>) -> String {
}
#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod tests {
use super::*;
-1
View File
@@ -20,7 +20,6 @@ pub(crate) enum UserNotification {
#[cfg(test)]
mod tests {
#![allow(clippy::unwrap_used)]
use super::*;
#[test]
-2
View File
@@ -1,5 +1,3 @@
#![expect(clippy::unwrap_used)]
use assert_cmd::Command as AssertCommand;
use codex_core::spawn::CODEX_SANDBOX_NETWORK_DISABLED_ENV_VAR;
use std::time::Duration;
+3 -16
View File
@@ -1,5 +1,3 @@
#![allow(clippy::expect_used, clippy::unwrap_used)]
use codex_core::ConversationManager;
use codex_core::ModelProviderInfo;
use codex_core::NewConversation;
@@ -27,10 +25,12 @@ fn sse_completed(id: &str) -> String {
load_sse_fixture_with_id("tests/fixtures/completed_template.json", id)
}
#[expect(clippy::unwrap_used)]
fn assert_message_role(request_body: &serde_json::Value, role: &str) {
assert_eq!(request_body["role"].as_str().unwrap(), role);
}
#[expect(clippy::expect_used)]
fn assert_message_starts_with(request_body: &serde_json::Value, text: &str) {
let content = request_body["content"][0]["text"]
.as_str()
@@ -42,6 +42,7 @@ fn assert_message_starts_with(request_body: &serde_json::Value, text: &str) {
);
}
#[expect(clippy::expect_used)]
fn assert_message_ends_with(request_body: &serde_json::Value, text: &str) {
let content = request_body["content"][0]["text"]
.as_str()
@@ -55,8 +56,6 @@ fn assert_message_ends_with(request_body: &serde_json::Value, text: &str) {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn includes_session_id_and_model_headers_in_request() {
#![allow(clippy::unwrap_used)]
if std::env::var(CODEX_SANDBOX_NETWORK_DISABLED_ENV_VAR).is_ok() {
println!(
"Skipping test because it cannot execute when network is disabled in a Codex sandbox."
@@ -129,8 +128,6 @@ async fn includes_session_id_and_model_headers_in_request() {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn includes_base_instructions_override_in_request() {
#![allow(clippy::unwrap_used)]
// Mock server
let server = MockServer::start().await;
@@ -187,8 +184,6 @@ async fn includes_base_instructions_override_in_request() {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn originator_config_override_is_used() {
#![allow(clippy::unwrap_used)]
// Mock server
let server = MockServer::start().await;
@@ -238,8 +233,6 @@ async fn originator_config_override_is_used() {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn chatgpt_auth_sends_correct_request() {
#![allow(clippy::unwrap_used)]
if std::env::var(CODEX_SANDBOX_NETWORK_DISABLED_ENV_VAR).is_ok() {
println!(
"Skipping test because it cannot execute when network is disabled in a Codex sandbox."
@@ -320,8 +313,6 @@ async fn chatgpt_auth_sends_correct_request() {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn includes_user_instructions_message_in_request() {
#![allow(clippy::unwrap_used)]
let server = MockServer::start().await;
let first = ResponseTemplate::new(200)
@@ -382,8 +373,6 @@ async fn includes_user_instructions_message_in_request() {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn azure_overrides_assign_properties_used_for_responses_url() {
#![allow(clippy::unwrap_used)]
let existing_env_var_with_random_value = if cfg!(windows) { "USERNAME" } else { "USER" };
// Mock server
@@ -460,8 +449,6 @@ async fn azure_overrides_assign_properties_used_for_responses_url() {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn env_var_overrides_loaded_auth() {
#![allow(clippy::unwrap_used)]
let existing_env_var_with_random_value = if cfg!(windows) { "USERNAME" } else { "USER" };
// Mock server
+1 -1
View File
@@ -1,4 +1,4 @@
#![allow(clippy::expect_used)]
#![expect(clippy::expect_used)]
use tempfile::TempDir;
+1 -2
View File
@@ -1,5 +1,4 @@
#![cfg(target_os = "macos")]
#![expect(clippy::unwrap_used, clippy::expect_used)]
use std::collections::HashMap;
@@ -24,6 +23,7 @@ fn skip_test() -> bool {
false
}
#[expect(clippy::expect_used)]
async fn run_test_cmd(tmp: TempDir, cmd: Vec<&str>) -> Result<ExecToolCallOutput> {
let sandbox_type = get_platform_sandbox().expect("should be able to get sandbox type");
assert_eq!(sandbox_type, SandboxType::MacosSeatbelt);
@@ -68,7 +68,6 @@ async fn truncates_output_lines() {
let tmp = TempDir::new().expect("should be able to create temp dir");
let cmd = vec!["seq", "300"];
#[expect(clippy::unwrap_used)]
let output = run_test_cmd(tmp, cmd).await.unwrap();
let expected_output = (1..=256)
+1 -2
View File
@@ -17,7 +17,7 @@ fn require_api_key() -> String {
/// Helper that spawns the binary inside a TempDir with minimal flags. Returns (Assert, TempDir).
fn run_live(prompt: &str) -> (assert_cmd::assert::Assert, TempDir) {
#![allow(clippy::unwrap_used)]
#![expect(clippy::unwrap_used)]
use std::io::Read;
use std::io::Write;
use std::thread;
@@ -113,7 +113,6 @@ fn run_live(prompt: &str) -> (assert_cmd::assert::Assert, TempDir) {
#[ignore]
#[test]
fn live_create_file_hello_txt() {
#![allow(clippy::unwrap_used)]
if std::env::var("OPENAI_API_KEY").is_err() {
eprintln!("skipping live_create_file_hello_txt – OPENAI_API_KEY not set");
return;
-3
View File
@@ -1,5 +1,3 @@
#![allow(clippy::expect_used, clippy::unwrap_used)]
use codex_core::ConversationManager;
use codex_core::ModelProviderInfo;
use codex_core::built_in_model_providers;
@@ -24,7 +22,6 @@ fn sse_completed(id: &str) -> String {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn prefixes_context_and_instructions_once_and_consistently_across_requests() {
#![allow(clippy::unwrap_used)]
use pretty_assertions::assert_eq;
let server = MockServer::start().await;
+2 -1
View File
@@ -1,5 +1,4 @@
#![cfg(target_os = "macos")]
#![expect(clippy::expect_used)]
//! Tests for the macOS sandboxing that are specific to Seatbelt.
//! Tests that apply to both Mac and Linux sandboxing should go in sandbox.rs.
@@ -160,6 +159,7 @@ async fn read_only_forbids_all_writes() {
.await;
}
#[expect(clippy::expect_used)]
fn create_test_scenario(tmp: &TempDir) -> TestScenario {
let repo_parent = tmp.path().to_path_buf();
let repo_root = repo_parent.join("repo");
@@ -177,6 +177,7 @@ fn create_test_scenario(tmp: &TempDir) -> TestScenario {
}
}
#[expect(clippy::expect_used)]
/// Note that `path` must be absolute.
async fn touch(path: &Path, policy: &SandboxPolicy) -> bool {
assert!(path.is_absolute(), "Path must be absolute: {path:?}");
@@ -25,7 +25,6 @@ fn sse_completed(id: &str) -> String {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn continue_after_stream_error() {
#![allow(clippy::unwrap_used)]
if std::env::var(CODEX_SANDBOX_NETWORK_DISABLED_ENV_VAR).is_ok() {
println!(
"Skipping test because it cannot execute when network is disabled in a Codex sandbox."
@@ -33,8 +33,6 @@ fn sse_completed(id: &str) -> String {
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn retries_on_early_close() {
#![allow(clippy::unwrap_used)]
if std::env::var(CODEX_SANDBOX_NETWORK_DISABLED_ENV_VAR).is_ok() {
println!(
"Skipping test because it cannot execute when network is disabled in a Codex sandbox."
@@ -191,7 +191,7 @@ impl EventProcessor for EventProcessorWithHumanOutput {
self.answer_started = true;
}
print!("{delta}");
#[allow(clippy::expect_used)]
#[expect(clippy::expect_used)]
std::io::stdout().flush().expect("could not flush stdout");
}
EventMsg::AgentReasoningDelta(AgentReasoningDeltaEvent { delta }) => {
@@ -207,7 +207,7 @@ impl EventProcessor for EventProcessorWithHumanOutput {
self.reasoning_started = true;
}
print!("{delta}");
#[allow(clippy::expect_used)]
#[expect(clippy::expect_used)]
std::io::stdout().flush().expect("could not flush stdout");
}
EventMsg::AgentReasoningSectionBreak(_) => {
@@ -215,7 +215,7 @@ impl EventProcessor for EventProcessorWithHumanOutput {
return CodexStatus::Running;
}
println!();
#[allow(clippy::expect_used)]
#[expect(clippy::expect_used)]
std::io::stdout().flush().expect("could not flush stdout");
}
EventMsg::AgentReasoningRawContent(AgentReasoningRawContentEvent { text }) => {
@@ -224,7 +224,7 @@ impl EventProcessor for EventProcessorWithHumanOutput {
}
if !self.raw_reasoning_started {
print!("{text}");
#[allow(clippy::expect_used)]
#[expect(clippy::expect_used)]
std::io::stdout().flush().expect("could not flush stdout");
} else {
println!();
@@ -241,7 +241,7 @@ impl EventProcessor for EventProcessorWithHumanOutput {
self.raw_reasoning_started = true;
}
print!("{delta}");
#[allow(clippy::expect_used)]
#[expect(clippy::expect_used)]
std::io::stdout().flush().expect("could not flush stdout");
}
EventMsg::AgentMessage(AgentMessageEvent { message }) => {
@@ -28,7 +28,7 @@ impl EventProcessor for EventProcessorWithJsonOutput {
.into_iter()
.map(|(key, value)| (key.to_string(), value))
.collect::<HashMap<String, String>>();
#[allow(clippy::expect_used)]
#[expect(clippy::expect_used)]
let config_json =
serde_json::to_string(&entries).expect("Failed to serialize config summary to JSON");
println!("{config_json}");
+1 -2
View File
@@ -1,6 +1,4 @@
#![cfg(unix)]
#![expect(clippy::expect_used)]
use codex_core::protocol::SandboxPolicy;
use codex_core::spawn::StdioPolicy;
use std::collections::HashMap;
@@ -180,6 +178,7 @@ async fn allow_unix_socketpair_recvfrom() {
const IN_SANDBOX_ENV_VAR: &str = "IN_SANDBOX";
#[expect(clippy::expect_used)]
pub async fn run_code_under_sandbox<F, Fut>(
test_selector: &str,
policy: &SandboxPolicy,
-1
View File
@@ -140,7 +140,6 @@ fn is_executable_file(path: &str) -> bool {
#[cfg(test)]
mod tests {
#![allow(clippy::unwrap_used)]
use tempfile::TempDir;
use super::*;
-1
View File
@@ -1,4 +1,3 @@
#![expect(clippy::expect_used)]
use codex_execpolicy::NegativeExamplePassedCheck;
use codex_execpolicy::get_default_policy;
+1 -1
View File
@@ -1,4 +1,3 @@
#![expect(clippy::expect_used)]
extern crate codex_execpolicy;
use codex_execpolicy::ArgMatcher;
@@ -12,6 +11,7 @@ use codex_execpolicy::Result;
use codex_execpolicy::ValidExec;
use codex_execpolicy::get_default_policy;
#[expect(clippy::expect_used)]
fn setup() -> Policy {
get_default_policy().expect("failed to load default policy")
}
-1
View File
@@ -1,4 +1,3 @@
#![expect(clippy::expect_used)]
use codex_execpolicy::PositiveExampleFailedCheck;
use codex_execpolicy::get_default_policy;
+1 -1
View File
@@ -1,4 +1,3 @@
#![expect(clippy::expect_used)]
use codex_execpolicy::ArgMatcher;
use codex_execpolicy::ArgType;
use codex_execpolicy::Error;
@@ -13,6 +12,7 @@ use codex_execpolicy::get_default_policy;
extern crate codex_execpolicy;
#[expect(clippy::expect_used)]
fn setup() -> Policy {
get_default_policy().expect("failed to load default policy")
}
-1
View File
@@ -1,4 +1,3 @@
#![expect(clippy::expect_used)]
use codex_execpolicy::ArgType;
use codex_execpolicy::Error;
use codex_execpolicy::ExecCall;
+1 -1
View File
@@ -1,4 +1,3 @@
#![expect(clippy::expect_used)]
extern crate codex_execpolicy;
use codex_execpolicy::ArgType;
@@ -12,6 +11,7 @@ use codex_execpolicy::Result;
use codex_execpolicy::ValidExec;
use codex_execpolicy::get_default_policy;
#[expect(clippy::expect_used)]
fn setup() -> Policy {
get_default_policy().expect("failed to load default policy")
}
+1 -1
View File
@@ -1,4 +1,3 @@
#![expect(clippy::expect_used)]
extern crate codex_execpolicy;
use std::vec;
@@ -12,6 +11,7 @@ use codex_execpolicy::PositionalArg;
use codex_execpolicy::ValidExec;
use codex_execpolicy::get_default_policy;
#[expect(clippy::expect_used)]
fn setup() -> Policy {
get_default_policy().expect("failed to load default policy")
}
+1 -1
View File
@@ -1,4 +1,3 @@
#![expect(clippy::expect_used)]
extern crate codex_execpolicy;
use codex_execpolicy::ArgType;
@@ -13,6 +12,7 @@ use codex_execpolicy::Result;
use codex_execpolicy::ValidExec;
use codex_execpolicy::get_default_policy;
#[expect(clippy::expect_used)]
fn setup() -> Policy {
get_default_policy().expect("failed to load default policy")
}
+2 -3
View File
@@ -1,6 +1,4 @@
#![cfg(target_os = "linux")]
#![expect(clippy::unwrap_used, clippy::expect_used)]
use codex_core::config_types::ShellEnvironmentPolicy;
use codex_core::error::CodexErr;
use codex_core::error::SandboxErr;
@@ -35,7 +33,7 @@ fn create_env_from_core_vars() -> HashMap<String, String> {
create_env(&policy)
}
#[allow(clippy::print_stdout)]
#[expect(clippy::print_stdout, clippy::expect_used, clippy::unwrap_used)]
async fn run_cmd(cmd: &[&str], writable_roots: &[PathBuf], timeout_ms: u64) {
let params = ExecParams {
command: cmd.iter().map(|elm| elm.to_string()).collect(),
@@ -132,6 +130,7 @@ async fn test_timeout() {
/// does NOT succeed (i.e. returns a non‑zero exit code) **unless** the binary
/// is missing in which case we silently treat it as an accepted skip so the
/// suite remains green on leaner CI images.
#[expect(clippy::expect_used)]
async fn assert_network_blocked(cmd: &[&str]) {
let cwd = std::env::current_dir().expect("cwd should exist");
let params = ExecParams {
-1
View File
@@ -427,7 +427,6 @@ pub struct AuthDotJson {
#[cfg(test)]
mod tests {
#![expect(clippy::expect_used, clippy::unwrap_used)]
use super::*;
use crate::token_data::IdTokenInfo;
use crate::token_data::KnownPlan;
-1
View File
@@ -155,7 +155,6 @@ mod tests {
use serde::Serialize;
#[test]
#[expect(clippy::expect_used, clippy::unwrap_used)]
fn id_token_info_parses_email_and_plan() {
#[derive(Serialize)]
struct Header {
+1 -1
View File
@@ -1,4 +1,4 @@
#![allow(clippy::unwrap_used)]
#![expect(clippy::unwrap_used)]
use std::net::SocketAddr;
use std::net::TcpListener;
use std::thread;
@@ -236,7 +236,6 @@ mod tests {
#[test]
fn verify_codex_tool_json_schema() {
let tool = create_tool_for_codex_tool_call_param();
#[expect(clippy::expect_used)]
let tool_json = serde_json::to_value(&tool).expect("tool serializes");
let expected_tool_json = serde_json::json!({
"name": "codex",
@@ -305,7 +304,6 @@ mod tests {
#[test]
fn verify_codex_tool_reply_json_schema() {
let tool = create_tool_for_codex_tool_call_reply_param();
#[expect(clippy::expect_used)]
let tool_json = serde_json::to_value(&tool).expect("tool serializes");
let expected_tool_json = serde_json::json!({
"description": "Continue a Codex session by providing the session id and prompt.",
-1
View File
@@ -28,7 +28,6 @@ pub(crate) fn json_to_toml(v: JsonValue) -> TomlValue {
}
#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod tests {
use super::*;
use pretty_assertions::assert_eq;
-2
View File
@@ -293,8 +293,6 @@ pub enum ClientNotification {
}
#[cfg(test)]
#[allow(clippy::expect_used)]
#[allow(clippy::unwrap_used)]
mod tests {
use std::path::PathBuf;
+1 -3
View File
@@ -101,7 +101,7 @@ impl OutgoingMessageSender {
event: &Event,
meta: Option<OutgoingNotificationMeta>,
) {
#[allow(clippy::expect_used)]
#[expect(clippy::expect_used)]
let event_json = serde_json::to_value(event).expect("Event must serialize");
let params = if let Ok(params) = serde_json::to_value(OutgoingNotificationParams {
@@ -244,8 +244,6 @@ pub(crate) struct OutgoingError {
#[cfg(test)]
mod tests {
#![allow(clippy::unwrap_used)]
use codex_core::protocol::EventMsg;
use codex_core::protocol::SessionConfiguredEvent;
use pretty_assertions::assert_eq;
-1
View File
@@ -222,7 +222,6 @@ pub struct ApplyPatchApprovalResponse {
pub decision: ReviewDecision,
}
#[allow(clippy::unwrap_used)]
#[cfg(test)]
mod tests {
use super::*;
@@ -1,5 +1,3 @@
#![allow(clippy::expect_used, clippy::unwrap_used)]
use std::path::Path;
use codex_core::spawn::CODEX_SANDBOX_NETWORK_DISABLED_ENV_VAR;
+1 -1
View File
@@ -304,7 +304,7 @@ async fn test_codex_tool_passes_base_instructions() {
}
async fn codex_tool_passes_base_instructions() -> anyhow::Result<()> {
#![allow(clippy::unwrap_used)]
#![expect(clippy::unwrap_used)]
let server =
create_mock_chat_completions_server(vec![create_final_assistant_message_sse_response(
@@ -1,5 +1,3 @@
#![allow(clippy::expect_used, clippy::unwrap_used)]
use std::path::Path;
use mcp_test_support::McpProcess;
@@ -1,5 +1,3 @@
#![allow(clippy::expect_used)]
use std::path::Path;
use std::thread::sleep;
use std::time::Duration;
-1
View File
@@ -1,4 +1,3 @@
#![expect(clippy::expect_used)]
use mcp_types::ClientCapabilities;
use mcp_types::ClientRequest;
use mcp_types::Implementation;
@@ -1,4 +1,3 @@
#![expect(clippy::expect_used)]
use mcp_types::JSONRPCMessage;
use mcp_types::ProgressNotificationParams;
use mcp_types::ProgressToken;
+1 -2
View File
@@ -53,7 +53,7 @@ impl OllamaClient {
/// Build a client from a provider definition and verify the server is reachable.
async fn try_from_provider(provider: &ModelProviderInfo) -> io::Result<Self> {
#![allow(clippy::expect_used)]
#![expect(clippy::expect_used)]
let base_url = provider
.base_url
.as_ref()
@@ -235,7 +235,6 @@ impl OllamaClient {
#[cfg(test)]
mod tests {
#![allow(clippy::expect_used, clippy::unwrap_used)]
use super::*;
// Happy-path tests using a mock HTTP server; skip if sandbox network is disabled.
+1 -1
View File
@@ -188,7 +188,7 @@ impl App<'_> {
}
}
#[allow(clippy::expect_used)]
#[expect(clippy::expect_used)]
let deadline = next_deadline.expect("deadline set");
let now = Instant::now();
let timeout = if deadline > now {
@@ -182,7 +182,6 @@ impl ChatComposerHistory {
#[cfg(test)]
mod tests {
#![expect(clippy::expect_used)]
use super::*;
use crate::app_event::AppEvent;
use codex_core::protocol::Op;
+1 -3
View File
@@ -801,7 +801,7 @@ impl TextArea {
}
}
#[allow(clippy::unwrap_used)]
#[expect(clippy::unwrap_used)]
fn wrapped_lines(&self, width: u16) -> Ref<'_, Vec<Range<usize>>> {
// Ensure cache is ready (potentially mutably borrow, then drop)
{
@@ -926,7 +926,6 @@ impl TextArea {
}
#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod tests {
use super::*;
// crossterm types are intentionally not imported here to avoid unused warnings
@@ -1432,7 +1431,6 @@ mod tests {
// Seed the RNG based on the current day in Pacific Time (PST/PDT). This
// keeps the fuzz test deterministic within a day while still varying
// day-to-day to improve coverage.
#[allow(clippy::unwrap_used)]
let pst_today_seed: u64 = (chrono::Utc::now() - chrono::Duration::hours(8))
.date_naive()
.and_hms_opt(0, 0, 0)
+5
View File
@@ -59,6 +59,7 @@ use crate::streaming::controller::AppEventHistorySink;
use crate::streaming::controller::StreamController;
use codex_core::ConversationManager;
use codex_file_search::FileMatch;
use uuid::Uuid;
// Track information about an in-flight exec command.
struct RunningCommand {
@@ -86,6 +87,7 @@ pub(crate) struct ChatWidget<'a> {
interrupts: InterruptManager,
// Whether a redraw is needed after handling the current event
needs_redraw: bool,
session_id: Option<Uuid>,
}
struct UserMessage {
@@ -125,6 +127,7 @@ impl ChatWidget<'_> {
fn on_session_configured(&mut self, event: codex_core::protocol::SessionConfiguredEvent) {
self.bottom_pane
.set_history_metadata(event.history_log_id, event.history_entry_count);
self.session_id = Some(event.session_id);
self.add_to_history(&history_cell::new_session_info(&self.config, event, true));
if let Some(user_message) = self.initial_user_message.take() {
self.submit_user_message(user_message);
@@ -528,6 +531,7 @@ impl ChatWidget<'_> {
task_complete_pending: false,
interrupts: InterruptManager::new(),
needs_redraw: false,
session_id: None,
}
}
@@ -675,6 +679,7 @@ impl ChatWidget<'_> {
self.add_to_history(&history_cell::new_status_output(
&self.config,
&self.total_token_usage,
&self.session_id,
));
}
+1 -2
View File
@@ -1,5 +1,3 @@
#![allow(clippy::unwrap_used, clippy::expect_used, unnameable_test_items)]
use super::*;
use crate::app_event::AppEvent;
use crate::app_event_sender::AppEventSender;
@@ -143,6 +141,7 @@ fn make_chatwidget_manual() -> (
task_complete_pending: false,
interrupts: InterruptManager::new(),
needs_redraw: false,
session_id: None,
};
(widget, rx, op_rx)
}
+1 -1
View File
@@ -1,4 +1,4 @@
#![allow(clippy::expect_used)]
#![expect(clippy::expect_used)]
use regex_lite::Regex;
-1
View File
@@ -357,7 +357,6 @@ fn style_del() -> Style {
Style::default().fg(Color::Red)
}
#[allow(clippy::expect_used)]
#[cfg(test)]
mod tests {
use super::*;
+4 -7
View File
@@ -31,10 +31,7 @@ use std::time::Duration;
use crate::app_event::AppEvent;
use crate::app_event_sender::AppEventSender;
#[allow(clippy::unwrap_used)]
const MAX_FILE_SEARCH_RESULTS: NonZeroUsize = NonZeroUsize::new(8).unwrap();
#[allow(clippy::unwrap_used)]
const NUM_FILE_SEARCH_THREADS: NonZeroUsize = NonZeroUsize::new(2).unwrap();
/// How long to wait after a keystroke before firing the first search when none
@@ -84,7 +81,7 @@ impl FileSearchManager {
/// Call whenever the user edits the `@` token.
pub fn on_user_query(&self, query: String) {
{
#[allow(clippy::unwrap_used)]
#[expect(clippy::unwrap_used)]
let mut st = self.state.lock().unwrap();
if query == st.latest_query {
// No change, nothing to do.
@@ -125,7 +122,7 @@ impl FileSearchManager {
// `active_search` is cleared.
thread::sleep(FILE_SEARCH_DEBOUNCE);
loop {
#[allow(clippy::unwrap_used)]
#[expect(clippy::unwrap_used)]
if state.lock().unwrap().active_search.is_none() {
break;
}
@@ -137,7 +134,7 @@ impl FileSearchManager {
let cancellation_token = Arc::new(AtomicBool::new(false));
let token = cancellation_token.clone();
let query = {
#[allow(clippy::unwrap_used)]
#[expect(clippy::unwrap_used)]
let mut st = state.lock().unwrap();
let query = st.latest_query.clone();
st.is_search_scheduled = false;
@@ -188,7 +185,7 @@ impl FileSearchManager {
// that we are clearing the ActiveSearch that corresponds to the
// cancellation token we were given.
{
#[allow(clippy::unwrap_used)]
#[expect(clippy::unwrap_used)]
let mut st = search_state.lock().unwrap();
if let Some(active_search) = &st.active_search {
if Arc::ptr_eq(&active_search.cancellation_token, &cancellation_token) {
+13 -1
View File
@@ -37,6 +37,7 @@ use std::path::PathBuf;
use std::time::Duration;
use std::time::Instant;
use tracing::error;
use uuid::Uuid;
#[derive(Clone)]
pub(crate) struct CommandOutput {
@@ -483,7 +484,11 @@ pub(crate) fn new_diff_output(message: String) -> PlainHistoryCell {
PlainHistoryCell { lines }
}
pub(crate) fn new_status_output(config: &Config, usage: &TokenUsage) -> PlainHistoryCell {
pub(crate) fn new_status_output(
config: &Config,
usage: &TokenUsage,
session_id: &Option<Uuid>,
) -> PlainHistoryCell {
let mut lines: Vec<Line<'static>> = Vec::new();
lines.push(Line::from("/status".magenta()));
@@ -521,6 +526,13 @@ pub(crate) fn new_status_output(config: &Config, usage: &TokenUsage) -> PlainHis
sandbox_name.into(),
]));
if let Some(session_id) = session_id {
lines.push(Line::from(vec![
" • Session ID: ".into(),
session_id.to_string().into(),
]));
}
lines.push(Line::from(""));
// 👤 Account (only if ChatGPT tokens exist), shown under the first block
-1
View File
@@ -379,7 +379,6 @@ fn slice_line_spans(
#[cfg(test)]
mod tests {
#![allow(clippy::unwrap_used)]
use super::*;
#[test]
-1
View File
@@ -295,7 +295,6 @@ fn restore() {
}
}
#[allow(clippy::unwrap_used)]
fn should_show_login_screen(config: &Config) -> bool {
if config.model_provider.requires_openai_auth {
// Reading the OpenAI API key is an async operation because it may need
-1
View File
@@ -102,7 +102,6 @@ pub(crate) fn truncate_text(text: &str, max_graphemes: usize) -> String {
#[cfg(test)]
mod tests {
#![allow(clippy::unwrap_used)]
use super::*;
use pretty_assertions::assert_eq;