diff --git a/.github/workflows/docs-links.yml b/.github/workflows/docs-links.yml new file mode 100644 index 00000000..7942f817 --- /dev/null +++ b/.github/workflows/docs-links.yml @@ -0,0 +1,69 @@ +# External-link checker for the documentation and repo-root prose. +# +# `mkdocs build --strict` (in ci.yml's docs-build) already resolves in-repo +# links and the source_links.py rewrites, but it never touches an `https://` +# link to a third-party site — so a dead one merges silently and rots +# (see #626: a FreeRTOS-Plus-FAT 404 sat on main until found by chance). +# +# This lane checks the *external* URLs with lychee. +# +# Advisory by design: +# - On pull requests it never fails the check (`fail: false`) — a merge must +# not be blocked because someone else's docs host had a bad minute. It is +# also intentionally NOT a required status check. +# - On the weekly schedule it DOES fail (`fail: true`) so link rot that +# appears without us touching a file surfaces as a failed run we get +# notified about — which is exactly how the Plus-FAT 404 slipped in. +name: Docs Links + +on: + pull_request: + branches: [ main ] + paths: + - 'docs/**' + - '*.md' + - 'lychee.toml' + - '.github/workflows/docs-links.yml' + schedule: + # Mondays 06:17 UTC — an off-peak, non-round minute. + - cron: '17 6 * * 1' + workflow_dispatch: + +permissions: + contents: read + +# Serialise runs so PR updates, manual runs, and the weekly sweep don't overlap +# and burn external crawl quota. Only cancel superseded pull_request runs — let +# scheduled and manual runs finish. +concurrency: + group: docs-links-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +jobs: + docs-links: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + + - name: Check external links + uses: lycheeverse/lychee-action@e7477775783ea5526144ba13e8db5eec57747ce8 # v2.9.0 + with: + # Config (retries, timeout, user agent, excludes) lives in lychee.toml. + # Scope: the docs tree plus the repo-root prose files. Excludes + # CHANGELOG.md (release-please owns it) and generated content. + args: >- + --config lychee.toml + docs + README.md + CONTRIBUTING.md + CODE_OF_CONDUCT.md + SECURITY.md + SUPPORT.md + # Advisory on PR / manual, blocking only on the weekly rot sweep. + # failIfEmpty defaults to true in v2.9.0, so mirror the same guard — + # an empty scan must not fail a PR either. + fail: ${{ github.event_name == 'schedule' }} + failIfEmpty: ${{ github.event_name == 'schedule' }} + jobSummary: true diff --git a/docs/integrating-mbedtls.md b/docs/integrating-mbedtls.md index d15aa702..6aa9d447 100644 --- a/docs/integrating-mbedtls.md +++ b/docs/integrating-mbedtls.md @@ -110,7 +110,7 @@ process-wide hooks to install and nothing to teardown beyond the matching If you're bringing Mbed TLS in fresh for SolidSyslog, do that work first following the upstream -[Mbed TLS porting guide](https://mbed-tls.readthedocs.io/en/latest/kb/how-to/how-do-i-port-mbed-tls-to-a-new-environment-os/). +[Mbed TLS porting guide](https://mbed-tls.readthedocs.io/en/latest/kb/how-to/how-do-i-port-mbed-tls-to-a-new-environment-OS/). Once Mbed TLS itself is building on your target, you need the following specifically for this adapter: diff --git a/docs/security/release-verification.md b/docs/security/release-verification.md index 2302713c..78e15cab 100644 --- a/docs/security/release-verification.md +++ b/docs/security/release-verification.md @@ -7,7 +7,7 @@ they'd naturally run it. Prerequisites: -- [cosign](https://docs.sigstore.dev/system_config/installation/) v2 or +- [cosign](https://docs.sigstore.dev/cosign/system_config/installation/) v2 or later on your `$PATH`. - [cyclonedx-cli](https://github.com/CycloneDX/cyclonedx-cli) v0.30.0 or later (optional, only needed to re-validate the SBOM). diff --git a/lychee.toml b/lychee.toml new file mode 100644 index 00000000..ebcffd7f --- /dev/null +++ b/lychee.toml @@ -0,0 +1,29 @@ +# lychee configuration for the docs-links CI lane (see .github/workflows/docs-links.yml). +# Only external URL liveness is in scope here — in-repo and rewritten source +# links are already validated by `mkdocs build --strict` in the docs-build lane. + +# Third-party hosts flap; retry before believing a failure. A timeout is not a 404. +max_retries = 3 +retry_wait_time = 2 +timeout = 20 + +# Some hosts reject unknown user agents with a 403; present a real one. +user_agent = "Mozilla/5.0 (compatible; SolidSyslog-lychee-linkcheck; +https://cososo-ltd.github.io/solid-syslog/)" + +# Any 2xx is success; rate-limited responses are not dead links either. +accept = ["200..=299", "429"] + +# Check http/https only — leave file:// and mailto: to other tooling. +scheme = ["https", "http"] + +exclude = [ + # Our own repository. The source_links.py hook rewrites in-repo references to + # canonical github.com/cososo-ltd/solid-syslog URLs at *build* time only, and + # `mkdocs build --strict` already resolves them pre-rewrite — so checking them + # here would be redundant (and rate-limit-prone against ~99 self-links). + '^https?://github\.com/cososo-ltd/solid-syslog(?:[/?#]|$)', +] + +# NOTE (#626): known suspects are intentionally NOT excluded so the first run +# gives a verdict on them — notably http://elm-chan.org/fsw/ff/ (FatFs), which +# refused 443 and never answered 80 when added. Confirm/replace/drop per the run.