Skip to content

Nightly Fuzz

Nightly Fuzz #131

Workflow file for this run

name: Nightly Fuzz
on:
workflow_dispatch:
inputs:
max_total_time:
description: "Per-target fuzz duration in seconds"
default: "600"
required: false
schedule:
- cron: "0 2 * * *"
jobs:
fuzz:
runs-on: ubuntu-24.04
permissions:
contents: read
actions: write # needed to save the corpus cache
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y clang llvm libbpf-dev pkg-config cmake ninja-build libgtest-dev
- name: Configure
env:
CC: clang
CXX: clang++
run: cmake -S . -B build-fuzz -G Ninja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DENABLE_FUZZING=ON -DBUILD_TESTING=OFF -DSKIP_BPF_BUILD=ON
- name: Build
run: cmake --build build-fuzz --target fuzz_policy fuzz_bundle fuzz_network fuzz_path fuzz_event
# The runtime corpus is a union of (a) checked-in seeds and
# (b) interesting inputs libFuzzer discovered on previous nightly
# runs. Restoring from cache lets coverage compound night-over-night
# rather than starting from zero-byte seeds every run.
- name: Restore previous corpus
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: runtime-corpus
key: fuzz-corpus-${{ github.run_id }}
restore-keys: |
fuzz-corpus-
- name: Prepare runtime corpus
run: |
for target in fuzz_policy fuzz_bundle fuzz_network fuzz_path fuzz_event; do
mkdir -p "runtime-corpus/${target}"
# -n: do not overwrite inputs discovered by previous runs
if [ -d "tests/fuzz/corpus/${target}" ]; then
cp -an "tests/fuzz/corpus/${target}/." "runtime-corpus/${target}/" 2>/dev/null || true
fi
echo "${target}: $(ls "runtime-corpus/${target}" | wc -l) inputs"
done
- name: Run fuzzers (nightly deep)
env:
MAX_TOTAL_TIME: ${{ inputs.max_total_time || '600' }}
run: |
for target in fuzz_policy fuzz_bundle fuzz_network fuzz_path fuzz_event; do
echo "Fuzzing ${target} for ${MAX_TOTAL_TIME}s"
if [ "${target}" = "fuzz_event" ]; then
# fuzz_event decodes events to stdout; redirect to keep logs
# manageable while still surfacing libFuzzer stderr stats.
./build-fuzz/${target} "runtime-corpus/${target}" \
-max_total_time="${MAX_TOTAL_TIME}" \
-print_final_stats=1 \
>/dev/null
else
./build-fuzz/${target} "runtime-corpus/${target}" \
-max_total_time="${MAX_TOTAL_TIME}" \
-print_final_stats=1
fi
done
# Save the grown corpus so tomorrow's run starts from here.
# Key includes run_id so we never overwrite; actions/cache uses LRU
# eviction if the repo exceeds its 10 GB quota.
- name: Save corpus cache
if: always()
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: runtime-corpus
key: fuzz-corpus-${{ github.run_id }}
- name: Upload fuzz crash artifacts
if: failure()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: nightly-fuzz-crashes
path: |
crash-*
build-fuzz/crash-*