feat(fuzzer): add bounded fuzzing and CI action for prism-core - #298
Conversation
|
@Peaostrel Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
📝 WalkthroughWalkthroughThe fuzzer adds bounded execution, structured JSON reporting, parser panic capture with reproducer output, and CI automation that runs the bounded fuzz command and uploads failures. ChangesFuzzer reporting and CI execution
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant CLI
participant FuzzModes
participant Parser
participant Report
participant GitHubActions
CLI->>FuzzModes: Select mode and max_iterations
FuzzModes->>Parser: Parse fuzz input
Parser-->>FuzzModes: Findings, divergences, or panic
FuzzModes->>Report: Record run metrics
Report-->>CLI: Print JSON report
GitHubActions->>CLI: Run bounded release fuzz command
CLI-->>GitHubActions: Exit status and reproducer.txt
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
2c39756 to
54dc0af
Compare
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/fuzz.yml:
- Around line 3-6: Update the workflow’s on.push trigger to remove the branches
filter, so fuzzing runs on every push while preserving the existing pull_request
trigger.
In `@examples/rust-address-fuzzer/src/main.rs`:
- Line 105: Replace unwrap_or_default() in the corpus line-reading path at
examples/rust-address-fuzzer/src/main.rs:105-105 with explicit error handling
that reports the read or UTF-8 error and terminates with an input-error status
instead of calling fuzz_one on an empty string. Apply the same handling to the
stdin path at examples/rust-address-fuzzer/src/main.rs:116-116.
- Around line 139-142: Update the panic handling in
examples/rust-address-fuzzer/src/main.rs:139-142 around the Err(_) branch to
write each reproducer to a distinct file under reproducers, using the panic
count for uniqueness, and surface any write failure instead of discarding it.
Update .github/workflows/fuzz.yml:23-28 to upload
examples/rust-address-fuzzer/reproducers/** so all captured panic inputs are
retained.
In `@examples/rust-address-fuzzer/src/report.rs`:
- Around line 1-14: Implement the Default trait for Report so Stats::default()
can construct its report field, preserving the zero-value initialization
currently provided by Report::new. Prefer deriving Default on Report and retain
Report::new as appropriate for existing callers.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 9aed8557-eafc-411e-8414-417c410e7b1e
📒 Files selected for processing (3)
.github/workflows/fuzz.ymlexamples/rust-address-fuzzer/src/main.rsexamples/rust-address-fuzzer/src/report.rs
| on: | ||
| push: | ||
| branches: ["main"] | ||
| pull_request: |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Run the fuzzer on every push.
The branch filter limits push-triggered fuzzing to main; direct pushes to other branches are skipped, contrary to the PR objective.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/fuzz.yml around lines 3 - 6, Update the workflow’s on.push
trigger to remove the branches filter, so fuzzing runs on every push while
preserving the existing pull_request trigger.
| if let Some(m) = max_iters { | ||
| if i >= m { break; } | ||
| } | ||
| fuzz_one(&line.unwrap_or_default(), verbose, &mut stats); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Do not fuzz an empty string on input read failure. unwrap_or_default() hides corpus/stdin I/O or UTF-8 errors, inflates inputs_run, and can let CI pass after processing corrupted input.
examples/rust-address-fuzzer/src/main.rs#L105-L105: report the line-read error and terminate with an input-error status.examples/rust-address-fuzzer/src/main.rs#L116-L116: apply the same error handling for stdin.
📍 Affects 1 file
examples/rust-address-fuzzer/src/main.rs#L105-L105(this comment)examples/rust-address-fuzzer/src/main.rs#L116-L116
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@examples/rust-address-fuzzer/src/main.rs` at line 105, Replace
unwrap_or_default() in the corpus line-reading path at
examples/rust-address-fuzzer/src/main.rs:105-105 with explicit error handling
that reports the read or UTF-8 error and terminates with an input-error status
instead of calling fuzz_one on an empty string. Apply the same handling to the
stdin path at examples/rust-address-fuzzer/src/main.rs:116-116.
| Err(_) => { | ||
| stats.panics += 1; | ||
| eprintln!("PANIC ← {input:?}"); | ||
| let _ = std::fs::write("reproducer.txt", input); |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Preserve each distinct panic reproducer. Writing every finding to reproducer.txt overwrites prior failures, and CI uploads only that final file.
examples/rust-address-fuzzer/src/main.rs#L139-L142: write each panic to a unique file, such asreproducers/panic-<count>.txt, and surface write failures..github/workflows/fuzz.yml#L23-L28: uploadexamples/rust-address-fuzzer/reproducers/**so all captured inputs are retained.
📍 Affects 2 files
examples/rust-address-fuzzer/src/main.rs#L139-L142(this comment).github/workflows/fuzz.yml#L23-L28
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@examples/rust-address-fuzzer/src/main.rs` around lines 139 - 142, Update the
panic handling in examples/rust-address-fuzzer/src/main.rs:139-142 around the
Err(_) branch to write each reproducer to a distinct file under reproducers,
using the panic count for uniqueness, and surface any write failure instead of
discarding it. Update .github/workflows/fuzz.yml:23-28 to upload
examples/rust-address-fuzzer/reproducers/** so all captured panic inputs are
retained.
| pub struct Report { | ||
| pub inputs_run: usize, | ||
| pub findings_count: usize, | ||
| pub divergences: usize, | ||
| } | ||
|
|
||
| impl Report { | ||
| pub fn new() -> Self { | ||
| Self { | ||
| inputs_run: 0, | ||
| findings_count: 0, | ||
| divergences: 0, | ||
| } | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
ast-grep outline examples/rust-address-fuzzer/src/main.rs --items all --type struct,impl
rg -n -A10 -B3 'struct Stats|impl Default for Stats|derive\(.*Default' examples/rust-address-fuzzer/src/main.rsRepository: Boxkit-Labs/stellar-address-kit
Length of output: 452
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== report.rs =="
cat -n examples/rust-address-fuzzer/src/report.rs
echo
echo "== main.rs stats section =="
sed -n '1,90p' examples/rust-address-fuzzer/src/main.rsRepository: Boxkit-Labs/stellar-address-kit
Length of output: 3517
Implement Default for Report. Stats derives Default, so Stats::default() requires report::Report: Default; add that impl here, or replace Stats with a manual Default.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@examples/rust-address-fuzzer/src/report.rs` around lines 1 - 14, Implement
the Default trait for Report so Stats::default() can construct its report field,
preserving the zero-value initialization currently provided by Report::new.
Prefer deriving Default on Report and retain Report::new as appropriate for
existing callers.
Fixes #296
Added the following:
--max-iterationsflag inrust-address-fuzzer.fuzz.ymlGitHub action to run bounded fuzz testing in CI.Summary by CodeRabbit
New Features
Chores