CI: link checker silently succeeds when the checker is unavailable
Problem
At current master commit 1eacf6cb9bfcba006ca972a804c5faace8c2758a, the Markdown link-check job can exit successfully without checking any links.
package.json runs markdown-link-check, but that executable is not declared in devDependencies or the lockfile. The script invokes it through find -exec; an execution failure makes the expression false for that file but does not make find itself exit non-zero. The final condition only searches err for the literal text ERROR:, so “command not found” errors are ignored and the script prints All good.
Reproduction
From a clean checkout of the commit above:
npm ci --ignore-scripts
npm run link-checkObserved:
- exit status:
0 - stdout ends with
All good - stderr contains 121 instances of
find: ‘markdown-link-check’: No such file or directory - no Markdown links were checked
The workflow .github/workflows/md-link-check.yml installs only the locked dependencies before running this command, so it inherits the same fail-open behavior.
There is a second consistency problem: scripts/Apply_Link_Check.sh and the contributor instructions use .markdownlinkcheck.json, which does not exist. The repository’s actual configuration file is markdown-link-check-config.json.
Impact
The required link-integrity check can report success when the checker is unavailable. Contributors and reviewers therefore cannot treat a green Markdown Link Check job as evidence that links were exercised.
Proposed resolution
- Add
markdown-link-checkas a pinned direct development dependency and update the lockfile. - Make the link-check command fail immediately when the executable is unavailable or any per-file invocation exits non-zero.
- Use one canonical configuration filename in
package.json, the helper script, andCONTRIBUTING.md. - Preserve useful per-file failure output for the workflow’s PR comment step.
- Add regression coverage for failure propagation rather than relying only on a successful live run.
Acceptance criteria
- A clean
npm ci --ignore-scriptsprovides the checker used bynpm run link-check. - A valid fixture exits zero.
- A fixture containing a deliberately broken link exits non-zero.
- A missing or deliberately failing checker exits non-zero and cannot print
All good. - The workflow still reports the affected file and link when a real broken-link failure occurs.
- Every documented command names the configuration file that exists in the repository.
I am happy to implement this after maintainer acknowledgment and assignment.
Disclosure: I used OpenAI Codex (GPT-5) to help inspect the repository and draft this issue. I reproduced the command behavior in a clean checkout and verified the referenced files against the commit above.
Source: OWASP/CheatSheetSeries