checkgate is a read-only CLI that audits the contract between GitHub Actions
workflow jobs and required check names. It catches configuration drift that can
leave a pull request permanently waiting for a status that the workflow cannot
emit.
It works offline: you supply the required check names, and checkgate reads
local workflow YAML. It does not need a GitHub token and never modifies files.
REQUIRED_CHECK_NEVER_EMITTED— no static job emits the required name.REQUIRED_CONTEXT_RENAMED— a similar job name suggests configuration drift.REQUIRED_CHECK_NOT_ON_PULL_REQUEST— the matching job cannot run for PRs.WORKFLOW_PATH_FILTER_CAN_SKIP_REQUIRED— workflow-levelpathsorpaths-ignorecan skip the entire required workflow.MERGE_GROUP_TRIGGER_MISSING— opt-in merge-queue validation finds a missingmerge_grouptrigger.REQUIRED_CONTEXT_UNVERIFIABLE— an expression or matrix makes the emitted check names dynamic; this is a warning rather than a false certainty.
Output is available as human-readable text, stable JSON, or SARIF 2.1.0.
Python 3.10+ is required.
python -m pip install .For development from a clone:
python -m pip install -e .This copy-paste trial clones the project into a temporary directory, installs it
in an isolated virtual environment, proves the safe fixture exits 0, and then
shows the findings from the intentionally broken fixture:
trial="$(mktemp -d)" && \
git clone --depth 1 https://github.com/canilbey/checkgate.git "$trial/checkgate" && \
python3 -m venv "$trial/venv" && \
"$trial/venv/bin/pip" install -q "$trial/checkgate" && \
"$trial/venv/bin/checkgate" audit \
--workflows "$trial/checkgate/fixtures/safe/workflows" \
--required-file "$trial/checkgate/fixtures/safe/required.txt" && \
( set +e
"$trial/venv/bin/checkgate" audit \
--workflows "$trial/checkgate/fixtures/workflows" \
--required-file "$trial/checkgate/fixtures/required.txt" \
--require-merge-group
broken_rc=$?
test "$broken_rc" -eq 1 )Expected result: the safe fixture prints OK; the broken fixture reports four
contract errors and the final trial status is successful. The trial only reads
the included local fixtures. Remove its temporary directory afterwards if you
wish (rm -rf "$trial").
Copy the required check names from your branch protection or ruleset into a newline-delimited file:
unit-tests
lint
security-scan
Audit the repository's workflows:
checkgate audit \
--workflows .github/workflows \
--required-file required-checks.txtYou can also repeat or comma-separate values:
checkgate audit --required unit-tests,lint --required security-scanIf the repository uses GitHub merge queues, enable the additional contract check explicitly:
checkgate audit --required-file required-checks.txt --require-merge-groupMachine-readable output:
checkgate audit --required-file required-checks.txt --format json
checkgate audit --required-file required-checks.txt --format sarif > checkgate.sarifThe intentionally broken fixture demonstrates renamed and missing contexts, workflow-level path-filter risk, and an absent merge-queue trigger:
checkgate audit \
--workflows fixtures/workflows \
--required-file fixtures/required.txt \
--require-merge-groupThe safe fixture exits successfully:
checkgate audit \
--workflows fixtures/safe/workflows \
--required-file fixtures/safe/required.txt0: no errors (warnings may be present)1: one or more contract errors2: invalid CLI input, unreadable input, or invalid workflow YAML
GitHub users have repeatedly documented required checks getting stuck when a
workflow is skipped by path filters, including long-running community threads
#13690,
#44490, and
#26251. Existing tools
are excellent at workflow syntax or path selection; checkgate focuses on the
small contract between names, PR triggers, path filters, and merge queues.
Version 0.1 audits local YAML against a user-supplied list. It does not discover
branch protection or rulesets through the GitHub API, resolve reusable
workflows, or expand expressions/matrices. Dynamic names produce a warning.
The --require-merge-group check is opt-in because a workflow without that
trigger is only defective when the repository actually uses merge queues.
python -m pytest
python -m ruff check src testsSee VALIDATION.md for fixture and public-repository dry-run
evidence.
Use the privacy-safe feedback form for trial results, unexpected findings, documentation improvements, or narrow requests. It requires a minimal public-data confirmation; do not post secrets, private repository details, personal information, proprietary workflows, or full logs. Report security-sensitive problems through GitHub's private Security advisory form.
MIT