Skip to content

Pin the third-party actions by commit, name the Homebrew secret, scope the docs token and stop persisting checkout credentials - #3200

Open
Totara-thib wants to merge 4 commits into
replicate:mainfrom
Totara-thib:ci-hardening
Open

Totara-thib wants to merge 4 commits into
replicate:mainfrom
Totara-thib:ci-hardening

Conversation

@Totara-thib

Copy link
Copy Markdown

Hello, four commits on the workflows.

  • The 47 third-party references move from tags to commit SHAs, the tag kept as a comment, Dependabot keeps bumping them. Two branch refs are pinned to the releases they point at, the review agent to its latest release.
  • The Homebrew tap update was called with secrets: inherit. The call now names the one secret that job uses and the reusable workflow declares it.
  • The docs deploy was the one job without a permissions block, it now says contents: write for the gh-pages push.
  • 32 of the 36 checkouts stop persisting the token. The four that push keep it: docs deploy, Bonk agent, Homebrew tap, compatibility-matrix PR.

Why: a tag is a movable pointer, and these workflows hold the Docker Hub login, the PyPI and crates.io trusted publishers and the Homebrew app key. The tj-actions incident (CVE-2025-30066) went through exactly that door.

For the best OpenSSF Scorecard result you would also pin GitHub's own actions.

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

A tag is a movable pointer: whoever controls one of these repositories
can move it, and the next run picks the new code up with the Docker
Hub login, the PyPI and crates.io trusted publishers and the Homebrew
app key in reach. The tj-actions incident (CVE-2025-30066) went
through exactly that door. Every third-party reference now names the
commit its tag resolves to, with the tag kept as a comment so the
version stays readable and Dependabot keeps bumping it. The two
branch references, the PyPI publisher on release/v1 and the crates.io
auth action on v1, are pinned to the releases those branches point at,
and the review agent moves from main to its latest release. GitHub's
own actions stay on their tags.
secrets: inherit hands the called workflow every secret the repository
holds, the Docker Hub login and the Cloudflare token included. The tap
update uses the Homebrew app key and nothing else, so the release
publish now names that one secret and the reusable workflow declares
it as its input. The manual run reads it directly as before.
The docs workflow was the one job without a permissions block, so it
ran with the repository default. It pushes the built site to gh-pages
with git, which is contents: write and nothing else, and it now says
so.
actions/checkout writes the job token into .git/config unless told not
to, so every later step in the job can read it. The CI matrix, CodeQL,
the mirror, the advisory check, the release build and publish and the
PR review (which runs with NO_PUSH) never push from their checkout,
so those checkouts now opt out. Four keep the token: the docs deploy,
the Bonk agent with write permissions, the Homebrew tap update and
the compatibility-matrix pull request, each pushes from its tree.
@Totara-thib
Totara-thib requested a review from a team as a code owner October 20, 2026 15:14

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