Skip to content

Pin changesets/action and pnpm/action-setup, and tighten workflow tokens - #10041

Open
Totara-thib wants to merge 3 commits into
keystonejs:mainfrom
Totara-thib:ci-hardening
Open

Totara-thib wants to merge 3 commits into
keystonejs:mainfrom
Totara-thib:ci-hardening

Conversation

@Totara-thib

Copy link
Copy Markdown

Pins the two third-party actions, sets a read-only token on three workflows, and stops checkouts from keeping the token. One commit each.

changesets/action@v1 and pnpm/action-setup@v4 can be repointed by whoever controls those repos, and the next run picks up the new code. That is how tj-actions/changed-files leaked CI secrets in March 2025 (CVE-2025-30066). Here changesets runs in Version Packages with contents: write, and pnpm runs in the Pages build with pages: write and id-token: write.

  • Each SHA is the commit the current ref points to today, tag kept as a comment, so behavior is unchanged. pnpm/action-setup@v4 resolves to v4.3.0 rather than v4.4.0, so that is what the pin says.
  • CI, CI - Windows and Publish (Preview) had no permissions: block and none of them uses the token, so they now get contents: read.
  • persist-credentials: false on every checkout. The tag push at the end of Publish now sets the token on the remote right before git push, so releases work as before and npm Trusted Publishing is untouched.

First-party actions/* refs keep their tags, pinning those too would help an OpenSSF Scorecard score.

Renovate will bump the pins as digest updates, one PR per action with your current config. To group them, a packageRule with matchManagers: ["github-actions"] and matchUpdateTypes: ["digest", "pin"] does it.

If your org restricts allowed actions with tag patterns like owner/action@v1, those stop matching SHAs. owner/action@* fixes it.

Found and fixed by Plumber's analysis, reviewed and submitted by me.

Both are third-party actions referenced by a movable ref: changesets/action
by its v1 branch, pnpm/action-setup by its v4 tag. Whoever controls those
repos can repoint the ref, and the next run picks up the new code. Here
that code runs with contents and pull-requests write in Version Packages,
and inside the Pages deploy build.

Each pin is the commit the ref resolves to today, so behavior is
unchanged: v1 points at the v1.9.0 release commit, v4 at the v4.3.0 one.
The version comments let Renovate keep proposing updates.
CI, CI - Windows and Publish (Preview) had no permissions block, so their
GITHUB_TOKEN got whatever the repository default is, which can be write
access to contents, pull requests and more. None of their steps need that.
The jobs check out code, install, build and test, and pkg-pr-new publishes
through its GitHub App with --comment=off, without using the workflow
token at all.

contents: read covers all of it and keeps the token harmless in jobs that
build and run pull request code.
actions/checkout writes the GITHUB_TOKEN into .git/config by default, and
it stays there for every later step: installs, builds, tests and their
lifecycle scripts, the pkg.pr.new preview build of pull request code.
Nothing reads it from there except the final tag push in Publish, so
persist-credentials is now false on every checkout.

Publish needed the token only for `git push origin --tags`. That step now
sets the remote URL with the token right before pushing, so the release
flow is unchanged while pnpm build, the starter catalog script and
changeset publish run without it in .git/config.

Version Packages is unaffected: changesets/action writes its own
credentials for its push. Update Draft Release talks to the API through
GITHUB_TOKEN in env, not through git.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant