Site-wide linter for SEO tags, security headers, TLS and links https://dbuho.me/project/spiderlint/
  • TypeScript 96.7%
  • JavaScript 2.4%
  • Shell 0.7%
  • Dockerfile 0.2%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Damián Búho 9b22ac84b5
All checks were successful
published / fetched (push) Successful in 1s
published / deps-installed (push) Successful in 1s
published / source-is-tested (push) Successful in 0s
published / projectfile-is-valid (push) Successful in 4s
published / signing-is-ready (push) Successful in 5s
published / source-is-compliant (push) Successful in 6s
published / projectfile-is-ok (push) Successful in 4s
published / documentation-passes-lint (push) Successful in 52s
published / documentation-is-ok (push) Successful in 0s
published / source-is-secure (push) Successful in 57s
published / source-passes-lint (push) Successful in 3m11s
published / source-is-ok (push) Successful in 0s
published / inputs-are-ok (push) Successful in 0s
published / image-is-built (amd64) (push) Successful in 4m2s
published / image-has-sbom (amd64) (push) Has been skipped
published / secrets-ready (push) Successful in 0s
published / images-are-ok (push) Successful in 0s
published / container-is-ok (push) Successful in 0s
published / container-ready-to-test (push) Successful in 0s
published / container-is-diagnosed (push) Successful in 0s
published / container-is-verified (amd64) (push) Successful in 3m41s
published / image-is-secure (amd64) (push) Successful in 7m40s
published / image-is-ready (push) Successful in 0s
published / artifacts-are-ok (push) Successful in 0s
published / ready-to-publish (push) Successful in 0s
published / npm-published (push) Has been skipped
published / publish-image (push) Successful in 0s
published / image-is-signed (push) Has been skipped
published / image-is-attested (dockerhub) (push) Successful in 6s
published / image-is-attested (kiota) (push) Successful in 8s
published / release-is-published (push) Has been skipped
published / release-notes-are-published (push) Has been skipped
published / published (push) Successful in 0s
feat: multiple fixes for one violation
2026-10-12 21:01:30 -03:00
.compose fix(compose): keep the server config out of the compose file glob 2026-10-10 05:29:23 -03:00
.container chore(license): relicense to AGPL-3.0-only 2026-10-09 02:48:23 -03:00
.forgejo/workflows ci: regenerate workflows 2026-10-11 23:37:13 -03:00
.github/workflows ci: regenerate workflows 2026-10-11 23:37:13 -03:00
.makefile chore(m6e): bump core and b19 2026-10-11 23:35:30 -03:00
.projectfile chore(license): relicense to AGPL-3.0-only 2026-10-09 02:48:23 -03:00
.scripts/action refactor(usage): capture help from bin/spiderlint.js through m6e 2026-10-10 05:29:01 -03:00
bin chore(license): relicense to AGPL-3.0-only 2026-10-09 02:48:23 -03:00
docs chore(version): 0.143.1 2026-10-12 08:21:03 -03:00
LICENSES chore(license): add AGPL license. 2026-10-09 19:32:19 -03:00
locales fix(rules): show an exact-value miss as the value, not its length 2026-10-09 18:05:00 -03:00
presets feat: multiple fixes for one violation 2026-10-12 21:01:30 -03:00
src feat: multiple fixes for one violation 2026-10-12 21:01:30 -03:00
tests feat: multiple fixes for one violation 2026-10-12 21:01:30 -03:00
vendors feat(stack): detect the services an origin runs on 2026-10-09 18:38:29 -03:00
.claudeignore chore(license): relicense to AGPL-3.0-only 2026-10-09 02:48:23 -03:00
.containerignore chore(license): relicense to AGPL-3.0-only 2026-10-09 02:48:23 -03:00
.dockerignore chore(license): relicense to AGPL-3.0-only 2026-10-09 02:48:23 -03:00
.git-blame-ignore-revs chore(license): relicense to AGPL-3.0-only 2026-10-09 02:48:23 -03:00
.gitattributes chore(license): relicense to AGPL-3.0-only 2026-10-09 02:48:23 -03:00
.gitignore chore(license): relicense to AGPL-3.0-only 2026-10-09 02:48:23 -03:00
.gitmodules chore(license): relicense to AGPL-3.0-only 2026-10-09 02:48:23 -03:00
.grype.yaml chore(license): relicense to AGPL-3.0-only 2026-10-09 02:48:23 -03:00
.npmignore chore(license): relicense to AGPL-3.0-only 2026-10-09 02:48:23 -03:00
.prettierrc.yaml chore(license): relicense to AGPL-3.0-only 2026-10-09 02:48:23 -03:00
.trivyignore chore(license): relicense to AGPL-3.0-only 2026-10-09 02:48:23 -03:00
.yamllint chore(license): relicense to AGPL-3.0-only 2026-10-09 02:48:23 -03:00
action.yaml fix(action): list as Spiderlint Site Audit on the Marketplace 2026-10-12 02:09:15 -03:00
AGENTS.md fix(compose): keep the server config out of the compose file glob 2026-10-10 05:29:23 -03:00
AI_POLICY.md chore(license): relicense to AGPL-3.0-only 2026-10-09 02:48:23 -03:00
audit-ci.jsonc chore(license): relicense to AGPL-3.0-only 2026-10-09 02:48:23 -03:00
CITATION.cff chore(version): 0.143.1 2026-10-12 08:21:03 -03:00
CODE_OF_CONDUCT.md chore(license): relicense to AGPL-3.0-only 2026-10-09 02:48:23 -03:00
CODEOWNERS chore(license): relicense to AGPL-3.0-only 2026-10-09 02:48:23 -03:00
CONTRIBUTING.md chore(license): relicense to AGPL-3.0-only 2026-10-09 02:48:23 -03:00
Dockerfile build(docker): own the download cache as the build user 2026-10-10 04:22:57 -03:00
eslint.config.js fix(lint): adopt unicorn 77 recommended set 2026-10-12 03:09:21 -03:00
knip.json chore: configure knip entry points 2026-10-09 17:46:11 -03:00
knip.json.license chore(license): add knip license 2026-10-09 22:41:14 -03:00
lefthook.yaml chore: regenerate lefthook.yaml 2026-09-29 22:28:52 -03:00
LICENSE chore(license): relicense to AGPL-3.0-only 2026-10-09 02:48:23 -03:00
Makefile chore(license): relicense to AGPL-3.0-only 2026-10-09 02:48:23 -03:00
MARKETPLACE.md docs(action): add the Marketplace listing 2026-10-12 02:10:01 -03:00
osv-scanner.toml chore(license): relicense to AGPL-3.0-only 2026-10-09 02:48:23 -03:00
package-lock.json fix(deps): bump typescript-eslint 8.71.2 2026-10-12 19:04:28 -03:00
package-lock.json.license chore(license): relicense to AGPL-3.0-only 2026-10-09 02:48:23 -03:00
package.json fix(deps): bump typescript-eslint 8.71.2 2026-10-12 19:04:28 -03:00
package.json.license chore(license): relicense to AGPL-3.0-only 2026-10-09 02:48:23 -03:00
projectfile.yaml chore(version): 0.143.1 2026-10-12 08:21:03 -03:00
README.md chore(version): 0.143.1 2026-10-12 08:21:03 -03:00
SECURITY.md chore(license): relicense to AGPL-3.0-only 2026-10-09 02:48:23 -03:00
SUPPORT.md chore(license): relicense to AGPL-3.0-only 2026-10-09 02:48:23 -03:00
tsconfig.build.json feat(build): ship a compiled build in the packed package 2026-10-04 01:26:46 -03:00
tsconfig.build.json.license chore(license): relicense to AGPL-3.0-only 2026-10-09 02:48:23 -03:00
tsconfig.json feat(transport): record 103 Early Hints and cookie Path and Domain 2026-09-25 20:17:10 -03:00
tsconfig.json.license chore(license): relicense to AGPL-3.0-only 2026-10-09 02:48:23 -03:00

