From e55956017f0c8bb37fa435aa8af0dd2a2634331b Mon Sep 17 00:00:00 2001 From: "Thomas B." Date: Wed, 29 Jul 2026 21:52:24 +1200 Subject: [PATCH 1/2] Fix preview URL mapping for index.md pages The a11y audit on #1355 died three URLs in: page.addScriptTag: Executing inline script violates the following Content Security Policy directive 'default-src 'none'' AccessLint injects axe as an inline script, so it cannot audit a page whose response carries a strict CSP - which is what GitHub Pages serves on a 404. The URL it choked on was `.../Announcements/Release_Notes/index/`, and that page does not exist: with `use_directory_urls`, mkdocs publishes `a/b/index.md` at `a/b/`, not `a/b/index/`. Stripping only the extension left the `index` segment behind and pointed the audit at a 404. Strip a trailing `index` path segment, and map `docs/index.md` onto the site root. The segment is matched with a case pattern rather than `${h%index}` so a page like `reindex.md` is not truncated to `re`. The root entry is already the first URL in the list, so the list is deduplicated. This never fired before because no recent PR had touched an `index.md`. Two related changes in the same steps: - The wait loop already existed to keep 404s away from the audit, with a comment saying exactly that, but it gave up silently after 30 tries and let the audit run anyway. It now fails with the offending URL and its status code, so the next occurrence reads as "preview URL never became live" rather than an unrelated-looking CSP error. It was also where most of that run's 10m34s went, spinning on three URLs that were never going to resolve. - The URL list is passed to that step through the environment instead of being interpolated into the script. It derives from the head branch name, which a fork PR controls and which may contain a double quote. Co-Authored-By: Claude Opus 5 --- .github/workflows/demo_deploy.yml | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/.github/workflows/demo_deploy.yml b/.github/workflows/demo_deploy.yml index b48746f64..8bf1b8013 100644 --- a/.github/workflows/demo_deploy.yml +++ b/.github/workflows/demo_deploy.yml @@ -96,21 +96,35 @@ jobs: run: | changed_pages=$(gh api repos/${GITHUB_REPOSITORY}/compare/${{ github.event.pull_request.base.sha }}...${{ github.event.pull_request.head.sha }} \ --jq '.files[] | select(.filename | endswith(".md")) | .filename') - urls="${DEPLOY_URL}/${GITHUB_REPOSITORY}/${HEAD}/"$'\n' + prefix="${DEPLOY_URL}/${GITHUB_REPOSITORY}/${HEAD}" + urls="${prefix}/"$'\n' for f in ${changed_pages}; do - g=${f#*/}; h=${g%.*} - urls="${urls}${DEPLOY_URL}/${GITHUB_REPOSITORY}/${HEAD}/${h}/"$'\n' + g=${f#*/}; h=${g%.md} + # use_directory_urls publishes `a/b.md` at `a/b/` and `a/b/index.md` + # at `a/b/`. Keeping the `index` segment points at a page that does + # not exist, and a 404 breaks the audit below - see that step. + # Matched as a whole path segment so `reindex.md` survives intact. + case "$h" in + index) h="" ;; + */index) h="${h%/index}" ;; + esac + urls="${urls}${prefix}${h:+/$h}/"$'\n' done + # docs/index.md maps onto the site root, which is already the first entry. + urls=$(printf '%s' "${urls}" | awk 'NF && !seen[$0]++') echo "urls<> $GITHUB_OUTPUT echo "$urls" >> $GITHUB_OUTPUT echo "EOF" >> $GITHUB_OUTPUT - name: Wait for preview URLs to be live if: steps.wait.outputs.conclusion == 'success' + env: + URLS: ${{ steps.pages.outputs.urls }} run: | # GitHub Pages CDN can lag behind the deploy; a URL that 404s serves # GitHub's default 404 page, whose strict CSP breaks AccessLint's # script injection. Poll each URL until it returns 200 first. + failed="" while IFS= read -r url; do [ -z "$url" ] && continue echo "Waiting for $url" @@ -123,7 +137,14 @@ jobs: echo " Got $code, retrying (${i}/30)..." sleep 5 done - done <<< "${{ steps.pages.outputs.urls }}" + # Falling through with a non-200 used to be silent, and the audit + # then died on that URL with an unrelated-looking CSP error. + if [ "$code" != "200" ]; then + echo "::error title=Preview URL never became live::${url} last returned ${code}" + failed="${failed} ${url}" + fi + done <<< "${URLS}" + [ -z "${failed}" ] - name: Run AccessLint WCAG audit if: steps.wait.outputs.conclusion == 'success' From d8c8e922495bf351d5fd8396a8da99c0f88efc09 Mon Sep 17 00:00:00 2001 From: "Thomas B." Date: Wed, 29 Jul 2026 21:53:08 +1200 Subject: [PATCH 2/2] Fix the same index.md link bug in the PR comment The "pages differ" list in the deploy comment strips only the extension too, so a changed `a/b/index.md` was linked as `.../a/b/index` - a 404 - and labelled "index" rather than something meaningful. Same segment handling as the audit URLs, with the root page labelled "Home". Co-Authored-By: Claude Opus 5 --- .github/workflows/demo_deploy.yml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/.github/workflows/demo_deploy.yml b/.github/workflows/demo_deploy.yml index 8bf1b8013..4c961dd8b 100644 --- a/.github/workflows/demo_deploy.yml +++ b/.github/workflows/demo_deploy.yml @@ -76,8 +76,17 @@ jobs: if [ -n "${changed_pages}" ]; then msg="${msg}

Seems the following pages differ;
    " for f in ${changed_pages};do - g=${f#*/}; h=${g%.*} - msg="${msg}
  • ${h##*/}
  • " + g=${f#*/}; h=${g%.md} + # `a/b/index.md` is published at `a/b/` - see the URL + # mapping step below. Without this the link 404s and is + # labelled "index". + case "$h" in + index) h="" ;; + */index) h="${h%/index}" ;; + esac + label="${h##*/}" + if [ -z "${label}" ]; then label="Home"; fi + msg="${msg}
  • ${label}
  • " done msg="${msg}
" echo "::info title=Deploy Succeeded::${DEPLOY_URL}/${GITHUB_REPOSITORY}/${HEAD}"