Skip to content

links

links #18

Workflow file for this run

# vendor-kit: links@ea0ead6abc84 — generated; edit km/packages/km-infra/vendor-kit/templates/links.yml in km, then re-sync
name: links
# Per-PR + weekly link checking via lychee. The cheapest fast-feedback layer
# for broken links in repo docs; complements the cross-site /marketing
# link-check (monthly cadence, catches bit-rot from external sites).
#
# Hardening (2026-06-10, 19779): GITHUB_TOKEN makes github.com checks
# authenticated — the unauthenticated Monday-cron stampede across vendor
# repos drew secondary rate limiting that surfaced as 504 storms (5 repos
# red, zero real dead links). Cron minutes are staggered per repo via the
# manifest var for the same reason. --max-retries absorbs transient
# external 5xx (one-off 503s).
#
# Hardening (2026-07-06, 20887): some external sites (e.g. asciinema.org)
# consistently time out from GitHub Actions egress IPs while resolving fine
# from other networks — --max-retries can't fix a host that only stalls for
# datacenter ASNs. `linksExtraExcludes` (manifest var, per-repo) is a
# `--exclude` block for such CI-hostile hosts; use it instead of loosening
# `--accept` or dropping the link from docs. Keep exclusions narrow (exact
# host/path, not a broad prefix) so real breakage on the same site still
# fails the check. (This block was live in termless since 2026-07-06 but the
# template change never landed in km — recovered 2026-08-18 from the stamped
# repo file when a re-sync silently deleted it.)
on:
pull_request:
paths: ["**/*.md", "**/*.html", "docs/**"]
schedule:
- cron: "40 6 * * 1" # Mondays 06:xx UTC, staggered per repo
workflow_dispatch:
jobs:
lychee:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: lycheeverse/lychee-action@v2
env:
# Authenticated github.com checks — API-rate-limited instead of
# anonymously throttled into 504s.
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
# Scoped glob: lint top-level + docs only — skips node_modules
# entirely (which the workspace pulls in via bun install on CI
# and pollutes the scan with thousands of npm-vendor README
# links). --root-dir lets lychee parse VitePress root-relative
# paths (/guide/…) without erroring; --exclude '^file:' then
# skips the resulting file:// checks since VitePress validates
# internal links at build time. Accept 401 for rate-limited
# endpoints. CHANGELOG v0.0.1 placeholder URLs excluded. Optional
# files use GLOB form ('CHANGELOG*.md') — lychee URL-interprets a
# literal arg naming a missing file (http://changelog.md/ …), while
# an unmatched glob is skipped.
# archive.org 503s under load; the mirror is the fallback for an
# already-dead original, so checking it is non-signal — ruled @cto
# 2026-08-18. (A '#' inside `args: |` would reach lychee as an
# argument, which is why this reason lives up here.)
args: |
--max-concurrency 24
--max-retries 2
--no-progress
--root-dir '${{ github.workspace }}/docs'
--accept '200..=204,206,301,302,303,307,308,401,403,429'
--exclude '^(mailto|tel|javascript):'
--exclude '^file:'
--exclude '^https://web\.archive\.org/'
--exclude 'github\.com/.*/(compare|releases/tag)/v0\.0\.1'
README.md
'CHANGELOG*.md'
'CLAUDE*.md'
'docs/**/*.md'
'docs/**/*.html'
fail: true