diff --git a/.bazelrc b/.bazelrc index b9275426f..fd6ff75be 100644 --- a/.bazelrc +++ b/.bazelrc @@ -76,6 +76,44 @@ common:ci-bazel --build_metadata=TAG_workflow=bazel build:clippy --aspects=@rules_rust//rust:defs.bzl%rust_clippy_aspect build:clippy --output_groups=+clippy_checks build:clippy --@rules_rust//rust/settings:clippy.toml=//codex-rs:clippy.toml +# Keep this deny-list in sync with `codex-rs/Cargo.toml` `[workspace.lints.clippy]`. +# Cargo applies those lint levels to member crates that opt into `[lints] workspace = true` +# in their own `Cargo.toml`, but `rules_rust` Bazel clippy does not read Cargo lint levels. +# `clippy.toml` can configure lint behavior, but it cannot set allow/warn/deny/forbid levels. +build:clippy --@rules_rust//rust/settings:clippy_flag=-Dwarnings +build:clippy --@rules_rust//rust/settings:clippy_flag=--deny=clippy::expect_used +build:clippy --@rules_rust//rust/settings:clippy_flag=--deny=clippy::identity_op +build:clippy --@rules_rust//rust/settings:clippy_flag=--deny=clippy::manual_clamp +build:clippy --@rules_rust//rust/settings:clippy_flag=--deny=clippy::manual_filter +build:clippy --@rules_rust//rust/settings:clippy_flag=--deny=clippy::manual_find +build:clippy --@rules_rust//rust/settings:clippy_flag=--deny=clippy::manual_flatten +build:clippy --@rules_rust//rust/settings:clippy_flag=--deny=clippy::manual_map +build:clippy --@rules_rust//rust/settings:clippy_flag=--deny=clippy::manual_memcpy +build:clippy --@rules_rust//rust/settings:clippy_flag=--deny=clippy::manual_non_exhaustive +build:clippy --@rules_rust//rust/settings:clippy_flag=--deny=clippy::manual_ok_or +build:clippy --@rules_rust//rust/settings:clippy_flag=--deny=clippy::manual_range_contains +build:clippy --@rules_rust//rust/settings:clippy_flag=--deny=clippy::manual_retain +build:clippy --@rules_rust//rust/settings:clippy_flag=--deny=clippy::manual_strip +build:clippy --@rules_rust//rust/settings:clippy_flag=--deny=clippy::manual_try_fold +build:clippy --@rules_rust//rust/settings:clippy_flag=--deny=clippy::manual_unwrap_or +build:clippy --@rules_rust//rust/settings:clippy_flag=--deny=clippy::needless_borrow +build:clippy --@rules_rust//rust/settings:clippy_flag=--deny=clippy::needless_borrowed_reference +build:clippy --@rules_rust//rust/settings:clippy_flag=--deny=clippy::needless_collect +build:clippy --@rules_rust//rust/settings:clippy_flag=--deny=clippy::needless_late_init +build:clippy --@rules_rust//rust/settings:clippy_flag=--deny=clippy::needless_option_as_deref +build:clippy --@rules_rust//rust/settings:clippy_flag=--deny=clippy::needless_question_mark +build:clippy --@rules_rust//rust/settings:clippy_flag=--deny=clippy::needless_update +build:clippy --@rules_rust//rust/settings:clippy_flag=--deny=clippy::redundant_clone +build:clippy --@rules_rust//rust/settings:clippy_flag=--deny=clippy::redundant_closure +build:clippy --@rules_rust//rust/settings:clippy_flag=--deny=clippy::redundant_closure_for_method_calls +build:clippy --@rules_rust//rust/settings:clippy_flag=--deny=clippy::redundant_static_lifetimes +build:clippy --@rules_rust//rust/settings:clippy_flag=--deny=clippy::trivially_copy_pass_by_ref +build:clippy --@rules_rust//rust/settings:clippy_flag=--deny=clippy::uninlined_format_args +build:clippy --@rules_rust//rust/settings:clippy_flag=--deny=clippy::unnecessary_filter_map +build:clippy --@rules_rust//rust/settings:clippy_flag=--deny=clippy::unnecessary_lazy_evaluations +build:clippy --@rules_rust//rust/settings:clippy_flag=--deny=clippy::unnecessary_sort_by +build:clippy --@rules_rust//rust/settings:clippy_flag=--deny=clippy::unnecessary_to_owned +build:clippy --@rules_rust//rust/settings:clippy_flag=--deny=clippy::unwrap_used # Shared config for Bazel-backed argument-comment-lint. build:argument-comment-lint --aspects=//tools/argument-comment-lint:lint_aspect.bzl%rust_argument_comment_lint_aspect diff --git a/.github/scripts/verify_bazel_clippy_lints.py b/.github/scripts/verify_bazel_clippy_lints.py new file mode 100644 index 000000000..6b2797397 --- /dev/null +++ b/.github/scripts/verify_bazel_clippy_lints.py @@ -0,0 +1,234 @@ +#!/usr/bin/env python3 + +from __future__ import annotations + +import argparse +import re +import sys +import tomllib +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[2] +DEFAULT_CARGO_TOML = ROOT / "codex-rs" / "Cargo.toml" +DEFAULT_BAZELRC = ROOT / ".bazelrc" +BAZEL_CLIPPY_FLAG_PREFIX = "build:clippy --@rules_rust//rust/settings:clippy_flag=" +BAZEL_SPECIAL_FLAGS = {"-Dwarnings"} +VALID_LEVELS = {"allow", "warn", "deny", "forbid"} +LONG_FLAG_RE = re.compile( + r"^--(?Pallow|warn|deny|forbid)=clippy::(?P[a-z0-9_]+)$" +) +SHORT_FLAG_RE = re.compile(r"^-(?P[AWDF])clippy::(?P[a-z0-9_]+)$") +SHORT_LEVEL_NAMES = { + "A": "allow", + "W": "warn", + "D": "deny", + "F": "forbid", +} + + +def main() -> int: + parser = argparse.ArgumentParser( + description=( + "Verify that Bazel clippy flags in .bazelrc stay in sync with " + "codex-rs/Cargo.toml [workspace.lints.clippy]." + ) + ) + parser.add_argument( + "--cargo-toml", + type=Path, + default=DEFAULT_CARGO_TOML, + help="Path to the workspace Cargo.toml to inspect.", + ) + parser.add_argument( + "--bazelrc", + type=Path, + default=DEFAULT_BAZELRC, + help="Path to the .bazelrc file to inspect.", + ) + args = parser.parse_args() + + cargo_toml = args.cargo_toml.resolve() + bazelrc = args.bazelrc.resolve() + + cargo_lints = load_workspace_clippy_lints(cargo_toml) + bazel_lints = load_bazel_clippy_lints(bazelrc) + + missing = sorted(cargo_lints.keys() - bazel_lints.keys()) + extra = sorted(bazel_lints.keys() - cargo_lints.keys()) + mismatched = sorted( + lint + for lint in cargo_lints.keys() & bazel_lints.keys() + if cargo_lints[lint] != bazel_lints[lint] + ) + + if missing or extra or mismatched: + print_sync_error( + cargo_toml=cargo_toml, + bazelrc=bazelrc, + cargo_lints=cargo_lints, + bazel_lints=bazel_lints, + missing=missing, + extra=extra, + mismatched=mismatched, + ) + return 1 + + print( + "Bazel clippy flags in " + f"{display_path(bazelrc)} match " + f"{display_path(cargo_toml)} [workspace.lints.clippy]." + ) + return 0 + + +def load_workspace_clippy_lints(cargo_toml: Path) -> dict[str, str]: + workspace = tomllib.loads(cargo_toml.read_text())["workspace"] + clippy_lints = workspace["lints"]["clippy"] + parsed: dict[str, str] = {} + for lint, level in clippy_lints.items(): + if not isinstance(level, str): + raise SystemExit( + f"expected string lint level for clippy::{lint} in {cargo_toml}, got {level!r}" + ) + normalized = level.strip().lower() + if normalized not in VALID_LEVELS: + raise SystemExit( + f"unsupported lint level {level!r} for clippy::{lint} in {cargo_toml}" + ) + parsed[lint] = normalized + return parsed + + +def load_bazel_clippy_lints(bazelrc: Path) -> dict[str, str]: + parsed: dict[str, str] = {} + line_numbers: dict[str, int] = {} + + for lineno, line in enumerate(bazelrc.read_text().splitlines(), start=1): + if not line.startswith(BAZEL_CLIPPY_FLAG_PREFIX): + continue + + flag = line.removeprefix(BAZEL_CLIPPY_FLAG_PREFIX).strip() + if flag in BAZEL_SPECIAL_FLAGS: + continue + + parsed_flag = parse_bazel_lint_flag(flag) + if parsed_flag is None: + continue + + lint, level = parsed_flag + if lint in parsed: + raise SystemExit( + f"duplicate Bazel clippy entry for clippy::{lint} at " + f"{bazelrc}:{line_numbers[lint]} and {bazelrc}:{lineno}" + ) + parsed[lint] = level + line_numbers[lint] = lineno + + return parsed + + +def parse_bazel_lint_flag(flag: str) -> tuple[str, str] | None: + long_match = LONG_FLAG_RE.match(flag) + if long_match: + return long_match["lint"], long_match["level"] + + short_match = SHORT_FLAG_RE.match(flag) + if short_match: + return short_match["lint"], SHORT_LEVEL_NAMES[short_match["level"]] + + return None + + +def print_sync_error( + *, + cargo_toml: Path, + bazelrc: Path, + cargo_lints: dict[str, str], + bazel_lints: dict[str, str], + missing: list[str], + extra: list[str], + mismatched: list[str], +) -> None: + cargo_toml_display = display_path(cargo_toml) + bazelrc_display = display_path(bazelrc) + example_manifest = find_workspace_lints_example_manifest() + + print( + "ERROR: Bazel clippy flags are out of sync with Cargo workspace clippy lints.", + file=sys.stderr, + ) + print(file=sys.stderr) + print( + f"Cargo defines the source of truth in {cargo_toml_display} " + "[workspace.lints.clippy].", + file=sys.stderr, + ) + if example_manifest is not None: + print( + "Cargo applies those lint levels to member crates that opt into " + f"`[lints] workspace = true`, for example {example_manifest}.", + file=sys.stderr, + ) + print( + "Bazel clippy does not ingest Cargo lint levels automatically, and " + "`clippy.toml` can configure lint behavior but cannot set allow/warn/deny/forbid.", + file=sys.stderr, + ) + print( + f"Update {bazelrc_display} so its `build:clippy` " + "`clippy_flag` entries match Cargo.", + file=sys.stderr, + ) + + if missing: + print(file=sys.stderr) + print("Missing Bazel entries:", file=sys.stderr) + for lint in missing: + print(f" {render_bazelrc_line(lint, cargo_lints[lint])}", file=sys.stderr) + + if mismatched: + print(file=sys.stderr) + print("Mismatched lint levels:", file=sys.stderr) + for lint in mismatched: + cargo_level = cargo_lints[lint] + bazel_level = bazel_lints[lint] + print( + f" clippy::{lint}: Cargo has {cargo_level}, Bazel has {bazel_level}", + file=sys.stderr, + ) + print( + f" expected: {render_bazelrc_line(lint, cargo_level)}", + file=sys.stderr, + ) + + if extra: + print(file=sys.stderr) + print("Extra Bazel entries with no Cargo counterpart:", file=sys.stderr) + for lint in extra: + print(f" {render_bazelrc_line(lint, bazel_lints[lint])}", file=sys.stderr) + + +def render_bazelrc_line(lint: str, level: str) -> str: + return f"{BAZEL_CLIPPY_FLAG_PREFIX}--{level}=clippy::{lint}" + + +def display_path(path: Path) -> str: + try: + return str(path.relative_to(ROOT)) + except ValueError: + return str(path) + + +def find_workspace_lints_example_manifest() -> str | None: + for cargo_toml in sorted((ROOT / "codex-rs").glob("**/Cargo.toml")): + if cargo_toml == DEFAULT_CARGO_TOML: + continue + data = tomllib.loads(cargo_toml.read_text()) + if data.get("lints", {}).get("workspace") is True: + return str(cargo_toml.relative_to(ROOT)) + return None + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d32a8fd0a..76a8aa014 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,6 +17,9 @@ jobs: - name: Verify codex-rs Cargo manifests inherit workspace settings run: python3 .github/scripts/verify_cargo_workspace_manifests.py + - name: Verify Bazel clippy flags match Cargo workspace lints + run: python3 .github/scripts/verify_bazel_clippy_lints.py + - name: Setup pnpm uses: pnpm/action-setup@a8198c4bff370c8506180b035930dea56dbd5288 # v5 with: diff --git a/codex-rs/backend-client/src/types.rs b/codex-rs/backend-client/src/types.rs index 2559b2b39..4ef0fb846 100644 --- a/codex-rs/backend-client/src/types.rs +++ b/codex-rs/backend-client/src/types.rs @@ -309,7 +309,7 @@ where D: Deserializer<'de>, T: Deserialize<'de>, { - Option::>::deserialize(deserializer).map(|opt| opt.unwrap_or_default()) + Option::>::deserialize(deserializer).map(Option::unwrap_or_default) } #[derive(Clone, Debug, Deserialize)] diff --git a/codex-rs/core/tests/common/lib.rs b/codex-rs/core/tests/common/lib.rs index 8c03971ad..8aff42e96 100644 --- a/codex-rs/core/tests/common/lib.rs +++ b/codex-rs/core/tests/common/lib.rs @@ -287,7 +287,7 @@ where F: Fn(&codex_protocol::protocol::EventMsg) -> Option, { let ev = wait_for_event(codex, |ev| matcher(ev).is_some()).await; - matcher(&ev).unwrap() + matcher(&ev).expect("EventMsg should match matcher predicate") } pub async fn wait_for_event_with_timeout( @@ -417,7 +417,7 @@ pub mod fs_wait { let deadline = Instant::now() + timeout; loop { if path.exists() { - return Ok(path.clone()); + return Ok(path); } let now = Instant::now(); if now >= deadline { @@ -427,7 +427,7 @@ pub mod fs_wait { match rx.recv_timeout(remaining) { Ok(Ok(_event)) => { if path.exists() { - return Ok(path.clone()); + return Ok(path); } } Ok(Err(err)) => return Err(err.into()), diff --git a/codex-rs/core/tests/common/responses.rs b/codex-rs/core/tests/common/responses.rs index 0971c0284..2e2155ebd 100644 --- a/codex-rs/core/tests/common/responses.rs +++ b/codex-rs/core/tests/common/responses.rs @@ -1,3 +1,5 @@ +#![allow(clippy::unwrap_used)] + use std::collections::VecDeque; use std::sync::Arc; use std::sync::Mutex; diff --git a/codex-rs/core/tests/common/test_codex.rs b/codex-rs/core/tests/common/test_codex.rs index 90ea36776..3b910838b 100644 --- a/codex-rs/core/tests/common/test_codex.rs +++ b/codex-rs/core/tests/common/test_codex.rs @@ -270,7 +270,7 @@ fn docker_command_success(args: [&str; N]) -> Result<()> { let output = Command::new("docker") .args(args) .output() - .with_context(|| format!("run docker {:?}", args))?; + .with_context(|| format!("run docker {args:?}"))?; if !output.status.success() { return Err(anyhow!( "docker {:?} failed: stdout={} stderr={}", @@ -286,7 +286,7 @@ fn docker_command_capture_stdout(args: [&str; N]) -> Result Self { let new_model = model.to_string(); self.with_config(move |config| { - config.model = Some(new_model.clone()); + config.model = Some(new_model); }) } diff --git a/codex-rs/windows-sandbox-rs/src/acl.rs b/codex-rs/windows-sandbox-rs/src/acl.rs index 998bd5d70..f351dba19 100644 --- a/codex-rs/windows-sandbox-rs/src/acl.rs +++ b/codex-rs/windows-sandbox-rs/src/acl.rs @@ -327,13 +327,13 @@ unsafe fn ensure_allow_mask_aces_with_inheritance_impl( if !p_sd.is_null() { LocalFree(p_sd as HLOCAL); } - return Err(anyhow!("SetNamedSecurityInfoW failed: {}", code3)); + return Err(anyhow!("SetNamedSecurityInfoW failed: {code3}")); } } else { if !p_sd.is_null() { LocalFree(p_sd as HLOCAL); } - return Err(anyhow!("SetEntriesInAclW failed: {}", code2)); + return Err(anyhow!("SetEntriesInAclW failed: {code2}")); } } if !p_sd.is_null() { @@ -401,7 +401,7 @@ pub unsafe fn add_allow_ace(path: &Path, psid: *mut c_void) -> Result { &mut p_sd, ); if code != ERROR_SUCCESS { - return Err(anyhow!("GetNamedSecurityInfoW failed: {}", code)); + return Err(anyhow!("GetNamedSecurityInfoW failed: {code}")); } // Already has write? Skip costly DACL rewrite. if dacl_has_write_allow_for_sid(p_dacl, psid) { @@ -467,7 +467,7 @@ pub unsafe fn add_deny_write_ace(path: &Path, psid: *mut c_void) -> Result &mut p_sd, ); if code != ERROR_SUCCESS { - return Err(anyhow!("GetNamedSecurityInfoW failed: {}", code)); + return Err(anyhow!("GetNamedSecurityInfoW failed: {code}")); } let mut added = false; if !dacl_has_write_deny_for_sid(p_dacl, psid) { diff --git a/codex-rs/windows-sandbox-rs/src/audit.rs b/codex-rs/windows-sandbox-rs/src/audit.rs index 0f115323e..9ee371ce6 100644 --- a/codex-rs/windows-sandbox-rs/src/audit.rs +++ b/codex-rs/windows-sandbox-rs/src/audit.rs @@ -194,8 +194,7 @@ pub fn audit_everyone_writable( } crate::logging::log_note( &format!( - "AUDIT: world-writable scan FAILED; cwd={cwd:?}; checked={checked}; duration_ms={elapsed_ms}; flagged:{}", - list + "AUDIT: world-writable scan FAILED; cwd={cwd:?}; checked={checked}; duration_ms={elapsed_ms}; flagged:{list}", ), logs_base_dir, ); @@ -229,7 +228,7 @@ pub fn apply_world_writable_scan_and_denies( logs_base_dir, ) { log_note( - &format!("AUDIT: failed to apply capability deny ACEs: {}", err), + &format!("AUDIT: failed to apply capability deny ACEs: {err}"), logs_base_dir, ); } diff --git a/codex-rs/windows-sandbox-rs/src/cap.rs b/codex-rs/windows-sandbox-rs/src/cap.rs index a699d81d2..79f3b2f26 100644 --- a/codex-rs/windows-sandbox-rs/src/cap.rs +++ b/codex-rs/windows-sandbox-rs/src/cap.rs @@ -34,7 +34,7 @@ fn make_random_cap_sid_string() -> String { let b = rng.next_u32(); let c = rng.next_u32(); let d = rng.next_u32(); - format!("S-1-5-21-{}-{}-{}-{}", a, b, c, d) + format!("S-1-5-21-{a}-{b}-{c}-{d}") } fn persist_caps(path: &Path, caps: &CapSids) -> Result<()> { diff --git a/codex-rs/windows-sandbox-rs/src/elevated/command_runner_win.rs b/codex-rs/windows-sandbox-rs/src/elevated/command_runner_win.rs index 5572c1bf8..7777055e2 100644 --- a/codex-rs/windows-sandbox-rs/src/elevated/command_runner_win.rs +++ b/codex-rs/windows-sandbox-rs/src/elevated/command_runner_win.rs @@ -480,7 +480,7 @@ pub fn main() -> Result<()> { let _ = send_error(&pipe_write, "spawn_failed", err.to_string()); return Err(err); } - let log_dir_owned = log_dir.map(|p| p.to_path_buf()); + let log_dir_owned = log_dir.map(Path::to_path_buf); let out_thread = spawn_output_reader( Arc::clone(&pipe_write), stdout_handle, diff --git a/codex-rs/windows-sandbox-rs/src/elevated/ipc_framed.rs b/codex-rs/windows-sandbox-rs/src/elevated/ipc_framed.rs index d56ec1d0e..3f3425eb0 100644 --- a/codex-rs/windows-sandbox-rs/src/elevated/ipc_framed.rs +++ b/codex-rs/windows-sandbox-rs/src/elevated/ipc_framed.rs @@ -144,7 +144,7 @@ pub fn read_frame(mut reader: R) -> Result> { } let len = u32::from_le_bytes(len_buf) as usize; if len > MAX_FRAME_LEN { - anyhow::bail!("frame too large: {}", len); + anyhow::bail!("frame too large: {len}"); } let mut payload = vec![0u8; len]; reader.read_exact(&mut payload)?; diff --git a/codex-rs/windows-sandbox-rs/src/elevated_impl.rs b/codex-rs/windows-sandbox-rs/src/elevated_impl.rs index 588e65d96..87ff706e7 100644 --- a/codex-rs/windows-sandbox-rs/src/elevated_impl.rs +++ b/codex-rs/windows-sandbox-rs/src/elevated_impl.rs @@ -93,7 +93,7 @@ mod windows_impl { } else { cur.join(gitdir) }; - return resolved.parent().map(|p| p.to_path_buf()).or(Some(cur)); + return resolved.parent().map(Path::to_path_buf).or(Some(cur)); } return Some(cur); } @@ -270,17 +270,22 @@ mod windows_impl { } let caps = load_or_create_cap_sids(codex_home)?; let (psid_to_use, cap_sids) = match &policy { - SandboxPolicy::ReadOnly { .. } => ( - unsafe { convert_string_sid_to_sid(&caps.readonly).unwrap() }, - vec![caps.readonly.clone()], - ), - SandboxPolicy::WorkspaceWrite { .. } => ( - unsafe { convert_string_sid_to_sid(&caps.workspace).unwrap() }, - vec![ - caps.workspace.clone(), - crate::cap::workspace_cap_sid_for_cwd(codex_home, cwd)?, - ], - ), + SandboxPolicy::ReadOnly { .. } => { + #[allow(clippy::unwrap_used)] + let psid = unsafe { convert_string_sid_to_sid(&caps.readonly).unwrap() }; + (psid, vec![caps.readonly]) + } + SandboxPolicy::WorkspaceWrite { .. } => { + #[allow(clippy::unwrap_used)] + let psid = unsafe { convert_string_sid_to_sid(&caps.workspace).unwrap() }; + ( + psid, + vec![ + caps.workspace, + crate::cap::workspace_cap_sid_for_cwd(codex_home, cwd)?, + ], + ) + } SandboxPolicy::DangerFullAccess | SandboxPolicy::ExternalSandbox { .. } => { unreachable!("DangerFullAccess handled above") } @@ -302,7 +307,7 @@ mod windows_impl { let runner_exe = find_runner_exe(codex_home, logs_base_dir); let runner_cmdline = runner_exe .to_str() - .map(|s| s.to_string()) + .map(ToString::to_string) .unwrap_or_else(|| "codex-command-runner.exe".to_string()); let runner_full_cmd = format!( "{} {} {}", @@ -365,7 +370,7 @@ mod windows_impl { ), logs_base_dir, ); - return Err(anyhow::anyhow!("CreateProcessWithLogonW failed: {}", err)); + return Err(anyhow::anyhow!("CreateProcessWithLogonW failed: {err}")); } if let Err(err) = connect_pipe(h_pipe_in) { @@ -451,7 +456,7 @@ mod windows_impl { if exit_code == 0 { log_success(&command, logs_base_dir); } else { - log_failure(&command, &format!("exit code {}", exit_code), logs_base_dir); + log_failure(&command, &format!("exit code {exit_code}"), logs_base_dir); } Ok(CaptureResult { diff --git a/codex-rs/windows-sandbox-rs/src/env.rs b/codex-rs/windows-sandbox-rs/src/env.rs index c3f85cfff..93275e1ab 100644 --- a/codex-rs/windows-sandbox-rs/src/env.rs +++ b/codex-rs/windows-sandbox-rs/src/env.rs @@ -48,7 +48,7 @@ fn prepend_path(env_map: &mut HashMap, prefix: &str) { .cloned() .or_else(|| env::var("PATH").ok()) .unwrap_or_default(); - let parts: Vec = existing.split(';').map(|s| s.to_string()).collect(); + let parts: Vec = existing.split(';').map(ToString::to_string).collect(); if parts .first() .map(|p| p.eq_ignore_ascii_case(prefix)) @@ -74,7 +74,7 @@ fn reorder_pathext_for_stubs(env_map: &mut HashMap) { let exts: Vec = default .split(';') .filter(|e| !e.is_empty()) - .map(|s| s.to_string()) + .map(ToString::to_string) .collect(); let exts_norm: Vec = exts.iter().map(|e| e.to_ascii_uppercase()).collect(); let want = [".BAT", ".CMD"]; @@ -110,7 +110,7 @@ fn ensure_denybin(tools: &[&str], denybin_dir: Option<&Path>) -> Result fs::create_dir_all(&base)?; for tool in tools { for ext in [".bat", ".cmd"] { - let path = base.join(format!("{}{}", tool, ext)); + let path = base.join(format!("{tool}{ext}")); if !path.exists() { let mut f = File::create(&path)?; f.write_all(b"@echo off\\r\\nexit /b 1\\r\\n")?; @@ -162,7 +162,7 @@ pub fn apply_no_network_to_env(env_map: &mut HashMap) -> Result< let base = ensure_denybin(&["ssh", "scp"], /*denybin_dir*/ None)?; for tool in ["curl", "wget"] { for ext in [".bat", ".cmd"] { - let p = base.join(format!("{}{}", tool, ext)); + let p = base.join(format!("{tool}{ext}")); if p.exists() { let _ = fs::remove_file(&p); } diff --git a/codex-rs/windows-sandbox-rs/src/identity.rs b/codex-rs/windows-sandbox-rs/src/identity.rs index b7768c1a3..70ec48fe6 100644 --- a/codex-rs/windows-sandbox-rs/src/identity.rs +++ b/codex-rs/windows-sandbox-rs/src/identity.rs @@ -122,7 +122,7 @@ fn select_identity( }; let password = decode_password(&chosen)?; Ok(Some(SandboxIdentity { - username: chosen.username.clone(), + username: chosen.username, password, })) } @@ -187,8 +187,8 @@ pub fn require_logon_sandbox_creds( proxy_enforced, }, crate::setup::SetupRootOverrides { - read_roots: Some(needed_read.clone()), - write_roots: Some(needed_write.clone()), + read_roots: Some(needed_read), + write_roots: Some(needed_write), }, )?; identity = select_identity(network_identity, codex_home)?; diff --git a/codex-rs/windows-sandbox-rs/src/lib.rs b/codex-rs/windows-sandbox-rs/src/lib.rs index 2030919fd..9dea9414b 100644 --- a/codex-rs/windows-sandbox-rs/src/lib.rs +++ b/codex-rs/windows-sandbox-rs/src/lib.rs @@ -335,14 +335,20 @@ mod windows_impl { let (h_token, psid_generic, psid_workspace): (HANDLE, *mut c_void, Option<*mut c_void>) = unsafe { match &policy { SandboxPolicy::ReadOnly { .. } => { - let psid = convert_string_sid_to_sid(&caps.readonly).unwrap(); + #[allow(clippy::expect_used)] + let psid = + convert_string_sid_to_sid(&caps.readonly).expect("valid readonly SID"); let (h, _) = super::token::create_readonly_token_with_cap(psid)?; (h, psid, None) } SandboxPolicy::WorkspaceWrite { .. } => { - let psid_generic = convert_string_sid_to_sid(&caps.workspace).unwrap(); + #[allow(clippy::expect_used)] + let psid_generic = + convert_string_sid_to_sid(&caps.workspace).expect("valid workspace SID"); let ws_sid = workspace_cap_sid_for_cwd(codex_home, cwd)?; - let psid_workspace = convert_string_sid_to_sid(&ws_sid).unwrap(); + #[allow(clippy::expect_used)] + let psid_workspace = + convert_string_sid_to_sid(&ws_sid).expect("valid workspace SID"); let base = super::token::get_current_token_for_restriction()?; let h_res = create_workspace_write_token_with_caps_from( base, @@ -363,7 +369,7 @@ mod windows_impl { && let Ok(base) = super::token::get_current_token_for_restriction() { if let Ok(bytes) = super::token::get_logon_sid_bytes(base) { - let mut tmp = bytes.clone(); + let mut tmp = bytes; let psid2 = tmp.as_mut_ptr() as *mut c_void; allow_null_device(psid2); } @@ -536,7 +542,7 @@ mod windows_impl { if exit_code == 0 { log_success(&command, logs_base_dir); } else { - log_failure(&command, &format!("exit code {}", exit_code), logs_base_dir); + log_failure(&command, &format!("exit code {exit_code}"), logs_base_dir); } if !persist_aces { @@ -569,9 +575,11 @@ mod windows_impl { ensure_codex_home_exists(codex_home)?; let caps = load_or_create_cap_sids(codex_home)?; + #[allow(clippy::expect_used)] let psid_generic = unsafe { convert_string_sid_to_sid(&caps.workspace) }.expect("valid workspace SID"); let ws_sid = workspace_cap_sid_for_cwd(codex_home, cwd)?; + #[allow(clippy::expect_used)] let psid_workspace = unsafe { convert_string_sid_to_sid(&ws_sid) }.expect("valid workspace SID"); let current_dir = cwd.to_path_buf(); diff --git a/codex-rs/windows-sandbox-rs/src/process.rs b/codex-rs/windows-sandbox-rs/src/process.rs index 683048959..ec31b06b5 100644 --- a/codex-rs/windows-sandbox-rs/src/process.rs +++ b/codex-rs/windows-sandbox-rs/src/process.rs @@ -43,7 +43,7 @@ pub fn make_env_block(env: &HashMap) -> Vec { }); let mut w: Vec = Vec::new(); for (k, v) in items { - let mut s = to_wide(format!("{}={}", k, v)); + let mut s = to_wide(format!("{k}={v}")); s.pop(); w.extend_from_slice(&s); w.push(0); @@ -149,7 +149,7 @@ pub unsafe fn create_process_as_user( creation_flags, ); logging::debug_log(&msg, logs_base_dir); - return Err(anyhow!("CreateProcessAsUserW failed: {}", err)); + return Err(anyhow!("CreateProcessAsUserW failed: {err}")); } Ok(CreatedProcess { process_info: pi, diff --git a/codex-rs/windows-sandbox-rs/src/read_acl_mutex.rs b/codex-rs/windows-sandbox-rs/src/read_acl_mutex.rs index 643d70fa3..d77129467 100644 --- a/codex-rs/windows-sandbox-rs/src/read_acl_mutex.rs +++ b/codex-rs/windows-sandbox-rs/src/read_acl_mutex.rs @@ -35,7 +35,7 @@ pub fn read_acl_mutex_exists() -> Result { if err == ERROR_FILE_NOT_FOUND { return Ok(false); } - return Err(anyhow::anyhow!("OpenMutexW failed: {}", err)); + return Err(anyhow::anyhow!("OpenMutexW failed: {err}")); } unsafe { CloseHandle(handle); diff --git a/codex-rs/windows-sandbox-rs/src/setup_main_win.rs b/codex-rs/windows-sandbox-rs/src/setup_main_win.rs index 569643285..e3f200ca7 100644 --- a/codex-rs/windows-sandbox-rs/src/setup_main_win.rs +++ b/codex-rs/windows-sandbox-rs/src/setup_main_win.rs @@ -312,8 +312,7 @@ fn lock_sandbox_dir( ); if set != 0 { return Err(anyhow::anyhow!( - "SetEntriesInAclW sandbox dir failed: {}", - set + "SetEntriesInAclW sandbox dir failed: {set}", )); } let path_w = to_wide(dir.as_os_str()); @@ -328,8 +327,7 @@ fn lock_sandbox_dir( ); if res != 0 { return Err(anyhow::anyhow!( - "SetNamedSecurityInfoW sandbox dir failed: {}", - res + "SetNamedSecurityInfoW sandbox dir failed: {res}", )); } if !new_dacl.is_null() { @@ -424,7 +422,7 @@ fn real_main() -> Result<()> { }); let report = SetupErrorReport { code: failure.code, - message: failure.message.clone(), + message: failure.message, }; if let Err(write_err) = write_setup_error_report(&payload.codex_home, &report) { let _ = log_line( @@ -496,7 +494,7 @@ fn run_read_acl_only(payload: &Payload, log: &mut File) -> Result<()> { if !refresh_errors.is_empty() { log_line( log, - &format!("read ACL run completed with errors: {:?}", refresh_errors), + &format!("read ACL run completed with errors: {refresh_errors:?}"), )?; if payload.refresh_only { anyhow::bail!("read ACL run had errors"); @@ -637,7 +635,7 @@ fn run_setup_full(payload: &Payload, log: &mut File, sbx_dir: &Path) -> Result<( } } - let cap_sid_str = caps.workspace.clone(); + let cap_sid_str = caps.workspace; let sandbox_group_sid_str = string_from_sid_bytes(&sandbox_group_sid).map_err(anyhow::Error::msg)?; let write_mask = @@ -895,7 +893,7 @@ fn run_setup_full(payload: &Payload, log: &mut File, sbx_dir: &Path) -> Result<( if refresh_only && !refresh_errors.is_empty() { log_line( log, - &format!("setup refresh completed with errors: {:?}", refresh_errors), + &format!("setup refresh completed with errors: {refresh_errors:?}"), )?; anyhow::bail!("setup refresh had errors"); } diff --git a/codex-rs/windows-sandbox-rs/src/setup_orchestrator.rs b/codex-rs/windows-sandbox-rs/src/setup_orchestrator.rs index f6583e0de..99a11e631 100644 --- a/codex-rs/windows-sandbox-rs/src/setup_orchestrator.rs +++ b/codex-rs/windows-sandbox-rs/src/setup_orchestrator.rs @@ -201,7 +201,7 @@ fn run_setup_refresh_inner( &format!("setup refresh: exited with status {status:?}"), Some(&sandbox_dir(request.codex_home)), ); - return Err(anyhow!("setup refresh failed with status {}", status)); + return Err(anyhow!("setup refresh failed with status {status}")); } Ok(()) } diff --git a/codex-rs/windows-sandbox-rs/src/token.rs b/codex-rs/windows-sandbox-rs/src/token.rs index 56d97ff01..7d7a6c5c4 100644 --- a/codex-rs/windows-sandbox-rs/src/token.rs +++ b/codex-rs/windows-sandbox-rs/src/token.rs @@ -78,7 +78,7 @@ unsafe fn set_default_dacl(h_token: HANDLE, sids: &[*mut c_void]) -> Result<()> &mut p_new_dacl, ); if res != ERROR_SUCCESS { - return Err(anyhow!("SetEntriesInAclW failed: {}", res)); + return Err(anyhow!("SetEntriesInAclW failed: {res}")); } let mut info = TokenDefaultDaclInfo { default_dacl: p_new_dacl, @@ -95,8 +95,7 @@ unsafe fn set_default_dacl(h_token: HANDLE, sids: &[*mut c_void]) -> Result<()> LocalFree(p_new_dacl as HLOCAL); } return Err(anyhow!( - "SetTokenInformation(TokenDefaultDacl) failed: {}", - err + "SetTokenInformation(TokenDefaultDacl) failed: {err}", )); } if !p_new_dacl.is_null() { @@ -277,7 +276,7 @@ unsafe fn enable_single_privilege(h_token: HANDLE, name: &str) -> Result<()> { } let err = GetLastError(); if err != 0 { - return Err(anyhow!("AdjustTokenPrivileges error {}", err)); + return Err(anyhow!("AdjustTokenPrivileges error {err}")); } Ok(()) } diff --git a/codex-rs/windows-sandbox-rs/src/winutil.rs b/codex-rs/windows-sandbox-rs/src/winutil.rs index 6ba34f620..1486c7f85 100644 --- a/codex-rs/windows-sandbox-rs/src/winutil.rs +++ b/codex-rs/windows-sandbox-rs/src/winutil.rs @@ -83,7 +83,7 @@ pub fn format_last_error(err: i32) -> String { std::ptr::null_mut(), ); if len == 0 || buf_ptr.is_null() { - return format!("Win32 error {}", err); + return format!("Win32 error {err}"); } let slice = std::slice::from_raw_parts(buf_ptr, len as usize); let mut s = String::from_utf16_lossy(slice);