ci: set least-privilege top-level token permissions (P21.1b) (#103)

The auto-injected GITHUB_TOKEN defaulted to write-all in ci.yml, bench.yml
and release.yml (no top-level permissions block), and codeql.yml declared
its scopes only at job level. Add a top-level `permissions: contents: read`
to all four so the token starts read-only and only the jobs that genuinely
write through it raise the scope:

- release.yml: github-release keeps contents: write; node-/wasm-publish and
  attestations keep their id-token / attestations: write blocks. The
  cargo/python/node publish jobs push to crates.io/PyPI/npm via their own
  registry secrets, not the GITHUB_TOKEN, so read-only is correct for them.
- codeql.yml: analyze keeps security-events: write (job level).
- ci.yml / bench.yml: no job writes back to the repo (coverage uploads via
  CODECOV_TOKEN; bench only uploads an artifact), so no job override is needed.

sync-about.yml already had a top-level block but at contents: write; demote
the top level to read and move contents: write down to the single `sync` job
(the PR-head counter push is the only GITHUB_TOKEN write). The cross-repo
About/docs/webpage/org writes are unaffected — they run through the
fine-grained ABOUT_SYNC_TOKEN, which the permissions key does not govern.

Raises OpenSSF Scorecard Token-Permissions from 0 toward 10.
This commit is contained in:
kingchenc
2026-06-01 02:01:31 +02:00
committed by GitHub
parent eab2649f1c
commit ebddc5e376
5 changed files with 44 additions and 6 deletions
+7
View File
@@ -22,6 +22,13 @@ on:
required: false
default: "10"
# Least-privilege default for the auto-injected GITHUB_TOKEN. The single job
# only builds and uploads an artifact (upload-artifact uses the artifact
# storage API, not the contents scope), so it never needs repo write (OpenSSF
# Scorecard: Token-Permissions).
permissions:
contents: read
env:
CARGO_TERM_COLOR: always
+7
View File
@@ -6,6 +6,13 @@ on:
pull_request:
branches: [main]
# Least-privilege default for the auto-injected GITHUB_TOKEN. None of the CI
# jobs write back to the repo — coverage uploads via CODECOV_TOKEN, everything
# else is build/test/lint — so a read-only token is sufficient (OpenSSF
# Scorecard: Token-Permissions).
permissions:
contents: read
env:
CARGO_TERM_COLOR: always
RUSTFLAGS: "-D warnings"
+7
View File
@@ -12,6 +12,13 @@ on:
schedule:
- cron: '31 3 * * 0' # Sundays 03:31 UTC
# Least-privilege default for the auto-injected GITHUB_TOKEN. The analyze job
# raises exactly the scopes CodeQL needs (security-events: write to upload
# results) in its own job-level block below; this top-level read-only default
# covers any future job (OpenSSF Scorecard: Token-Permissions).
permissions:
contents: read
jobs:
analyze:
name: Analyze (${{ matrix.language }})
+11
View File
@@ -5,6 +5,17 @@ on:
tags: ["v*"]
workflow_dispatch:
# Least-privilege default for the auto-injected GITHUB_TOKEN. The publish jobs
# (cargo/python/node) push to external registries via their own secrets
# (CARGO_REGISTRY_TOKEN / PYPI_API_TOKEN / NPM_TOKEN), not the GITHUB_TOKEN, so
# they need no repo write. The jobs that genuinely write through the
# GITHUB_TOKEN — github-release (contents: write), node-/wasm-publish and
# attestations (id-token / attestations: write) — declare those rights in their
# own job-level permissions blocks, which override this default (OpenSSF
# Scorecard: Token-Permissions).
permissions:
contents: read
env:
CARGO_TERM_COLOR: always
+12 -6
View File
@@ -55,18 +55,24 @@ on:
types: [opened, synchronize, reopened]
workflow_dispatch:
# `contents: write` is needed so the workflow can push the counter
# fix-up commit to the PR head branch via the auto-provided
# GITHUB_TOKEN. The wider About / Wiki writes still go through the
# fine-grained PAT (ABOUT_SYNC_TOKEN) because they need
# `Administration: write` (gh repo edit) which GITHUB_TOKEN lacks.
# Least-privilege default for the auto-injected GITHUB_TOKEN. The `contents:
# write` the workflow needs — to push the counter fix-up commit to the PR head
# branch — is raised at the job level below, not here, so the top-level default
# stays read-only (OpenSSF Scorecard: Token-Permissions). The wider About /
# docs / webpage / org writes still go through the fine-grained PAT
# (ABOUT_SYNC_TOKEN), which the `permissions:` key does not govern at all.
permissions:
contents: write
contents: read
pull-requests: read
jobs:
sync:
runs-on: ubuntu-latest
# The only GITHUB_TOKEN write in this workflow: pushing the counter fix-up
# commit onto a same-repo PR head branch (git push origin HEAD:<ref>).
permissions:
contents: write
pull-requests: read
steps:
# On PRs from forks the head ref lives in another repo; pushing
# back to it from this workflow is blocked by GitHub. We still