Skip to content

Commit 9ddce37

Browse files
mmckyclaude
andcommitted
Harden linkcheck.yml, declare known false positives, pin to v1
Closes #566. Hardening, as filed ------------------- The three improvements from #566, already proven in lecture-python-intro #783: - `contents: read` in permissions. The block only granted `issues: write`, and because `permissions:` resets every unlisted scope to none, the `gh api .../releases/latest` call was running with `contents: none`. - `set -euo pipefail` and single-asset selection. The old jq emitted one line per matching asset with nothing to stop an empty or multi-line result flowing into curl; it now selects the first match and fails with a clear message when there is none. - `curl -fsSL` rather than `-sL`, so an HTTP error page is a download failure rather than a cryptic tar extraction error. Verified the new jq against this repo's current latest release: it returns the publish-2026aug03 tarball, same URL as the old form. Known false positives --------------------- action-link-checker v1.1.0 adds an `ignore-patterns` input (QuantEcon/action-link-checker#2, shipped in #3 there). This declares the same exemptions the repo already keeps in `lectures/_config.yml` under `linkcheck_ignore`, which Sphinx's built-in checker honours but this checker never sees -- it scans built HTML, not the Sphinx config. The regex syntax is identical, so the entries move across unchanged. FRED is the one that mattered: it throttles datacenter IP ranges, so it times out from a runner while returning 200 in under half a second from a normal network. Seventeen duplicate issues were filed for those links between April and July. Checked the patterns against the actual published HTML from the current release, using the shipped v1.1.0 code rather than a reimplementation: across 33 files and 955 external anchors, 7 anchors match, 6 distinct URLs, and no FRED link remains checked. The other 948 are unaffected. Pinning ------- Moves from `@main` to `@v1`. #566 recorded the decision to stay on `@main` on the grounds that it is a first-party action, and that holds, but v1.1.0 shipped a default-on behaviour change (a recurring finding now refreshes one issue instead of opening a new one weekly) which reached this repo the moment it merged. `@v1` still takes patches and features automatically; it just means a future change of that kind is something we adopt rather than receive. The other three consumers -- lecture-python-intro, lecture-python-advanced.myst and continuous_time_mcs -- should move to `@v1` too, so the series does not end up split across pinning schemes. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 1bb37dd commit 9ddce37

1 file changed

Lines changed: 26 additions & 5 deletions

File tree

.github/workflows/linkcheck.yml

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ jobs:
99
name: QuantEcon AI link checking
1010
runs-on: "ubuntu-latest"
1111
permissions:
12+
contents: read # read latest release assets via gh api
1213
issues: write # required for QuantEcon link-checker
1314
steps:
1415
# Download the latest release HTML archive (permanent, not subject to artifact expiry)
@@ -17,19 +18,39 @@ jobs:
1718
env:
1819
GH_TOKEN: ${{ github.token }}
1920
run: |
21+
set -euo pipefail
2022
ASSET_URL=$(gh api repos/${{ github.repository }}/releases/latest \
21-
--jq '.assets[] | select(.name | endswith(".tar.gz")) | .browser_download_url')
22-
echo "asset-url=$ASSET_URL" >> $GITHUB_OUTPUT
23+
--jq '[.assets[] | select(.name | endswith(".tar.gz")) | .browser_download_url] | first // ""')
24+
if [ -z "$ASSET_URL" ]; then
25+
echo "::error::No .tar.gz asset found on the latest release"
26+
exit 1
27+
fi
28+
echo "asset-url=$ASSET_URL" >> "$GITHUB_OUTPUT"
2329
- name: Download and extract release HTML
2430
run: |
31+
set -euo pipefail
2532
mkdir -p _site
26-
curl -sL "${{ steps.release.outputs.asset-url }}" | tar -xz -C _site
33+
curl -fsSL "${{ steps.release.outputs.asset-url }}" | tar -xz -C _site
2734
- name: AI-Powered Link Checker
28-
uses: QuantEcon/action-link-checker@main
35+
uses: QuantEcon/action-link-checker@v1
2936
with:
3037
html-path: '_site'
3138
fail-on-broken: 'false'
3239
silent-codes: '403,503'
3340
ai-suggestions: 'true'
3441
create-issue: 'true'
35-
42+
# Known false positives, kept in step with the linkcheck_ignore list in
43+
# lectures/_config.yml. Sphinx's built-in checker reads that list; this
44+
# checker scans the built HTML and never sees it, so the exemptions have
45+
# to be stated in both places. Same regex syntax, so entries move across
46+
# unchanged -- update both when adding one.
47+
ignore-patterns: |
48+
https://github.com/matplotlib/matplotlib/blob/v3.6.2/lib/matplotlib/axes/_axes.py#L1417-L1669
49+
https://ieeexplore.ieee.org/document/8757088
50+
https://www.sciencedirect.com/science/article/pii/S1477388021000177
51+
https://keras.io/
52+
https://data.oecd.org/
53+
https://www.reddit.com/
54+
https://openai.com
55+
https://chatgpt.com/
56+
https://fred.stlouisfed.org/.*

0 commit comments

Comments
 (0)