GitHub - kjanat/actionlint: Find problems in your GitHub Actions workflows · GitHub
Skip to content
forked from rhysd/actionlint

About

Find problems in your GitHub Actions workflows

Topics

Resources

Contributing

Security policy

Stars

50 stars

Watchers

0 watching

Forks

Use this GitHub action with your project
Add this Action to an existing workflow or create a new one
View on Marketplace
 
 

Latest commit

 

History

2,720 Commits

Folders and files

Repository files navigation

actionlint

CI Status Latest release NPM Version Docker image version API Document Sponsor this project

actionlint is a static checker for GitHub Actions workflow files. Try it online!

This is an actively maintained fork of rhysd/actionlint. It carries the upstream checks plus cache safety policies enabled by default, configurable opt-in policy checks, composite action step validation, shell completion, and a first-party GitHub Action, and it ships attested binaries, a Docker image on GHCR and Docker Hub, and a Go module at actionlint.kjanat.dev/v2. Report problems through this fork's issue tracker.

Fork provenance and versioning

This fork builds on upstream v1.7.12 (rhysd/actionlint@914e7df). Its independent release series starts at v1.8.0. Tags published by kjanat/actionlint identify this fork's releases; a matching tag need not exist in rhysd/actionlint.

The changelog separates fork releases from inherited upstream history. Releases follow Semantic Versioning for the supported CLI and configuration contracts, with CLI compatibility maintained for existing integrations. New or corrected lint findings can affect CI results; the Go library API remains unstable.

Features

  • Syntax check for workflow files to check unexpected or missing keys following workflow syntax
  • Strong type check for ${{ }} expressions to catch several semantic errors like access to not existing property, type mismatches, ...
  • Actions usage check to check that inputs at with: and outputs in steps.{id}.outputs are correct
  • Reusable workflow check to check inputs/outputs/secrets of reusable workflows and workflow calls
  • shellcheck integration for scripts at run:
  • Ruff integration for Python run: scripts, without requiring a Python interpreter
  • Security checks; script injection by untrusted inputs, hard-coded credentials
  • Other several useful checks; glob syntax validation, dependencies check for needs:, runner label validation, cron syntax validation, ...

See the full list of checks done by actionlint.

A terminal running actionlint on a workflow file, reporting each problem with the offending line underlined

Example of a broken workflow

The same files the animation above records, run through both linters. This section is generated from them by internal/documentation/check-readme.

docs/screenshots/demo-workflow.yaml:

name: Release
on:
  push:
    branches: [main]
jobs:
  build:
    strategy:
      matrix:
        node: ["20", "22"]
    runs-on: ubuntu-26.04
    timeout-minutes: ${{ matrix.node }}
    steps:
      - uses: actions/checkout@v7
      - run: npm run mock-api
        id: mock
        background: true
      - run: npm test
      - wait: api

docs/screenshots/actionlint.yaml:

# yaml-language-server: $schema=../../actionlint.schema.json
---
policy:
  require-commit-hash: true

Upstream actionlint 1.7.12 reports 3: runner-label, syntax-check ×2

demo-workflow.yaml:10:14: label "ubuntu-26.04" is unknown. available labels are "windows-latest", "windows-latest-8-cores", "windows-2025", "windows-2025-vs2026", "windows-2022", "windows-11-arm", "ubuntu-slim", "ubuntu-latest", "ubuntu-latest-4-cores", "ubuntu-latest-8-cores", "ubuntu-latest-16-cores", "ubuntu-24.04", "ubuntu-24.04-arm", "ubuntu-22.04", "ubuntu-22.04-arm", "macos-latest", "macos-latest-xlarge", "macos-latest-large", "macos-26-intel", "macos-26-xlarge", "macos-26-large", "macos-26", "macos-15-intel", "macos-15-xlarge", "macos-15-large", "macos-15", "macos-14-xlarge", "macos-14-large", "macos-14", "self-hosted", "x64", "arm", "arm64", "linux", "macos", "windows". if it is a custom label for self-hosted runner, set list of labels in actionlint.yaml config file [runner-label]
   |
10 |     runs-on: ubuntu-26.04
   |              ^~~~~~~~~~~~
demo-workflow.yaml:16:9: unexpected key "background" for step to run shell command. expected one of "continue-on-error", "env", "id", "if", "name", "run", "shell", "timeout-minutes", "working-directory" [syntax-check]
   |
16 |         background: true
   |         ^~~~~~~~~~~
demo-workflow.yaml:18:9: step must run script with "run" section or run action with "uses" section [syntax-check]
   |
18 |       - wait: api
   |         ^~~~~