Español · Українська

Spiderlint

Spiderlint crawls every page a site serves, collects facts about each request (HTML, headers, TLS, timings, sizes) and lints them against rulesets scoped by URL group, so a template missing a heading is one finding rather than one per page. Built on Node and Crawlee.

Stand with Ukraine Projectfile inside License Cosign ClamAV scanned PRs welcome REUSE compliance

Project status Last commit on kiota.ch Last commit on Codeberg Last commit on GitHub

npm version npm downloads per month Dependency freshness

Publish pipeline on GitHub Vulnerability audit on GitHub Dependency freshness on GitHub Analysis sweep on GitHub

Publish pipeline on kiota.ch Vulnerability audit on kiota.ch Dependency freshness on kiota.ch Analysis sweep on kiota.ch

Features

  • Accessibility checked from every side
  • Client-rendered pages audited as visitors see them
  • Every kind of page early, whatever the limit
  • CSS checked as browsers read it
  • The DNS behind every crawled host
  • Feeds checked the way readers see them
  • One finding per template, not per page
  • Icons fetched and measured
  • Image weight measured, not estimated
  • The site measured as a whole
  • Dead links, on the site and off it
  • Mail authentication of every domain it crawls
  • Each origin checked once, beyond its pages
  • Structured data and markup checked on every page
  • Speed problems found without a browser
  • Privacy before consent
  • Sites on any network, crawled politely
  • Reports for people, pipelines and coding agents
  • Page dependencies fetched once
  • robots.txt read the way crawlers read it
  • Over 500 rules, and new ones written as data
  • Search visibility checked across the whole site
  • Security headers judged, not just detected
  • Scan server
  • Crawl once, lint many times
  • The footprint of every page view
  • TLS configuration scanned in-house
  • Transport checked per page, not per host
  • What the CDN or host adds, kept apart
  • The files a site publishes beside its pages

It also inherits the features of B19 / Ubuntu — see Features for the full list.

What this provides

  • CI action damian-buho/spiderlint@0.143.1
  • Container image ghcr.io/damian-buho/spiderlint:latest
  • Container image damianbuho/spiderlint:latest
  • npm package spiderlint — command spiderlint

Installation

