Why it matters
A workflow file can look fine and still go wrong: a job that needs one that doesn't exist, so nothing starts; a matrix that quietly runs 60 jobs; a pull_request_target trigger that gives a fork's code your secrets; actions on a moving tag that someone else can change. GitHub only tells you some of this after you push.
This tool reads the workflow in your browser and draws the job graph from needs:. It expands each matrix the way the runner does, applying include and exclude, so you can see how many runs each push costs. It runs actionlint's checks for needs:, matrices and permissions, and zizmor's checks for permissions, pinning, dangerous triggers and inherited secrets, each with its own message and a fix.
How to use it
- Paste a workflow, or choose a file from .github/workflows.
- Check the job graph: grey boxes and red arrows mean the workflow won't start.
- Look at the runs per job and trim matrices that are bigger than they need to be.
- Fix the findings, starting with the red ones, then run actionlint and zizmor in CI.
FAQ
Is this the same as actionlint and zizmor?
It ports actionlint 1.7.12's job-needs, matrix and permissions rules and zizmor 1.31.1's unpinned-uses, excessive-permissions, dangerous-triggers and secrets-inherit audits, with their messages. Both tools check much more, such as expressions, shell scripts and template injection, so run them in CI as well.
How is the matrix counted?
Every combination of the matrix values, minus any that match an exclude entry. An include entry that fits an existing combination adds its values to it; otherwise it becomes a new run. A matrix built from an expression like fromJSON is only known when the workflow runs.
Why pin actions to a commit SHA?
A tag like v4 can be moved to different code at any time, by the owner or by anyone who takes over the repository. A 40-character commit SHA can't change. Keep the tag in a comment so updates stay readable.
Why is pull_request_target risky?
It runs with your repository's secrets and a write token, even for pull requests from forks. If the workflow checks out and runs the pull request's code, that code gets those secrets.
Is my workflow uploaded?
No. It's parsed and checked in your browser.
Credits and licences
Rules and messages ported from actionlint 1.7.12 (MIT License, rhysd) and zizmor 1.31.1 (MIT License, William Woodruff), matrix expansion from act (MIT License), YAML parsed with yaml 2.9.1 (ISC License, Eemeli Aro).