1
0
Fork 0
mirror of https://github.com/imjasonh/rustvulncheck synced 2026-07-08 04:08:07 +00:00

Precise golden integration tests and scanner fixes for edge cases

Scanner fixes:
- Block comment tracking: skip lines inside /* ... */ blocks
- Skip `use` statements from being matched as call sites
- Free function call detection: `parse_cookie(...)` after direct import
- Type-aware suppression: when the receiver's type is positively known
  and doesn't match the vulnerable type, suppress the finding entirely
  (e.g., .abort() on MyHandle vs JoinHandle)

Golden test improvements:
- All assertions are now specific: exact counts (deps, reachable symbols,
  files scanned), exact advisory IDs listed vs reachable, exact call site
  locations (file:line), exact confidence levels (HIGH vs MEDIUM)
- Each test documents its fixture layout and expected positive/negative
  findings in a header comment

New edge_cases_project fixture covering:
- Aliased imports (Decoder as HyperDecoder → dec.decode detected)
- Free function calls (parse_cookie after direct import)
- Commented-out code (block & line comments correctly skipped)
- False positive suppression (abort() on MyHandle, parse() on String)
- Typed method calls (jar.add(c) with explicit CookieJar type)

38 tests total (33 unit + 5 integration), all passing.

https://claude.ai/code/session_011sdj18ZvQYbDVwEKqrWDj1
This commit is contained in:
Claude 2026-03-25 13:01:33 +00:00
parent a2db0d4d15
commit 76921cfde0
No known key found for this signature in database
10 changed files with 530 additions and 99 deletions

View file

@ -235,7 +235,15 @@ fn find_call_sites(
}
}
// 4. After `use hyper::http::Request;` and calling as method: foo.parse(...)
// 4. Free function import: `use cookie::parse::parse_cookie;` → bare `parse_cookie(...)`
// When the full symbol is imported directly, the bare name is a valid caller.
for (local, full) in &import_map {
if *full == symbol {
local_callers.push(local.to_string());
}
}
// 5. After `use hyper::http::Request;` and calling as method: foo.parse(...)
// This is lower confidence since we can't verify the receiver type.
let method_pattern = format!(".{}(", fn_name);
@ -248,12 +256,32 @@ fn find_call_sites(
.unwrap_or(false)
});
let mut in_block_comment = false;
for (line_num, line) in source.lines().enumerate() {
let trimmed = line.trim();
// Skip comments
if trimmed.starts_with("//") || trimmed.starts_with("/*") || trimmed.starts_with('*')
{
// Track block comments: /* ... */
if in_block_comment {
if trimmed.contains("*/") {
in_block_comment = false;
}
continue;
}
if trimmed.starts_with("/*") {
if !trimmed.contains("*/") {
in_block_comment = true;
}
continue;
}
// Skip line comments
if trimmed.starts_with("//") || trimmed.starts_with('*') {
continue;
}
// Skip `use` statements — they are imports, not calls
if trimmed.starts_with("use ") {
continue;
}
@ -290,9 +318,18 @@ fn find_call_sites(
b.var_name.ends_with(&format!(".{}", &receiver_var[5..]))
&& b.type_path == parent_path
});
if receiver_matches || field_matches {
Confidence::High
} else {
// If we positively know the receiver's type and it
// doesn't match, suppress the finding entirely.
let type_is_known = type_bindings
.iter()
.any(|b| b.var_name == receiver_var);
if type_is_known {
continue; // Known wrong type — not a match
}
Confidence::Medium
}
} else {