Skip to content

ci: use OIDC token-exchange for gh-pages deploys - #426

Open
OGPoyraz wants to merge 3 commits into
mainfrom
fix/publish-docs-to-gh-page
Open

ci: use OIDC token-exchange for gh-pages deploys#426
OGPoyraz wants to merge 3 commits into
mainfrom
fix/publish-docs-to-gh-page

Conversation

@OGPoyraz

@OGPoyraz OGPoyraz commented Sep 1, 2026

Copy link
Copy Markdown
Member

Summary

Docs deploys to gh-pages were failing (GH013 ruleset rejection) because #421 switched the deploy token to GITHUB_TOKEN, which isn't allowed to bypass the org's push-protection ruleset on gh-pages.

Fixes it by switching to OIDC token-exchange (same pattern as MetaMask/snaps): each deploy job exchanges its OIDC identity for a short-lived contents: write token via MetaMask/github-tools/.github/actions/get-token@v1, instead of using a stored secret.

Why this approach over reverting to the old PUBLISH_DOCS_TOKEN secret

That secret still exists and would also fix the immediate issue, but it's been unused/unrotated since #421 — exactly the kind of staleness that let this regression go unnoticed.

Validation

  • actionlint v1.7.12: 0 errors on all changed files
  • Matches snaps' working implementation exactly (permissions, get-token step, personal_token wiring)
  • vars.TOKEN_EXCHANGE_URL confirmed already inherited by this repo at the org level

Caveat

Can't verify from the API whether the token-exchange service's server-side trust policy already allows eth-sig-util to bypass the gh-pages ruleset (it evidently does for snaps). If not yet configured, the Get access token step will fail with a clear error rather than a silent bad push.

The gh-pages branch is protected by an org-wide ruleset that blocks
direct pushes (requires a PR). The default GITHUB_TOKEN identity used
by the gh-pages deploy step is not on that ruleset's bypass list, so
every docs deploy has been failing with:

  remote: error: GH013: Repository rule violations found for
  refs/heads/gh-pages.
  remote: - Changes must be made through a pull request.

Prior to #421, the workflow used personal_token: ${{
secrets.PUBLISH_DOCS_TOKEN }} instead of GITHUB_TOKEN, and that token's
identity is allowed to bypass the ruleset (confirmed by successful
gh-pages deploys through March 2025, well after the ruleset was
created in May 2024). #421 switched to GITHUB_TOKEN as an intentional
deviation from the module template, which is what broke this.

Revert to PUBLISH_DOCS_TOKEN across the call chain, matching the
current metamask-module-template:
- publish-docs.yml: require PUBLISH_DOCS_TOKEN secret, use
  personal_token instead of github_token in the deploy step
- publish-main-docs.yml / publish-rc-docs.yml: forward
  PUBLISH_DOCS_TOKEN to publish-docs.yml
- publish-release.yml: require PUBLISH_DOCS_TOKEN secret, forward it
  to both gh-pages jobs
- main.yml: forward PUBLISH_DOCS_TOKEN to publish-release.yml
Switch the gh-pages deploy from the static PUBLISH_DOCS_TOKEN secret to
the org's OIDC token-exchange service, matching the pattern already
used by MetaMask/snaps (publish-github-pages.yml).

Each job requests a short-lived contents:write token via
MetaMask/github-tools/.github/actions/get-token@v1, which exchanges
the job's signed OIDC identity token against ${{ vars.TOKEN_EXCHANGE_URL
}} (an org variable already inherited by this repo). That token is fed
into peaceiris/actions-gh-pages as personal_token, replacing the
static PUBLISH_DOCS_TOKEN secret used in the previous commit.

Benefits over the static-token approach:
- No long-lived secret stored in the github-pages environment.
- Token is minted per-run and expires in minutes.
- Nothing to rotate or accidentally leave stale (this is what caused
  the original outage: PUBLISH_DOCS_TOKEN silently going unused for
  months after #421 switched to GITHUB_TOKEN).

Changes:
- publish-docs.yml: add id-token: write permission, add "Get access
  token" step using MetaMask/github-tools/.github/actions/get-token@v1,
  use the exchanged token as personal_token instead of
  secrets.PUBLISH_DOCS_TOKEN. Drop the now-unused PUBLISH_DOCS_TOKEN
  secret declaration.
- publish-main-docs.yml / publish-rc-docs.yml: update caller
  permissions to contents: read + id-token: write; drop the
  PUBLISH_DOCS_TOKEN secret forwarding (no longer needed).
- publish-release.yml: same permission update for both gh-pages jobs;
  drop the PUBLISH_DOCS_TOKEN secret requirement and forwarding.
- main.yml: drop the now-unused PUBLISH_DOCS_TOKEN forward to
  publish-release.yml.
@OGPoyraz OGPoyraz changed the title ci: use PUBLISH_DOCS_TOKEN for gh-pages deploys ci: use OIDC token-exchange for gh-pages deploys Sep 1, 2026

@mcmire mcmire left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good, as long as a policy for the new token is present in token-exchange-service.

@mcmire

mcmire commented Sep 1, 2026

Copy link
Copy Markdown

Can't verify from the API whether the token-exchange service's server-side trust policy already allows eth-sig-util to bypass the gh-pages ruleset (it evidently does for snaps).

This is something that we had to explicitly ask TechOps to do, so you may have to do the same.

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.

2 participants