Skip to content

Commit a41db7a

Browse files
committed
Merge develop and resolve fuzz.yml conflicts
- Accept develop's refactored approach using reusable workflow - Keep automation integration with attempt-fix jobs - Remove inline Claude prompt in favor of report-fuzz-crash.yml
2 parents 31bb757 + 9d938cd commit a41db7a

File tree

55 files changed

+2321
-678
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+2321
-678
lines changed

.github/workflows/fuzz.yml

Lines changed: 74 additions & 207 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)