CtrlK
BlogDocsLog inGet started
Tessl Logo
SkillPublic

github-actions-validator

Comprehensive toolkit for validating, linting, and testing GitHub Actions workflow files, custom local actions, and public actions. Use this skill when working with GitHub Actions YAML files (.github/workflows/*.yml), validating workflow syntax, testing workflow execution with act, or debugging workflow issues.

Quality

86%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide
SecuritybySnyk

Low

Low-risk findings worth noting

SKILL.md
Quality
Evals
Security

GitHub Actions Validator

Overview

Validate and test GitHub Actions workflows, custom actions, and public actions using industry-standard tools (actionlint and act). This skill provides comprehensive validation including syntax checking, static analysis, local workflow execution testing, and action verification with version-aware documentation lookup.

Philosophy

  • Lint first, execute second: actionlint is fast and needs no Docker, so it always runs before act.
  • Every reported error maps to a documented fix in references/; quote that fix rather than improvising one.
  • Treat security findings (script injection, unpinned actions) as defects, never as style preferences.
  • Static analysis has limits: state plainly what actionlint and act cannot prove.

When to Use

  • Validating a workflow file under .github/workflows/ before commit or merge
  • Debugging a workflow that fails syntax, expression or schema checks
  • Testing a workflow locally with act before pushing
  • Checking that public actions use current, non-deprecated versions
  • Reviewing a workflow for script injection and other actionlint security findings

When Not to Use

  • Authoring a new workflow from scratch (use the GitHub Actions generator skill instead)
  • Validating CI definitions for other systems such as GitLab CI, Jenkins or Azure Pipelines
  • Diagnosing failures that only occur on GitHub-hosted runners at run time, which static analysis cannot reproduce
  • Validating private actions you cannot access

CRITICAL: Assistant Workflow (MUST FOLLOW)

Every validation MUST follow these steps. Skipping any step is non-compliant.

Step 1: Run Validation Script

cd <skill-directory>  # the folder containing this SKILL.md
bash scripts/validate_workflow.sh <workflow-file-or-directory>

Step 2: For EACH Error - Consult Reference File

When actionlint or act reports ANY error, you MUST:

  1. Read the appropriate reference file (see mapping below)
  2. Find the matching error pattern
  3. Extract the fix/solution

Step 3: Quote the Fix to User

For each error, provide:

  1. Error message (from script output)
  2. Explanation (from reference file)
  3. Fix code (quoted from reference file)
  4. Corrected code (applied to user's workflow)

Step 4: Verify Public Actions (if present)

For any public actions (uses: owner/action@version):

  1. First check references/action_versions.md for known actions and versions
  2. Use web search for unknown actions: "[action-name] [version] github action documentation"
  3. Verify required inputs match
  4. Check for deprecation warnings

Step 5: Provide Complete Summary

After all errors are addressed:

  • List all fixes applied
  • Note any warnings
  • Recommend best practices from references/

Error-to-Reference Mapping

Error Pattern / Output CategoryReference FileSection to Consult
runs-on:, runner, ubuntu, macos, windowsreferences/runners.mdRunner labels
cron, schedule / [SCHEDULE]references/common_errors.mdSchedule Errors
${{, expression, if: / [EXPRESSION]references/common_errors.mdExpression Errors
needs:, job, dependency / [SYNTAX]references/common_errors.mdJob Configuration Errors
uses:, action, input / [ACTION]references/common_errors.mdAction Errors
untrusted, injection, security / [SECURITY]references/common_errors.mdScript Injection section
syntax, yaml, unexpectedreferences/common_errors.mdSyntax Errors
docker, container / [DOCKER]references/act_usage.mdTroubleshooting
[ACT-LIMIT], act fails but GitHub worksreferences/act_usage.mdLimitations
@v3, @v4, deprecated, outdatedreferences/action_versions.mdVersion table
workflow_call, reusable, oidcreferences/modern_features.mdRelevant section
glob, path, paths:, patternreferences/common_errors.mdPath Filter Errors
User asks about actionlint configreferences/actionlint_usage.mdProvide examples
Runner questions/errorsreferences/runners.mdLabels and availability

Quick Start

Initial Setup

cd <skill-directory>  # the folder containing this SKILL.md
bash scripts/install_tools.sh  # Installs act and actionlint to scripts/.tools/

Validation Commands

# Full validation (lint + test)
bash scripts/validate_workflow.sh .github/workflows/ci.yml

# Lint-only (fastest, no Docker required)
bash scripts/validate_workflow.sh --lint-only .github/workflows/ci.yml

# Test-only with act (requires Docker)
bash scripts/validate_workflow.sh --test-only .github/workflows/ci.yml

# Validate all workflows
bash scripts/validate_workflow.sh .github/workflows/

actionlint checks: YAML syntax, schema compliance, expression syntax, runner labels, action inputs/outputs, job dependencies, CRON syntax, glob patterns, shell scripts, security vulnerabilities.

Note: act has limitations: see references/act_usage.md.

Validating Resource Types

Workflows

# Single workflow
bash scripts/validate_workflow.sh .github/workflows/ci.yml

# All workflows
bash scripts/validate_workflow.sh .github/workflows/

Key validation points: triggers, job configurations, runner labels, environment variables, secrets, conditionals, matrix strategies.

Custom Local Actions

Create a test workflow that uses the custom action, then validate:

bash scripts/validate_workflow.sh .github/workflows/test-custom-action.yml

Public Actions

When workflows use public actions (e.g., actions/checkout@v6):

  1. Use web search to find action documentation
  2. Verify required inputs and version
  3. Check for deprecation warnings
  4. Run validation script

Search format: "[action-name] [version] github action documentation"

Reference Files Summary

FileContent
references/act_usage.mdAct tool usage, commands, options, limitations, troubleshooting
references/actionlint_usage.mdActionlint validation categories, configuration, integration
references/common_errors.mdCommon errors catalog with fixes
references/action_versions.mdCurrent action versions, deprecation timeline, SHA pinning
references/modern_features.mdReusable workflows, SBOM, OIDC, environments, containers
references/runners.mdGitHub-hosted runners (ARM64, GPU, M2 Pro, deprecations)

Troubleshooting

IssueSolution
"Tools not found"Run bash scripts/install_tools.sh
"Docker daemon not running"Start Docker or use --lint-only
"Permission denied"Run chmod +x scripts/*.sh
act fails but GitHub worksSee references/act_usage.md Limitations

Debug Mode

actionlint -verbose .github/workflows/ci.yml  # Verbose actionlint
act -v                                         # Verbose act
act -n                                         # Dry-run (no execution)

Limitations

  • act limitations: Not all GitHub Actions features work locally
  • Docker requirement: act requires Docker to be running
  • Network actions: Some GitHub API actions may fail locally
  • Private actions: Cannot validate without access
  • Runtime behavior: Static analysis cannot catch all issues
  • File location: act can only validate workflows in .github/workflows/ directory; files outside (like assets/) can only be validated with actionlint

Quick Examples

Example 1: Pre-commit Validation

cd <skill-directory>  # the folder containing this SKILL.md
bash scripts/validate_workflow.sh .github/workflows/
git add .github/workflows/ && git commit -m "Update workflows"

Example 2: Debug Failing Workflow

bash scripts/validate_workflow.sh --lint-only .github/workflows/failing.yml
# Fix issues
bash scripts/validate_workflow.sh .github/workflows/failing.yml

Complete Worked Example: Multi-Error Workflow

User's Problematic Workflow

name: Broken CI
on:
  schedule:
    - cron: '0 0 * * 8'  # ERROR 1
jobs:
  build:
    runs-on: ubuntu-lastest  # ERROR 2
    steps:
      - uses: actions/checkout@v3  # ERROR 3 (outdated)
      - run: echo ${{ github.event.issue.title }}  # ERROR 4 (security)
  deploy:
    needs: biuld  # ERROR 5 (typo)
    runs-on: ubuntu-latest
    steps:
      - run: echo "Deploying"

Step 1: Run Validation

bash scripts/validate_workflow.sh --lint-only workflow.yml

Output:

[ERROR] invalid CRON format "0 0 * * 8"
[ERROR] label "ubuntu-lastest" is unknown
[WARN] "github.event.issue.title" is potentially untrusted
[ERROR] job "deploy" needs job "biuld" which does not exist

Step 2-3: Consult References and Quote Fixes to User

Using the Error-to-Reference Mapping table above, consult the relevant reference file for each error and quote the fix to the user:

#ErrorReference FileFix
1invalid CRON format "0 0 * * 8"common_errors.md - Schedule ErrorsChange 8 to 0 (weekday range is 0–6)
2label "ubuntu-lastest" is unknowncommon_errors.md + runners.mdChange to ubuntu-latest
3checkout@v3 (outdated)action_versions.mdUpdate to @v6 or SHA-pinned equivalent
4Untrusted input in run:common_errors.md - Script InjectionPass through environment variable
5needs: biuld (typo)common_errors.md - Job ConfigurationChange to needs: build

Step 4: Corrected Workflow

name: Fixed CI
on:
  schedule:
    - cron: '0 0 * * 0'  # Fixed: Sunday (valid range 0-6)
jobs:
  build:
    runs-on: ubuntu-latest  # Fixed: typo corrected
    steps:
      - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3  # v6.0.0
      - name: Process issue
        env:
          TITLE: ${{ github.event.issue.title }}  # Fixed: sanitized via env var
        run: echo "$TITLE"
  deploy:
    needs: build  # Fixed: typo corrected
    runs-on: ubuntu-latest
    steps:
      - run: echo "Deploying"

Step 5: Summary

ErrorTypeFix Applied
CRON 0 0 * * 8ScheduleChanged to 0 0 * * 0
ubuntu-lastestRunnerChanged to ubuntu-latest
checkout@v3Outdated ActionUpdated to @v6.0.0 (SHA-pinned)
Direct ${{ }} in runSecurityWrapped in environment variable
needs: biuldJob DependencyChanged to needs: build

Recommendations:

  • Run bash scripts/validate_workflow.sh --check-versions regularly
  • Use SHA pinning for all actions in production workflows
  • Always pass untrusted input through environment variables

Anti-Patterns

NEVER skip lint-only mode when Docker is unavailable

WHY: Skipping validation entirely because Docker is not installed leaves syntax errors, schema violations, and security issues undetected. actionlint catches the majority of real errors without Docker.

BAD: Skip all validation when Docker is not installed.

GOOD: Run bash scripts/validate_workflow.sh --lint-only <file>, which covers syntax, schema, and security checks without a container runtime.

NEVER ignore script injection warnings from actionlint

WHY: Script injection warnings flag real attack vectors. Untrusted github.event.* values interpolated directly into shell commands allow a pull request author to execute arbitrary code in your workflow.

BAD: Dismiss script injection warnings as low priority and merge anyway.

GOOD: Pass untrusted input through environment variables (env: PR_TITLE: ${{ github.event.pull_request.title }}) and reference "$PR_TITLE" in the run: step.

NEVER validate a workflow file in isolation when it uses workflow_call or matrix

WHY: Reusable workflows and matrix strategies depend on caller-provided inputs and context that cannot be resolved by validating the file alone. Skipping caller validation misses entire classes of type and expression errors.

BAD: Validate only the reusable workflow file without also validating the calling workflow.

GOOD: Validate both the caller and callee, and note any warnings that need runtime context that static analysis cannot resolve.

NEVER accept deprecation warnings as harmless

WHY: Deprecated action major versions (for example @v2 when @v4 is current) may receive no security patches. A known vulnerability in a deprecated version is an open door into your CI environment.

BAD: Leave actions/checkout@v2 in place after the validator warns it is outdated.

GOOD: Update to the current SHA-pinned version listed in references/action_versions.md.

NEVER fix an error without consulting the reference file first

WHY: The workflow requires each actionlint or act error to be matched against references/ and the documented fix quoted to the user. Guessing a fix risks a change that silences the message but leaves the underlying defect.

BAD: See label "ubuntu-lastest" is unknown and edit the workflow without checking references/runners.md.

GOOD: Look the error up in the Error-to-Reference Mapping, quote the explanation and fix, then apply it.

NEVER use web search for an action that references/action_versions.md already covers

WHY: The reference file is the first source of truth for known actions and versions. Searching first wastes effort and can surface stale or unofficial documentation.

BAD: Search the web for actions/checkout documentation before opening references/action_versions.md.

GOOD: Check references/action_versions.md first and search the web only for actions it does not list.

NEVER treat a passing act run as proof the workflow works on GitHub

WHY: act has documented limitations, and some GitHub API actions fail or behave differently locally. A local pass or fail is a signal, not a guarantee.

BAD: Report a workflow as verified because act succeeded, or as broken because act failed while actionlint is clean.

GOOD: Combine the actionlint result with act, and consult the Limitations section of references/act_usage.md before concluding either way.

NEVER run act against files outside .github/workflows/

WHY: act can only validate workflows in the .github/workflows/ directory. Files elsewhere, such as under assets/, can only be checked with actionlint.

BAD: Run bash scripts/validate_workflow.sh --test-only assets/valid-ci.yml and read the result as a pass.

GOOD: Use --lint-only for files outside .github/workflows/.

NEVER leave actions unpinned in production workflows

WHY: Mutable tags such as @v3 can change underneath you. The recommended practice in this skill is SHA pinning for production workflows, with the version noted in a comment.

BAD: uses: actions/checkout@v3

GOOD: uses: actions/checkout@<full-commit-sha> # v6.0.0, with the SHA taken from references/action_versions.md.

Summary

  1. Setup: Install tools with install_tools.sh
  2. Validate: Run validate_workflow.sh on workflow files
  3. Fix: Address issues using reference documentation
  4. Test: Verify locally with act (when possible)
  5. Search: Use web search to verify unknown actions
  6. Commit: Push validated workflows with confidence

References

TopicReferenceWhen to Use
actionlint error patterns with explanations and fixesCommon ErrorsDiagnosing a specific actionlint error message
Runner labels, availability, and hardware specsRunnersChoosing or validating a runs-on label
Current version table for popular actions with SHA pinsAction VersionsUpdating a deprecated or unpinned action reference
Local workflow testing with act, limitations and workaroundsact UsageRunning workflows locally before pushing
actionlint configuration and custom rule examplesactionlint UsageConfiguring actionlint or adding custom ignore rules
Modern GHA features: job summaries, environments, containersModern FeaturesValidating workflows that use newer GitHub Actions APIs
Repository

pantheon-org/tekhne

Path

skills/ci-cd/github-actions/validator/SKILL.md

Last updated
First committed

Also appears in

pantheon-ai/github-actions-toolkit
Stale

last in sync Aug 28, 2026

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.