devops-skills-plugin/skills/github-actions-validator/SKILL.md
Validate, lint, audit, fix GitHub Actions workflows (.github/workflows).
npx skillsauth add akin-ozer/cc-devops-skills github-actions-validatorInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
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.
Use this skill when the request includes phrases like:
.github/workflows/*.yml file"Use this skill when:
.github/workflows/*.yml for syntax errors and best practicesact before pushing to GitHubEvery validation run should follow these steps in order.
Run commands from the repository root that contains .github/workflows/.
SKILL_DIR="devops-skills-plugin/skills/github-actions-validator"
bash "$SKILL_DIR/scripts/validate_workflow.sh" <workflow-file-or-directory>
For each actionlint/act error, consult the mapping table below, then extract the matching fix pattern.
For each issue:
references/ (prefer <=8 lines).If an error does not match any mapping:
UNMAPPED.references/common_errors.md general sections first.provisional until post-fix rerun passes.For each uses: owner/action@version:
references/action_versions.md.Offline mode behavior:
references/action_versions.md only.UNVERIFIED-OFFLINE.After applying fixes, rerun validation before finalizing:
SKILL_DIR="devops-skills-plugin/skills/github-actions-validator"
bash "$SKILL_DIR/scripts/validate_workflow.sh" <workflow-file-or-directory>
Final output should include:
UNMAPPED or UNVERIFIED-OFFLINE items| Error Pattern in Output | Reference File to Read | Section to Quote |
|------------------------|----------------------|------------------|
| runs-on:, runner, ubuntu, macos, windows | references/runners.md | Runner labels |
| cron, schedule | references/common_errors.md | Schedule Errors |
| ${{, expression, if: | references/common_errors.md | Expression Errors |
| needs:, job, dependency | references/common_errors.md | Job Configuration Errors |
| uses:, action, input | references/common_errors.md | Action Errors |
| untrusted, injection, security | references/common_errors.md | Script Injection section |
| syntax, yaml, unexpected | references/common_errors.md | Syntax Errors |
| docker, container | references/act_usage.md | Troubleshooting |
| @v3, @v4, deprecated, outdated | references/action_versions.md | Version table |
| workflow_call, reusable, oidc | references/modern_features.md | Relevant section |
| glob, path, paths:, pattern | references/common_errors.md | Path Filter Errors |
User's workflow has this error:
runs-on: ubuntu-lastest
Step 1 - Script output:
label "ubuntu-lastest" is unknown
Step 2 - Read references/runners.md or references/common_errors.md:
Find the "Invalid Runner Label" section.
Step 3 - Quote the fix to user:
Error:
label "ubuntu-lastest" is unknownCause: Typo in runner label (from
references/common_errors.md):# Bad runs-on: ubuntu-lastest # TypoFix (from
references/common_errors.md):# Good runs-on: ubuntu-latestValid runner labels (from
references/runners.md):
ubuntu-latest,ubuntu-24.04,ubuntu-22.04windows-latest,windows-2025,windows-2022macos-latest,macos-15,macos-14
Step 4 - Provide corrected code:
runs-on: ubuntu-latest
Set once per shell session:
SKILL_DIR="devops-skills-plugin/skills/github-actions-validator"
bash "$SKILL_DIR/scripts/install_tools.sh"
This installs act (local workflow execution) and actionlint (static analysis) to scripts/.tools/.
# Validate a single workflow
bash "$SKILL_DIR/scripts/validate_workflow.sh" .github/workflows/ci.yml
# Validate all workflows
bash "$SKILL_DIR/scripts/validate_workflow.sh" .github/workflows/
# Lint-only (fastest)
bash "$SKILL_DIR/scripts/validate_workflow.sh" --lint-only .github/workflows/ci.yml
# Test-only with act (requires Docker)
bash "$SKILL_DIR/scripts/validate_workflow.sh" --test-only .github/workflows/
Start with static analysis to catch syntax errors and common issues:
bash "$SKILL_DIR/scripts/validate_workflow.sh" --lint-only .github/workflows/ci.yml
What actionlint checks: YAML syntax, schema compliance, expression syntax, runner labels, action inputs/outputs, job dependencies, CRON syntax, glob patterns, shell scripts, security vulnerabilities.
After passing static analysis, test workflow execution:
bash "$SKILL_DIR/scripts/validate_workflow.sh" --test-only .github/workflows/
Note: act has limitations - see references/act_usage.md.
bash "$SKILL_DIR/scripts/validate_workflow.sh" .github/workflows/ci.yml
Default behavior if tools/runtime are unavailable:
act is missing, full validation falls back to actionlint-only.--check-versions works in offline/local mode using references/action_versions.md.# Single workflow
bash "$SKILL_DIR/scripts/validate_workflow.sh" .github/workflows/ci.yml
# All workflows
bash "$SKILL_DIR/scripts/validate_workflow.sh" .github/workflows/
Key validation points: triggers, job configurations, runner labels, environment variables, secrets, conditionals, matrix strategies.
Create a test workflow that uses the custom action, then validate:
bash "$SKILL_DIR/scripts/validate_workflow.sh" .github/workflows/test-custom-action.yml
When workflows use public actions (e.g., actions/checkout@v6):
references/action_versions.md firstIf offline:
UNVERIFIED-OFFLINESearch format: "[action-name] [version] github action documentation"
| Situation | Reference File | Action |
|-----------|---------------|--------|
| actionlint reports any mapped error | references/common_errors.md | Find matching error and apply minimal quote policy |
| actionlint reports unmapped error | references/common_errors.md + official docs | Label as UNMAPPED, capture exact output and verify by rerun |
| act fails with Docker/runtime error | references/act_usage.md | Check Troubleshooting section |
| act fails but workflow works on GitHub | references/act_usage.md | Read Limitations section |
| User asks about actionlint config | references/actionlint_usage.md | Provide examples |
| User asks about act options | references/act_usage.md | Read Advanced Options |
| Security vulnerability detected | references/common_errors.md | Quote minimal safe fix snippet |
| Validating action versions | references/action_versions.md | Check version table and offline note |
| Using modern features | references/modern_features.md | Check syntax examples |
| Runner questions/errors | references/runners.md | Check labels and availability |
| Output Pattern | Reference File |
|----------------|----------------|
| [syntax-check], parse, YAML errors | common_errors.md - Syntax Errors |
| [expression], ${{, condition parsing | common_errors.md - Expression Errors |
| [action], uses:, input/output mismatch | common_errors.md - Action Errors |
| [events] with CRON/schedule text | common_errors.md - Schedule Errors |
| potentially untrusted, injection warnings | common_errors.md - Security section |
| [runner-label] or unknown runs-on label | runners.md |
| [job-needs] dependency errors | common_errors.md - Job Configuration Errors |
| [glob], paths, pattern errors | common_errors.md - Path Filter Errors |
| Docker/pull/image errors from act | act_usage.md - Troubleshooting |
| No pattern match | common_errors.md + official docs (label UNMAPPED) |
| File | Content |
|------|---------|
| references/act_usage.md | Act tool usage, commands, options, limitations, troubleshooting |
| references/actionlint_usage.md | Actionlint validation categories, configuration, integration |
| references/common_errors.md | Common errors catalog with fixes |
| references/action_versions.md | Current action versions, deprecation timeline, SHA pinning |
| references/modern_features.md | Reusable workflows, SBOM, OIDC, environments, containers |
| references/runners.md | GitHub-hosted runners (ARM64, GPU, M2 Pro, deprecations) |
| Issue | Solution |
|-------|----------|
| "Tools not found" | Run bash "$SKILL_DIR/scripts/install_tools.sh" |
| "Docker daemon not running" | Start Docker or use --lint-only |
| "Permission denied" | Run chmod +x "$SKILL_DIR"/scripts/*.sh |
| act fails but GitHub works | See references/act_usage.md Limitations |
actionlint -verbose .github/workflows/ci.yml # Verbose actionlint
act -v # Verbose act
act -n # Dry-run (no execution)
@v6 not @main for stability; SHA pinning for securityreferences/action_versions.md.github/workflows/ directory; files outside (like examples/) can only be validated with actionlintSKILL_DIR="devops-skills-plugin/skills/github-actions-validator"
bash "$SKILL_DIR/scripts/validate_workflow.sh" .github/workflows/
git add .github/workflows/ && git commit -m "Update workflows"
bash "$SKILL_DIR/scripts/validate_workflow.sh" --lint-only .github/workflows/failing.yml
# Fix issues
bash "$SKILL_DIR/scripts/validate_workflow.sh" .github/workflows/failing.yml
This example demonstrates the full assistant workflow for handling multiple errors.
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"
bash "$SKILL_DIR/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
Error 1: Invalid CRON Expression
From references/common_errors.md - Schedule Errors:
Cause: Day of week 8 doesn't exist (valid: 0-6, where 0 = Sunday)
# Bad schedule: - cron: '0 0 * * 8' # Day 8 doesn't exist # Good schedule: - cron: '0 0 * * 0' # SundayCRON format:
minute hour day month weekday
- Weekday: 0-6 (0 = Sunday)
Fix: Change 8 to 0 (Sunday) or 1-6 for Monday-Saturday.
Error 2: Invalid Runner Label
From references/common_errors.md - Job Configuration Errors and references/runners.md:
Cause: Typo in runner label
# Bad runs-on: ubuntu-lastest # Typo # Good runs-on: ubuntu-latestValid labels (from
references/runners.md):
ubuntu-latest(Ubuntu 24.04)ubuntu-24.04,ubuntu-22.04macos-latest(macOS 15)windows-latest(Windows Server 2022)
Fix: Change ubuntu-lastest to ubuntu-latest.
Error 3: Outdated Action Version
From references/action_versions.md:
| Action | Current Version | Minimum Supported | |--------|----------------|-------------------| |
actions/checkout| v6 | v4 |SHA Pinning Best Practice:
# Recommended: SHA pinning with version comment - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
Fix: Update from @v3 to @v6 (or SHA-pinned version).
Error 4: Security Vulnerability (Script Injection)
From references/common_errors.md - Expression Errors:
Warning: Potential script injection via untrusted input
# Bad - vulnerable to injection run: echo ${{ github.event.issue.title }} # Good - use environment variables env: TITLE: ${{ github.event.issue.title }} run: echo "$TITLE"Why: Untrusted input (issue titles, PR bodies, commit messages) can contain malicious commands. Using environment variables sanitizes the input.
Fix: Pass untrusted input through environment variable.
Error 5: Undefined Job Dependency
From references/common_errors.md - Job Configuration Errors:
Error: Job 'deploy' depends on job 'biuld' which does not exist
# Bad jobs: build: runs-on: ubuntu-latest deploy: needs: biuld # Typo # Good jobs: build: runs-on: ubuntu-latest deploy: needs: build
Fix: Change biuld to build.
name: Fixed CI
on:
schedule:
- cron: '0 0 * * 0' # Fixed: Sunday (0-6 valid)
jobs:
build:
runs-on: ubuntu-latest # Fixed: typo corrected
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - Fixed: updated version
- name: Process issue
env:
TITLE: ${{ github.event.issue.title }} # Fixed: use env var
run: echo "$TITLE"
deploy:
needs: build # Fixed: typo corrected
runs-on: ubuntu-latest
steps:
- run: echo "Deploying"
bash "$SKILL_DIR/scripts/validate_workflow.sh" --lint-only workflow.yml
Expected rerun result:
| Error | Type | Fix Applied |
|-------|------|-------------|
| CRON 0 0 * * 8 | Schedule | Changed to 0 0 * * 0 |
| ubuntu-lastest | Runner | Changed to ubuntu-latest |
| checkout@v3 | Outdated Action | Updated to @v6.0.0 (SHA-pinned) |
| Direct ${{ }} in run | Security | Wrapped in environment variable |
| needs: biuld | Job Dependency | Changed to needs: build |
Recommendations:
bash "$SKILL_DIR/scripts/validate_workflow.sh" --check-versions regularlyValidation work is complete when all are true:
UNMAPPED with exact output captured.UNVERIFIED-OFFLINE.install_tools.shvalidate_workflow.sh on workflow filesFor detailed information, consult the appropriate reference file in references/.
development
Validate, lint, audit, or check Terragrunt .hcl/terragrunt.hcl files, stacks, modules, compliance.
data-ai
Generate/create/scaffold Terragrunt HCL files — root.hcl, terragrunt.hcl, child modules, stacks, multi-env layouts.
development
Validate, lint, audit, or plan Terraform/.tf/HCL files; runs tflint, checkov, terraform validate.
devops
Create, generate, write, or scaffold Terraform .tf HCL — resources, modules, providers, variables, outputs.