SKILL.md
Workflow Audit
Comprehensive audit of .github/workflows/*.yml files against GitHub Actions best practices, security hardening guidelines, and project conventions.
When to Use
- User asks to audit, review, or check workflows
- Before committing changes to any workflow file
- After a workflow failure that needs root-cause analysis
- Periodic health check (e.g., monthly)
Workflow
- Discover — Glob
.github/workflows/*.ymland list all workflow files. - Parse — Read each file; validate YAML syntax.
- Audit — Run every check in the checklist below against each file.
- Cross-check — Run cross-workflow consistency checks.
- Report — Output a findings table sorted by severity (critical > high > medium > low).
- Fix offer — For each finding, suggest a concrete fix (diff or instruction).
Audit Checklist
1. YAML Validity
- File parses as valid YAML.
- No duplicate keys at the same level.
- No tabs (GitHub Actions requires spaces).
2. Action Version Currency
Check every uses: line.
| Pattern | Severity | Rule |
|---|---|---|
actions/checkout@v4 or lower |
critical | Upgrade to @v6. Node.js 20 actions break June 2, 2026 (forced to Node 24). |
actions/setup-node@v4 or lower |
critical | Same — upgrade to @v6. |
actions/cache@v3 or lower |
high | Upgrade to @v4. |
pnpm/action-setup@v3 or lower |
high | Upgrade to @v4. |
softprops/action-gh-release@v1 |
medium | Upgrade to @v2. |
actions/upload-pages-artifact@v2 or lower |
medium | Upgrade to @v3. |
actions/deploy-pages@v3 or lower |
medium | Upgrade to @v4. |
Any @main or @master pin |
high | Pin to a tag or SHA — mutable refs are a supply-chain risk. |
Node.js deprecation timeline (reference for findings):
- June 2, 2026: Node 24 becomes default (
FORCEJAVASCRIPTACTIONSTONODE24=trueto opt in early). - Fall 2026: Node 20 removed entirely from runners.
- Temporary opt-out after June 2:
ACTIONSALLOWUSEUNSECURENODE_VERSION=true(stops working fall 2026).
3. Security — Script Injection
For every run: block, check for untrusted context expressions used inline:
# DANGEROUS — attacker-controlled input interpreted by shell
run: echo "${{ github.event.issue.title }}"
# SAFE — passed via environment variable
env:
TITLE: ${{ github.event.issue.title }}
run: echo "$TITLE"
Untrusted contexts (must NEVER appear directly in run: blocks):
github.event.issue.title/.bodygithub.event.pull_request.title/.bodygithub.event.comment.bodygithub.event.review.body/github.event.review_comment.bodygithub.event.commits.*.messagegithub.event.head_commit.message/.author.email/.author.namegithub.event.pullrequest.head.ref/.head.label/.head.repo.defaultbranchgithub.head_refgithub.event.pages.*.page_name
Safe contexts (numeric or system-controlled, OK inline):
github.event.issue.number,github.event.pull_request.numbergithub.repository,github.run_id,github.shagithub.ref(only on push/tag events, not PR)secrets.,env.,matrix.*
4. Security — Permissions
| Check | Severity | Rule |
|---|---|---|
No permissions: block at all |
high | Add explicit permissions — defaults give broad access. |
permissions: write-all |
critical | Never use. Specify individual scopes. |
| Unused permission scopes | medium | Remove permissions not needed by any step. |
id-token: write without OIDC usage |
medium | Only needed for Bedrock/Vertex/Foundry or cloud OIDC. |
pullrequesttarget trigger |
high | Grants write access from forks — verify checkout uses PR base, not head. |
5. Security — Auto-merge and Bot Patterns
| Check | Severity | Rule |
|---|---|---|
gh pr merge --auto without author guard |
high | Restrict to bot PRs: if: github.event.pull_request.user.login == 'claude[bot]' |
allowed_bots: '*' in claude-code-action |
medium | Prefer explicit bot names over wildcard. |
6. Reliability — Timeouts
| Check | Severity | Rule |
|---|---|---|
Job without timeout-minutes |
high | Default is 360 min (6 hours). Always set explicit timeouts. |
| Claude Code action jobs | high | Must have timeout-minutes (recommended: 15 for review, 30 for fix). |
| Build jobs | medium | Recommended: 30-45 min depending on platform. |
7. Reliability — Error Handling
| Check | Severity | Rule | ||
|---|---|---|---|---|
git push to a protected branch |
critical | Will fail if branch protection requires status checks. Push to unprotected branch or use PR. | ||
gh pr merge without `\ |
\ | true or continue-on-error` |
medium | May fail if PR is not mergeable — handle gracefully. |
Steps after a continue-on-error step that depend on its output |
medium | Check if downstream steps handle the soft failure. | ||
Network-dependent steps without retry or continue-on-error |
low | CDN downloads, API calls can be flaky. |
8. Reliability — Concurrency
| Check | Severity | Rule |
|---|---|---|
Scheduled workflow without concurrency group |
medium | Overlapping runs waste resources. |
cancel-in-progress: true on deploy workflows |
high | Can corrupt partial deployments. Use false for deploys. |
Missing concurrency on Claude Code jobs |
medium | Multiple concurrent AI runs on the same issue/PR waste credits. |
9. Reliability — Branch Protection Awareness
| Check | Severity | Rule |
|---|---|---|
Workflow pushes to main (or default branch) |
critical | Check if branch protection allows this. Use a data branch or PR workflow. |
Workflow creates commits without checking git diff first |
medium | May create empty commits or fail on no-changes. |
10. Cross-Workflow Consistency
| Check | Severity | Rule |
|---|---|---|
Different node-version across workflows |
high | All workflows should use the same Node.js version (currently 22). |
Different pnpm version across workflows |
high | All workflows should use the same pnpm version (currently 10). |
| Different Rust toolchain specification | medium | Should be consistent unless intentionally testing multiple versions. |
| Duplicate triggers (same event in multiple workflows) | medium | Can cause double-execution. Verify intentional. |
11. Claude Code Action — Configuration
Reference: anthropics/claude-code-action@v1
| Check | Severity | Rule |
|---|---|---|
Using @beta or @v0 |
critical | Migrate to @v1. v0.x inputs are deprecated. |
Using deprecated inputs (directprompt, model, allowedtools, maxturns, timeoutminutes) |
high | Migrate to prompt + claude_args. |
Missing claudecodeoauthtoken or anthropicapi_key |
critical | One auth method is required. |
--model not specified in claude_args |
low | Defaults to action's default model. Specify for reproducibility. |
--max-turns not specified for fix/implementation jobs |
medium | Unbounded turns burn credits. Recommend 15-25 for fixes. |
showfulloutput: true on review jobs |
low | Verbose — only needed for debugging. |
Key claude_args flags:
--model <model-id>— e.g.,claude-opus-4-6,claude-sonnet-4-6--max-turns <N>— limit conversation turns--allowedTools <tool1>,<tool2>— restrict tool access--disallowedTools <tool1>— block specific tools--system-prompt "..."— custom system prompt
Authentication options:
anthropicapikey— direct Anthropic APIclaudecodeoauth_token— Claude Code OAuth (subscription-based)use_bedrock: true+ OIDC — Amazon Bedrockuse_vertex: true+ OIDC — Google Vertex AI
12. Trigger Hygiene
| Check | Severity | Rule |
|---|---|---|
release: [published] + workflow_dispatch for same logic |
medium | Choose one trigger path to avoid double-execution. |
push: branches: [main] on workflows that also have pull_request |
low | Intentional for CI — but verify both are needed. |
| Scheduled workflow that only runs on default branch | low | Verify schedule cron syntax with crontab.guru. |
Workflow with no paths filter on push trigger |
low | Consider adding paths: to avoid unnecessary runs. |
Report Format
Output a markdown table:
## Workflow Audit Report
| # | Severity | File | Check | Finding | Fix |
|---|----------|------|-------|---------|-----|
| 1 | critical | ci.yml | Action versions | `actions/checkout@v4` — Node 20 deprecated | Upgrade to `@v6` |
| 2 | high | claude.yml | Auto-merge | Enabled for all PRs | Add `if: github.event.pull_request.user.login == 'claude[bot]'` |
After the table, add a Summary line: X critical, Y high, Z medium, W low findings across N workflow files.
Notes
- Do NOT modify workflow files during audit — report only.
- When the user asks to fix findings, apply changes and re-audit to verify.
- For security findings, always explain the attack vector (not just the rule).
- Check
.github/workflows/only — ignore.github/actions/unless referenced.