From bf9a87f2c99778165514a451e7dd41056a8b24f7 Mon Sep 17 00:00:00 2001 From: Rich Megginson Date: Thu, 13 Aug 2026 13:22:33 -0600 Subject: [PATCH] ci: refactor build_docs so that pandoc runs in isolated read-only job [citest_skip] The pandoc conversion part of the workflow does not need write access, so refactor that into a separate job. Add permissions to woke because it does not need write permisssion. The latest security guidance is to use the full commit hash, which is immutable, instead of a tag or version, which can be mutable, for the reference to a version of a github action. There are known attacks which inserted unauthorized code in a version tag and moved the tag. This prevents this sort of attack, at the cost of more maintenance burden, but dependabot will largely take care of this for us. We already did this for the other workflows, this is specific for the build_docs workflow. Signed-off-by: Rich Megginson --- .github/workflows/build_docs.yml | 101 ++++++++++++++++++++++--------- .github/workflows/woke.yml | 2 + 2 files changed, 73 insertions(+), 30 deletions(-) diff --git a/.github/workflows/build_docs.yml b/.github/workflows/build_docs.yml index 6bf540363b..7ac40612c3 100644 --- a/.github/workflows/build_docs.yml +++ b/.github/workflows/build_docs.yml @@ -13,7 +13,60 @@ on: # yamllint disable-line rule:truthy permissions: contents: read jobs: + # Pandoc runs in an isolated read-only job so a compromised container cannot + # use a runner-mounted contents: write credential to push. build_docs: + runs-on: ubuntu-latest + steps: + - name: Check out README and Pandoc template + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 + with: + persist-credentials: false + sparse-checkout: | + README.md + .pandoc_template.html5 + sparse-checkout-cone-mode: false + - name: Set RELEASE_VERSION based on whether run on release or on push + env: + RELEASE_TAG: ${{ github.event.release.tag_name }} + run: | + set -euxo pipefail + if [ ${{ github.event_name }} = release ]; then + tag_name="$RELEASE_TAG" + if [[ "$tag_name" =~ ^[0-9]+[.][0-9]+[.][0-9]+$ ]]; then + echo "RELEASE_VERSION=$tag_name" >> $GITHUB_ENV + else + echo "RELEASE_VERSION=${{ github.event.release.id }}" >> $GITHUB_ENV + fi + elif [ ${{ github.event_name }} = push ]; then + echo "RELEASE_VERSION=latest" >> $GITHUB_ENV + else + echo Unsupported event + exit 1 + fi + + - name: Ensure that version directory exists + run: mkdir -p ${{ env.RELEASE_VERSION }} + + - name: Remove badges from README.md prior to converting to HTML + run: sed -i '1,8 {/^\[\!.*actions\/workflows/d}' README.md + + - name: Convert README.md to HTML and save to the version directory + uses: docker://pandoc/core:8d7467e8ee40b0365a344c3d41067d6d2349da52e9961e4229f331094806fb14 + with: + args: >- + --from gfm --to html5 --toc --shift-heading-level-by=-1 + --template .pandoc_template.html5 + --output ${{ env.RELEASE_VERSION }}/README.html README.md + + - name: Upload docs HTML artifact + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: docs-html + path: ${{ env.RELEASE_VERSION }}/README.html + + publish_docs: + needs: build_docs runs-on: ubuntu-latest permissions: contents: write @@ -27,6 +80,7 @@ jobs: - name: Check out code uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 with: + persist-credentials: true # needed for docs branch initialization push fetch-depth: 0 - name: Ensure the docs branch run: | @@ -51,20 +105,19 @@ jobs: uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 with: ref: docs - - - name: Fetch README.md and .pandoc_template.html5 template from the workflow branch - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 - with: - sparse-checkout: | - README.md - .pandoc_template.html5 - sparse-checkout-cone-mode: false - path: ref_branch + persist-credentials: true # needed for commit and push - name: Set RELEASE_VERSION based on whether run on release or on push + env: + RELEASE_TAG: ${{ github.event.release.tag_name }} run: | set -euxo pipefail if [ ${{ github.event_name }} = release ]; then - echo "RELEASE_VERSION=${{ github.event.release.tag_name }}" >> $GITHUB_ENV + tag_name="$RELEASE_TAG" + if [[ "$tag_name" =~ ^[0-9]+[.][0-9]+[.][0-9]+$ ]]; then + echo "RELEASE_VERSION=$tag_name" >> $GITHUB_ENV + else + echo "RELEASE_VERSION=${{ github.event.release.id }}" >> $GITHUB_ENV + fi elif [ ${{ github.event_name }} = push ]; then echo "RELEASE_VERSION=latest" >> $GITHUB_ENV else @@ -72,29 +125,17 @@ jobs: exit 1 fi - - name: Ensure that version and docs directories exist - run: mkdir -p ${{ env.RELEASE_VERSION }} docs - - - name: Remove badges from README.md prior to converting to HTML - run: sed -i '1,8 {/^\[\!.*actions\/workflows/d}' ref_branch/README.md - - - name: Convert README.md to HTML and save to the version directory - uses: docker://pandoc/core:latest + - name: Download docs HTML artifact + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7 with: - args: >- - --from gfm --to html5 --toc --shift-heading-level-by=-1 - --template ref_branch/.pandoc_template.html5 - --output ${{ env.RELEASE_VERSION }}/README.html ref_branch/README.md + name: docs-html + path: ${{ env.RELEASE_VERSION }} - name: Copy latest README.html to docs/index.html for GitHub pages if: env.RELEASE_VERSION == 'latest' - run: cp ${{ env.RELEASE_VERSION }}/README.html docs/index.html - - - name: Upload README.html as an artifact - uses: actions/upload-artifact@v7 - with: - name: README.html - path: ${{ env.RELEASE_VERSION }}/README.html + run: | + mkdir -p docs + cp ${{ env.RELEASE_VERSION }}/README.html docs/index.html - name: Commit changes run: | @@ -104,7 +145,7 @@ jobs: git commit -m "Update README.html for ${{ env.RELEASE_VERSION }}" - name: Push changes - uses: ad-m/github-push-action@master + uses: ad-m/github-push-action@881a6320fdb16eb5318c5054f31c218aec2b324c # master with: github_token: ${{ secrets.GITHUB_TOKEN }} branch: docs diff --git a/.github/workflows/woke.yml b/.github/workflows/woke.yml index ab44dceae1..cf419af0f7 100644 --- a/.github/workflows/woke.yml +++ b/.github/workflows/woke.yml @@ -3,6 +3,8 @@ name: Woke on: # yamllint disable-line rule:truthy - pull_request +permissions: + contents: read jobs: woke: if: |