From aaf95ec5108d0cc74600ece62e669a58f57d3a2d Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Thu, 4 Jun 2026 19:55:14 +0000 Subject: [PATCH 1/2] Add lychee link checker config and CI workflow Part of STF-557. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/links.yml | 32 ++++++++++++++++++++ .gitignore | 1 + lychee.toml | 60 +++++++++++++++++++++++++++++++++++++ mise.lock | 28 +++++++++++++++++ mise.toml | 5 ++++ 5 files changed, 126 insertions(+) create mode 100644 .github/workflows/links.yml create mode 100644 lychee.toml diff --git a/.github/workflows/links.yml b/.github/workflows/links.yml new file mode 100644 index 0000000..5e3255b --- /dev/null +++ b/.github/workflows/links.yml @@ -0,0 +1,32 @@ +name: Links + +on: + push: + pull_request: + schedule: + - cron: "0 13 * * 1" # weekly, to catch external link rot without a commit + workflow_dispatch: + +permissions: + contents: read + +jobs: + linkChecker: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: Setup mise + uses: jdx/mise-action@6d1e696aa24c1aa1bcc1adea0212707c71ab78a8 # v3.6.1 + with: + install: false + + # Install only lychee (not the repo's full toolchain) and run the check. + - name: Check links + env: + MISE_AUTO_INSTALL: "false" + run: | + mise install lychee + mise run check-links diff --git a/.gitignore b/.gitignore index abf75b2..1a4126a 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ *.so *.so.* *.sw? +.lycheecache docs/.hugo_build.lock docs/public/ .libs diff --git a/lychee.toml b/lychee.toml new file mode 100644 index 0000000..e023170 --- /dev/null +++ b/lychee.toml @@ -0,0 +1,60 @@ +# Lychee link checker configuration +# https://lychee.cli.rs/#/usage/config +# +# Run locally with: +# lychee './**/*.md' './src/**/*.c' + +# Include URL fragments in checks +include_fragments = true + +# Don't allow any redirects, so links that have moved are surfaced and can be +# updated to their canonical destination. +max_redirects = 0 + +# Accept these HTTP status codes +# 100-103: Informational responses +# 200-299: Success responses +# 403: Forbidden (some sites use this for rate limiting) +# 429: Too Many Requests +# 500-599: Server errors (temporary issues shouldn't fail CI) +# 999: LinkedIn's custom status code +accept = ["100..=103", "200..=299", "403", "429", "500..=599", "999"] + +# Exclude URL patterns from checking (treated as regular expressions) +exclude = [ + # Live / auth-gated MaxMind endpoints: appear as code string literals or + # require login, so they can't be verified by an anonymous request. + '^https://geoip\.maxmind\.com', + '^https://geolite\.info', + '^https://updates\.maxmind\.com', + '^https://www\.maxmind\.com/en/accounts/', + # Local / placeholder URLs + '^file://', + '^https?://example\.(com|org|net)', + '^http://localhost', + '127\.0\.0\.1', +] + +# Exclude file paths from getting checked (regular expressions, matched against +# the path relative to the working directory). Patterns are segment-anchored +# with (^|/) so short names like "build" don't match unintended paths. +exclude_path = [ + # Build / generated directories + '(^|/)build/', + '(^|/)\.libs/', + '(^|/)autom4te\.cache/', + # Generated Hugo site output + '(^|/)docs/public/', + # Vendored submodule and test harness/fixtures + '(^|/)maxmind-db/', + '(^|/)t/', + # Changelog: historical entries are preserved as-is, not rewritten + '(^|/)Changes\.md$', +] + +# Cache results for 1 day to speed up repeated checks +cache = true +max_cache_age = "1d" + +# Skip missing input files instead of erroring +skip_missing = true diff --git a/mise.lock b/mise.lock index 6f4350e..9e1c09e 100644 --- a/mise.lock +++ b/mise.lock @@ -31,3 +31,31 @@ url = "https://github.com/gohugoio/hugo/releases/download/v0.161.1/hugo_0.161.1_ [tools.hugo."platforms.windows-x64"] checksum = "sha256:7f8d030b37600c60bf2a782611257e6a768934fbe7724c1f3a1a501e6724cf0d" url = "https://github.com/gohugoio/hugo/releases/download/v0.161.1/hugo_0.161.1_windows-amd64.zip" + +[[tools.lychee]] +version = "0.23.0" +backend = "aqua:lycheeverse/lychee" + +[tools.lychee."platforms.linux-arm64"] +checksum = "sha256:97eb93b02a7d78a752fc33e5b0983439ccaadbf3db952b68a0a4401acd92e6e0" +url = "https://github.com/lycheeverse/lychee/releases/download/lychee-v0.23.0/lychee-aarch64-unknown-linux-gnu.tar.gz" + +[tools.lychee."platforms.linux-arm64-musl"] +checksum = "sha256:97eb93b02a7d78a752fc33e5b0983439ccaadbf3db952b68a0a4401acd92e6e0" +url = "https://github.com/lycheeverse/lychee/releases/download/lychee-v0.23.0/lychee-aarch64-unknown-linux-gnu.tar.gz" + +[tools.lychee."platforms.linux-x64"] +checksum = "sha256:5538440d2c69a45a0a09983271e5dee0c2fe7137d8035d25b2632e10a66a090a" +url = "https://github.com/lycheeverse/lychee/releases/download/lychee-v0.23.0/lychee-x86_64-unknown-linux-musl.tar.gz" + +[tools.lychee."platforms.linux-x64-musl"] +checksum = "sha256:5538440d2c69a45a0a09983271e5dee0c2fe7137d8035d25b2632e10a66a090a" +url = "https://github.com/lycheeverse/lychee/releases/download/lychee-v0.23.0/lychee-x86_64-unknown-linux-musl.tar.gz" + +[tools.lychee."platforms.macos-arm64"] +checksum = "sha256:4c8034900e11083b68ac6f6582c377ff1f704e268991999e09d717973e493e7f" +url = "https://github.com/lycheeverse/lychee/releases/download/lychee-v0.23.0/lychee-arm64-macos.dmg" + +[tools.lychee."platforms.windows-x64"] +checksum = "sha256:0fda7ff0a60c0250939fc25361c2d4e6e7853c31c996733fdd5a1dd760bcb824" +url = "https://github.com/lycheeverse/lychee/releases/download/lychee-v0.23.0/lychee-x86_64-windows.exe" diff --git a/mise.toml b/mise.toml index ecc6698..7e9a519 100644 --- a/mise.toml +++ b/mise.toml @@ -7,6 +7,7 @@ disable_backends = [ [tools] hugo = "latest" +lychee = "latest" [hooks] enter = "mise install --quiet" @@ -22,3 +23,7 @@ run = "hugo --source docs --minify" [tasks.serve-docs] description = "Serve the docs site locally with Hugo dev server" run = "hugo server --source docs" + +[tasks.check-links] +description = "Check links with lychee" +run = "lychee --no-progress './**/*.md' './src/**/*.c'" From 0a72a0d818a10942683a445f28189aa13fbedf27 Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Thu, 4 Jun 2026 19:57:31 +0000 Subject: [PATCH 2/2] Update stale and redirecting links Validated all links with lychee and updated those that redirected elsewhere to their canonical destination: - dev.maxmind.com/geoip/geolite2-free-geolocation-data?lang=en -> .../geolite2-free-geolocation-data/?lang=en (canonical trailing slash) - dev.maxmind.com/geoip/geolocate-an-ip/databases?lang=en -> .../geolocate-an-ip/databases/?lang=en (canonical trailing slash) - www.maxmind.com/en/geoip2-databases -> www.maxmind.com/en/geoip-databases - www.maxmind.com/en/support -> support.maxmind.com/knowledge-base - github.com/SpiderLabs/ModSecurity/ -> github.com/owasp-modsecurity/ModSecurity - http://www.apache.org/licenses/LICENSE-2.0 -> https://www.apache.org/licenses/LICENSE-2.0 (license header) Part of STF-557. Co-Authored-By: Claude Opus 4.8 (1M context) --- README.md | 10 +++++----- src/mod_maxminddb.c | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 4100b0c..0d9f9cc 100644 --- a/README.md +++ b/README.md @@ -65,8 +65,8 @@ somewhere in your config, such as `LoadModule maxminddb_module ## Usage ## To use this module, you must first download or create a MaxMind DB file. We -provide [free GeoLite databases](https://dev.maxmind.com/geoip/geolite2-free-geolocation-data?lang=en) -as well as [commercial GeoIP databases](https://www.maxmind.com/en/geoip2-databases). +provide [free GeoLite databases](https://dev.maxmind.com/geoip/geolite2-free-geolocation-data/?lang=en) +as well as [commercial GeoIP databases](https://www.maxmind.com/en/geoip-databases). After installing this module and obtaining a database, you must now set up the module in your Apache configuration file (e.g., `/etc/apache2/apache2.conf`) @@ -159,7 +159,7 @@ Apache notes. In case you want supply your own value for the IP address to lookup, it may be done by setting the environment variable `MMDB_ADDR`. This can be done, for instance, with -[ModSecurity](https://github.com/SpiderLabs/ModSecurity/) in (real) phase 1. +[ModSecurity](https://github.com/owasp-modsecurity/ModSecurity) in (real) phase 1. Note that mod_setenvif and mod_rewrite cannot be used for this as they are running after this module. For most usages, [mod_remoteip](https://httpd.apache.org/docs/current/mod/mod_remoteip.html) @@ -283,7 +283,7 @@ Note that data stored as the "bytes" type in a MaxMind DB database can contain null bytes and may end up truncated when stored in an environment variable. If you really need to access this data, we recommend using [one of our programming language -APIs](https://dev.maxmind.com/geoip/geolocate-an-ip/databases?lang=en) instead. +APIs](https://dev.maxmind.com/geoip/geolocate-an-ip/databases/?lang=en) instead. ## Support ## @@ -292,7 +292,7 @@ tracker](https://github.com/maxmind/mod_maxminddb/issues). If you are having an issue with a commercial MaxMind database that is not specific to this module, please see [our support -page](https://www.maxmind.com/en/support). +page](https://support.maxmind.com/knowledge-base). ## Versioning ## diff --git a/src/mod_maxminddb.c b/src/mod_maxminddb.c index 3bd29db..7fac86a 100644 --- a/src/mod_maxminddb.c +++ b/src/mod_maxminddb.c @@ -9,7 +9,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS,