Skip to content

Repository files navigation

dead-domain-pinger

A GitHub composite action that probes the domains referenced by AdGuard-style filter list rules (via Globalping) and removes the ones that are dead.

A domain is judged dead when DNS resolution fails, when TLS certificate validation fails, or when it redirects to a different registrable domain. Redirects that stay inside the same registrable domain are only detected and reported; those domains are kept. Ambiguous probe results never delete a rule.

Usage

- uses: actions/checkout@v4
  with:
    # The queue is ordered by git history, which a shallow clone does not have.
    fetch-depth: 0

- uses: FilteringDev/dead-domain-pinger@v1
  with:
    filter-root: filterslists
    max-candidates: '50'
    state-directory: dead-domain-state
    state-artifact-name: dead-domain-pinger-state
    dry-run: 'false'
    globalping-api-token: ${{ secrets.GLOBALPING_API_TOKEN }}

Inputs

Name Default Description
filter-root . Directory (relative to the workspace) to scan for filter list files
file-extension .txt File extension used by filter list files
max-candidates 50 Maximum probe jobs to run in a single workflow run, including queued HTTP follow-ups
state-directory dead-domain-state Directory used to write the Markdown report and PR body files
state-artifact-name dead-domain-pinger-state GitHub Actions artifact name used to carry the SQLite state database between runs
worker-count os.cpus().length Number of Node.js worker threads used to probe selected domains; when provided, it must be a positive integer
dry-run false Probe domains but do not write any file changes
globalping-api-token - Required Globalping access token

Globalping configuration

An optional dead-domain-pinger-config.json at the repository root configures the Globalping measurement fields. Its locations and limit fields use the Globalping API request format:

{
  "locations": [{ "country": "KR", "tags": ["eyeball-network"] }],
  "limit": 5
}

When the file is absent, or either field is omitted, the action uses limit: 5 and one eyeball-network probe each from the US, Europe, Korea, Japan, and India. An invalid config file fails the workflow instead of silently changing the requested measurement.

HTTPS TLS failures are queued for an HTTP retry before ordinary candidates in the next workflow run. For a registrable-domain root with DNS or TLS failure, its HTTP retry is attempted first; if that also has DNS or TLS failure, www.<domain> is queued over HTTP for the following run. Each queued probe counts toward max-candidates, and a dead queued result removes the source filter-domain rule.

Outputs

Name Description
has_changes Whether any filter list file was changed (always false in dry-run mode)
dead_domains JSON array of domains judged dead in this run
changed_files JSON array of filter list files that were changed
probed_count Number of domains actually probed in this run
rate_limited Whether probing stopped early because of a Globalping rate limit
warning_count Number of warnings collected while evaluating probe results
report_path Workspace-relative path to the generated Markdown report
pr_body_path Workspace-relative path to the generated pull request body

State

The action persists per-domain last-checked timestamps in a SQLite database carried by a GitHub Actions artifact. During a run, that database is restored to a temporary directory under runner.temp, updated by the action, and uploaded again as state-artifact-name with maximum artifact compression. The generated Markdown report and pull request body still go under state-directory in the workspace.

SQLite loading, verdict recording and saving stay in the main process. Probe workers do not touch the database file; they send serializable probe results back to the main process, which updates the state.

Each domain is dated individually from the git history: adding a domain to an existing rule refreshes only that domain, and moving or reformatting a rule keeps the dates of the domains it already carried. This needs the full history, so check the repository out with fetch-depth: 0. The first run starts with an empty SQLite state when no artifact exists yet.

Selected domains are probed by a bounded Node.js worker-thread pool. By default the pool size is os.cpus().length. Lower worker-count if the Globalping quota is tight or if parallel requests trigger rate limiting too quickly.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages