workflow-audit
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 (
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24=trueto opt in early). - Fall 2026: Node 20 removed entirely from runners.
- Temporary opt-out after June 2:
ACTIONS_ALLOW_USE_UNSECURE_NODE_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.pull_request.head.ref/.head.label/.head.repo.default_branchgithub.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. |
pull_request_target 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 (direct_prompt, model, allowed_tools, max_turns, timeout_minutes) |
high | Migrate to prompt + claude_args. |
Missing claude_code_oauth_token or anthropic_api_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. |
show_full_output: 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:
anthropic_api_key— direct Anthropic APIclaude_code_oauth_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.
More from xiaolai/vmark
tiptap-editor
Tiptap editor API patterns for vmark WYSIWYG development. Use when working with editor commands, node traversal, selection handling, or format operations.
269ai-coding-agents
Comprehensive guide for using Codex CLI (OpenAI) and Claude Code CLI (Anthropic) - AI-powered coding agents. Use when orchestrating CLI commands, automating tasks, configuring agents, or troubleshooting issues.
138tiptap-dev
Expert guidance for building rich text editors with Tiptap - a headless, framework-agnostic editor built on ProseMirror. Use when creating custom nodes, marks, or extensions for Tiptap, implementing input rules or paste rules, working with the Tiptap commands API, building React integrations with useEditor, extending existing extensions, or creating custom node views.
71tauri-app-dev
Expert guidance for building cross-platform desktop applications with Tauri 2.0 and Rust. Use when developing Tauri apps including commands and IPC, file system operations, window management, state management, system tray, menus, plugin development, security configuration (capabilities/permissions), bundling/distribution, and auto-updates. Covers patterns for editor applications requiring file dialogs, native menus, and frontend-backend communication.
67tauri-mcp-testing
E2E testing expert for Tauri applications using Tauri MCP server. Use when testing running Tauri apps - session management, webview interaction, IPC verification, screenshot capture, and debugging. ALWAYS use tauri_* tools, NEVER Chrome DevTools MCP for Tauri apps.
65rust-tauri-backend
Implement or modify VMark's Rust/Tauri backend. Use when adding Tauri commands, menu items, filesystem integration, or platform behaviors in src-tauri.
62