nix: put libstdc++ on the fuzz shell's LD_LIBRARY_PATH for Linux #2
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
| # SPDX-License-Identifier: AGPL-3.0-only | |
| # Copyright (C) 2026 RS-Key contributors | |
| # Scheduled deep checks — the slow adversarial suites that are deliberately | |
| # not part of the merge gate (docs/testing.md): | |
| # miri — fuzz/tests/miri.rs: every fuzz target's logic under Miri's UB | |
| # checker. MIRIFLAGS policy comes from the .#fuzz dev shell. | |
| # fuzz — a timed libFuzzer pass over every cargo-fuzz target. The corpus | |
| # is carried between runs via the actions cache, so coverage | |
| # accumulates week over week; crash artifacts are uploaded. | |
| # | |
| # Runs weekly, on demand (workflow_dispatch, with a per-target time knob), | |
| # and self-tests on any push that edits this file. Local equivalents: | |
| # nix develop .#fuzz -c cargo miri test --manifest-path fuzz/Cargo.toml | |
| # nix develop .#fuzz -c cargo fuzz run <target> -- -max_total_time=120 | |
| name: deep-checks | |
| on: | |
| schedule: | |
| - cron: "17 5 * * 1" # Mondays 05:17 UTC | |
| workflow_dispatch: | |
| inputs: | |
| fuzz_seconds: | |
| description: seconds of fuzzing per target | |
| default: "120" | |
| push: | |
| branches: [main] | |
| # The dev shell defines this workflow's runtime environment — self-test on | |
| # changes to either. | |
| paths: [".github/workflows/deep-checks.yml", "nix/devshells.nix"] | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: deep-checks | |
| cancel-in-progress: true | |
| jobs: | |
| miri: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 180 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: DeterminateSystems/nix-installer-action@v16 | |
| # Own prefix (the nightly toolchain only this workflow needs), falling | |
| # back to the ci cache for the shared store. | |
| - uses: nix-community/cache-nix-action@v6 | |
| with: | |
| primary-key: nix-fuzz-${{ runner.os }}-${{ hashFiles('flake.lock') }} | |
| restore-prefixes-first-match: | | |
| nix-fuzz-${{ runner.os }}- | |
| nix-${{ runner.os }}- | |
| - uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.cargo/registry | |
| ~/.cargo/git | |
| fuzz/target | |
| key: miri-${{ runner.os }}-${{ hashFiles('fuzz/Cargo.lock', 'flake.lock') }} | |
| restore-keys: miri-${{ runner.os }}- | |
| - name: miri — every fuzz target's logic under the UB checker | |
| run: nix develop .#fuzz -c cargo miri test --manifest-path fuzz/Cargo.toml | |
| fuzz: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 240 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: DeterminateSystems/nix-installer-action@v16 | |
| - uses: nix-community/cache-nix-action@v6 | |
| with: | |
| primary-key: nix-fuzz-${{ runner.os }}-${{ hashFiles('flake.lock') }} | |
| restore-prefixes-first-match: | | |
| nix-fuzz-${{ runner.os }}- | |
| nix-${{ runner.os }}- | |
| - uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.cargo/registry | |
| ~/.cargo/git | |
| fuzz/target | |
| key: fuzz-${{ runner.os }}-${{ hashFiles('fuzz/Cargo.lock', 'flake.lock') }} | |
| restore-keys: fuzz-${{ runner.os }}- | |
| # The corpus is gitignored (fuzz/corpus) — in CI it lives in the cache: | |
| # restore the newest, save under a fresh key even when a target crashes. | |
| - uses: actions/cache/restore@v4 | |
| with: | |
| path: fuzz/corpus | |
| key: fuzz-corpus-${{ github.run_id }} | |
| restore-keys: fuzz-corpus- | |
| - name: build every fuzz target | |
| run: nix develop .#fuzz -c cargo fuzz build | |
| # One pass over every target; a crash does not stop the loop, so one | |
| # bad target cannot mask another's findings. | |
| - name: fuzz every target | |
| run: | | |
| nix develop .#fuzz -c bash -euo pipefail -c ' | |
| failed="" | |
| for t in $(cargo fuzz list); do | |
| echo "::group::${t} (${FUZZ_SECONDS}s)" | |
| if ! cargo fuzz run "$t" -- -max_total_time="$FUZZ_SECONDS" -print_final_stats=1; then | |
| failed="$failed $t" | |
| fi | |
| echo "::endgroup::" | |
| done | |
| if [ -n "$failed" ]; then | |
| echo "::error::crashing targets:$failed" | |
| exit 1 | |
| fi | |
| ' | |
| env: | |
| FUZZ_SECONDS: ${{ inputs.fuzz_seconds || '120' }} | |
| - name: upload crash artifacts | |
| if: failure() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: fuzz-artifacts-${{ github.run_id }} | |
| path: fuzz/artifacts/ | |
| if-no-files-found: ignore | |
| - uses: actions/cache/save@v4 | |
| if: always() | |
| with: | |
| path: fuzz/corpus | |
| key: fuzz-corpus-${{ github.run_id }} |