gh-action-pulse scans a repository for GitHub Actions uses: references, checks them against the GitHub API, and rewrites them to safer or more current references when a better upstream target exists.
It is aimed at repositories that want to keep GitHub Actions dependencies understandable, current, and pinned with more confidence.
- Automatic scanning: Detects
uses:statements across workflow and reusable action files. - Reference classification: Distinguishes whether an action is currently pinned to a commit SHA, tag, or branch.
- Recommendation engine: Looks up upstream metadata and recommends an updated reference based on available SemVer tags and branch state.
- Repository redirect handling: Rewrites moved repositories to their canonical name when GitHub reports a redirect.
- Freshness checks: Warns or fails when the newest eligible SemVer tag is older than your configured threshold.
- Node.js runtime check: Recursively verifies that actions, including composite and local composite dependencies, run on at least a configurable minimum Node.js version (
--minimum-nodejs-version, default24), failing with a dedicated exit code (3) when an outdated runtime is detected.
For each detected uses: line, gh-action-pulse:
- Finds GitHub Actions references in the configured workflow and action directories.
- Queries the GitHub API for the referenced repository.
- Detects whether the current reference is a tag, branch, or SHA.
- Selects the newest SemVer tag that is at least
--min-agedays old. - Falls back to a branch recommendation when that is safer or newer than the eligible tag.
- Rewrites redirected repositories to their canonical upstream name.
In practice, this means the tool can:
- convert branch or tag references into pinned SHAs annotated with the matching tag,
- preserve branch intent when no suitable tag exists,
- surface stale upstream action releases with a non-zero exit code.
Before:
- uses: google-github-actions/auth@v2After:
- uses: google-github-actions/auth@<commit-sha> # v2.1.10If an action repository has moved, the repository name may also be rewritten to the canonical upstream location.
gh-action-pulse talks to the GitHub API.
Set a token explicitly:
export GITHUB_TOKEN=your_github_token_hereIf GITHUB_TOKEN is not set, the tool can fall back to using the GitHub CLI authentication flow when gh is available.
The project currently requires Python >= 3.14.
uv tool install gh-action-pulsepipx install gh-action-pulseuv tool install . --force --reinstallRun against the current repository:
gh-action-pulsePreview changes without writing files:
gh-action-pulse --dry-runRequire action tags to be at least 14 days old before they can be selected:
gh-action-pulse --min-age 14Fail when the newest eligible tag is older than 180 days:
gh-action-pulse --min-age 14 --max-age 180Require actions to run on at least Node.js 20:
gh-action-pulse --minimum-nodejs-version 20Show more detail while debugging:
gh-action-pulse --log-level DEBUGPrint the installed version:
gh-action-pulse --versionThe CLI uses Rich for progress and summaries on stderr:
- a progress bar while enriching actions from the GitHub API (and while checking Node.js runtimes);
- colored phase lines for scan, freshness, and Node.js checks;
- a table of proposed or applied
uses:rewrites (yellow header in--dry-run); - a closing summary panel with update counts, warnings, and the exit code.
Routine per-file and per-action chatter is logged at DEBUG. Use --log-level DEBUG (or WARNING / ERROR) when you need diagnostic detail; warnings and errors still use Rich-formatted logging without repeating the main user-facing summary.
--dry-run(GH_ACTION_PULSE_DRY_RUN): show the updates without writing files.--log-level(GH_ACTION_PULSE_LOG_LEVEL): set the logging level (DEBUG,INFO,WARNING,ERROR,CRITICAL).--min-age(GH_ACTION_PULSE_MIN_AGE): require tags to be at least this many days old before recommending them.--max-age(GH_ACTION_PULSE_MAX_AGE): fail when the chosen--min-age-eligible upstream tag is older than this many days. Use0to disable the check.--minimum-nodejs-version(GH_ACTION_PULSE_MINIMUM_NODEJS_VERSION): fail when an action, or any of its composite/local dependencies, runs on a Node.js major version below this value (default24). Use0to disable the check.--version: print the package version and exit.
CLI flags override the matching environment variables when both are set.
gh-action-pulse uses its exit code to signal the outcome of a run:
0: the run completed and no failing condition was detected.2: GitHub authentication failed (GITHUB_TOKENcould not be resolved).3: a Node.js runtime problem was detected in the repository. When an action, or any of its composite/local composite dependencies, runs on a Node.js major version below--minimum-nodejs-version(default24), the tool logs an error and exits with status3. Set--minimum-nodejs-version 0to disable this check.4: a referenced upstream action repository is archived.5: a--max-agestaleness failure occurred.
When multiple failing conditions are detected in the same run, the exit code with the lowest number is returned: authentication (2) and archived repositories (4) stop the run early, and among end-of-run checks the Node.js exit code (3) takes precedence over stale tags (5).
- Local actions such as
./.github/actions/my-actionare not part of the GitHub API lookup flow. - Recommendations depend on repositories exposing usable SemVer tags.
- The tool needs GitHub API access, so rate limits and authentication still apply.
The Node.js runtime check does not inspect every uses: line in the repository. In practice it:
- only starts from remote GitHub Actions referenced as
owner/repo@ref(orowner/repo/path@ref) in.github/workflowsand.github/actions; - skips local actions such as
uses: ./.github/actions/my-actionbecause they do not match thename@referencepattern used during scanning; - inspects the recommended upstream reference (the one the tool would update to), not the currently pinned reference when a recommendation exists;
- only flags JavaScript actions whose manifest declares
runs.using: nodeXX(for examplenode20,node24); - skips Docker actions (
docker://), unresolvable references, missing manifests, and other non-nodeXXruntimes; - walks composite actions recursively and checks nested
uses:dependencies, including relative./pathsteps inside a remote composite action (resolved within that upstream repository); - does not meaningfully check reusable workflows referenced as
uses: org/repo/.github/workflows/foo.yml@ref, because it looks foraction.yml/action.yamlmanifests rather than workflow files.
Set --minimum-nodejs-version 0 to disable this check entirely.
Possible future improvements:
- Maybe Separate unit tests with appropriate workflow (pytest) if checks takes times
- Add E2E tests with appropriate workflow (pytest and/or bats)
- Change to versioned version of tools in mise.toml when near stable version (could depend on tools)
Potential future CLI options (to get the idea):
--config-file: load configuration, including ignore parameters or specific rules for some workflows (needs thinking).--only-workflow: restrict scanning to a specific workflow.--workflow-omit: exclude specific workflows from scanning.--github-action-omit: exclude specific GitHub Actions from the checks.
Contributions are welcome. See CONTRIBUTING.md for the code layout, local setup, and the full list of linters and checks run in CI.