|
19 | 19 | outputs: |
20 | 20 | crashes_found: ${{ steps.check.outputs.crashes_found }} |
21 | 21 | crash_count: ${{ steps.check.outputs.crash_count }} |
| 22 | + first_crash_name: ${{ steps.check.outputs.first_crash_name }} |
22 | 23 | steps: |
23 | 24 | - uses: runs-on/action@v2 |
24 | 25 | with: |
|
55 | 56 | run: | |
56 | 57 | if [ -d "fuzz/artifacts" ] && [ "$(ls -A fuzz/artifacts 2>/dev/null)" ]; then |
57 | 58 | echo "crashes_found=true" >> $GITHUB_OUTPUT |
58 | | - CRASH_COUNT=$(find fuzz/artifacts -type f \( -name "crash-*" -o -name "leak-*" -o -name "timeout-*" -o -name "oom-*" \) | wc -l) |
59 | | - echo "crash_count=$CRASH_COUNT" >> $GITHUB_OUTPUT |
60 | | - echo "Found $CRASH_COUNT crash(es)" |
| 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 |
61 | 72 | else |
62 | 73 | echo "crashes_found=false" >> $GITHUB_OUTPUT |
63 | 74 | echo "crash_count=0" >> $GITHUB_OUTPUT |
@@ -115,16 +126,136 @@ jobs: |
115 | 126 | name: io-fuzzing-logs |
116 | 127 | path: ./logs |
117 | 128 |
|
118 | | - - name: List downloaded files |
| 129 | + - name: Extract first crash only |
119 | 130 | run: | |
120 | | - echo "=== Crash Artifacts ===" |
121 | | - ls -lah crash_artifacts/ || echo "No crash artifacts" |
| 131 | + # Only keep the first crash file for analysis |
| 132 | + FIRST_CRASH="${{ needs.io_fuzz.outputs.first_crash_name }}" |
| 133 | + echo "Processing only first crash: $FIRST_CRASH" |
| 134 | +
|
| 135 | + # Create a clean directory with just the first crash |
| 136 | + mkdir -p ./first_crash |
| 137 | + if [ -f "crash_artifacts/$FIRST_CRASH" ]; then |
| 138 | + cp "crash_artifacts/$FIRST_CRASH" ./first_crash/ |
| 139 | + echo "Copied first crash to ./first_crash/" |
| 140 | + else |
| 141 | + echo "Warning: Could not find crash file $FIRST_CRASH" |
| 142 | + echo "Available files:" |
| 143 | + ls -la crash_artifacts/ || echo "No files in crash_artifacts" |
| 144 | + fi |
| 145 | +
|
| 146 | + - name: Show crash info |
| 147 | + run: | |
| 148 | + echo "=== Crash Summary ===" |
| 149 | + echo "Total crashes found: ${{ needs.io_fuzz.outputs.crash_count }}" |
| 150 | + echo "Processing first crash: ${{ needs.io_fuzz.outputs.first_crash_name }}" |
122 | 151 | echo "" |
123 | | - echo "=== Fuzzer Logs ===" |
124 | | - ls -lah logs/ || echo "No logs" |
| 152 | + echo "=== First crash file size ===" |
| 153 | + ls -lh first_crash/ || echo "No crash file" |
125 | 154 | echo "" |
126 | | - echo "=== Log preview (first 50 lines) ===" |
127 | | - head -50 logs/fuzz_output.log || echo "No log file" |
| 155 | + echo "=== Fuzzer log preview (last 100 lines, where crashes are reported) ===" |
| 156 | + tail -100 logs/fuzz_output.log || echo "No log file" |
| 157 | +
|
| 158 | + - name: Create GitHub issue |
| 159 | + env: |
| 160 | + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
| 161 | + run: | |
| 162 | + # Extract crash type from filename |
| 163 | + CRASH_FILE="${{ needs.io_fuzz.outputs.first_crash_name }}" |
| 164 | + if [[ "$CRASH_FILE" == crash-* ]]; then |
| 165 | + CRASH_TYPE="Crash" |
| 166 | + elif [[ "$CRASH_FILE" == leak-* ]]; then |
| 167 | + CRASH_TYPE="Memory Leak" |
| 168 | + elif [[ "$CRASH_FILE" == timeout-* ]]; then |
| 169 | + CRASH_TYPE="Timeout" |
| 170 | + elif [[ "$CRASH_FILE" == oom-* ]]; then |
| 171 | + CRASH_TYPE="Out of Memory" |
| 172 | + else |
| 173 | + CRASH_TYPE="Unknown" |
| 174 | + fi |
| 175 | +
|
| 176 | + # Create issue with gh CLI |
| 177 | + gh issue create \ |
| 178 | + --repo ${{ github.repository }} \ |
| 179 | + --title "Fuzzing $CRASH_TYPE: file_io - $(date -u +%Y-%m-%d)" \ |
| 180 | + --label "bug,fuzzing,file_io-fuzz,needs-triage" \ |
| 181 | + --body-file - <<'EOF' |
| 182 | + ## Fuzzing Crash Report |
| 183 | +
|
| 184 | + The `file_io` fuzzing target detected a $CRASH_TYPE during a scheduled fuzzing run. |
| 185 | +
|
| 186 | + ### Summary |
| 187 | +
|
| 188 | + - **Crash Type**: $CRASH_TYPE |
| 189 | + - **Target**: `file_io` |
| 190 | + - **Crash File**: `${{ needs.io_fuzz.outputs.first_crash_name }}` |
| 191 | + - **Total Crashes Found**: ${{ needs.io_fuzz.outputs.crash_count }} |
| 192 | + - **Workflow Run**: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} |
| 193 | + - **Timestamp**: $(date -u +"%Y-%m-%d %H:%M:%S UTC") |
| 194 | + - **Branch**: ${{ github.ref_name }} |
| 195 | + - **Commit**: ${{ github.sha }} |
| 196 | +
|
| 197 | + ### Crash Artifacts |
| 198 | +
|
| 199 | + Download crash artifacts from the workflow run: |
| 200 | + **https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}** |
| 201 | +
|
| 202 | + Artifacts available: |
| 203 | + - `io-fuzzing-crash-artifacts` - All crash files found (includes ${{ needs.io_fuzz.outputs.crash_count }} crashes) |
| 204 | + - `io-fuzzing-logs` - Complete fuzzer output with stack traces |
| 205 | +
|
| 206 | + ### Reproduction Steps |
| 207 | +
|
| 208 | + 1. Download the `io-fuzzing-crash-artifacts` from the workflow run above |
| 209 | + 2. Extract the crash file to your local `fuzz/artifacts/file_io/` directory |
| 210 | + 3. Reproduce the crash locally: |
| 211 | +
|
| 212 | + ```bash |
| 213 | + cargo +nightly fuzz run file_io fuzz/artifacts/file_io/${{ needs.io_fuzz.outputs.first_crash_name }} |
| 214 | + ``` |
| 215 | +
|
| 216 | + 4. Get full backtrace: |
| 217 | +
|
| 218 | + ```bash |
| 219 | + RUST_BACKTRACE=full cargo +nightly fuzz run file_io fuzz/artifacts/file_io/${{ needs.io_fuzz.outputs.first_crash_name }} |
| 220 | + ``` |
| 221 | +
|
| 222 | + 5. Minimize the test case (optional): |
| 223 | +
|
| 224 | + ```bash |
| 225 | + cargo +nightly fuzz tmin file_io fuzz/artifacts/file_io/${{ needs.io_fuzz.outputs.first_crash_name }} |
| 226 | + ``` |
| 227 | +
|
| 228 | + ### Investigation Checklist |
| 229 | +
|
| 230 | + - [ ] Download crash artifacts from workflow run |
| 231 | + - [ ] Reproduce crash locally with full backtrace |
| 232 | + - [ ] Analyze stack trace and identify root cause |
| 233 | + - [ ] Determine severity (security vs stability) |
| 234 | + - [ ] Check if this is a duplicate of an existing issue |
| 235 | + - [ ] Minimize test case if needed |
| 236 | + - [ ] Create fix PR with reference to this issue |
| 237 | + - [ ] Add regression test |
| 238 | + - [ ] Verify fix with: `cargo +nightly fuzz run file_io <crash-file>` |
| 239 | +
|
| 240 | + ### Environment |
| 241 | +
|
| 242 | + - **Runner**: ubuntu24-full-arm64 |
| 243 | + - **Rust Toolchain**: nightly |
| 244 | + - **Fuzz Duration**: 7200 seconds (2 hours) |
| 245 | + - **Fuzzer**: cargo-fuzz (libFuzzer) |
| 246 | +
|
| 247 | + ### Additional Context |
| 248 | +
|
| 249 | + This issue was automatically created by the fuzzing workflow. If multiple crashes were found, this issue represents the first crash detected. All crash artifacts are available for download. |
| 250 | +
|
| 251 | + **Note**: If this issue is a duplicate of an existing bug, please close it and reference the original issue. |
| 252 | +
|
| 253 | + --- |
| 254 | +
|
| 255 | + *Automatically created by fuzzing workflow* |
| 256 | + *Workflow file: [fuzz.yml](https://github.com/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/fuzz.yml)* |
| 257 | + *Run: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}* |
| 258 | + EOF |
128 | 259 |
|
129 | 260 | ops_fuzz: |
130 | 261 | name: "Array Operations Fuzz" |
|
0 commit comments