@@ -107,216 +107,23 @@ jobs:
107107 name : " Report IO Fuzz Failures"
108108 needs : io_fuzz
109109 if : always() && needs.io_fuzz.outputs.crashes_found == 'true'
110- runs-on : ubuntu-latest
111- outputs :
112- issue_number : ${{ steps.extract_issue.outputs.issue_number }}
113110 permissions :
114111 issues : write
115112 contents : read
116113 id-token : write
117114 pull-requests : read
118- steps :
119- - name : Checkout repository
120- uses : actions/checkout@v5
121-
122- - name : Download fuzzer logs
123- uses : actions/download-artifact@v4
124- with :
125- name : io-fuzzing-logs
126- path : ./logs
127-
128- - name : Analyze and report crash with Claude
129- id : claude_report
130- env :
131- CRASH_FILE : ${{ needs.io_fuzz.outputs.first_crash_name }}
132- ARTIFACT_URL : ${{ needs.io_fuzz.outputs.artifact_url }}
133- BRANCH : ${{ github.ref_name }}
134- COMMIT : ${{ github.sha }}
135- uses : anthropics/claude-code-action@v1
136- with :
137- claude_code_oauth_token : ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
138- github_token : ${{ secrets.GITHUB_TOKEN }}
139- show_full_output : true
140- prompt : |
141- # Fuzzer Crash Analysis and Reporting
142-
143- A fuzzing run for the `file_io` target has detected a crash. Analyze it and report by creating or updating a GitHub issue.
144-
145- ## Step 1: Analyze the Crash
146-
147- 1. Read the fuzzer log: `logs/fuzz_output.log`
148- 2. Extract:
149- - Stack trace (lines with `#0`, `#1`, etc.)
150- - Error message ("panicked at" or "ERROR:")
151- - Crash location (top user code frame, not std/core/libfuzzer)
152- - Debug output (look for "Output of `std::fmt::Debug`:" section before the crash)
153- 3. Read the source code at the crash location to understand root cause
154-
155- ## Step 2: Check for Duplicates
156-
157- 1. List existing fuzzer issues:
158- ```bash
159- gh issue list --repo ${{ github.repository }} --label fuzzer --state open --json number,title,body --limit 50
160- ```
161-
162- 2. For each existing issue, compare:
163- - **Crash location**: Same file + function? (line numbers can differ)
164- - **Error pattern**: Same error after normalizing values?
165- - "index 5 out of bounds" = "index 12 out of bounds" (SAME)
166- - "len is 100" = "len is 5" (SAME)
167- - Read source code if needed to verify same root cause
168-
169- 3. Determine duplication level:
170- - **EXACT DUPLICATE**: Same crash location + same error pattern → Add reaction
171- - **SIMILAR**: Same general area but unclear → Add comment
172- - **NEW BUG**: Different location or different error type → Create new issue
173-
174- ## Step 3: Take Action
175-
176- ### If EXACT DUPLICATE (high confidence):
177- Update or create a tracking comment to count occurrences:
178-
179- 1. First, check if there's already a tracking comment (look for a comment starting with "<!-- occurrences: ")
180- 2. If found, extract the count, increment it, and edit the comment
181- 3. If not found, create a new comment
182-
183- Comment format:
184- ```markdown
185- <!-- occurrences: N -->
186- **Crash seen N time(s)**
187-
188- Latest occurrence:
189- - Crash file: $CRASH_FILE
190- - Artifact: $ARTIFACT_URL
191- - Branch: $BRANCH
192- - Commit: $COMMIT
193- ```
194-
195- Use:
196- - `gh api repos/${{ github.repository }}/issues/ISSUE_NUM/comments` to list comments
197- - `gh api repos/${{ github.repository }}/issues/comments/COMMENT_ID -X PATCH` to update
198- - `gh issue comment ISSUE_NUM` to create new
199-
200- ### If SIMILAR (medium confidence):
201- Comment on the existing issue with analysis:
202- ```bash
203- gh issue comment ISSUE_NUM --repo ${{ github.repository }} --body "..."
204- ```
205-
206- Include in comment:
207- - Note that another crash was detected
208- - Your confidence level and reasoning
209- - Key differences if any
210- - Crash file: $CRASH_FILE
211- - Workflow: $WORKFLOW_RUN
212-
213- ### If NEW BUG (not a duplicate):
214- Create a new issue with `gh issue create` and save the issue number:
215- ```bash
216- ISSUE_URL=$(gh issue create --repo ${{ github.repository }} \
217- --title "Fuzzing Crash: [brief description]" \
218- --label "bug,fuzzer" \
219- --body "...")
220-
221- # Extract issue number from URL and save to file
222- ISSUE_NUMBER=$(echo "$ISSUE_URL" | grep -oP '\d+$')
223- echo "$ISSUE_NUMBER" > issue_number.txt
224- echo "Created issue #$ISSUE_NUMBER"
225- ```
226-
227- Issue body must include:
228- ```markdown
229- ## Fuzzing Crash Report
230-
231- ### Analysis
232-
233- **Crash Location**: `file.rs:function_name`
234-
235- **Error Message**:
236- ```
237- [error message]
238- ```
239-
240- **Stack Trace**:
241- ```
242- [top 5-7 frames - keep in code block to prevent markdown rendering issues]
243- ```
244-
245- Note: Keep stack traces in code blocks to prevent `#0`, `#1` from being interpreted as markdown headers.
246-
247- **Root Cause**: [Your analysis]
248-
249- <details>
250- <summary>Debug Output</summary>
251-
252- ```
253- [Include the complete "Output of std::fmt::Debug:" section from the fuzzer log]
254- ```
255- </details>
256-
257- ### Summary
258-
259- - **Target**: `file_io`
260- - **Crash File**: `$CRASH_FILE`
261- - **Branch**: $BRANCH
262- - **Commit**: $COMMIT
263- - **Crash Artifact**: $ARTIFACT_URL
264-
265- ### Reproduction
266-
267- 1. Download the crash artifact:
268- - **Direct download**: $ARTIFACT_URL
269- - Or find `io-fuzzing-crash-artifacts` at: $WORKFLOW_RUN
270- - Extract the zip file
271-
272- 2. Reproduce locally:
273- ```bash
274- # The artifact contains file_io/$CRASH_FILE
275- cargo +nightly fuzz run --sanitizer=none file_io file_io/$CRASH_FILE
276- ```
277-
278- 3. Get full backtrace:
279- ```bash
280- RUST_BACKTRACE=full cargo +nightly fuzz run --sanitizer=none file_io file_io/$CRASH_FILE
281- ```
282-
283- ---
284- *Auto-created by fuzzing workflow with Claude analysis*
285- ```
286-
287- ## Important Guidelines
288-
289- - Be conservative: when unsure, prefer creating a new issue over marking as duplicate
290- - Focus on ROOT CAUSE, not specific values in error messages
291- - You have full repo access - read source code to understand crashes
292- - Only use +1 reaction for truly identical crashes
293-
294- ## Environment Variables
295-
296- - CRASH_FILE: $CRASH_FILE
297- - ARTIFACT_URL: $ARTIFACT_URL (direct link to crash artifact)
298- - BRANCH: $BRANCH
299- - COMMIT: $COMMIT
300-
301- Start by reading `logs/fuzz_output.log`.
302-
303- **IMPORTANT**: After creating a new issue, you MUST save the issue number to `issue_number.txt` as shown above. This is required for the automated fix workflow.
304- claude_args : |
305- --model claude-sonnet-4-5-20250929
306- --max-turns 25
307- --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:*)"
308-
309- - name : Extract issue number
310- id : extract_issue
311- run : |
312- if [ -f issue_number.txt ]; then
313- ISSUE_NUM=$(cat issue_number.txt)
314- echo "issue_number=$ISSUE_NUM" >> $GITHUB_OUTPUT
315- echo "New issue created: #$ISSUE_NUM"
316- else
317- echo "No new issue created (duplicate or similar)"
318- echo "issue_number=" >> $GITHUB_OUTPUT
319- fi
115+ uses : ./.github/workflows/report-fuzz-crash.yml
116+ with :
117+ fuzz_target : file_io
118+ crash_file : ${{ needs.io_fuzz.outputs.first_crash_name }}
119+ artifact_url : ${{ needs.io_fuzz.outputs.artifact_url }}
120+ artifact_name : io-fuzzing-crash-artifacts
121+ logs_artifact_name : io-fuzzing-logs
122+ branch : ${{ github.ref_name }}
123+ commit : ${{ github.sha }}
124+ secrets :
125+ claude_code_oauth_token : ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
126+ gh_token : ${{ secrets.GITHUB_TOKEN }}
320127
321128 attempt-fix-io :
322129 name : " Attempt Fix for IO Fuzz Crash"
@@ -337,6 +144,10 @@ jobs:
337144 - disk=large
338145 - extras=s3-cache
339146 - tag=ops-fuzz
147+ outputs :
148+ crashes_found : ${{ steps.check.outputs.crashes_found }}
149+ first_crash_name : ${{ steps.check.outputs.first_crash_name }}
150+ artifact_url : ${{ steps.upload_artifacts.outputs.artifact-url }}
340151 steps :
341152 - uses : runs-on/action@v2
342153 with :
@@ -365,13 +176,47 @@ jobs:
365176 AWS_ENDPOINT_URL : " https://01e9655179bbec953276890b183039bc.r2.cloudflarestorage.com"
366177 - name : Run fuzzing target
367178 id : fuzz
368- run : RUST_BACKTRACE=1 cargo +nightly fuzz run --release --debug-assertions array_ops -- -max_total_time=7200
179+ run : |
180+ RUST_BACKTRACE=1 cargo +nightly fuzz run --release --debug-assertions array_ops -- -max_total_time=7200 2>&1 | tee fuzz_output.log
369181 continue-on-error : true
182+ - name : Check for crashes
183+ id : check
184+ run : |
185+ if [ -d "fuzz/artifacts" ] && [ "$(ls -A fuzz/artifacts 2>/dev/null)" ]; then
186+ echo "crashes_found=true" >> $GITHUB_OUTPUT
187+
188+ # Get the first crash file only
189+ FIRST_CRASH=$(find fuzz/artifacts -type f \( -name "crash-*" -o -name "leak-*" -o -name "timeout-*" -o -name "oom-*" \) | head -1)
190+
191+ if [ -n "$FIRST_CRASH" ]; then
192+ echo "first_crash=$FIRST_CRASH" >> $GITHUB_OUTPUT
193+ echo "first_crash_name=$(basename $FIRST_CRASH)" >> $GITHUB_OUTPUT
194+
195+ # Count all crashes for reporting
196+ CRASH_COUNT=$(find fuzz/artifacts -type f \( -name "crash-*" -o -name "leak-*" -o -name "timeout-*" -o -name "oom-*" \) | wc -l)
197+ echo "crash_count=$CRASH_COUNT" >> $GITHUB_OUTPUT
198+ echo "Found $CRASH_COUNT crash(es), will process first: $(basename $FIRST_CRASH)"
199+ fi
200+ else
201+ echo "crashes_found=false" >> $GITHUB_OUTPUT
202+ echo "crash_count=0" >> $GITHUB_OUTPUT
203+ echo "No crashes found"
204+ fi
370205 - name : Archive crash artifacts
206+ id : upload_artifacts
207+ if : steps.check.outputs.crashes_found == 'true'
371208 uses : actions/upload-artifact@v5
372209 with :
373210 name : operations-fuzzing-crash-artifacts
374211 path : fuzz/artifacts
212+ retention-days : 30
213+ - name : Archive fuzzer output log
214+ if : steps.check.outputs.crashes_found == 'true'
215+ uses : actions/upload-artifact@v4
216+ with :
217+ name : ops-fuzzing-logs
218+ path : fuzz_output.log
219+ retention-days : 30
375220 - name : Persist corpus
376221 shell : bash
377222 run : |
@@ -383,5 +228,27 @@ jobs:
383228 AWS_REGION : " us-east-1"
384229 AWS_ENDPOINT_URL : " https://01e9655179bbec953276890b183039bc.r2.cloudflarestorage.com"
385230 - name : Fail job if fuzz run found a bug
386- if : steps.fuzz.outcome == 'failure '
231+ if : steps.check.outputs.crashes_found == 'true '
387232 run : exit 1
233+
234+ report-ops-fuzz-failures :
235+ name : " Report Array Operations Fuzz Failures"
236+ needs : ops_fuzz
237+ if : always() && needs.ops_fuzz.outputs.crashes_found == 'true'
238+ permissions :
239+ issues : write
240+ contents : read
241+ id-token : write
242+ pull-requests : read
243+ uses : ./.github/workflows/report-fuzz-crash.yml
244+ with :
245+ fuzz_target : array_ops
246+ crash_file : ${{ needs.ops_fuzz.outputs.first_crash_name }}
247+ artifact_url : ${{ needs.ops_fuzz.outputs.artifact_url }}
248+ artifact_name : operations-fuzzing-crash-artifacts
249+ logs_artifact_name : ops-fuzzing-logs
250+ branch : ${{ github.ref_name }}
251+ commit : ${{ github.sha }}
252+ secrets :
253+ claude_code_oauth_token : ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
254+ gh_token : ${{ secrets.GITHUB_TOKEN }}
0 commit comments