From 65b9fe062c9f98d47ab4d56e4082c71624fb8101 Mon Sep 17 00:00:00 2001 From: Erik Marks Date: Thu, 3 Sep 2026 16:05:59 -0700 Subject: [PATCH 1/2] ci: deploy GitHub Pages from an artifact The deploy authenticated as a personal access token on an account with no write access to this repository, so the push to `gh-pages` was rejected. Rather than reissue it, publish through the Pages deployment API: the job trades `contents: write` for `pages: write`, so it can no longer write to any branch, and there is no long-lived credential to rotate. This also moves off the deprecated node20 runtime that `peaceiris/actions-gh-pages` still runs on. Requires the repository's Pages source to be set to GitHub Actions. Co-Authored-By: Claude Opus 5 --- .github/workflows/main.yml | 6 ++--- .github/workflows/publish-gh-pages.yml | 32 +++++++++++++------------- 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 53d6266ec0..c77f7e850d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -177,13 +177,11 @@ jobs: if: github.event_name == 'push' && github.ref == 'refs/heads/main' uses: ./.github/workflows/publish-gh-pages.yml with: - publish_dir: ./coverage destination_dir: coverage artifact_name: coverage permissions: - contents: write - secrets: - PUBLISH_DOCS_TOKEN: ${{ secrets.PUBLISH_DOCS_TOKEN }} + pages: write + id-token: write is-release: name: Determine whether this is a release merge commit diff --git a/.github/workflows/publish-gh-pages.yml b/.github/workflows/publish-gh-pages.yml index 41b6cbf30f..65ae64e568 100644 --- a/.github/workflows/publish-gh-pages.yml +++ b/.github/workflows/publish-gh-pages.yml @@ -3,39 +3,39 @@ name: Publish to GitHub Pages on: workflow_call: inputs: - publish_dir: - description: 'Directory to publish' - required: true - type: string destination_dir: - description: 'Destination directory on gh-pages branch' + description: 'Subdirectory of the site to publish into' required: true type: string artifact_name: description: 'Name of artifact to download' required: true type: string - secrets: - PUBLISH_DOCS_TOKEN: - required: true jobs: publish: name: Publish to GitHub Pages runs-on: ubuntu-latest - environment: github-pages + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + # Deploying from an artifact rather than pushing to `gh-pages` keeps + # `contents` out of this job entirely. permissions: - contents: write + pages: write + id-token: write steps: - name: Download artifact uses: actions/download-artifact@v8 with: name: ${{ inputs.artifact_name }} - path: ${{ inputs.publish_dir }} + path: _site/${{ inputs.destination_dir }} - - name: Deploy to GitHub Pages - uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e + - name: Upload Pages artifact + uses: actions/upload-pages-artifact@v5 with: - personal_token: ${{ secrets.PUBLISH_DOCS_TOKEN }} - publish_dir: ${{ inputs.publish_dir }} - destination_dir: ${{ inputs.destination_dir }} + path: _site + + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v5 From 295da9623ba676072ef0f1b24031e2fee0d7f979 Mon Sep 17 00:00:00 2001 From: Erik Marks Date: Thu, 3 Sep 2026 16:15:00 -0700 Subject: [PATCH 2/2] ci: note that a Pages deploy replaces the whole site Co-Authored-By: Claude Opus 5 --- .github/workflows/main.yml | 2 ++ .github/workflows/publish-gh-pages.yml | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c77f7e850d..e66ecd75d2 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -179,6 +179,8 @@ jobs: with: destination_dir: coverage artifact_name: coverage + # A called workflow's jobs cannot request more than the caller grants, and + # an enumerated block sets every unlisted scope to `none`. permissions: pages: write id-token: write diff --git a/.github/workflows/publish-gh-pages.yml b/.github/workflows/publish-gh-pages.yml index 65ae64e568..f1aa65ffaf 100644 --- a/.github/workflows/publish-gh-pages.yml +++ b/.github/workflows/publish-gh-pages.yml @@ -4,7 +4,9 @@ on: workflow_call: inputs: destination_dir: - description: 'Subdirectory of the site to publish into' + description: + 'Subdirectory of the site to publish into; the deployment replaces the + entire site' required: true type: string artifact_name: @@ -19,8 +21,6 @@ jobs: environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} - # Deploying from an artifact rather than pushing to `gh-pages` keeps - # `contents` out of this job entirely. permissions: pages: write id-token: write