Container image

Pull the published container image:

Pull from GHCR — linux/amd64

docker pull ghcr.io/damian-buho/spiderlint:latest
alias spiderlint='docker run --rm --user "$(id -u):$(id -g)" --group-add 0 --volume "$PWD:/app/ws" --workdir /app/ws ghcr.io/damian-buho/spiderlint:latest spiderlint'

Pull from DockerHub — linux/amd64

docker pull damianbuho/spiderlint:latest
alias spiderlint='docker run --rm --user "$(id -u):$(id -g)" --group-add 0 --volume "$PWD:/app/ws" --workdir /app/ws damianbuho/spiderlint:latest spiderlint'

Stable releases also publish X.Y.Z, X.Y and X tags — pull the precision you want to pin.

If the registries above are unreachable, pull from the origin instead:

Pull from Kiota — linux/amd64

docker pull kiota.ch/damian-buho/spiderlint:latest
alias spiderlint='docker run --rm --user "$(id -u):$(id -g)" --group-add 0 --volume "$PWD:/app/ws" --workdir /app/ws kiota.ch/damian-buho/spiderlint:latest spiderlint'

Then run it as if it were installed — the alias runs every example as written against the current directory:

spiderlint --help

npm package

Install the command globally:

npm install --global spiderlint

Needs Node.js >=26.

Usage

Run it as a step in a GitHub Actions workflow:

- uses: damian-buho/spiderlint@0.143.1

The action takes these inputs:

Input Default Description
urls Newline-separated seed URLs. Empty takes the targets from the config file.
config_file Projectfile or plain YAML carrying the org.spiderlint subtree, relative to the workspace.
site One org.spiderlint.sites name to audit; a config declaring several needs one step per site.
rules Comma-separated rulesets replacing every group’s rules (e.g. recommended,axe).
args More audit flags, one per line with its value after a space (e.g. --max-pages 200).
fail_on error Severity that fails the job: error | warning | info | never
upload_sarif false Upload the SARIF report to code scanning; needs the security-events: write permission.
cache true Keep the crawl store in the forge cache, so an unchanged site is re-audited with 304s.
version Image tag to pull (e.g. latest, 1.2.3). Empty follows the action’s own version tag, else latest.
image Full image reference. Takes precedence over version.

spiderlint

$ spiderlint --help
spiderlint
Site-wide linter for SEO tags, security headers, TLS and links
https://dbuho.me/project/spiderlint/

Usage: spiderlint <command> [domain…] [options]
A domain is example.com or a URL to start from; without a scheme, https:// is
assumed.

Check a site:
  audit [domain…]                 crawl a site, then lint it
  crawl [domain…]                 fetch pages into the store, lint nothing
  lint [domain…]                  lint the stored pages, with no network
  show-report [domain…]           print the stored report again, in any format

Inspect:
  show-facts <url>                fetch one page and print its facts
  export-facts [domain…]          print every stored page’s facts, no network
  list-groups [domain…]           count the pages in each URL group

Rules:
  list-rules [ruleset|id…]        list rules at the severity this config gives
  list-presets                    list the shipped rulesets and their groups
  explain-rule <rule>             show a rule’s facts, expectation and fix

Cache:
  show-cache [domain…]            show the entries, bytes and age of each bucket
  purge-cache [bucket] [domain…]  delete a site’s cached entries
  warm-cache [domain…]            fetch robots.txt and sitemaps without crawling

Commands:
  help [command]                  show a command’s options and examples

Options:
  --config <path>                 settings file
                                  (default: projectfile.yaml)
                                  (env: SPIDERLINT_CONFIG)
  --site <names>                  only these org.spiderlint.sites, repeatable
                                  (default: all)
  --[no-]color                    force or disable color
                                  (default: auto, env: NO_COLOR, FORCE_COLOR)
  --[no-]progress                 status line on an interactive stderr
                                  (default: auto)
  --log-level <level>             trace, debug, info, warn, error or silent
                                  (default: warn, env: SPIDERLINT_LOG_LEVEL)
  -V, --version                   show the version
  -h, --help                      show this screen, or a command’s

Run spiderlint <command> --help for a command’s options and examples.

Exit codes:
  0  clean
  1  findings at or above --fail-on
  2  usage or config error
  3  nothing fetched, or an --offline cache miss
  4  the run failed

Examples and every command’s help are in Usage.

Building

Clone the repository with its submodules:

git clone --recurse-submodules https://codeberg.org/damian-buho/spiderlint spiderlint && cd spiderlint

Build the container image locally:

make container-build

Run make with no arguments for the default target; run make help to list every target.

For the local dev loop, make dev-container brings up the dev-container.

Pipeline entry points:

  • make analyzed — Run the heavy analysis sweep (mutation testing, benchmarks)
  • make audited — Re-scan the pinned dependencies and published artifacts for new vulnerabilities
  • make check-outdated — Report every pinned dependency that lags upstream
  • make ready-to-publish — Run the pseudo-CI pipeline locally — build, test and scan, without publishing

Documentation

Policies

License

This project is licensed under AGPL-3.0-only — see the LICENSE file for details.