🦀 Rust Guard Improvement Report
Improvement 1: Add Unit Tests for check_file_secrecy
Category: Test Coverage
File(s): guards/github-guard/rust-guard/src/labels/tool_rules.rs
Effort: Small (< 15 min)
Risk: Low
Problem
check_file_secrecy (line 738) is the sole function deciding whether a get_file_contents request reveals private file paths (.env, workflow files, secrets.json, etc.). It is called from the get_file_contents arm of apply_tool_labels (line 390) and directly influences secrecy labels in production. Yet tool_rules.rs has zero unit tests across its 772 lines.
A typo in a pattern or a mis-ordered ends_with check could silently stop enforcing secrecy on sensitive files with no test catching it.
Suggested Change
Add a #[cfg(test)] module inside tool_rules.rs with targeted tests for check_file_secrecy:
Before
// tool_rules.rs — no test module exists
After
#[cfg(test)]
mod tests {
use super::*;
use crate::labels::helpers::PolicyContext;
fn ctx() -> PolicyContext { PolicyContext::default() }
fn private_secrecy(owner: &str, repo: &str, repo_id: &str) -> Vec<String> {
policy_private_scope_label(owner, repo, repo_id, &ctx())
}
#[test]
fn check_file_secrecy_env_file_triggers_private() {
let result = check_file_secrecy(".env", vec![], "octocat", "hello-world", "octocat/hello-world", &ctx());
assert_eq!(result, private_secrecy("octocat", "hello-world", "octocat/hello-world"));
}
#[test]
fn check_file_secrecy_workflow_file_triggers_private() {
let result = check_file_secrecy(".github/workflows/ci.yml", vec![], "octocat", "hello-world", "octocat/hello-world", &ctx());
assert_eq!(result, private_secrecy("octocat", "hello-world", "octocat/hello-world"));
}
#[test]
fn check_file_secrecy_secrets_json_triggers_private() {
let result = check_file_secrecy("config/secrets.json", vec![], "octocat", "hello-world", "octocat/hello-world", &ctx());
assert_eq!(result, private_secrecy("octocat", "hello-world", "octocat/hello-world"));
}
#[test]
fn check_file_secrecy_normal_source_file_keeps_default() {
let default = vec!["private:octocat/hello-world".to_string()];
let result = check_file_secrecy("src/main.rs", default.clone(), "octocat", "hello-world", "octocat/hello-world", &ctx());
assert_eq!(result, default);
}
#[test]
fn check_file_secrecy_dotenv_extension_triggers_private() {
// file named "config.env" or path ending in ".env"
let result = check_file_secrecy("deploy/config.env", vec![], "octocat", "hello-world", "octocat/hello-world", &ctx());
assert_eq!(result, private_secrecy("octocat", "hello-world", "octocat/hello-world"));
}
}
Why This Matters
check_file_secrecy is a security gate. Without tests, any future refactor (e.g., adjusting SENSITIVE_FILE_PATTERNS or SENSITIVE_FILE_KEYWORDS in constants.rs) could silently break enforcement and expose private file contents with no CI signal. These tests take under 15 minutes to write and provide an immediate safety net.
Improvement 2: Wrap RUNTIME_POLICY_CONTEXT in Arc<PolicyContext>
Category: Performance
File(s): guards/github-guard/rust-guard/src/lib.rs
Effort: Small (< 15 min)
Risk: Low
Problem
get_runtime_policy_context() (line 56) is called at the start of every label_resource (line 651) and label_response (line 815) invocation. It currently deep-clones the stored PolicyContext from the Mutex:
fn get_runtime_policy_context() -> PolicyContext {
RUNTIME_POLICY_CONTEXT
.lock()
.ok()
.and_then(|guard| guard.clone()) // ← deep-clone
.unwrap_or_default()
}
PolicyContext contains 6 Vec<String> fields (scopes, trusted_bots, blocked_users, approval_labels, trusted_users, endorsement_reactions, disapproval_reactions) and 4 plain String fields. Each call allocates and copies all of these.
In a production WASM guard, every tool call triggers at least one label_resource + one label_response, so this clone runs at least twice per incoming MCP request.
Suggested Change
Store Arc<PolicyContext> in the Mutex so get_runtime_policy_context only bumps an atomic refcount:
Before
static RUNTIME_POLICY_CONTEXT: Mutex<Option<PolicyContext>> = Mutex::new(None);
fn get_runtime_policy_context() -> PolicyContext {
RUNTIME_POLICY_CONTEXT
.lock()
.ok()
.and_then(|guard| guard.clone())
.unwrap_or_default()
}
fn set_runtime_policy_context(ctx: PolicyContext) {
if let Ok(mut guard) = RUNTIME_POLICY_CONTEXT.lock() {
*guard = Some(ctx);
}
}
After
use std::sync::Arc;
static RUNTIME_POLICY_CONTEXT: Mutex<Option<Arc<PolicyContext>>> = Mutex::new(None);
fn get_runtime_policy_context() -> Arc<PolicyContext> {
RUNTIME_POLICY_CONTEXT
.lock()
.ok()
.and_then(|guard| guard.clone()) // clones Arc (atomic refcount)
.unwrap_or_else(|| Arc::new(PolicyContext::default()))
}
fn set_runtime_policy_context(ctx: PolicyContext) {
if let Ok(mut guard) = RUNTIME_POLICY_CONTEXT.lock() {
*guard = Some(Arc::new(ctx));
}
}
All existing callers (label_resource, label_response) assign let ctx = get_runtime_policy_context() and pass &ctx to downstream functions. Since Arc<T> implements Deref<Target = T>, &ctx continues to coerce to &PolicyContext — no caller changes required.
Why This Matters
Eliminates 7+ heap allocations and memcpys of Vec contents on every guard invocation, replaced by a single AtomicUsize increment. In a WASM-constrained environment where allocator overhead is higher than on native, this is a measurable win — especially for agents calling many tools in sequence (each call re-invokes the guard).
Codebase Health Summary
- Total Rust files: 10
- Total lines: ~13,544
- Areas analyzed: lib.rs, labels/mod.rs, labels/helpers.rs, labels/tool_rules.rs, labels/response_items.rs, labels/response_paths.rs, labels/backend.rs, labels/constants.rs, tools.rs
- Areas with no further improvements: tools.rs (tests added, BLOCKED_TOOLS const added)
- Critical gap remaining:
tool_rules.rs and response_paths.rs still have 0 unit tests
Generated by Rust Guard Improver • Run: §25369159959
Generated by Rust Guard Improver · ● 2.4M · ◷
🦀 Rust Guard Improvement Report
Improvement 1: Add Unit Tests for
check_file_secrecyCategory: Test Coverage
File(s):
guards/github-guard/rust-guard/src/labels/tool_rules.rsEffort: Small (< 15 min)
Risk: Low
Problem
check_file_secrecy(line 738) is the sole function deciding whether aget_file_contentsrequest reveals private file paths (.env, workflow files,secrets.json, etc.). It is called from theget_file_contentsarm ofapply_tool_labels(line 390) and directly influences secrecy labels in production. Yettool_rules.rshas zero unit tests across its 772 lines.A typo in a pattern or a mis-ordered
ends_withcheck could silently stop enforcing secrecy on sensitive files with no test catching it.Suggested Change
Add a
#[cfg(test)]module insidetool_rules.rswith targeted tests forcheck_file_secrecy:Before
// tool_rules.rs — no test module existsAfter
Why This Matters
check_file_secrecyis a security gate. Without tests, any future refactor (e.g., adjustingSENSITIVE_FILE_PATTERNSorSENSITIVE_FILE_KEYWORDSinconstants.rs) could silently break enforcement and expose private file contents with no CI signal. These tests take under 15 minutes to write and provide an immediate safety net.Improvement 2: Wrap
RUNTIME_POLICY_CONTEXTinArc<PolicyContext>Category: Performance
File(s):
guards/github-guard/rust-guard/src/lib.rsEffort: Small (< 15 min)
Risk: Low
Problem
get_runtime_policy_context()(line 56) is called at the start of everylabel_resource(line 651) andlabel_response(line 815) invocation. It currently deep-clones the storedPolicyContextfrom the Mutex:PolicyContextcontains 6Vec<String>fields (scopes,trusted_bots,blocked_users,approval_labels,trusted_users,endorsement_reactions,disapproval_reactions) and 4 plainStringfields. Each call allocates and copies all of these.In a production WASM guard, every tool call triggers at least one
label_resource+ onelabel_response, so this clone runs at least twice per incoming MCP request.Suggested Change
Store
Arc<PolicyContext>in the Mutex soget_runtime_policy_contextonly bumps an atomic refcount:Before
After
All existing callers (
label_resource,label_response) assignlet ctx = get_runtime_policy_context()and pass&ctxto downstream functions. SinceArc<T>implementsDeref<Target = T>,&ctxcontinues to coerce to&PolicyContext— no caller changes required.Why This Matters
Eliminates 7+ heap allocations and memcpys of
Veccontents on every guard invocation, replaced by a singleAtomicUsizeincrement. In a WASM-constrained environment where allocator overhead is higher than on native, this is a measurable win — especially for agents calling many tools in sequence (each call re-invokes the guard).Codebase Health Summary
tool_rules.rsandresponse_paths.rsstill have 0 unit testsGenerated by Rust Guard Improver • Run: §25369159959