@@ -155,44 +155,113 @@ jobs:
155155 echo "=== Fuzzer log preview (last 100 lines, where crashes are reported) ==="
156156 tail -100 logs/fuzz_output.log || echo "No log file"
157157
158- - name : Setup Python
159- uses : actions/setup-python@v5
158+ # Use Claude Code Action to analyze crash and decide if duplicate
159+ - name : Analyze crash with Claude
160+ uses : anthropics/claude-code-action@v1
160161 with :
161- python-version : ' 3.11'
162-
163- - name : Install dependencies
164- run : pip install anthropic
165-
166- # - name: Check for duplicate issue
167- # id: dedup
168- # env:
169- # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
170- # ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
171- # run: |
172- # python scripts/check_fuzzer_duplicate.py \
173- # "${{ needs.io_fuzz.outputs.first_crash_name }}" \
174- # "logs/fuzz_output.log" \
175- # "${{ github.repository }}" > dedup_result.json
176- #
177- # # Check exit code (0 = not duplicate, 1 = duplicate)
178- # if [ $? -eq 0 ]; then
179- # echo "is_duplicate=false" >> $GITHUB_OUTPUT
180- # echo "Not a duplicate, will create new issue"
181- # else
182- # echo "is_duplicate=true" >> $GITHUB_OUTPUT
183- # ISSUE_NUM=$(jq -r '.issue_number' dedup_result.json)
184- # echo "issue_number=$ISSUE_NUM" >> $GITHUB_OUTPUT
185- # echo "Duplicate of issue #$ISSUE_NUM"
186- # fi
187- #
188- # # Show result
189- # cat dedup_result.json
190-
191- - name : Create GitHub issue
192- if : 0 && steps.dedup.outputs.is_duplicate == 'false'
162+ anthropic_api_key : ${{ secrets.ANTHROPIC_API_KEY }}
163+ prompt : |
164+ # Fuzzer Crash Analysis Task
165+
166+ A fuzzing run for the `file_io` target has detected a crash. Your task is to analyze it and determine if it's a duplicate of an existing issue.
167+
168+ ## Step 1: Analyze the Crash
169+
170+ 1. Read the fuzzer log: `logs/fuzz_output.log`
171+ 2. Extract the stack trace (lines starting with `#0`, `#1`, etc.)
172+ 3. Extract the error message (look for "panicked at" or "ERROR:")
173+ 4. Identify the crash location (top frame in the stack trace from user code, not std/core)
174+ 5. Read the source code at the crash location to understand what failed
175+
176+ ## Step 2: Check for Duplicates
177+
178+ 1. List existing fuzzer issues:
179+ ```bash
180+ gh issue list --repo ${{ github.repository }} --label fuzzer --state open --json number,title,body --limit 50
181+ ```
182+
183+ 2. For each existing issue:
184+ - Compare stack traces: Do they crash at the same location (same file + function)?
185+ - Compare error messages: Are they the same error pattern?
186+ - IMPORTANT: Normalize values when comparing!
187+ - "index 5 out of bounds" and "index 12 out of bounds" are THE SAME bug
188+ - "len is 100" and "len is 5" are THE SAME bug
189+ - If needed, read source code at the crash location to understand if it's the same assertion/panic
190+
191+ 3. Make a decision:
192+ - **DUPLICATE** if: Same crash location + same error pattern (values can differ)
193+ - **NEW BUG** if: Different location OR different error type
194+
195+ ## Step 3: Output Decision
196+
197+ Create a file `decision.json` with this exact format:
198+
199+ ```json
200+ {
201+ "is_duplicate": true or false,
202+ "duplicate_of": issue_number (if duplicate) or null,
203+ "confidence": "high" | "medium" | "low",
204+ "reasoning": "Explain your decision in 2-3 sentences",
205+ "crash_location": "file.rs:function_name",
206+ "error_message": "the extracted error message",
207+ "stack_trace_preview": "top 5 frames",
208+ "suggested_title": "Brief title for new issue (if not duplicate)"
209+ }
210+ ```
211+
212+ ## Important Notes
213+
214+ - You have full access to the repository - read any source files you need
215+ - Be conservative: when unsure, mark as NEW BUG (false negatives are better than false positives)
216+ - The goal is to prevent duplicate issues while being careful not to merge distinct bugs
217+ - Focus on the ROOT CAUSE, not the specific values in error messages
218+
219+ ## Context
220+
221+ - Target: file_io
222+ - Crash file: ${{ needs.io_fuzz.outputs.first_crash_name }}
223+ - Total crashes: ${{ needs.io_fuzz.outputs.crash_count }}
224+ - Workflow: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
225+
226+ Start by reading the fuzzer log.
227+ claude_args : |
228+ --model claude-sonnet-4-5-20250929
229+ --max-turns 20
230+
231+ - name : Read Claude's decision
232+ id : decision
233+ run : |
234+ if [ ! -f decision.json ]; then
235+ echo "Error: decision.json not found"
236+ exit 1
237+ fi
238+
239+ cat decision.json
240+
241+ IS_DUP=$(jq -r '.is_duplicate' decision.json)
242+ DUPLICATE_OF=$(jq -r '.duplicate_of // empty' decision.json)
243+
244+ echo "is_duplicate=$IS_DUP" >> $GITHUB_OUTPUT
245+ echo "duplicate_of=$DUPLICATE_OF" >> $GITHUB_OUTPUT
246+
247+ if [ "$IS_DUP" = "true" ]; then
248+ echo "✓ Claude identified this as a duplicate of issue #$DUPLICATE_OF"
249+ else
250+ echo "✓ Claude identified this as a NEW bug"
251+ fi
252+
253+ - name : Create GitHub issue for new bug
254+ if : steps.decision.outputs.is_duplicate == 'false'
193255 env :
194256 GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
195257 run : |
258+ # Extract data from Claude's analysis
259+ TITLE=$(jq -r '.suggested_title' decision.json)
260+ CRASH_LOCATION=$(jq -r '.crash_location' decision.json)
261+ ERROR_MESSAGE=$(jq -r '.error_message' decision.json)
262+ STACK_TRACE=$(jq -r '.stack_trace_preview' decision.json)
263+ REASONING=$(jq -r '.reasoning' decision.json)
264+
196265 # Extract crash type from filename
197266 CRASH_FILE="${{ needs.io_fuzz.outputs.first_crash_name }}"
198267 if [[ "$CRASH_FILE" == crash-* ]]; then
@@ -207,21 +276,37 @@ jobs:
207276 CRASH_TYPE="Unknown"
208277 fi
209278
210- # Create issue with gh CLI
279+ # Create issue with gh CLI, using Claude's analysis
211280 gh issue create \
212281 --repo ${{ github.repository }} \
213- --title "Fuzzing $CRASH_TYPE: file_io - $(date -u +%Y-%m-%d) " \
282+ --title "Fuzzing $CRASH_TYPE: $TITLE " \
214283 --label "bug,fuzzer" \
215- --body-file - <<'EOF'
284+ --body "$(cat <<EOF_BODY
216285 ## Fuzzing Crash Report
217286
218- The `file_io` fuzzing target detected a $CRASH_TYPE during a scheduled fuzzing run.
287+ The \`file_io\` fuzzing target detected a $CRASH_TYPE during a scheduled fuzzing run.
288+
289+ ### Claude's Analysis
290+
291+ **Crash Location**: \`$CRASH_LOCATION\`
292+
293+ **Error Message**:
294+ \`\`\`
295+ $ERROR_MESSAGE
296+ \`\`\`
297+
298+ **Stack Trace Preview**:
299+ \`\`\`
300+ $STACK_TRACE
301+ \`\`\`
302+
303+ **Analysis**: $REASONING
219304
220305 ### Summary
221306
222307 - **Crash Type**: $CRASH_TYPE
223- - **Target**: `file_io`
224- - **Crash File**: `${{ needs.io_fuzz.outputs.first_crash_name }}`
308+ - **Target**: \ `file_io\ `
309+ - **Crash File**: \ `${{ needs.io_fuzz.outputs.first_crash_name }}\ `
225310 - **Total Crashes Found**: ${{ needs.io_fuzz.outputs.crash_count }}
226311 - **Workflow Run**: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
227312 - **Timestamp**: $(date -u +"%Y-%m-%d %H:%M:%S UTC")
@@ -234,38 +319,37 @@ jobs:
234319 **https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}**
235320
236321 Artifacts available:
237- - `io-fuzzing-crash-artifacts` - All crash files found (includes ${{ needs.io_fuzz.outputs.crash_count }} crashes)
238- - `io-fuzzing-logs` - Complete fuzzer output with stack traces
322+ - \ `io-fuzzing-crash-artifacts\ ` - All crash files found (includes ${{ needs.io_fuzz.outputs.crash_count }} crashes)
323+ - \ `io-fuzzing-logs\ ` - Complete fuzzer output with stack traces
239324
240325 ### Reproduction Steps
241326
242- 1. Download the `io-fuzzing-crash-artifacts` from the workflow run above
243- 2. Extract the crash file to your local `fuzz/artifacts/file_io/` directory
327+ 1. Download the \ `io-fuzzing-crash-artifacts\ ` from the workflow run above
328+ 2. Extract the crash file to your local \ `fuzz/artifacts/file_io/\ ` directory
244329 3. Reproduce the crash locally:
245330
246- `` `bash
331+ \`\`\ `bash
247332 cargo +nightly fuzz run file_io fuzz/artifacts/file_io/${{ needs.io_fuzz.outputs.first_crash_name }}
248- `` `
333+ \`\`\ `
249334
250335 4. Get full backtrace:
251336
252- `` `bash
337+ \`\`\ `bash
253338 RUST_BACKTRACE=full cargo +nightly fuzz run file_io fuzz/artifacts/file_io/${{ needs.io_fuzz.outputs.first_crash_name }}
254- `` `
339+ \`\`\ `
255340
256341 5. Minimize the test case (optional):
257342
258- `` `bash
343+ \`\`\ `bash
259344 cargo +nightly fuzz tmin file_io fuzz/artifacts/file_io/${{ needs.io_fuzz.outputs.first_crash_name }}
260- `` `
345+ \`\`\ `
261346
262347 ### Investigation Checklist
263348
264349 - [ ] Download crash artifacts from workflow run
265350 - [ ] Reproduce crash locally with full backtrace
266351 - [ ] Analyze stack trace and identify root cause
267352 - [ ] Determine severity (security vs stability)
268- - [ ] Check if this is a duplicate of an existing issue
269353 - [ ] Minimize test case if needed
270354 - [ ] Create fix PR with reference to this issue
271355 - [ ] Add regression test
@@ -286,28 +370,37 @@ jobs:
286370
287371 ---
288372
289- *Automatically created by fuzzing workflow*
373+ *Automatically created by fuzzing workflow with Claude AI analysis *
290374 *Workflow file: [fuzz.yml](https://github.com/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/fuzz.yml)*
291375 *Run: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}*
292- EOF
376+ EOF_BODY
377+ )"
293378
294379 - name : Comment on duplicate issue
295- if : steps.dedup .outputs.is_duplicate == 'true'
380+ if : steps.decision .outputs.is_duplicate == 'true'
296381 env :
297382 GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
298383 run : |
299- ISSUE_NUM="${{ steps.dedup.outputs.issue_number }}"
384+ ISSUE_NUM="${{ steps.decision.outputs.duplicate_of }}"
385+ REASONING=$(jq -r '.reasoning' decision.json)
386+ CONFIDENCE=$(jq -r '.confidence' decision.json)
300387
301388 gh issue comment "$ISSUE_NUM" \
302389 --repo ${{ github.repository }} \
303- --body-file - <<'EOF'
390+ --body "$(cat <<EOF_COMMENT
304391 ## Additional Crash Detected
305392
306- Another crash was found in the `file_io` fuzzing target that appears to be a duplicate of this issue.
393+ Another crash was found in the \`file_io\` fuzzing target that appears to be a duplicate of this issue.
394+
395+ ### Claude's Analysis
396+
397+ **Confidence**: $CONFIDENCE
398+
399+ **Reasoning**: $REASONING
307400
308401 ### Details
309402
310- - **Crash File**: `${{ needs.io_fuzz.outputs.first_crash_name }}`
403+ - **Crash File**: \ `${{ needs.io_fuzz.outputs.first_crash_name }}\ `
311404 - **Total Crashes**: ${{ needs.io_fuzz.outputs.crash_count }} found in this run
312405 - **Workflow Run**: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
313406 - **Timestamp**: $(date -u +"%Y-%m-%d %H:%M:%S UTC")
@@ -316,11 +409,12 @@ jobs:
316409
317410 Download crash artifacts from: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
318411
319- The fuzzing infrastructure detected this as a likely duplicate based on similar stack traces and error messages .
412+ Claude analyzed the crash and determined it matches this issue based on crash location, error pattern, and code analysis .
320413
321414 ---
322415 *Automatically added by fuzzing workflow*
323- EOF
416+ EOF_COMMENT
417+ )"
324418
325419 ops_fuzz :
326420 name : " Array Operations Fuzz"
0 commit comments