Skip to content

CI/CD

Gate pull requests on what the change introduces, not on the backlog it inherited.

#The workflow Rust Doctor writes for you

The interactive report offers to add .github/workflows/rust-doctor.yml to the workspace it just scanned. It is the only file the tool writes, it never overwrites an existing one, and what it writes is the workflow below.

#GitHub Actions

name: Rust Doctor

on:
  push:
    branches: [main]
  pull_request:
    types: [opened, synchronize, reopened, ready_for_review]

permissions:
  contents: read

jobs:
  inspect:
    name: Inspect
    runs-on: ubuntu-latest
    timeout-minutes: 30
    steps:
      # Baseline scope compares against the base ref, so the shallow default
      # clone is not enough.
      - uses: actions/checkout@v5
        with:
          fetch-depth: 0

      # rust-doctor runs `cargo clippy` inside the scanned workspace.
      - uses: dtolnay/rust-toolchain@stable
        with:
          components: clippy

      - uses: Swatinem/rust-cache@v2

      # BASE_REF reaches the shell through the environment rather than through
      # `${{ }}` interpolation: a branch name is attacker-controlled text on a
      # fork pull request, and interpolating it into a run block is a command
      # injection.
      - name: Inspect the workspace
        env:
          BASE_REF: ${{ github.event.pull_request.base.ref }}
        run: |
          if [ -n "$BASE_REF" ]; then
            npx -y rust-doctor@latest . --yes --verbose \
              --scope baseline --base "origin/$BASE_REF" --blocking error
          else
            npx -y rust-doctor@latest . --yes --verbose --blocking error
          fi

#Why baseline scope on a pull request

A first scan of an existing codebase reports the backlog of every decision taken before today. Failing a contributor's pull request on it teaches everyone to ignore the job.

--scope baseline --base origin/<base> judges only the findings the change introduces. The backlog stays visible on main, where it belongs, and the gate stays credible.

Fingerprints are computed from normalized content, never from source positions, so inserting lines above an existing finding does not make it look new.

#What breaks the build

--blocking decides: none, error, or warning. The step exits with the tool's own exit code, non-zero only when a diagnostic reaches that level. Start at error and tighten once the score is where you want it.

#Any other CI

There is no special mode. Run the same command and read the exit code:

npx -y rust-doctor@latest . --yes --blocking error

For a machine-readable trail, add --json and keep the report as an artifact. Its paths are workspace-relative, so it carries nothing about the runner.