From 2197a13c32e88c920c898fbb871e8fbe418c51a5 Mon Sep 17 00:00:00 2001 From: Anay Dhawan Date: Sun, 18 Oct 2026 10:39:11 +0530 Subject: [PATCH] ci: add job timeouts and PR concurrency to every workflow (#1050) Every job now sets timeout-minutes (5 to 30, recent runs finish in under five minutes), and workflows that run on pull_request cancel superseded PR runs via a concurrency group. Runs on main are never cancelled. The policy is written up in .github/ACTIONS-AUDIT.md. --- .github/ACTIONS-AUDIT.md | 19 +++++++++++++++++++ .github/workflows/audits.yml | 8 ++++++++ .github/workflows/browser-smoke.yml | 5 +++++ .github/workflows/build-explainers.yml | 5 +++++ .github/workflows/citation.yml | 5 +++++ .github/workflows/codeowners-access.yml | 5 +++++ .github/workflows/codeql.yml | 5 +++++ .github/workflows/favicons.yml | 5 +++++ .github/workflows/first.interaction.yml | 1 + .github/workflows/frozen-files.yml | 5 +++++ .github/workflows/lint.yml | 5 +++++ .github/workflows/pr-review-ping.yml | 1 + .github/workflows/validate-workflow.yml | 5 +++++ 13 files changed, 74 insertions(+) diff --git a/.github/ACTIONS-AUDIT.md b/.github/ACTIONS-AUDIT.md index 97a28fd2..ef7435ab 100644 --- a/.github/ACTIONS-AUDIT.md +++ b/.github/ACTIONS-AUDIT.md @@ -73,6 +73,25 @@ direct commit (`b632cfb`) rather than going through this audit first, exactly the gap #188 asked to close. Treat this entry as the audit that should have gated that merge, not one that happened before it. +## Job timeouts and concurrency (#1050) + +GitHub's default job timeout is six hours, so a hung benchmark or browser job can hold a +runner for that long, and pushing again to a pull request used to leave every superseded +run going. Policy for every workflow in `.github/workflows/`: + +- **Every job sets `timeout-minutes`.** Recent runs finish in under five minutes end to end, + so the limits leave a wide margin: 5 for the small check jobs, 10 for lint, favicons, + explainers and browser smoke, 15 for the audit matrix, 20 for the profiler tests, 30 for + the benchmark harness and CodeQL. Raise a limit in the same PR that makes a job slower. +- **Workflows that run on `pull_request` set `concurrency`**, grouped by workflow and pull + request number (or ref for pushes). `cancel-in-progress` is on only for `pull_request` + events, so a new commit cancels the stale PR run but a run on `main` is never cancelled. +- **Left alone:** `first.interaction.yml` and `pr-review-ping.yml` (`pull_request_target` and + `issues` events post one-off comments and must not be cancelled). +- **Not changed:** several workflows still trigger on both `push` and `pull_request`, so a + commit on a branch with an open PR starts each of those jobs twice. Restricting `push` to + `main` would fix that but changes which events gate a merge, so it is a separate decision. + ## Conclusion All five audited version jumps (including `github/codeql-action`'s first diff --git a/.github/workflows/audits.yml b/.github/workflows/audits.yml index a806a37d..8fcd66c4 100644 --- a/.github/workflows/audits.yml +++ b/.github/workflows/audits.yml @@ -11,6 +11,10 @@ on: permissions: contents: read +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + jobs: changes: # Decides whether `profiler`/`benchmark-harness` below need to run at @@ -26,6 +30,7 @@ jobs: # (#237) - same question ("could this change affect the test suite?"), # same answer. Keep the two in sync. runs-on: ubuntu-latest + timeout-minutes: 5 outputs: code_relevant: ${{ steps.filter.outputs.code_relevant }} steps: @@ -62,6 +67,7 @@ jobs: run-audits: runs-on: ubuntu-latest + timeout-minutes: 15 strategy: fail-fast: false matrix: @@ -104,6 +110,7 @@ jobs: needs: changes if: needs.changes.outputs.code_relevant == 'true' runs-on: ubuntu-latest + timeout-minutes: 20 steps: - uses: actions/checkout@v7 @@ -152,6 +159,7 @@ jobs: needs: changes if: needs.changes.outputs.code_relevant == 'true' runs-on: ubuntu-latest + timeout-minutes: 30 steps: - uses: actions/checkout@v7 diff --git a/.github/workflows/browser-smoke.yml b/.github/workflows/browser-smoke.yml index c6d3c742..849c9b72 100644 --- a/.github/workflows/browser-smoke.yml +++ b/.github/workflows/browser-smoke.yml @@ -10,9 +10,14 @@ on: permissions: contents: read +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + jobs: browser: runs-on: ubuntu-latest + timeout-minutes: 10 steps: - uses: actions/checkout@v7 diff --git a/.github/workflows/build-explainers.yml b/.github/workflows/build-explainers.yml index dd117a16..eab5312a 100644 --- a/.github/workflows/build-explainers.yml +++ b/.github/workflows/build-explainers.yml @@ -62,9 +62,14 @@ on: permissions: contents: read +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + jobs: check: runs-on: ubuntu-latest + timeout-minutes: 10 steps: - uses: actions/checkout@v7 with: diff --git a/.github/workflows/citation.yml b/.github/workflows/citation.yml index ccabf4a7..2c00af0c 100644 --- a/.github/workflows/citation.yml +++ b/.github/workflows/citation.yml @@ -8,10 +8,15 @@ on: paths: - CITATION.cff +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + jobs: validate: name: Validate CITATION.cff runs-on: ubuntu-latest + timeout-minutes: 5 steps: - name: Check out repository uses: actions/checkout@v7 diff --git a/.github/workflows/codeowners-access.yml b/.github/workflows/codeowners-access.yml index 90f414ec..f10ee9e0 100644 --- a/.github/workflows/codeowners-access.yml +++ b/.github/workflows/codeowners-access.yml @@ -25,10 +25,15 @@ on: permissions: contents: read +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + jobs: check-write-access: if: github.repository == 'yakew7/Fair-Code' runs-on: ubuntu-latest + timeout-minutes: 5 steps: - uses: actions/checkout@v7 diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index f94f7cac..1232e29b 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -13,10 +13,15 @@ permissions: contents: read security-events: write +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + jobs: analyze: name: Analyze runs-on: ubuntu-latest + timeout-minutes: 30 strategy: fail-fast: false diff --git a/.github/workflows/favicons.yml b/.github/workflows/favicons.yml index 711c6fd2..63020519 100644 --- a/.github/workflows/favicons.yml +++ b/.github/workflows/favicons.yml @@ -32,9 +32,14 @@ on: permissions: contents: read +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + jobs: check: runs-on: ubuntu-latest + timeout-minutes: 10 steps: - uses: actions/checkout@v7 diff --git a/.github/workflows/first.interaction.yml b/.github/workflows/first.interaction.yml index 2e27f228..b4b4e9dd 100644 --- a/.github/workflows/first.interaction.yml +++ b/.github/workflows/first.interaction.yml @@ -9,6 +9,7 @@ on: jobs: greet: runs-on: ubuntu-latest + timeout-minutes: 5 permissions: issues: write pull-requests: write diff --git a/.github/workflows/frozen-files.yml b/.github/workflows/frozen-files.yml index 649d4f7f..90ac47c6 100644 --- a/.github/workflows/frozen-files.yml +++ b/.github/workflows/frozen-files.yml @@ -18,9 +18,14 @@ on: permissions: contents: read +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + jobs: check-frozen-files: runs-on: ubuntu-latest + timeout-minutes: 5 steps: - name: No-op (freeze lifted) run: echo "Paper freeze lifted - no files are protected anymore." diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 4060b94f..7f86540b 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -9,9 +9,14 @@ permissions: issues: read pull-requests: read +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + jobs: lint: runs-on: ubuntu-latest + timeout-minutes: 10 steps: - uses: actions/checkout@v7 diff --git a/.github/workflows/pr-review-ping.yml b/.github/workflows/pr-review-ping.yml index 080f3020..5c0f7981 100644 --- a/.github/workflows/pr-review-ping.yml +++ b/.github/workflows/pr-review-ping.yml @@ -23,6 +23,7 @@ permissions: jobs: ping: runs-on: ubuntu-latest + timeout-minutes: 5 steps: - name: Checkout base ref uses: actions/checkout@v7 diff --git a/.github/workflows/validate-workflow.yml b/.github/workflows/validate-workflow.yml index b7abc655..3ebf5981 100644 --- a/.github/workflows/validate-workflow.yml +++ b/.github/workflows/validate-workflow.yml @@ -8,10 +8,15 @@ on: paths: - '.github/workflows/*.yml' +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + jobs: validate: name: Validate workflow YAML runs-on: ubuntu-latest + timeout-minutes: 5 steps: - name: Check out repository