From ffbcbe2d4a79343369d2acd70ddd0d1308de351d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sarek=20H=C3=B8verstad=20Skot=C3=A5m?= Date: Fri, 21 Aug 2026 18:46:32 -0700 Subject: [PATCH 1/3] Fix the weekly cron job and its broken failure notifier The `Cron jobs` workflow has failed on every scheduled run since at least mid-June. Two independent bugs, one of which hid the other. 1. The `audit` job fails because `cargo audit` exits 1 on RUSTSEC-2022-0040 (`owning_ref` 0.4.1, multiple soundness issues, no fixed upgrade available). The advisory is not reachable in anything we build: `owning_ref` only enters Cargo.lock as an *optional* dependency of `lock_api`, reached via `parking_lot` 0.12, `dashmap` 6, and `shuttle-parking_lot-impl`. Pulling it in requires the non-default `owning_ref` feature, which nothing in this workspace enables, and `cargo tree -i owning_ref --workspace` confirms it is absent from the resolved build graph. `cargo audit` flags it regardless because it scans the lockfile, which records optional dependencies whether or not their feature is activated. Since there is no fixed version to upgrade to, add `.cargo/audit.toml` ignoring the advisory, with the reachability analysis and the conditions for removing the entry recorded alongside it. 2. Nobody was notified, because the notifier was broken too. The workflow set a top-level `permissions: contents: write`, and naming any scope implicitly sets every unnamed scope to `none`. That left `issues: none`, so `jayqi/failed-build-issue-action` could not open an issue and failed with "Resource not accessible by integration". Drop to `contents: read` at the top level, which is all either job actually needs, and grant `contents: read` + `issues: write` on the `beta` job so the notify step works. Also bump `actions/checkout` v2 -> v5 here; see the following commit. Verified by reproducing `cargo audit` locally against cargo-audit 0.22.2: exit 1 before this change, exit 0 after, with output matching CI run 31987845860 exactly. --- .cargo/audit.toml | 24 ++++++++++++++++++++++++ .github/workflows/crons.yml | 15 ++++++++++++--- 2 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 .cargo/audit.toml diff --git a/.cargo/audit.toml b/.cargo/audit.toml new file mode 100644 index 00000000..a3459b84 --- /dev/null +++ b/.cargo/audit.toml @@ -0,0 +1,24 @@ +# Configuration for `cargo audit`, run by the weekly cron in +# .github/workflows/crons.yml. See: +# https://github.com/rustsec/rustsec/blob/main/cargo-audit/audit.toml.example + +[advisories] +ignore = [ + # RUSTSEC-2022-0040: multiple soundness issues in `owning_ref`. + # + # Not reachable in any build we produce. `owning_ref` enters Cargo.lock only + # as an *optional* dependency of `lock_api`, which is reached three ways: + # `parking_lot` 0.12 and `dashmap` 6 (transitively), and + # `shuttle-parking_lot-impl` (directly). In every case pulling in + # `owning_ref` requires the non-default `owning_ref` feature, which nothing + # in this workspace enables. `cargo tree -i owning_ref --workspace` reports + # no match, confirming it is absent from the resolved build graph; `cargo + # audit` flags it anyway because it scans the lockfile, which records + # optional dependencies whether or not their feature is activated. + # + # The advisory has no fixed upgrade available, so it cannot be resolved by + # bumping. Revisit if `lock_api` drops the `owning_ref` dependency, or if + # this workspace ever enables the `owning_ref` feature by default -- at that + # point the code would genuinely be exposed and this entry must be removed. + "RUSTSEC-2022-0040", +] diff --git a/.github/workflows/crons.yml b/.github/workflows/crons.yml index 8139002a..43f8e6c5 100644 --- a/.github/workflows/crons.yml +++ b/.github/workflows/crons.yml @@ -1,6 +1,9 @@ name: Cron jobs + +# Least privilege by default. Note that naming any scope here implicitly sets +# every unnamed scope to `none`, so jobs needing more must opt in explicitly. permissions: - contents: write + contents: read on: push: @@ -14,7 +17,7 @@ jobs: audit: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v5 - name: Install Rust run: rustup update stable - name: Install Audit @@ -26,8 +29,14 @@ jobs: # Exists to not get "caught off guard" by new Rust versions bringing new clippies. beta: runs-on: ubuntu-latest + # `issues: write` is required by the "Notify failed build" step below, which + # opens an issue when this job fails. Job-level permissions replace the + # top-level block outright, so `contents: read` has to be restated here. + permissions: + contents: read + issues: write steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v5 - name: Install Rust run: rustup update beta - name: Default to beta From c0c7b7f2d2e904d71fa30385705af33e17cb5b1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sarek=20H=C3=B8verstad=20Skot=C3=A5m?= Date: Fri, 21 Aug 2026 18:46:50 -0700 Subject: [PATCH 2/3] Move workflows off the deprecated Node 20 action runtime Every workflow run currently carries the annotation "Node.js 20 is deprecated. The following actions target Node.js 20 but are being forced to run on Node.js 24". Node 20 is removed from the runners on 2026-09-16, at which point these actions stop working entirely. Bump `actions/checkout` v3 -> v5 across the remaining workflows (v2 -> v5 in crons.yml in the previous commit). v5 is the first major that declares `using: node24`. Deliberately stopping at v5 rather than the current v7: v6 changed checkout to persist git credentials to a separate file, and `bench.yml` uses `boa-dev/criterion-compare-action@v3`, which last shipped in 2022 and runs its own git operations against the base branch. v5 clears the Node 20 deadline without taking on that behavioural change. Two unrelated fixes to workflows touched anyway: - `release.yml` had no `name:` and no `permissions:` block at any level, so it was displayed by file path and inherited the repository default token scope. Add both. - The `clippy` job in `tests.yml` ran `rustup component add rustfmt`, so it never installed the component it is named for. It only worked because the runner image ships clippy already. --- .github/workflows/bench.yml | 2 +- .github/workflows/release.yml | 6 +++++- .github/workflows/tests.yml | 10 +++++----- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/.github/workflows/bench.yml b/.github/workflows/bench.yml index bb9027e5..3bc685bc 100644 --- a/.github/workflows/bench.yml +++ b/.github/workflows/bench.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest continue-on-error: true # This step will not fail the job if it errors steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 - name: Install Rust run: rustup update stable - uses: boa-dev/criterion-compare-action@v3 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 70b90cde..5287e07f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,3 +1,7 @@ +name: Release +permissions: + contents: read + on: push: branches: [main] @@ -18,7 +22,7 @@ jobs: name: Benchmarks (with vector clocks) runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 - name: Install Rust run: rustup update stable - name: cargo bench diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 10f90efc..cb766f0e 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -20,7 +20,7 @@ jobs: name: Tests runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 - name: Install Rust run: rustup update stable - name: Install nextest @@ -34,7 +34,7 @@ jobs: name: rustfmt runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 - name: Install Rust run: rustup update stable - name: Install rustfmt @@ -46,11 +46,11 @@ jobs: name: Clippy runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 - name: Install Rust run: rustup update stable - name: Install clippy - run: rustup component add rustfmt + run: rustup component add clippy - name: clippy run: cargo clippy --all-targets -- -D clippy::all @@ -58,7 +58,7 @@ jobs: name: Docs runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 - name: Install Rust run: rustup update stable - name: cargo doc From 4458f2281a28f78a7e0bf26b12e7e62cbbb62708 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sarek=20H=C3=B8verstad=20Skot=C3=A5m?= Date: Tue, 25 Aug 2026 12:59:31 -0700 Subject: [PATCH 3/3] Notify on audit failures and move the notifier off Node 20 Two gaps in how the cron reports its own failures. The notify step was only wired to the `beta` job, so the `audit` job -- the one that has actually been failing every week -- had no notification path at all. Add the same step there, with its own `issues: write` grant. It uses a distinct label and title rather than sharing the default with `beta`. The action reuses an open issue carrying the configured label, so a shared label would file an audit failure as a comment on a beta toolchain issue. Those are unrelated failures with unrelated fixes and should not share a thread. Separately, the action itself referenced `jayqi/failed-build-issue-action@v1`, which resolved to v1.2.0 and declares `runs.using: node20`. Node 20 is removed from the runners on 2026-09-16, so the step that tells us the cron broke would itself have broken. Upstream released v1.3.0 on the node24 runtime, and `v1` now points at it, so tracking `v1` is enough. The action also moved from jayqi/ to drivendataorg/. The old path still redirects, but reference the canonical owner rather than rely on that. --- .github/workflows/crons.yml | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/.github/workflows/crons.yml b/.github/workflows/crons.yml index 43f8e6c5..a5bf692e 100644 --- a/.github/workflows/crons.yml +++ b/.github/workflows/crons.yml @@ -16,6 +16,10 @@ on: jobs: audit: runs-on: ubuntu-latest + # See the note on the `beta` job below. + permissions: + contents: read + issues: write steps: - uses: actions/checkout@v5 - name: Install Rust @@ -24,6 +28,17 @@ jobs: run: cargo install cargo-audit - name: cargo audit run: cargo audit + # Uses its own label so this is tracked separately from the `beta` job's + # notification: a new advisory and a beta toolchain regression are + # unrelated failures with unrelated fixes, and should not share an issue + # thread. + - name: Notify failed build + uses: drivendataorg/failed-build-issue-action@v1 + if: failure() + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + label-name: "audit failed" + title-template: "Failed cargo audit: {{workflow}}" # Runs Clippy, fmt, doc and tests on beta. # Exists to not get "caught off guard" by new Rust versions bringing new clippies. @@ -57,8 +72,14 @@ jobs: run: cargo nextest run --release --workspace - name: cargo test --doc run: cargo test --release --doc --workspace + # Requires v1.3.0 or newer: earlier releases declare `runs.using: node20`, + # and Node 20 is removed from the runners on 2026-09-16. The action also + # moved from jayqi/ to drivendataorg/; the old path still redirects, but + # naming the canonical owner avoids depending on that. - name: Notify failed build - uses: jayqi/failed-build-issue-action@v1 - if: failure() + uses: drivendataorg/failed-build-issue-action@v1 + if: failure() with: + # Optional as of v1.3.0, which defaults it to `github.token`, but kept + # explicit to keep the token this step uses obvious at the call site. github-token: ${{ secrets.GITHUB_TOKEN }}