AI Skill Report Card

Reviewing GitHub Actions

A90·Sep 22, 2026·Source: Web
15 / 15

When reviewing a workflow file, check it in this order:

  1. Syntax & structure - valid YAML, correct top-level keys (on, jobs, steps)
  2. Triggers - on: matches intended events, no accidental broad triggers
  3. Permissions - explicit permissions: block, least privilege
  4. Secrets & security - no hardcoded secrets, safe handling of untrusted input
  5. Actions versions - pinned to SHA or trusted tag, not @master/@main
  6. Job/step logic - correct needs:, if:, matrix, working-directory
  7. Script consistency - scripts called by workflow still match invoked args/paths
Bash
# Quick local validation before deep review actionlint .github/workflows/*.yml yamllint .github/workflows/*.yml
Recommendation
Add a third example showing a clean/passing workflow to demonstrate a good outcome, not just violations
15 / 15
Progress:
- [ ] Validate YAML syntax (actionlint/yamllint)
- [ ] Check triggers (on:) for scope and safety
- [ ] Verify permissions block is least-privilege
- [ ] Audit secrets usage and untrusted-input handling
- [ ] Confirm third-party actions are pinned (SHA preferred)
- [ ] Trace job dependencies (needs, if conditions)
- [ ] Cross-check invoked scripts match current signatures/paths
- [ ] Check caching, concurrency, and timeout settings
- [ ] Confirm matrix builds cover intended combinations
- [ ] Flag redundant or dead steps

1. Syntax & structure

  • Run actionlint — catches invalid contexts, unknown keys, shellcheck issues in run: blocks.
  • Confirm indentation matches YAML spec; no tabs.

2. Triggers

  • pull_request vs pull_request_target — flag pull_request_target combined with checkout of PR head (code injection risk).
  • workflow_dispatch inputs should have type and default set.
  • Avoid on: push with no branch/path filters on large repos (wastes CI minutes).

3. Permissions

  • Repo default should be permissions: read-all or explicit per-job permissions:.
  • Flag jobs granting write-all or contents: write unless justified (e.g., release, tag push).
  • GITHUB_TOKEN scope should be minimal per job, not just workflow-level.

4. Secrets & security

  • No secret values in run: echo/print statements.
  • ${{ github.event.* }} values used directly in run: shell commands — flag as injection risk; require env var indirection:
    YAML
    # Bad run: echo "Title: ${{ github.event.issue.title }}" # Good env: TITLE: ${{ github.event.issue.title }} run: echo "Title: $TITLE"
  • Forked-PR workflows must not expose secrets to untrusted code (pull_request triggers don't get secrets by default — verify no pull_request_target misuse).

5. Action versions

  • Third-party actions (uses: owner/repo@ref) should pin to a full commit SHA, or at minimum a version tag — never @main/@master/@latest.
  • Official GitHub actions (actions/checkout, actions/setup-node) can use major version tags (@v4) but flag outdated majors.

6. Job/step logic

  • Check needs: graph has no cycles and reflects real dependencies.
  • if: conditions using always()/success()/failure() are used deliberately, not copy-pasted.
  • continue-on-error: true should be justified — flag silent failures in critical jobs.
  • timeout-minutes set on long-running jobs to avoid runaway costs.

7. Script consistency

  • When a workflow calls a script (run: ./scripts/deploy.sh $ARG1 $ARG2), verify the script's actual parameter count/order/names still match.
  • If script was refactored (renamed flags, changed exit codes), confirm workflow's error handling (if: failure(), exit code checks) still aligns.
  • Check working-directory assumptions (working-directory: or cd in script) match repo layout.
Recommendation
Include guidance on how to structure the final review output (e.g., severity levels, summary format) for consistency across reviews
18 / 20

Example 1: Input:

YAML
on: pull_request_target jobs: build: steps: - uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request.head.sha }} - run: npm install && npm test

Output:

⚠️ CRITICAL: pull_request_target checks out untrusted PR head SHA.
This exposes secrets/write-permissions to attacker-controlled code.
Fix: use `pull_request` trigger instead, or split into a trusted workflow
that only runs after manual approval/label, and never checkout untrusted
ref with elevated permissions.

Example 2: Input:

YAML
- uses: some-org/some-action@main - run: ./deploy.sh ${{ github.event.inputs.env }}

Output:

⚠️ Pin `some-org/some-action` to a commit SHA — @main is mutable and a
supply-chain risk.
⚠️ `${{ github.event.inputs.env }}` interpolated directly into shell —
route through env: block to avoid injection.
ℹ️ Verify deploy.sh still accepts a single positional `env` arg (last
refactor added a required --region flag on 2024-03-10 commit).
Recommendation
Consider adding a brief note on handling composite/reusable workflow files (workflow_call) review nuances
  • Prefer reusable workflows (workflow_call) over duplicated job logic across files.
  • Use concurrency: groups to cancel stale runs on the same ref (saves CI minutes).
  • Cache dependencies (actions/cache or built-in caching in setup actions) but scope cache keys to lockfile hash.
  • Keep run: blocks short; move complex logic into versioned scripts under scripts/ for testability.
  • Add actionlint and yamllint to a pre-commit hook or CI meta-check so review catches issues before human review.
  • When a script changes, search all workflow files for its invocation (grep -rn "script-name" .github/workflows/) to catch stale callers.
  • Trusting pull_request_target + PR-head checkout — classic secret-exfiltration vector.
  • Using @main/@master for third-party actions — untraceable supply-chain risk.
  • Workflow-level permissions: write-all "just in case."
  • Interpolating github.event.* directly into run: shell strings.
  • Forgetting to update workflow when the invoked script's CLI signature changes (silent breakage until next run).
  • Missing timeout-minutes, leading to stuck jobs consuming billable minutes indefinitely.
  • Matrix builds with unintended combinations (e.g., exclude: missing after adding a new OS/version).
0
Grade AAI Skill Framework
Scorecard
Criteria Breakdown
Quick Start
15/15
Workflow
15/15
Examples
18/20
Completeness
19/20
Format
15/15
Conciseness
14/15