This fork 1.17.0 reports 3: expression, require-commit-hash, parallel-steps

demo-workflow.yaml:11:22: type of expression at "float number value" must be number but found type string [expression]
   |
11 |     timeout-minutes: ${{ matrix.node }}
   |                      ^~~
demo-workflow.yaml:13:15: the ref "v7" of action "actions/checkout@v7" is not a commit SHA. actions must be pinned to a full-length commit SHA (40 or 64 hexadecimal digits) because "require-commit-hash" is enabled in the "policy" configuration. see https://docs.github.com/en/actions/security-for-github-actions/security-guides/security-hardening-for-github-actions#using-third-party-actions for more details [require-commit-hash]
   |
13 |       - uses: actions/checkout@v7
   |               ^~~~~~~~~~~~~~~~~~~
demo-workflow.yaml:18:15: "api" is not the ID of a preceding background step. "wait" and "cancel" steps can only refer to an earlier step that has "background: true" [parallel-steps]
   |
18 |       - wait: api
   |               ^~~

Quick start

Install with npm, Homebrew, AUR, Scoop, WinGet, or mise, or download a release archive. See the installation document for all options. To run it through npm:

npx @kjanat/actionlint

With a Go toolchain, install it from source:

go install actionlint.kjanat.dev/v2/cmd/actionlint@latest

actionlint.kjanat.dev/v2 is a Go vanity import path. The Go toolchain resolves it to this GitHub repository, where the source, releases, and issue tracker live. Further reading available here: GOPROXY protocol. Check for yourself: curl https://proxy.golang.org/actionlint.kjanat.dev/v2/@latest

Basically all you need to do is run the actionlint command in your repository. actionlint automatically detects workflows and checks errors. actionlint focuses on finding out mistakes. It tries to catch errors as much as possible and make false positives as minimal as possible.

actionlint

Another option to try actionlint is the online playground. Your browser can run actionlint through WebAssembly.

See the usage document for more details.

GitHub Action

Lint with annotations and a compact job summary:

name: Lint workflows
on: [push, pull_request]
permissions: { contents: read }
jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
        with: { persist-credentials: false }
      - uses: kjanat/actionlint@v1

Project settings belong in .github/actionlint.yaml. Use the config input for a one-run override. No with: block is required.

The upcoming JavaScript Action runs on Linux, macOS and Windows without Docker. Existing immutable releases retain their Docker implementation. Pin a published release commit SHA or normal vX.Y.Z tag; v1 and v1.X are moving pointers.

See the Action guide for configuration, saved reports, optional PR reviews, tool prerequisites, migration and the input/output reference.

pre-commit

For v2, hooks move to kjanat/actionlint-pre-commit. The first v2 hook release is pending. Once published, use its exact tag in .pre-commit-config.yaml:

repos:
  - repo: https://github.com/kjanat/actionlint-pre-commit
    rev: <published-v2-tag>
    hooks: [id: actionlint]

The default hook installs the matching binary wheel in an isolated Python environment. Project configuration and the plugin lockfile select ShellCheck and Ruff Wasm plugins. See v2 migration for existing hook configurations.

Documents

  • AI usage and policy and CLI compatibility: How this fork uses AI and approaches compatibility for existing workflows and CI integrations.
  • Checks: Full list of all checks done by actionlint with example inputs, outputs, and playground links.
  • Installation: Install with npm, Homebrew, AUR, Scoop, WinGet, aqua, mise, the community pip/uv wrapper, release archives, the download script, Docker, or Go. Includes upstream-only package names.
  • Usage: How to use actionlint command locally or on GitHub Actions, the online playground, an official Docker image, and integrations with reviewdog, Problem Matchers, super-linter, pre-commit, VS Code.
  • Configuration: Runner labels, variables, secrets, default permissions, error filters, and opt-in policy checks, with YAML Language Server schema support.
  • Go API: How to use actionlint as Go library.
  • Schema audit: Pinned upstream definitions, compatibility fixes, validation evidence, and retained differences.
  • Expression behavior: Reproduce GitHub's runtime behavior, understand parser differences, and avoid surprising workflow decisions.
  • References: Links to resources.
  • GitHub Actions changelog: Browse and search the latest entries from GitHub's Actions changelog feed.

Bug reporting

When you see some bugs or false positives, it is helpful to file a new issue with a minimal example of input. Feature requests and ideas for additional checks are welcome too.

See the contribution guide for more details.

License

actionlint's code is distributed under the MIT license. Its branding artwork is separately licensed under CC BY 4.0.

About

Find problems in your GitHub Actions workflows

Topics

Resources

Contributing

Security policy

Stars

50 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages