From 0ed7af35ec7137c346411834e9df97c8a6ed5708 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Mon, 29 Apr 2024 17:54:17 +0100 Subject: [PATCH] Add a daily workflow to fuzz the parser with randomly selected seeds (#11203) --- .github/workflows/daily_fuzz.yaml | 72 +++++++++++++++++++++++++++++++ scripts/fuzz-parser/fuzz.py | 7 +-- 2 files changed, 76 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/daily_fuzz.yaml diff --git a/.github/workflows/daily_fuzz.yaml b/.github/workflows/daily_fuzz.yaml new file mode 100644 index 0000000000..48b0f2eac4 --- /dev/null +++ b/.github/workflows/daily_fuzz.yaml @@ -0,0 +1,72 @@ +name: Daily parser fuzz + +on: + workflow_dispatch: + schedule: + - cron: "0 0 * * *" + pull_request: + paths: + - ".github/workflows/daily_fuzz.yaml" + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +env: + CARGO_INCREMENTAL: 0 + CARGO_NET_RETRY: 10 + CARGO_TERM_COLOR: always + RUSTUP_MAX_RETRIES: 10 + PACKAGE_NAME: ruff + FORCE_COLOR: 1 + +jobs: + fuzz: + name: Fuzz + runs-on: ubuntu-latest + timeout-minutes: 20 + # Don't run the cron job on forks: + if: ${{ github.repository == 'astral-sh/ruff' || github.event_name != 'schedule' }} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + - name: Install uv + run: curl -LsSf https://astral.sh/uv/install.sh | sh + - name: Install Python requirements + run: uv pip install -r scripts/fuzz-parser/requirements.txt --system + - name: "Install Rust toolchain" + run: rustup show + - name: "Install mold" + uses: rui314/setup-mold@v1 + - uses: Swatinem/rust-cache@v2 + - name: Build ruff + # A debug build means the script runs slower once it gets started, + # but this is outweighed by the fact that a release build takes *much* longer to compile in CI + run: cargo build --locked + - name: Fuzz + run: python scripts/fuzz-parser/fuzz.py $(shuf -i 0-9999999999999999999 -n 1000) --test-executable target/debug/ruff + + create-issue-on-failure: + name: Create an issue if the daily fuzz surfaced any bugs + runs-on: ubuntu-latest + needs: fuzz + if: ${{ github.repository == 'astral-sh/ruff' && always() && github.event_name == 'schedule' && needs.fuzz.result == 'failure' }} + permissions: + issues: write + steps: + - uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + await github.rest.issues.create({ + owner: "astral-sh", + repo: "ruff", + title: `Daily parser fuzz failed on ${new Date().toDateString()}`, + body: "Runs listed here: https://github.com/astral-sh/ruff/actions/workflows/daily_fuzz.yml", + labels: ["bug", "parser", "fuzzer"], + }) diff --git a/scripts/fuzz-parser/fuzz.py b/scripts/fuzz-parser/fuzz.py index 6e2da9ee54..51a66cdaa3 100644 --- a/scripts/fuzz-parser/fuzz.py +++ b/scripts/fuzz-parser/fuzz.py @@ -77,7 +77,7 @@ class FuzzResult: if self.maybe_bug else colored(f"Ran fuzzer successfully on seed {self.seed}", "green") ) - print(f"{msg:<55} {progress:>15}", flush=True) + print(f"{msg:<60} {progress:>15}", flush=True) if self.maybe_bug: print(colored("The following code triggers a bug:", "red")) print() @@ -298,11 +298,12 @@ def parse_args() -> ResolvedCliArgs: if not args.test_executable: print( - "Running `cargo build --release` since no test executable was specified..." + "Running `cargo build --release` since no test executable was specified...", + flush=True, ) try: subprocess.run( - ["cargo", "build", "--release", "--color", "always"], + ["cargo", "build", "--release", "--locked", "--color", "always"], check=True, capture_output=True, text=True,