1616 - disk=large
1717 - extras=s3-cache
1818 - tag=io-fuzz
19+ outputs :
20+ crashes_found : ${{ steps.check.outputs.crashes_found }}
21+ first_crash_name : ${{ steps.check.outputs.first_crash_name }}
22+ artifact_url : ${{ steps.upload_artifacts.outputs.artifact-url }}
1923 steps :
2024 - uses : runs-on/action@v2
2125 with :
@@ -44,13 +48,47 @@ jobs:
4448 AWS_ENDPOINT_URL : " https://01e9655179bbec953276890b183039bc.r2.cloudflarestorage.com"
4549 - name : Run fuzzing target
4650 id : fuzz
47- run : RUST_BACKTRACE=1 cargo +nightly fuzz run --release --debug-assertions file_io -- -max_total_time=7200
51+ run : |
52+ RUST_BACKTRACE=1 cargo +nightly fuzz run --release --debug-assertions file_io -- -max_total_time=7200 2>&1 | tee fuzz_output.log
4853 continue-on-error : true
54+ - name : Check for crashes
55+ id : check
56+ run : |
57+ if [ -d "fuzz/artifacts" ] && [ "$(ls -A fuzz/artifacts 2>/dev/null)" ]; then
58+ echo "crashes_found=true" >> $GITHUB_OUTPUT
59+
60+ # Get the first crash file only
61+ FIRST_CRASH=$(find fuzz/artifacts -type f \( -name "crash-*" -o -name "leak-*" -o -name "timeout-*" -o -name "oom-*" \) | head -1)
62+
63+ if [ -n "$FIRST_CRASH" ]; then
64+ echo "first_crash=$FIRST_CRASH" >> $GITHUB_OUTPUT
65+ echo "first_crash_name=$(basename $FIRST_CRASH)" >> $GITHUB_OUTPUT
66+
67+ # Count all crashes for reporting
68+ CRASH_COUNT=$(find fuzz/artifacts -type f \( -name "crash-*" -o -name "leak-*" -o -name "timeout-*" -o -name "oom-*" \) | wc -l)
69+ echo "crash_count=$CRASH_COUNT" >> $GITHUB_OUTPUT
70+ echo "Found $CRASH_COUNT crash(es), will process first: $(basename $FIRST_CRASH)"
71+ fi
72+ else
73+ echo "crashes_found=false" >> $GITHUB_OUTPUT
74+ echo "crash_count=0" >> $GITHUB_OUTPUT
75+ echo "No crashes found"
76+ fi
4977 - name : Archive crash artifacts
78+ id : upload_artifacts
79+ if : steps.check.outputs.crashes_found == 'true'
5080 uses : actions/upload-artifact@v5
5181 with :
5282 name : io-fuzzing-crash-artifacts
5383 path : fuzz/artifacts
84+ retention-days : 30
85+ - name : Archive fuzzer output log
86+ if : steps.check.outputs.crashes_found == 'true'
87+ uses : actions/upload-artifact@v4
88+ with :
89+ name : io-fuzzing-logs
90+ path : fuzz_output.log
91+ retention-days : 30
5492 - name : Persist corpus
5593 shell : bash
5694 run : |
@@ -62,9 +100,203 @@ jobs:
62100 AWS_REGION : " us-east-1"
63101 AWS_ENDPOINT_URL : " https://01e9655179bbec953276890b183039bc.r2.cloudflarestorage.com"
64102 - name : Fail job if fuzz run found a bug
65- if : steps.fuzz.outcome == 'failure '
103+ if : steps.check.outputs.crashes_found == 'true '
66104 run : exit 1
67105
106+ report-io-fuzz-failures :
107+ name : " Report IO Fuzz Failures"
108+ needs : io_fuzz
109+ if : always() && needs.io_fuzz.outputs.crashes_found == 'true'
110+ runs-on : ubuntu-latest
111+ permissions :
112+ issues : write
113+ contents : read
114+ id-token : write
115+ pull-requests : read
116+ steps :
117+ - name : Checkout repository
118+ uses : actions/checkout@v5
119+
120+ - name : Download fuzzer logs
121+ uses : actions/download-artifact@v4
122+ with :
123+ name : io-fuzzing-logs
124+ path : ./logs
125+
126+ - name : Analyze and report crash with Claude
127+ env :
128+ CRASH_FILE : ${{ needs.io_fuzz.outputs.first_crash_name }}
129+ ARTIFACT_URL : ${{ needs.io_fuzz.outputs.artifact_url }}
130+ BRANCH : ${{ github.ref_name }}
131+ COMMIT : ${{ github.sha }}
132+ uses : anthropics/claude-code-action@v1
133+ with :
134+ claude_code_oauth_token : ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
135+ github_token : ${{ secrets.GITHUB_TOKEN }}
136+ show_full_output : true
137+ prompt : |
138+ # Fuzzer Crash Analysis and Reporting
139+
140+ A fuzzing run for the `file_io` target has detected a crash. Analyze it and report by creating or updating a GitHub issue.
141+
142+ ## Step 1: Analyze the Crash
143+
144+ 1. Read the fuzzer log: `logs/fuzz_output.log`
145+ 2. Extract:
146+ - Stack trace (lines with `#0`, `#1`, etc.)
147+ - Error message ("panicked at" or "ERROR:")
148+ - Crash location (top user code frame, not std/core/libfuzzer)
149+ - Debug output (look for "Output of `std::fmt::Debug`:" section before the crash)
150+ 3. Read the source code at the crash location to understand root cause
151+
152+ ## Step 2: Check for Duplicates
153+
154+ 1. List existing fuzzer issues:
155+ ```bash
156+ gh issue list --repo ${{ github.repository }} --label fuzzer --state open --json number,title,body --limit 50
157+ ```
158+
159+ 2. For each existing issue, compare:
160+ - **Crash location**: Same file + function? (line numbers can differ)
161+ - **Error pattern**: Same error after normalizing values?
162+ - "index 5 out of bounds" = "index 12 out of bounds" (SAME)
163+ - "len is 100" = "len is 5" (SAME)
164+ - Read source code if needed to verify same root cause
165+
166+ 3. Determine duplication level:
167+ - **EXACT DUPLICATE**: Same crash location + same error pattern → Add reaction
168+ - **SIMILAR**: Same general area but unclear → Add comment
169+ - **NEW BUG**: Different location or different error type → Create new issue
170+
171+ ## Step 3: Take Action
172+
173+ ### If EXACT DUPLICATE (high confidence):
174+ Update or create a tracking comment to count occurrences:
175+
176+ 1. First, check if there's already a tracking comment (look for a comment starting with "<!-- occurrences: ")
177+ 2. If found, extract the count, increment it, and edit the comment
178+ 3. If not found, create a new comment
179+
180+ Comment format:
181+ ```markdown
182+ <!-- occurrences: N -->
183+ **Crash seen N time(s)**
184+
185+ Latest occurrence:
186+ - Crash file: $CRASH_FILE
187+ - Artifact: $ARTIFACT_URL
188+ - Branch: $BRANCH
189+ - Commit: $COMMIT
190+ ```
191+
192+ Use:
193+ - `gh api repos/${{ github.repository }}/issues/ISSUE_NUM/comments` to list comments
194+ - `gh api repos/${{ github.repository }}/issues/comments/COMMENT_ID -X PATCH` to update
195+ - `gh issue comment ISSUE_NUM` to create new
196+
197+ ### If SIMILAR (medium confidence):
198+ Comment on the existing issue with analysis:
199+ ```bash
200+ gh issue comment ISSUE_NUM --repo ${{ github.repository }} --body "..."
201+ ```
202+
203+ Include in comment:
204+ - Note that another crash was detected
205+ - Your confidence level and reasoning
206+ - Key differences if any
207+ - Crash file: $CRASH_FILE
208+ - Workflow: $WORKFLOW_RUN
209+
210+ ### If NEW BUG (not a duplicate):
211+ Create a new issue with `gh issue create`:
212+ ```bash
213+ gh issue create --repo ${{ github.repository }} \
214+ --title "Fuzzing Crash: [brief description]" \
215+ --label "bug,fuzzer" \
216+ --body "..."
217+ ```
218+
219+ Issue body must include:
220+ ```markdown
221+ ## Fuzzing Crash Report
222+
223+ ### Analysis
224+
225+ **Crash Location**: `file.rs:function_name`
226+
227+ **Error Message**:
228+ ```
229+ [error message]
230+ ```
231+
232+ **Stack Trace**:
233+ ```
234+ [top 5-7 frames - keep in code block to prevent markdown rendering issues]
235+ ```
236+
237+ Note: Keep stack traces in code blocks to prevent `#0`, `#1` from being interpreted as markdown headers.
238+
239+ **Root Cause**: [Your analysis]
240+
241+ <details>
242+ <summary>Debug Output</summary>
243+
244+ ```
245+ [Include the complete "Output of std::fmt::Debug:" section from the fuzzer log]
246+ ```
247+ </details>
248+
249+ ### Summary
250+
251+ - **Target**: `file_io`
252+ - **Crash File**: `$CRASH_FILE`
253+ - **Branch**: $BRANCH
254+ - **Commit**: $COMMIT
255+ - **Crash Artifact**: $ARTIFACT_URL
256+
257+ ### Reproduction
258+
259+ 1. Download the crash artifact:
260+ - **Direct download**: $ARTIFACT_URL
261+ - Or find `io-fuzzing-crash-artifacts` at: $WORKFLOW_RUN
262+ - Extract the zip file
263+
264+ 2. Reproduce locally:
265+ ```bash
266+ # The artifact contains file_io/$CRASH_FILE
267+ cargo +nightly fuzz run --sanitizer=none file_io file_io/$CRASH_FILE
268+ ```
269+
270+ 3. Get full backtrace:
271+ ```bash
272+ RUST_BACKTRACE=full cargo +nightly fuzz run --sanitizer=none file_io file_io/$CRASH_FILE
273+ ```
274+
275+ ---
276+ *Auto-created by fuzzing workflow with Claude analysis*
277+ ```
278+
279+ ## Important Guidelines
280+
281+ - Be conservative: when unsure, prefer creating a new issue over marking as duplicate
282+ - Focus on ROOT CAUSE, not specific values in error messages
283+ - You have full repo access - read source code to understand crashes
284+ - Only use +1 reaction for truly identical crashes
285+
286+ ## Environment Variables
287+
288+ - CRASH_FILE: $CRASH_FILE
289+ - ARTIFACT_URL: $ARTIFACT_URL (direct link to crash artifact)
290+ - BRANCH: $BRANCH
291+ - COMMIT: $COMMIT
292+
293+ Start by reading `logs/fuzz_output.log`.
294+ claude_args : |
295+ --model claude-sonnet-4-5-20250929
296+ --max-turns 25
297+ --allowedTools "Read,Write,Bash(gh issue list:*),Bash(gh issue view:*),Bash(gh issue create:*),Bash(gh issue comment:*),Bash(gh api:*),Bash(echo:*),Bash(cat:*),Bash(jq:*),Bash(grep:*),Bash(cargo +nightly fuzz run:*),Bash(RUST_BACKTRACE=* cargo +nightly fuzz run:*)"
298+
299+
68300 ops_fuzz :
69301 name : " Array Operations Fuzz"
70302 timeout-minutes : 230 # almost 4 hours
0 commit comments