Summary
.github/workflows/rust.yml's clippy_check job uses actions-rs/clippy-check@v1 (plus actions-rs/toolchain@v1). Both actions have been archived and unmaintained since October 2023. The job is green today, but only by luck of token configuration: this is the exact setup that kept pathscale/DataBucket CI red on every push from April to July 2026 while its code was lint-clean the whole time.
Mechanism
actions-rs/clippy-check does not merely run clippy — after running it, it POSTs to the GitHub Checks API to create a Check Run with inline annotations. That API call requires the job token to have checks: write. When the token lacks it, the API returns 403 and the action fails the whole job with ##[error]Resource not accessible by integration — even when clippy found nothing. The lint result is irrelevant; the failure is the annotation upload.
Evidence from DataBucket (identical job definition):
- Failing runs, every push, months apart: run 25128967124 (Apr), run 25129013462 (Apr), run 30222021476 (Jul) — all
clippy_check: failure with Resource not accessible by integration, all with clippy itself clean (the build job passed, and running CI's exact command locally produced zero lints).
- Fixed by replacing the action with a plain cargo invocation: pathscale/DataBucket@943b402 — CI green since.
Why WorkTable is currently green — and three concrete ways it flips red
This workflow has no permissions: block, so the job token inherits the repository/organization default workflow permissions, which are currently permissive enough to include checks: write. That is the only thing keeping the job green. Three realistic triggers, ranked:
1. Any pull request from a fork (reproducible today, no settings change needed).
The workflow triggers on pull_request. For PRs from forks, GitHub force-downgrades GITHUB_TOKEN to read-only regardless of repo/org defaults — checks: write is never granted. Reproduction:
gh repo fork pathscale/WorkTable --clone # as any account without push access
cd WorkTable && git checkout -b test-ci && git commit --allow-empty -m "ci probe"
git push origin test-ci
gh pr create --repo pathscale/WorkTable --head <fork-owner>:test-ci --title "CI probe"
The clippy_check job on that PR will fail with Resource not accessible by integration while build passes. Practical consequence: the first outside contribution — e.g. a patch from Handy-caT's fork or anyone in the indexset orbit — arrives pre-stamped with a red X for reasons that have nothing to do with their code. (Recent PRs #170–#173 were all same-repo branches, which is why this has not fired yet.)
2. Security hardening of the workflow.
Adding a least-privilege permissions: block — standard practice, recommended by GitHub's own hardening guide, and exactly what DataBucket's workflow had (contents: read, pull-requests: write) — turns every push red permanently. Whoever adds it will have no reason to suspect it breaks clippy.
3. Flipping the org/repo Actions default.
Settings → Actions → General → Workflow permissions → "Read repository contents and packages permissions" (GitHub's recommended default for new orgs) removes checks: write org-wide. This breaks the job without any commit to this repository, which makes the eventual failure maximally confusing to bisect.
Secondary rot, already visible in the logs: the archived actions run on deprecated Node runtimes ("target Node.js 20 but are being forced to run on Node.js 24"), and actions-rs/toolchain is equally archived — both are on borrowed time independent of the token issue.
Fix
Same as DataBucket: let the cargo exit code gate the job and drop the Checks-API dependency entirely. The inline annotations the action provided are barely a loss — the failure log shows the lints, and the job status is what gates merges.
clippy_check:
runs-on: ubicloud-standard-2
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- uses: Swatinem/rust-cache@v2
with:
cache-on-failure: "true"
add-job-id-key: "false"
- name: Clippy (deny warnings)
run: cargo clippy --all-targets --all-features -- -D warnings
(Also bumps actions/checkout v3 → v4 and drops the actions-rs/toolchain step — the runner's stable toolchain is what the build job already uses. If inline PR annotations are wanted later, the maintained pattern is cargo clippy --message-format=json piped to a problem-matcher, or giraffate/clippy-action — but the plain command is the boring, durable choice.)
One caveat when making the swap: the plain command actually enforces -D warnings, which the current job silently does not on the paths where it 403s before reporting. Run cargo clippy --all-targets --all-features -- -D warnings locally first (it was clean on the current tree as of the fix series) so the swap does not surface a backlog at an awkward time.
Summary
.github/workflows/rust.yml'sclippy_checkjob usesactions-rs/clippy-check@v1(plusactions-rs/toolchain@v1). Both actions have been archived and unmaintained since October 2023. The job is green today, but only by luck of token configuration: this is the exact setup that keptpathscale/DataBucketCI red on every push from April to July 2026 while its code was lint-clean the whole time.Mechanism
actions-rs/clippy-checkdoes not merely run clippy — after running it, it POSTs to the GitHub Checks API to create a Check Run with inline annotations. That API call requires the job token to havechecks: write. When the token lacks it, the API returns 403 and the action fails the whole job with##[error]Resource not accessible by integration— even when clippy found nothing. The lint result is irrelevant; the failure is the annotation upload.Evidence from DataBucket (identical job definition):
clippy_check: failurewithResource not accessible by integration, all with clippy itself clean (thebuildjob passed, and running CI's exact command locally produced zero lints).Why WorkTable is currently green — and three concrete ways it flips red
This workflow has no
permissions:block, so the job token inherits the repository/organization default workflow permissions, which are currently permissive enough to includechecks: write. That is the only thing keeping the job green. Three realistic triggers, ranked:1. Any pull request from a fork (reproducible today, no settings change needed).
The workflow triggers on
pull_request. For PRs from forks, GitHub force-downgradesGITHUB_TOKENto read-only regardless of repo/org defaults —checks: writeis never granted. Reproduction:The
clippy_checkjob on that PR will fail withResource not accessible by integrationwhilebuildpasses. Practical consequence: the first outside contribution — e.g. a patch from Handy-caT's fork or anyone in the indexset orbit — arrives pre-stamped with a red X for reasons that have nothing to do with their code. (Recent PRs #170–#173 were all same-repo branches, which is why this has not fired yet.)2. Security hardening of the workflow.
Adding a least-privilege
permissions:block — standard practice, recommended by GitHub's own hardening guide, and exactly what DataBucket's workflow had (contents: read,pull-requests: write) — turns every push red permanently. Whoever adds it will have no reason to suspect it breaks clippy.3. Flipping the org/repo Actions default.
Settings → Actions → General → Workflow permissions → "Read repository contents and packages permissions" (GitHub's recommended default for new orgs) removes
checks: writeorg-wide. This breaks the job without any commit to this repository, which makes the eventual failure maximally confusing to bisect.Secondary rot, already visible in the logs: the archived actions run on deprecated Node runtimes ("target Node.js 20 but are being forced to run on Node.js 24"), and
actions-rs/toolchainis equally archived — both are on borrowed time independent of the token issue.Fix
Same as DataBucket: let the cargo exit code gate the job and drop the Checks-API dependency entirely. The inline annotations the action provided are barely a loss — the failure log shows the lints, and the job status is what gates merges.
(Also bumps
actions/checkoutv3 → v4 and drops theactions-rs/toolchainstep — the runner's stable toolchain is what thebuildjob already uses. If inline PR annotations are wanted later, the maintained pattern iscargo clippy --message-format=jsonpiped to a problem-matcher, orgiraffate/clippy-action— but the plain command is the boring, durable choice.)One caveat when making the swap: the plain command actually enforces
-D warnings, which the current job silently does not on the paths where it 403s before reporting. Runcargo clippy --all-targets --all-features -- -D warningslocally first (it was clean on the current tree as of the fix series) so the swap does not surface a backlog at an awkward time.