From 5ccbc78d644146791ff4f4c891f090b9aa8cec16 Mon Sep 17 00:00:00 2001 From: tupe12334 Date: Thu, 18 Jun 2026 09:10:50 +0300 Subject: [PATCH] chore(lint): enable clippy::indexing_slicing Deny direct indexing/slicing, which panics on out-of-bounds access. This completes the crate's no-panic lint family (unwrap_used, expect_used, panic, unreachable) by closing the remaining common panic source. Especially important here since the installer parses untrusted GitHub API JSON and checksum files from the network. Fixes the three resulting violations in src/github.rs by switching to fallible accessors (Value::get, split_once) with identical behavior. Closes #7 Co-Authored-By: Claude Opus 4.8 (1M context) --- lib/Cargo.toml | 4 ++++ lib/src/github.rs | 13 ++++++------- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/lib/Cargo.toml b/lib/Cargo.toml index f6d30cb..dec9ba9 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -37,6 +37,10 @@ unwrap_used = "deny" expect_used = "deny" panic = "deny" unreachable = "deny" +# Forbid direct indexing/slicing (`a[i]`, `a[i..j]`) which panics out of bounds. +# Completes the no-panic family above by closing the remaining common panic +# source; prefer `.get(i)` / `.get(i..j)` so malformed input is handled, not fatal. +indexing_slicing = "deny" # Allow pedantic lints that are too noisy for this codebase missing_errors_doc = "allow" missing_panics_doc = "allow" diff --git a/lib/src/github.rs b/lib/src/github.rs index c749e05..90d9087 100644 --- a/lib/src/github.rs +++ b/lib/src/github.rs @@ -76,8 +76,9 @@ pub fn resolve_version_from( let body: serde_json::Value = serde_json::from_str(&text) .map_err(|e| format!("failed to parse release JSON: {e}"))?; - let tag = body["tag_name"] - .as_str() + let tag = body + .get("tag_name") + .and_then(serde_json::Value::as_str) .ok_or("no stable release found")? .to_string(); @@ -162,11 +163,9 @@ pub fn release_info(tag: &str, platform: &Platform) -> ReleaseInfo { pub fn parse_checksum(checksums_text: &str, asset_name: &str) -> Result { for line in checksums_text.lines() { // Format: " " or " " - let parts: Vec<&str> = line.splitn(2, char::is_whitespace).collect(); - if parts.len() == 2 { - let filename = parts[1].trim(); - if filename == asset_name { - return Ok(parts[0].to_string()); + if let Some((hash, filename)) = line.split_once(char::is_whitespace) { + if filename.trim() == asset_name { + return Ok(hash.to_string()); } } }