Skip to content

Fuzz

Fuzz #45

Workflow file for this run

# Fuzzing workflow for WRAITH Protocol
# Runs cargo-fuzz on nightly Rust to find crashes and undefined behavior
name: Fuzz
on:
# Run on manual trigger
workflow_dispatch:
inputs:
duration:
description: 'Fuzz duration in seconds per target'
required: false
default: '60'
type: string
target:
description: 'Specific fuzz target (leave empty for all)'
required: false
default: ''
type: string
# Run weekly on Sunday at midnight UTC
schedule:
- cron: '0 0 * * 0'
# Run on PRs that modify fuzz targets or core crypto code
pull_request:
paths:
- 'fuzz/**'
- 'crates/wraith-crypto/**'
- 'crates/wraith-core/src/frame.rs'
- 'crates/wraith-discovery/src/dht/**'
- 'crates/wraith-obfuscation/src/padding.rs'
- 'crates/wraith-files/src/tree_hash.rs'
env:
CARGO_TERM_COLOR: always
RUSTFLAGS: -D warnings
jobs:
fuzz:
name: Fuzz ${{ matrix.target }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
target:
- fuzz_frame_parser
- fuzz_dht_message
- fuzz_crypto
- fuzz_padding
- fuzz_tree_hash
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Install Rust nightly
uses: dtolnay/rust-toolchain@nightly
with:
components: llvm-tools-preview
- name: Install cargo-fuzz
run: cargo install cargo-fuzz
- name: Cache cargo registry
uses: actions/cache@v5
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-fuzz-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-fuzz-
- name: Create corpus directory
run: mkdir -p fuzz/corpus/${{ matrix.target }}
# Use cache instead of artifacts for corpus persistence across workflow runs
# actions/cache persists across runs; actions/download-artifact@v7 only works within the same run
- name: Restore corpus from cache
id: corpus-cache
uses: actions/cache@v5
with:
path: fuzz/corpus/${{ matrix.target }}
key: fuzz-corpus-${{ matrix.target }}-${{ github.sha }}
restore-keys: |
fuzz-corpus-${{ matrix.target }}-
- name: Run fuzzer
env:
FUZZ_DURATION: ${{ github.event.inputs.duration || '60' }}
FUZZ_TARGET_INPUT: ${{ github.event.inputs.target }}
FUZZ_TARGET: ${{ matrix.target }}
RUST_BACKTRACE: '1'
run: |
# If specific target requested and doesn't match, skip
if [ -n "$FUZZ_TARGET_INPUT" ] && [ "$FUZZ_TARGET_INPUT" != "$FUZZ_TARGET" ]; then
echo "Skipping $FUZZ_TARGET (requested: $FUZZ_TARGET_INPUT)"
exit 0
fi
echo "Fuzzing $FUZZ_TARGET for ${FUZZ_DURATION} seconds..."
cd fuzz
cargo +nightly fuzz run "$FUZZ_TARGET" -- \
-max_total_time="${FUZZ_DURATION}" \
-max_len=16384 \
-print_final_stats=1
# Note: Corpus is automatically saved to cache at job end (actions/cache post-job behavior)
# We only upload artifacts for crashes which need longer retention and explicit review
- name: Upload crash artifacts
if: failure()
uses: actions/upload-artifact@v6
with:
name: crashes-${{ matrix.target }}
path: |
fuzz/artifacts/${{ matrix.target }}
fuzz/corpus/${{ matrix.target }}/crash-*
retention-days: 90
# Summary job that fails if any fuzzer found a crash
fuzz-summary:
name: Fuzz Summary
runs-on: ubuntu-latest
needs: fuzz
if: always()
steps:
- name: Check fuzz results
env:
FUZZ_RESULT: ${{ needs.fuzz.result }}
run: |
if [ "$FUZZ_RESULT" != "success" ]; then
echo "One or more fuzzers found issues!"
exit 1
fi
echo "All fuzzers completed successfully"
# Coverage-guided fuzzing with longer duration (weekly only)
extended-fuzz:
name: Extended Fuzz (Coverage)
runs-on: ubuntu-latest
if: github.event_name == 'schedule'
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Install Rust nightly
uses: dtolnay/rust-toolchain@nightly
with:
components: llvm-tools-preview
- name: Install cargo-fuzz
run: cargo install cargo-fuzz
- name: Create corpus directories
run: |
mkdir -p fuzz/corpus/fuzz_frame_parser
mkdir -p fuzz/corpus/fuzz_dht_message
mkdir -p fuzz/corpus/fuzz_crypto
mkdir -p fuzz/corpus/fuzz_padding
mkdir -p fuzz/corpus/fuzz_tree_hash
# Restore all corpus caches for extended fuzzing
- name: Restore corpus caches
uses: actions/cache@v5
with:
path: |
fuzz/corpus/fuzz_frame_parser
fuzz/corpus/fuzz_dht_message
fuzz/corpus/fuzz_crypto
fuzz/corpus/fuzz_padding
fuzz/corpus/fuzz_tree_hash
key: fuzz-corpus-extended-${{ github.sha }}
restore-keys: |
fuzz-corpus-extended-
fuzz-corpus-fuzz_frame_parser-
fuzz-corpus-fuzz_dht_message-
fuzz-corpus-fuzz_crypto-
fuzz-corpus-fuzz_padding-
fuzz-corpus-fuzz_tree_hash-
- name: Extended fuzzing (all targets)
run: |
cd fuzz
for target in fuzz_frame_parser fuzz_dht_message fuzz_crypto fuzz_padding fuzz_tree_hash; do
echo "Extended fuzzing $target for 300 seconds..."
cargo +nightly fuzz run "$target" -- \
-max_total_time=300 \
-max_len=65536 \
-print_final_stats=1 || true
done
- name: Upload all artifacts
if: always()
uses: actions/upload-artifact@v6
with:
name: extended-fuzz-results
path: |
fuzz/artifacts/
fuzz/corpus/
retention-days: 90