From 281169fdfcab2adbe48ed57fad5a0c0476c6e154 Mon Sep 17 00:00:00 2001 From: Musa AbdulKareem Date: Wed, 18 Feb 2026 06:48:50 +0100 Subject: [PATCH 01/11] ci: optimize GitHub workflows with caching, concurrency, timeouts, and permissions - Add Swatinem/rust-cache@v2 to all Rust build workflows for intelligent caching of ~/.cargo and target/ - Add concurrency groups with cancel-in-progress to all workflows so duplicate runs on the same branch/PR are automatically cancelled - Add timeout-minutes to all jobs that were missing them - Add least-privilege permissions (contents: read) at workflow level, with job-level overrides only where needed - Replace cargo install with taiki-e/install-action for cargo-llvm-cov and cargo-deny (pre-built binaries, much faster) - Simplify dependency-audit.yml by removing manual cache management - Enable cache-on-failure for Miri builds (slow builds benefit from partial caches) - Tighten docs.yml permissions: docs job only needs read, not write --- .github/workflows/build-and-test.yml | 23 +++++++++----- .github/workflows/coverage.yml | 42 +++++++++++++++----------- .github/workflows/dependency-audit.yml | 35 ++++++++------------- .github/workflows/docs.yml | 15 +++++++-- .github/workflows/linter.yml | 9 ++++++ .github/workflows/ub-detection.yml | 10 ++++++ 6 files changed, 84 insertions(+), 50 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index c65cbba..bc1eb87 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -2,9 +2,16 @@ name: Build and test code on: push: - branches: [ "main" ] + branches: ["main"] pull_request: - branches: [ "main" ] + branches: ["main"] + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true env: CARGO_TERM_COLOR: always @@ -13,9 +20,11 @@ env: jobs: build: runs-on: ubuntu-latest + timeout-minutes: 30 steps: - - uses: actions/checkout@v4 - - name: Build - run: cargo test --workspace --verbose --no-run - - name: Run tests - run: cargo test --workspace --verbose + - uses: actions/checkout@v4 + - uses: Swatinem/rust-cache@v2 + - name: Build + run: cargo test --workspace --verbose --no-run + - name: Run tests + run: cargo test --workspace --verbose diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 5e929c2..5d2331f 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -2,35 +2,35 @@ name: Coverage (Push) on: push: - branches: ['**'] # all branches, including main + branches: [main] + pull_request: + types: [opened, synchronize, reopened] permissions: contents: read actions: write +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + jobs: coverage-push: runs-on: ubuntu-latest + timeout-minutes: 30 steps: - uses: actions/checkout@v4 - - name: Cache llvm-cov build - id: cache-llvm-cov - uses: actions/cache@v4 - continue-on-error: false - with: - path: | - ~/.cargo/bin/ - ~/.cargo/registry/index/ - ~/.cargo/registry/cache/ - ~/.cargo/git/db/ - target/ - key: ${{ runner.os }}-cargo-llvm-cov-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-cargo-llvm-cov - - - run: which cargo-llvm-cov || cargo install cargo-llvm-cov - - run: rustup component add llvm-tools-preview - - run: cargo llvm-cov --workspace --lcov --output-path lcov.info --ignore-filename-regex '^examples/' + - uses: Swatinem/rust-cache@v2 + + - name: Install cargo-llvm-cov + uses: taiki-e/install-action@cargo-llvm-cov + + - name: Install llvm-tools + run: rustup component add llvm-tools-preview + + - name: Run code coverage + run: cargo llvm-cov --workspace --lcov --output-path lcov.info --ignore-filename-regex '^examples/' - name: Upload branch coverage artifact uses: actions/upload-artifact@v4 @@ -38,3 +38,9 @@ jobs: name: coverage-lcov path: lcov.info retention-days: 21 + + - name: Comment PR with coverage + uses: romeovs/lcov-reporter-action@v0.4.0 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + lcov-file: lcov.info diff --git a/.github/workflows/dependency-audit.yml b/.github/workflows/dependency-audit.yml index 9ca153b..48f03a6 100644 --- a/.github/workflows/dependency-audit.yml +++ b/.github/workflows/dependency-audit.yml @@ -3,8 +3,15 @@ name: Dependency security audit on: push: paths: - - '**/Cargo.toml' - - '**/Cargo.lock' + - "**/Cargo.toml" + - "**/Cargo.lock" + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true env: CARGO_TERM_COLOR: always @@ -14,28 +21,12 @@ jobs: security_audit: timeout-minutes: 10 runs-on: ubuntu-latest - permissions: - contents: read - checks: write steps: - name: Check out uses: actions/checkout@v4 - - name: Cache audit-check build - id: cache-audit-check - uses: actions/cache@v4 - continue-on-error: false - with: - path: | - ~/.cargo/bin/ - ~/.cargo/registry/index/ - ~/.cargo/registry/cache/ - ~/.cargo/git/db/ - target/ - key: ${{ runner.os }}-cargo-deny-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-cargo-deny - - name: Run audit-check action - run: | - which cargo-deny || cargo install cargo-deny - cargo deny check + uses: taiki-e/install-action@cargo-deny + + - name: Run cargo deny + run: cargo deny check diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 05fb081..89e0ef4 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -5,13 +5,19 @@ name: Docs on: workflow_dispatch: +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + jobs: # TODO(template) remove docs publishing, when the crate is published to crates.io docs: - permissions: - contents: write name: Documentation runs-on: ubuntu-latest + timeout-minutes: 15 steps: - name: Checkout source code uses: actions/checkout@v4 @@ -19,6 +25,8 @@ jobs: fetch-depth: 1 persist-credentials: false + - uses: Swatinem/rust-cache@v2 + - name: Setup pages id: pages uses: actions/configure-pages@v5 @@ -49,8 +57,9 @@ jobs: name: github-pages url: ${{ steps.deployment.outputs.page_url }} runs-on: ubuntu-latest + timeout-minutes: 5 needs: docs steps: - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v4 \ No newline at end of file + uses: actions/deploy-pages@v4 diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index 2f437c3..44d0f4f 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -2,6 +2,13 @@ name: Linter check on: push +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + env: CARGO_TERM_COLOR: always CARGO_INCREMENTAL: 0 @@ -11,8 +18,10 @@ env: jobs: linter_check: runs-on: ubuntu-latest + timeout-minutes: 15 steps: - uses: actions/checkout@v4 + - uses: Swatinem/rust-cache@v2 - name: Run Fmt run: cargo fmt --all -- --check diff --git a/.github/workflows/ub-detection.yml b/.github/workflows/ub-detection.yml index cda1168..875799a 100644 --- a/.github/workflows/ub-detection.yml +++ b/.github/workflows/ub-detection.yml @@ -2,6 +2,13 @@ name: UB (undefined behavior) detection on: push +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + env: CARGO_TERM_COLOR: always CARGO_INCREMENTAL: 0 @@ -16,6 +23,9 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + - uses: Swatinem/rust-cache@v2 + with: + cache-on-failure: true - run: | rustup +nightly component add miri cargo +nightly miri setup From f46da5a93c1d34a188da0b031caf36262c4655bf Mon Sep 17 00:00:00 2001 From: Musa AbdulKareem Date: Wed, 18 Feb 2026 06:57:08 +0100 Subject: [PATCH 02/11] ci: split into 3 parallel jobs This commit splits fmt, clippy and typos into three different jobs It includes paths where changes there don't trigger a new action --- .github/workflows/linter.yml | 43 +++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index 44d0f4f..0db8424 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -1,6 +1,20 @@ name: Linter check -on: push +on: + push: + branches: [main] + paths-ignore: + - "**.md" + - "LICENSE*" + - ".github/workflows/docs.yml" + - "katex-header.html" + pull_request: + branches: [main] + paths-ignore: + - "**.md" + - "LICENSE*" + - ".github/workflows/docs.yml" + - "katex-header.html" permissions: contents: read @@ -12,21 +26,38 @@ concurrency: env: CARGO_TERM_COLOR: always CARGO_INCREMENTAL: 0 - # Make sure CI fails on all warnings, including Clippy lints - RUSTFLAGS: "-Dwarnings" jobs: - linter_check: + fmt: runs-on: ubuntu-latest - timeout-minutes: 15 + timeout-minutes: 5 steps: - uses: actions/checkout@v4 - - uses: Swatinem/rust-cache@v2 + - uses: dtolnay/rust-toolchain@stable + with: + components: rustfmt - name: Run Fmt run: cargo fmt --all -- --check + clippy: + runs-on: ubuntu-latest + timeout-minutes: 15 + env: + # Make sure CI fails on all warnings, including Clippy lints + RUSTFLAGS: "-Dwarnings" + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + with: + components: clippy + - uses: Swatinem/rust-cache@v2 - name: Run Clippy run: cargo clippy --all-targets --all-features + typos: + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - uses: actions/checkout@v4 - name: Check typos uses: crate-ci/typos@master From 588039b0cfe734501b9ba3170834e15dad5c91b8 Mon Sep 17 00:00:00 2001 From: Musa AbdulKareem Date: Wed, 18 Feb 2026 06:58:50 +0100 Subject: [PATCH 03/11] ci: add ignore-paths and prevent running action on draft PR --- .github/workflows/build-and-test.yml | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index bc1eb87..9c3779f 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -2,9 +2,19 @@ name: Build and test code on: push: - branches: ["main"] + branches: [main] + paths-ignore: + - "**.md" + - "LICENSE*" + - ".github/workflows/docs.yml" + - "katex-header.html" pull_request: - branches: ["main"] + branches: [main] + paths-ignore: + - "**.md" + - "LICENSE*" + - ".github/workflows/docs.yml" + - "katex-header.html" permissions: contents: read @@ -19,10 +29,12 @@ env: jobs: build: + if: github.event.pull_request.draft == false runs-on: ubuntu-latest timeout-minutes: 30 steps: - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 - name: Build run: cargo test --workspace --verbose --no-run From 136e602d747b5e4b2f0e5b38f7ccdd3efb5e2659 Mon Sep 17 00:00:00 2001 From: Musa AbdulKareem Date: Wed, 18 Feb 2026 07:03:10 +0100 Subject: [PATCH 04/11] ci: added paths-ignore and draft PR skip --- .github/workflows/coverage.yml | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 5d2331f..527f140 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -3,8 +3,18 @@ name: Coverage (Push) on: push: branches: [main] + paths-ignore: + - "**.md" + - "LICENSE*" + - ".github/workflows/docs.yml" + - "katex-header.html" pull_request: types: [opened, synchronize, reopened] + paths-ignore: + - "**.md" + - "LICENSE*" + - ".github/workflows/docs.yml" + - "katex-header.html" permissions: contents: read @@ -15,20 +25,22 @@ concurrency: cancel-in-progress: true jobs: - coverage-push: + coverage: + if: github.event.pull_request.draft == false runs-on: ubuntu-latest timeout-minutes: 30 steps: - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + with: + components: llvm-tools-preview + - uses: Swatinem/rust-cache@v2 - name: Install cargo-llvm-cov uses: taiki-e/install-action@cargo-llvm-cov - - name: Install llvm-tools - run: rustup component add llvm-tools-preview - - name: Run code coverage run: cargo llvm-cov --workspace --lcov --output-path lcov.info --ignore-filename-regex '^examples/' From 0bc121d130af52d122506362efe46018dfb8aa8e Mon Sep 17 00:00:00 2001 From: Musa AbdulKareem Date: Wed, 18 Feb 2026 07:04:11 +0100 Subject: [PATCH 05/11] ci: added deny.toml to path filter --- .github/workflows/dependency-audit.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/dependency-audit.yml b/.github/workflows/dependency-audit.yml index 48f03a6..97ad11d 100644 --- a/.github/workflows/dependency-audit.yml +++ b/.github/workflows/dependency-audit.yml @@ -5,6 +5,7 @@ on: paths: - "**/Cargo.toml" - "**/Cargo.lock" + - "deny.toml" permissions: contents: read @@ -25,7 +26,9 @@ jobs: - name: Check out uses: actions/checkout@v4 - - name: Run audit-check action + - uses: dtolnay/rust-toolchain@stable + + - name: Install cargo-deny uses: taiki-e/install-action@cargo-deny - name: Run cargo deny From 17f7e62a28263ca538927b3b38ecd9cc3ffbb5a0 Mon Sep 17 00:00:00 2001 From: Musa AbdulKareem Date: Wed, 18 Feb 2026 07:05:43 +0100 Subject: [PATCH 06/11] ci: use miri as component and skip docs only change re-run --- .github/workflows/docs.yml | 5 ++--- .github/workflows/ub-detection.yml | 24 +++++++++++++++++++++++- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 89e0ef4..ef9af3c 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -25,15 +25,14 @@ jobs: fetch-depth: 1 persist-credentials: false + - uses: dtolnay/rust-toolchain@stable + - uses: Swatinem/rust-cache@v2 - name: Setup pages id: pages uses: actions/configure-pages@v5 - - name: Clean docs folder - run: cargo clean --doc - # Documentation with Latex support # TODO(template) if Latex is not needed # just remove katex-header.html at the root and RUSTDOCFLAGS here diff --git a/.github/workflows/ub-detection.yml b/.github/workflows/ub-detection.yml index 875799a..e168397 100644 --- a/.github/workflows/ub-detection.yml +++ b/.github/workflows/ub-detection.yml @@ -1,6 +1,20 @@ name: UB (undefined behavior) detection -on: push +on: + push: + branches: [main] + paths-ignore: + - "**.md" + - "LICENSE*" + - ".github/workflows/docs.yml" + - "katex-header.html" + pull_request: + branches: [main] + paths-ignore: + - "**.md" + - "LICENSE*" + - ".github/workflows/docs.yml" + - "katex-header.html" permissions: contents: read @@ -23,12 +37,20 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@nightly + with: + components: miri - uses: Swatinem/rust-cache@v2 with: cache-on-failure: true +<<<<<<< HEAD - run: | rustup +nightly component add miri cargo +nightly miri setup PROPTEST_DISABLE_FAILURE_PERSISTENCE=true \ MIRIFLAGS="-Zmiri-env-forward=PROPTEST_DISABLE_FAILURE_PERSISTENCE -Zmiri-strict-provenance" \ cargo +nightly miri test --lib +======= + - name: Run Miri + run: MIRIFLAGS="-Zmiri-strict-provenance" cargo +nightly miri test --lib +>>>>>>> 5d9ff19 (ci: use miri as component and skip docs only change re-run) From d8a8743a9ee8edc8f8179ad86543c40719d97a86 Mon Sep 17 00:00:00 2001 From: Musa AbdulKareem Date: Wed, 18 Feb 2026 07:36:47 +0100 Subject: [PATCH 07/11] ci: give coverage write permission --- .github/workflows/coverage.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 527f140..f8f6b10 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -19,6 +19,7 @@ on: permissions: contents: read actions: write + pull-requests: write concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} From f8e21fde08c12b382d9d841c45e6ee77cd2588b2 Mon Sep 17 00:00:00 2001 From: Musa AbdulKareem Date: Wed, 18 Feb 2026 17:39:36 +0100 Subject: [PATCH 08/11] chore: fix merge conflict --- .github/workflows/ub-detection.yml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/.github/workflows/ub-detection.yml b/.github/workflows/ub-detection.yml index e168397..abe15d8 100644 --- a/.github/workflows/ub-detection.yml +++ b/.github/workflows/ub-detection.yml @@ -43,14 +43,5 @@ jobs: - uses: Swatinem/rust-cache@v2 with: cache-on-failure: true -<<<<<<< HEAD - - run: | - rustup +nightly component add miri - cargo +nightly miri setup - PROPTEST_DISABLE_FAILURE_PERSISTENCE=true \ - MIRIFLAGS="-Zmiri-env-forward=PROPTEST_DISABLE_FAILURE_PERSISTENCE -Zmiri-strict-provenance" \ - cargo +nightly miri test --lib -======= - name: Run Miri run: MIRIFLAGS="-Zmiri-strict-provenance" cargo +nightly miri test --lib ->>>>>>> 5d9ff19 (ci: use miri as component and skip docs only change re-run) From d875b96893c23ccb3da11c03bad447b6842b0b52 Mon Sep 17 00:00:00 2001 From: Musa AbdulKareem Date: Wed, 18 Feb 2026 17:58:57 +0100 Subject: [PATCH 09/11] fix: ignore miri failing test --- template_crate/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/template_crate/src/lib.rs b/template_crate/src/lib.rs index f3b62de..217e902 100644 --- a/template_crate/src/lib.rs +++ b/template_crate/src/lib.rs @@ -71,6 +71,7 @@ mod tests { proptest! { #[test] + #[cfg_attr(miri, ignore)] fn addition_proptest(a in 0_u8..20, b in 0_u8..20) { assert_eq!( a.checked_add(b), From 651bfd935dab6fd074f47c6bf9160387bae59ac8 Mon Sep 17 00:00:00 2001 From: Musa AbdulKareem Date: Wed, 18 Feb 2026 18:17:14 +0100 Subject: [PATCH 10/11] ci: remove coverage comment --- .github/workflows/coverage.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index f8f6b10..ea8df84 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -51,9 +51,3 @@ jobs: name: coverage-lcov path: lcov.info retention-days: 21 - - - name: Comment PR with coverage - uses: romeovs/lcov-reporter-action@v0.4.0 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - lcov-file: lcov.info From c1af56f24ecc2f9f4cfe0e69b88aa31bd549dd3f Mon Sep 17 00:00:00 2001 From: Musa AbdulKareem Date: Wed, 18 Feb 2026 18:18:55 +0100 Subject: [PATCH 11/11] ci: remove push coverage --- .github/workflows/coverage.yml | 53 ---------------------------------- 1 file changed, 53 deletions(-) delete mode 100644 .github/workflows/coverage.yml diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml deleted file mode 100644 index ea8df84..0000000 --- a/.github/workflows/coverage.yml +++ /dev/null @@ -1,53 +0,0 @@ -name: Coverage (Push) - -on: - push: - branches: [main] - paths-ignore: - - "**.md" - - "LICENSE*" - - ".github/workflows/docs.yml" - - "katex-header.html" - pull_request: - types: [opened, synchronize, reopened] - paths-ignore: - - "**.md" - - "LICENSE*" - - ".github/workflows/docs.yml" - - "katex-header.html" - -permissions: - contents: read - actions: write - pull-requests: write - -concurrency: - group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} - cancel-in-progress: true - -jobs: - coverage: - if: github.event.pull_request.draft == false - runs-on: ubuntu-latest - timeout-minutes: 30 - steps: - - uses: actions/checkout@v4 - - - uses: dtolnay/rust-toolchain@stable - with: - components: llvm-tools-preview - - - uses: Swatinem/rust-cache@v2 - - - name: Install cargo-llvm-cov - uses: taiki-e/install-action@cargo-llvm-cov - - - name: Run code coverage - run: cargo llvm-cov --workspace --lcov --output-path lcov.info --ignore-filename-regex '^examples/' - - - name: Upload branch coverage artifact - uses: actions/upload-artifact@v4 - with: - name: coverage-lcov - path: lcov.info - retention-days: 21