🦀 Rust Guard Improvement Report
Improvement 1: Avoid Heap Allocation in is_trusted_first_party_bot
Category: Performance (WASM-specific) / Type Safety & Idioms
File(s): guards/github-guard/rust-guard/src/labels/helpers.rs
Effort: Small (< 15 min)
Risk: Low
Problem
is_trusted_first_party_bot (line 1294) calls username.to_lowercase() before performing its comparisons. This allocates a new String on the heap on every single call — even when the input is already lowercase ASCII. The function is called on every PR, issue, and commit integrity decision.
This is inconsistent with the established pattern elsewhere in the same file: username_in_list (line 248) uses eq_ignore_ascii_case, which is a zero-allocation in-place comparison. All bot names in the hardcoded list are pure ASCII lowercase, so eq_ignore_ascii_case is semantically identical but allocation-free.
Before
// labels/helpers.rs:1294-1305
pub fn is_trusted_first_party_bot(username: &str) -> bool {
let lower = username.to_lowercase(); // heap allocation every call
lower == "dependabot[bot]"
|| lower == "github-actions[bot]"
|| lower == "github-actions"
|| lower == "app/github-actions"
|| lower == "github-merge-queue[bot]"
|| lower == "copilot"
|| lower == "copilot-swe-agent[bot]"
|| lower == "copilot-swe-agent"
|| lower == "app/copilot-swe-agent"
}
After
pub fn is_trusted_first_party_bot(username: &str) -> bool {
username.eq_ignore_ascii_case("dependabot[bot]")
|| username.eq_ignore_ascii_case("github-actions[bot]")
|| username.eq_ignore_ascii_case("github-actions")
|| username.eq_ignore_ascii_case("app/github-actions")
|| username.eq_ignore_ascii_case("github-merge-queue[bot]")
|| username.eq_ignore_ascii_case("copilot")
|| username.eq_ignore_ascii_case("copilot-swe-agent[bot]")
|| username.eq_ignore_ascii_case("copilot-swe-agent")
|| username.eq_ignore_ascii_case("app/copilot-swe-agent")
}
Why This Matters
- Zero allocation:
eq_ignore_ascii_case compares byte-by-byte in place — no String is created or dropped.
- WASM budget: In WASM, every heap allocation goes through the linear memory allocator. Avoiding it on a hot path matters.
- Consistency: The existing helper
username_in_list already uses eq_ignore_ascii_case for case-insensitive matching; this brings is_trusted_first_party_bot in line with that pattern.
- Correctness preserved: All bot name literals are pure ASCII lowercase, so
eq_ignore_ascii_case produces identical results to to_lowercase() + ==.
Improvement 2: Remove Stale #[allow(dead_code)] from Logging API in lib.rs
Category: Dead Code
File(s): guards/github-guard/rust-guard/src/lib.rs
Effort: Small (< 15 min)
Risk: Low
Problem
Six items in lib.rs carry #[allow(dead_code)] even though they are all actively used:
| Item |
Line |
Why the attribute is stale |
invoke_backend |
99 |
pub fn — Rust never emits dead_code for public items; additionally, it's referenced as crate::invoke_backend in labels/backend.rs:85,384,388,546 |
LogLevel enum |
137 |
All four variants are used by the log_xxx helpers below |
log_debug |
156 |
Called via crate::log_debug() in labels/backend.rs and labels/helpers.rs |
log_info |
161 |
Called via crate::log_info() in labels/backend.rs, labels/helpers.rs, labels/tool_rules.rs |
log_warn |
166 |
Called via crate::log_warn() in labels/backend.rs |
log_error |
171 |
Called via crate::log_error() in labels/backend.rs |
Suppressing dead_code on live code is misleading: it implies the items might be dead (or were dead at some point), making reviewers wonder whether they're safe to delete. It also disables the compiler's ability to alert on a future regression where the functions genuinely become unused.
Before
// lib.rs
#[allow(dead_code)]
pub fn invoke_backend(tool_name: &str, args_json: &str, result_buffer: &mut [u8]) -> Result<usize, i32> { ... }
#[repr(u32)]
#[allow(dead_code)]
pub enum LogLevel { Debug = 0, Info = 1, Warn = 2, Error = 3 }
#[allow(dead_code)]
fn log_debug(msg: &str) { log(LogLevel::Debug, msg); }
#[allow(dead_code)]
fn log_info(msg: &str) { log(LogLevel::Info, msg); }
#[allow(dead_code)]
fn log_warn(msg: &str) { log(LogLevel::Warn, msg); }
#[allow(dead_code)]
fn log_error(msg: &str) { log(LogLevel::Error, msg); }
After
pub fn invoke_backend(tool_name: &str, args_json: &str, result_buffer: &mut [u8]) -> Result<usize, i32> { ... }
#[repr(u32)]
pub enum LogLevel { Debug = 0, Info = 1, Warn = 2, Error = 3 }
fn log_debug(msg: &str) { log(LogLevel::Debug, msg); }
fn log_info(msg: &str) { log(LogLevel::Info, msg); }
fn log_warn(msg: &str) { log(LogLevel::Warn, msg); }
fn log_error(msg: &str) { log(LogLevel::Error, msg); }
Why This Matters
- Clarity: Removing the annotations signals clearly that these items are live and intentional, not leftover scaffolding.
- Compiler safety net restored: If a future refactor stops calling any of these, the compiler will immediately flag it — but only if
#[allow(dead_code)] isn't there to muffle the warning.
- Consistency: Items that are genuinely conditionally-dead use
#[cfg_attr(not(test), allow(dead_code))] (e.g., CollaboratorPermission::login in backend.rs:74). Plain #[allow(dead_code)] should be reserved for that pattern, not unconditionally live code.
Codebase Health Summary
- Total Rust files: 10
- Total lines: 10,934
- Areas analyzed:
lib.rs, tools.rs, labels/mod.rs, labels/helpers.rs, labels/backend.rs, labels/tool_rules.rs, labels/response_items.rs, labels/response_paths.rs, labels/constants.rs
- Areas with no further improvements found (this run): none — first analysis run
Generated by Rust Guard Improver • Run: §24074493118
Generated by Rust Guard Improver · ● 840.4K · ◷
🦀 Rust Guard Improvement Report
Improvement 1: Avoid Heap Allocation in
is_trusted_first_party_botCategory: Performance (WASM-specific) / Type Safety & Idioms
File(s):
guards/github-guard/rust-guard/src/labels/helpers.rsEffort: Small (< 15 min)
Risk: Low
Problem
is_trusted_first_party_bot(line 1294) callsusername.to_lowercase()before performing its comparisons. This allocates a newStringon the heap on every single call — even when the input is already lowercase ASCII. The function is called on every PR, issue, and commit integrity decision.This is inconsistent with the established pattern elsewhere in the same file:
username_in_list(line 248) useseq_ignore_ascii_case, which is a zero-allocation in-place comparison. All bot names in the hardcoded list are pure ASCII lowercase, soeq_ignore_ascii_caseis semantically identical but allocation-free.Before
After
Why This Matters
eq_ignore_ascii_casecompares byte-by-byte in place — noStringis created or dropped.username_in_listalready useseq_ignore_ascii_casefor case-insensitive matching; this bringsis_trusted_first_party_botin line with that pattern.eq_ignore_ascii_caseproduces identical results toto_lowercase()+==.Improvement 2: Remove Stale
#[allow(dead_code)]from Logging API inlib.rsCategory: Dead Code
File(s):
guards/github-guard/rust-guard/src/lib.rsEffort: Small (< 15 min)
Risk: Low
Problem
Six items in
lib.rscarry#[allow(dead_code)]even though they are all actively used:invoke_backendpub fn— Rust never emits dead_code for public items; additionally, it's referenced ascrate::invoke_backendinlabels/backend.rs:85,384,388,546LogLevelenumlog_xxxhelpers belowlog_debugcrate::log_debug()inlabels/backend.rsandlabels/helpers.rslog_infocrate::log_info()inlabels/backend.rs,labels/helpers.rs,labels/tool_rules.rslog_warncrate::log_warn()inlabels/backend.rslog_errorcrate::log_error()inlabels/backend.rsSuppressing dead_code on live code is misleading: it implies the items might be dead (or were dead at some point), making reviewers wonder whether they're safe to delete. It also disables the compiler's ability to alert on a future regression where the functions genuinely become unused.
Before
After
Why This Matters
#[allow(dead_code)]isn't there to muffle the warning.#[cfg_attr(not(test), allow(dead_code))](e.g.,CollaboratorPermission::logininbackend.rs:74). Plain#[allow(dead_code)]should be reserved for that pattern, not unconditionally live code.Codebase Health Summary
lib.rs,tools.rs,labels/mod.rs,labels/helpers.rs,labels/backend.rs,labels/tool_rules.rs,labels/response_items.rs,labels/response_paths.rs,labels/constants.rsGenerated by Rust Guard Improver • Run: §24074493118