ci: set a least-privilege default GITHUB_TOKEN scope - #1831
Merged
Conversation
CodeQL alert #64 (`actions/missing-workflow-permissions`, medium) on `.github/workflows/main.yml`: no `permissions` block, so every job inherits the repository's default GITHUB_TOKEN scope, which is broader than anything here needs. It matters more than the severity suggests because this is the workflow that publishes to npm under OIDC — an over-permissioned token in a job that mints publish credentials is worth tightening before 2.0.0 ships (#1818). Adds a workflow-level `permissions: contents: read`. The `publish` and `publish-github-container-registry` jobs already declare their own blocks (`id-token: write` and friends) and are unaffected: job-level permissions override the workflow-level default outright rather than merging with it. The comment records that, since it means each publish job must keep listing every scope it needs — including `contents: read` — and a future edit that trims one "because it's inherited" would break the publish. Surfaced by the v2 tree swap (#1817): `main` had never scanned this workflow before. Pre-existing on `v2/main`, not introduced by that merge. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Txmv2qqv3yeKgRzoqXytzD
This was referenced Jul 28, 2026
Closed
cliffhall
added a commit
that referenced
this pull request
Aug 2, 2026
…#1904) main's copy of .github/workflows/main.yml carried three release fixes v2/main never took -- #1831 (least-privilege default GITHUB_TOKEN scope), #1834 (derive the npm dist-tag from the version) and #1836 (publish via npm OIDC trusted publishing). Diffing the file both directions shows v2/main has NOTHING main lacks: its only unique content is the superseded publish step, run: npm publish --access public --provenance env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} which is exactly what #1836 replaced. Every other line already matched. So this is a verbatim copy of main's file rather than a hunk-by-hunk forward-port -- fewer ways to get it wrong, and it leaves the two branches byte-identical (`git diff origin/main -- .github/workflows` is now empty). Not a back-merge: only this one file is taken, so none of main's pre-swap v1 lineage enters v2/main's ancestry (see #1868). Claude-Session: https://claude.ai/code/session_01YAt8rqxysNbhYWLhoRm3fU Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes the one CodeQL alert left open after the v2 tree swap (#1817).
The alert
#64 — medium —
actions/missing-workflow-permissionson.github/workflows/main.yml:13:The other 10 alerts surfaced by the swap were all test fixtures and were dismissed as used in tests. This one is real infrastructure, so it wasn't dismissible under that reason.
Why it's worth more than "medium"
This is the workflow that publishes to npm under OIDC trusted publishing. An over-permissioned
GITHUB_TOKENin a workflow that mints publish credentials is worth tightening before 2.0.0 goes out (#1818), not after.The change
A workflow-level default:
The
buildjob needs nothing more. The two publish jobs already declare their own blocks (id-token: write,packages: write,attestations: write) and are unaffected — job-level permissions override the workflow-level default outright rather than merging with it.That override semantic is the one trap here, so the comment in the file records it: each publish job must keep listing every scope it needs, including
contents: read. A future edit that trims one "because it's inherited from the top" would silently break publishing.Verification
permissionsparses as a top-level key alongsidename/on/jobspermissions:blocks still present; bothid-token: writeoccurrences intactProvenance
Pre-existing on
v2/main—mainhad simply never scanned this workflow before the swap. Not introduced by #1830.🤖 Generated with Claude Code
https://claude.ai/code/session_01Txmv2qqv3yeKgRzoqXytzD