Fuzzing Tests #109
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Fuzzing Tests | |
| on: | |
| schedule: | |
| - cron: '0 2 * * 1' # Every Monday at 02:00 UTC | |
| pull_request: | |
| branches: [main] | |
| paths: | |
| - 'internal/**' | |
| - 'core/**' | |
| - 'fuzz/**' | |
| workflow_dispatch: | |
| inputs: | |
| fuzz_duration: | |
| description: 'Fuzzing duration in seconds' | |
| required: false | |
| default: '300' | |
| jobs: | |
| fuzz: | |
| name: Fuzz Testing | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 30 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v6 | |
| with: | |
| submodules: recursive | |
| - name: Checkout common_system (optional dependency) | |
| uses: actions/checkout@v6 | |
| continue-on-error: true | |
| with: | |
| repository: kcenon/common_system | |
| path: common_system | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Install dependencies | |
| run: | | |
| sudo apt-get update | |
| # Ubuntu 24.04 has GCC 14 by default with C++20 <format> support | |
| sudo apt-get install -y cmake ninja-build clang llvm libgtest-dev python3 | |
| - name: Generate seed corpus | |
| run: | | |
| python3 fuzz/generate_corpus.py | |
| ls -la corpus/ | |
| - name: Configure with Fuzzing | |
| run: | | |
| CC=clang CXX=clang++ cmake -B build -G Ninja \ | |
| -DCMAKE_BUILD_TYPE=Debug \ | |
| -DBUILD_FUZZING=ON \ | |
| -DBUILD_TESTS=OFF \ | |
| -DBUILD_CONTAINER_SAMPLES=OFF | |
| - name: Build fuzz targets | |
| run: cmake --build build --target fuzz_deserialize fuzz_container_deserialize | |
| - name: Run value deserialize fuzzing | |
| id: fuzz_value | |
| continue-on-error: true | |
| run: | | |
| DURATION=${{ github.event.inputs.fuzz_duration || '300' }} | |
| echo "Running fuzz_deserialize for ${DURATION} seconds..." | |
| timeout ${DURATION} ./build/fuzz/fuzz_deserialize corpus/deserialize \ | |
| -max_len=4096 \ | |
| -print_final_stats=1 \ | |
| 2>&1 | tee fuzz_deserialize.log || true | |
| # Check for crashes | |
| if ls crash-* 1> /dev/null 2>&1; then | |
| echo "crash_found=true" >> $GITHUB_OUTPUT | |
| echo "::error::Crash found in fuzz_deserialize" | |
| else | |
| echo "crash_found=false" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Run container deserialize fuzzing | |
| id: fuzz_container | |
| continue-on-error: true | |
| run: | | |
| DURATION=${{ github.event.inputs.fuzz_duration || '300' }} | |
| echo "Running fuzz_container_deserialize for ${DURATION} seconds..." | |
| timeout ${DURATION} ./build/fuzz/fuzz_container_deserialize corpus/container \ | |
| -max_len=8192 \ | |
| -print_final_stats=1 \ | |
| 2>&1 | tee fuzz_container.log || true | |
| # Check for crashes | |
| if ls crash-* 1> /dev/null 2>&1; then | |
| echo "crash_found=true" >> $GITHUB_OUTPUT | |
| echo "::error::Crash found in fuzz_container_deserialize" | |
| else | |
| echo "crash_found=false" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Check for crashes | |
| run: | | |
| if ls crash-* 1> /dev/null 2>&1; then | |
| echo "Crashes found!" | |
| ls -la crash-* | |
| for crash in crash-*; do | |
| echo "=== $crash ===" | |
| xxd "$crash" | head -20 | |
| done | |
| exit 1 | |
| fi | |
| echo "No crashes found - fuzzing completed successfully" | |
| - name: Generate summary | |
| if: always() | |
| run: | | |
| echo "## Fuzzing Results" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| if ls crash-* 1> /dev/null 2>&1; then | |
| echo ":x: **Crashes detected**" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "| File | Size |" >> $GITHUB_STEP_SUMMARY | |
| echo "|------|------|" >> $GITHUB_STEP_SUMMARY | |
| for crash in crash-*; do | |
| size=$(stat -c%s "$crash" 2>/dev/null || stat -f%z "$crash") | |
| echo "| $crash | $size bytes |" >> $GITHUB_STEP_SUMMARY | |
| done | |
| else | |
| echo ":white_check_mark: **No crashes found**" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### Corpus Statistics" >> $GITHUB_STEP_SUMMARY | |
| echo "- Deserialize corpus: $(ls corpus/deserialize 2>/dev/null | wc -l) files" >> $GITHUB_STEP_SUMMARY | |
| echo "- Container corpus: $(ls corpus/container 2>/dev/null | wc -l) files" >> $GITHUB_STEP_SUMMARY | |
| - name: Upload corpus | |
| if: always() | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: fuzz-corpus | |
| path: corpus/ | |
| retention-days: 90 | |
| - name: Upload crashes | |
| if: failure() | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: fuzz-crashes | |
| path: | | |
| crash-* | |
| fuzz_*.log | |
| - name: Upload logs | |
| if: always() | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: fuzz-logs | |
| path: fuzz_*.log | |
| retention-days: 30 |