You can find all of this by opening the files. The honest question is not whether you could — it is whether anyone will, on the day a workflow changes, across every file that writes to the same target, while already knowing which five patterns to look for. That is the gap this page is about.
For one file, once, by someone who knows the failure modes, reading is strictly better and this tool adds nothing. You are not limited to five patterns. You know whether your deploy step is idempotent, whether the target has its own locking, and whether your team has already decided a particular race is acceptable — three things a scanner cannot know and will not ask. It will also miss anything outside its five checks and say nothing about it, which is the failure mode of every checker.
So this is not a replacement for reading your pipeline. It is a floor underneath it.
Two workflows deploying the same environment under different concurrency group names is a defect in the relationship between two files. Each file is internally consistent and reviews clean. You only see it by holding both at once and comparing one string in each — which is a thing a person does badly and a scan does perfectly.
The review happened. Then someone added a second deploy job, or copied the workflow for staging, or changed the group key while fixing something else. None of those diffs looks like “reintroduce a deployment race”, and none of them triggers another read of the whole set. Wiring the check into the pull request is what makes the answer current rather than historical:
python3 check.py .github/workflows/ --fail-on-risk
group: deploy-${{ github.sha }} is the expensive one, and it
is expensive precisely because reading finds it only if you already know.
The block is there, the syntax is right, and the intent is obvious and
good. A reader who has not previously lost an afternoon to it ticks the
line off. A check does not need to have lost the afternoon.
| Situation | What to do |
|---|---|
| One deploy workflow, and you are already reading it | Read it. Use the five patterns as a checklist; you do not need this tool. |
| A dozen workflow files, several of which deploy something | Scan the directory — the cross-file finding is the one reading reliably misses. |
| You want the answer to stay true | check.py --fail-on-risk in the pull request that changes a workflow. |
| Someone reports “my fix isn’t live” and the check is green | Scan first. It takes seconds and rules this class out or in before you start reading logs. |
| You need to know if the deploy step itself is safe to interrupt | Neither. That is a property of your deploy script, and no workflow scan can see it. |
| You want a compliance artifact or an audit | Neither. This is evidence for an engineer, not a control or an attestation. |
For a single file you should, and you will find most of this. The two places reading breaks down are scale and recurrence. Scale: a repository with a dozen workflow files has to be read as a set, because one of these defects — two workflows deploying the same environment under different concurrency group names — is not present in either file. Recurrence: the reading is only true for the day it was done, and a workflow that gains a second deploy job six months later reintroduces the defect against a review that already happened.
Nothing, on one file, read carefully, by someone who already knows all five patterns. That last clause is where the value is: the pattern that costs the most — a concurrency group keyed on something that changes every run — looks correct to a reader who has not been caught by it before, because the block is present and correctly spelled. A checker does not have to have been caught by it before, and it reads the twelfth file as carefully as the first.
Yes, and that is the point of the CLI. check.py takes a directory of workflows and --fail-on-risk exits 1 on a high-risk finding, so it can run in the same pull request that changes a workflow. That converts the reading from something someone has to remember to do into something that happens on the diff that would have introduced the problem. It is Python standard library only, with no network access and no GitHub token.
No, and it is not built to. Every finding names the line, explains what goes wrong in terms of what a user would see, and prints the fix, because a finding you do not understand is one you will either apply wrongly or suppress. The explainer page is there for the same reason. A team that reads the findings and then decides a given race is acceptable for their target has used this correctly.
Nothing, in both directions. This page is free, has no sign-in, no account and no usage limit, and it uploads nothing — the scan runs in your browser and this page makes no network request once loaded. The CLI is MIT licensed, depends on the Python standard library alone, and never calls the GitHub API or reads a token. If you would rather not paste a workflow into any web page at all, use the CLI; the two are held to identical output by a test that runs both over the same files.
Check a workflow, or read how a deploy ships an older commit.
Not affiliated with, endorsed by, or sponsored by GitHub. “GitHub” and “GitHub Actions” are used only to name the system whose workflow files this tool reads, and no GitHub product is reproduced or evaluated here. Free and provided as is, with no warranty of any kind; this page is not professional advice and no liability is accepted for any deployment made after reading it. Sponsoring is optional and changes nothing about the tool.