@@ -307,6 +307,10 @@ jobs:
307307 - disk=large
308308 - extras=s3-cache
309309 - tag=ops-fuzz
310+ outputs :
311+ crashes_found : ${{ steps.check.outputs.crashes_found }}
312+ first_crash_name : ${{ steps.check.outputs.first_crash_name }}
313+ artifact_url : ${{ steps.upload_artifacts.outputs.artifact-url }}
310314 steps :
311315 - uses : runs-on/action@v2
312316 with :
@@ -335,13 +339,47 @@ jobs:
335339 AWS_ENDPOINT_URL : " https://01e9655179bbec953276890b183039bc.r2.cloudflarestorage.com"
336340 - name : Run fuzzing target
337341 id : fuzz
338- run : RUST_BACKTRACE=1 cargo +nightly fuzz run --release --debug-assertions array_ops -- -max_total_time=7200
342+ run : |
343+ RUST_BACKTRACE=1 cargo +nightly fuzz run --release --debug-assertions array_ops -- -max_total_time=7200 2>&1 | tee fuzz_output.log
339344 continue-on-error : true
345+ - name : Check for crashes
346+ id : check
347+ run : |
348+ if [ -d "fuzz/artifacts" ] && [ "$(ls -A fuzz/artifacts 2>/dev/null)" ]; then
349+ echo "crashes_found=true" >> $GITHUB_OUTPUT
350+
351+ # Get the first crash file only
352+ FIRST_CRASH=$(find fuzz/artifacts -type f \( -name "crash-*" -o -name "leak-*" -o -name "timeout-*" -o -name "oom-*" \) | head -1)
353+
354+ if [ -n "$FIRST_CRASH" ]; then
355+ echo "first_crash=$FIRST_CRASH" >> $GITHUB_OUTPUT
356+ echo "first_crash_name=$(basename $FIRST_CRASH)" >> $GITHUB_OUTPUT
357+
358+ # Count all crashes for reporting
359+ CRASH_COUNT=$(find fuzz/artifacts -type f \( -name "crash-*" -o -name "leak-*" -o -name "timeout-*" -o -name "oom-*" \) | wc -l)
360+ echo "crash_count=$CRASH_COUNT" >> $GITHUB_OUTPUT
361+ echo "Found $CRASH_COUNT crash(es), will process first: $(basename $FIRST_CRASH)"
362+ fi
363+ else
364+ echo "crashes_found=false" >> $GITHUB_OUTPUT
365+ echo "crash_count=0" >> $GITHUB_OUTPUT
366+ echo "No crashes found"
367+ fi
340368 - name : Archive crash artifacts
369+ id : upload_artifacts
370+ if : steps.check.outputs.crashes_found == 'true'
341371 uses : actions/upload-artifact@v5
342372 with :
343373 name : operations-fuzzing-crash-artifacts
344374 path : fuzz/artifacts
375+ retention-days : 30
376+ - name : Archive fuzzer output log
377+ if : steps.check.outputs.crashes_found == 'true'
378+ uses : actions/upload-artifact@v4
379+ with :
380+ name : ops-fuzzing-logs
381+ path : fuzz_output.log
382+ retention-days : 30
345383 - name : Persist corpus
346384 shell : bash
347385 run : |
@@ -353,5 +391,198 @@ jobs:
353391 AWS_REGION : " us-east-1"
354392 AWS_ENDPOINT_URL : " https://01e9655179bbec953276890b183039bc.r2.cloudflarestorage.com"
355393 - name : Fail job if fuzz run found a bug
356- if : steps.fuzz.outcome == 'failure '
394+ if : steps.check.outputs.crashes_found == 'true '
357395 run : exit 1
396+
397+ report-ops-fuzz-failures :
398+ name : " Report Array Operations Fuzz Failures"
399+ needs : ops_fuzz
400+ if : always() && needs.ops_fuzz.outputs.crashes_found == 'true'
401+ runs-on : ubuntu-latest
402+ permissions :
403+ issues : write
404+ contents : read
405+ id-token : write
406+ pull-requests : read
407+ steps :
408+ - name : Checkout repository
409+ uses : actions/checkout@v5
410+
411+ - name : Download fuzzer logs
412+ uses : actions/download-artifact@v4
413+ with :
414+ name : ops-fuzzing-logs
415+ path : ./logs
416+
417+ - name : Analyze and report crash with Claude
418+ env :
419+ CRASH_FILE : ${{ needs.ops_fuzz.outputs.first_crash_name }}
420+ ARTIFACT_URL : ${{ needs.ops_fuzz.outputs.artifact_url }}
421+ BRANCH : ${{ github.ref_name }}
422+ COMMIT : ${{ github.sha }}
423+ uses : anthropics/claude-code-action@v1
424+ with :
425+ claude_code_oauth_token : ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
426+ github_token : ${{ secrets.GITHUB_TOKEN }}
427+ show_full_output : true
428+ prompt : |
429+ # Fuzzer Crash Analysis and Reporting
430+
431+ A fuzzing run for the `array_ops` target has detected a crash. Analyze it and report by creating or updating a GitHub issue.
432+
433+ ## Step 1: Analyze the Crash
434+
435+ 1. Read the fuzzer log: `logs/fuzz_output.log`
436+ 2. Extract:
437+ - Stack trace (lines with `#0`, `#1`, etc.)
438+ - Error message ("panicked at" or "ERROR:")
439+ - Crash location (top user code frame, not std/core/libfuzzer)
440+ - Debug output (look for "Output of `std::fmt::Debug`:" section before the crash)
441+ 3. Read the source code at the crash location to understand root cause
442+
443+ ## Step 2: Check for Duplicates
444+
445+ 1. List existing fuzzer issues:
446+ ```bash
447+ gh issue list --repo ${{ github.repository }} --label fuzzer --state open --json number,title,body --limit 50
448+ ```
449+
450+ 2. For each existing issue, compare:
451+ - **Crash location**: Same file + function? (line numbers can differ)
452+ - **Error pattern**: Same error after normalizing values?
453+ - "index 5 out of bounds" = "index 12 out of bounds" (SAME)
454+ - "len is 100" = "len is 5" (SAME)
455+ - Read source code if needed to verify same root cause
456+
457+ 3. Determine duplication level:
458+ - **EXACT DUPLICATE**: Same crash location + same error pattern → Add reaction
459+ - **SIMILAR**: Same general area but unclear → Add comment
460+ - **NEW BUG**: Different location or different error type → Create new issue
461+
462+ ## Step 3: Take Action
463+
464+ ### If EXACT DUPLICATE (high confidence):
465+ Update or create a tracking comment to count occurrences:
466+
467+ 1. First, check if there's already a tracking comment (look for a comment starting with "<!-- occurrences: ")
468+ 2. If found, extract the count, increment it, and edit the comment
469+ 3. If not found, create a new comment
470+
471+ Comment format:
472+ ```markdown
473+ <!-- occurrences: N -->
474+ **Crash seen N time(s)**
475+
476+ Latest occurrence:
477+ - Crash file: $CRASH_FILE
478+ - Artifact: $ARTIFACT_URL
479+ - Branch: $BRANCH
480+ - Commit: $COMMIT
481+ ```
482+
483+ Use:
484+ - `gh api repos/${{ github.repository }}/issues/ISSUE_NUM/comments` to list comments
485+ - `gh api repos/${{ github.repository }}/issues/comments/COMMENT_ID -X PATCH` to update
486+ - `gh issue comment ISSUE_NUM` to create new
487+
488+ ### If SIMILAR (medium confidence):
489+ Comment on the existing issue with analysis:
490+ ```bash
491+ gh issue comment ISSUE_NUM --repo ${{ github.repository }} --body "..."
492+ ```
493+
494+ Include in comment:
495+ - Note that another crash was detected
496+ - Your confidence level and reasoning
497+ - Key differences if any
498+ - Crash file: $CRASH_FILE
499+ - Workflow: $WORKFLOW_RUN
500+
501+ ### If NEW BUG (not a duplicate):
502+ Create a new issue with `gh issue create`:
503+ ```bash
504+ gh issue create --repo ${{ github.repository }} \
505+ --title "Fuzzing Crash: [brief description]" \
506+ --label "bug,fuzzer" \
507+ --body "..."
508+ ```
509+
510+ Issue body must include:
511+ ```markdown
512+ ## Fuzzing Crash Report
513+
514+ ### Analysis
515+
516+ **Crash Location**: `file.rs:function_name`
517+
518+ **Error Message**:
519+ ```
520+ [error message]
521+ ```
522+
523+ **Stack Trace**:
524+ ```
525+ [top 5-7 frames - keep in code block to prevent markdown rendering issues]
526+ ```
527+
528+ Note: Keep stack traces in code blocks to prevent `#0`, `#1` from being interpreted as markdown headers.
529+
530+ **Root Cause**: [Your analysis]
531+
532+ <details>
533+ <summary>Debug Output</summary>
534+
535+ ```
536+ [Include the complete "Output of std::fmt::Debug:" section from the fuzzer log]
537+ ```
538+ </details>
539+
540+ ### Summary
541+
542+ - **Target**: `array_ops`
543+ - **Crash File**: `$CRASH_FILE`
544+ - **Branch**: $BRANCH
545+ - **Commit**: $COMMIT
546+ - **Crash Artifact**: $ARTIFACT_URL
547+
548+ ### Reproduction
549+
550+ 1. Download the crash artifact:
551+ - **Direct download**: $ARTIFACT_URL
552+ - Or find `operations-fuzzing-crash-artifacts` at: $WORKFLOW_RUN
553+ - Extract the zip file
554+
555+ 2. Reproduce locally:
556+ ```bash
557+ # The artifact contains array_ops/$CRASH_FILE
558+ cargo +nightly fuzz run --sanitizer=none array_ops array_ops/$CRASH_FILE
559+ ```
560+
561+ 3. Get full backtrace:
562+ ```bash
563+ RUST_BACKTRACE=full cargo +nightly fuzz run --sanitizer=none array_ops array_ops/$CRASH_FILE
564+ ```
565+
566+ ---
567+ *Auto-created by fuzzing workflow with Claude analysis*
568+ ```
569+
570+ ## Important Guidelines
571+
572+ - Be conservative: when unsure, prefer creating a new issue over marking as duplicate
573+ - Focus on ROOT CAUSE, not specific values in error messages
574+ - You have full repo access - read source code to understand crashes
575+ - Only use +1 reaction for truly identical crashes
576+
577+ ## Environment Variables
578+
579+ - CRASH_FILE: $CRASH_FILE
580+ - ARTIFACT_URL: $ARTIFACT_URL (direct link to crash artifact)
581+ - BRANCH: $BRANCH
582+ - COMMIT: $COMMIT
583+
584+ Start by reading `logs/fuzz_output.log`.
585+ claude_args : |
586+ --model claude-sonnet-4-5-20250929
587+ --max-turns 25
588+ --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:*)"
0 commit comments