GitHub Actions Advanced Skill
Expert guidance for designing, writing, debugging, and securing production-grade GitHub Actions workflows.
Detailed Guide
Read the detailed guide before executing this skill. It retains the complete procedure and reference material. Treat its safety, prerequisites, and validation requirements as mandatory. For focused work, load the relevant sections; for end-to-end work, read the guide completely.
When to Use This Skill
- User mentions GitHub Actions,
.github/workflows, CI/CD pipelines, runners, jobs, steps, or actions
- User wants to automate builds, tests, deployments, or releases via GitHub
- User asks about matrix builds, reusable workflows, composite actions, or self-hosted runners
- User needs help with OIDC authentication, caching strategies, or secrets management
- User says "my GitHub pipeline is failing" or "set up CI for my repo"
- User asks about workflow security, hardening, or environment protection rules
When NOT to Use This Skill
- The user is working with GitLab CI/CD → recommend
gitlab-ci-patterns
- The user is working with CircleCI, Jenkins, or other CI platforms
- The task is purely about Docker image building without GitHub context → recommend
docker-expert
- The task is about Kubernetes deployment configuration → recommend
kubernetes-architect
Security Hardening
1. Always Declare Permissions (Least Privilege)
# Workflow-level default — restrict everything
permissions:
contents: read
jobs:
publish:
# Job-level override — only expand what's needed
permissions:
contents: write # Only for release/publish jobs
packages: write # Only for container push jobs
pull-requests: write # Only for PR comment jobs
id-token: write # Only for OIDC auth jobs
2. Pin Third-Party Actions to Full Commit SHA
# ❌ UNSAFE — tag can be mutated or hijacked
- uses: actions/checkout@v4
# ✅ SAFE — commit SHA is immutable
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
# Tool to automate SHA pinning:
# npx pin-github-action .github/workflows/*.yml
# or: pip install ratchet && ratchet pin .github/workflows/
3. Prevent Script Injection
# ❌ UNSAFE — attacker controls PR title, which gets expanded in shell
- run: echo "${{ github.event.pull_request.title }}"
# ✅ SAFE — pass through environment variable (shell doesn't evaluate it)
- env:
PR_TITLE: ${{ github.event.pull_request.title }}
run: echo "$PR_TITLE"
# ✅ SAFE — expressions in if: conditions are evaluated by Actions, not shell
- if: github.event.pull_request.draft == false
run: echo "Not a draft"
Never place ${{ ... }} directly inside run: when the value can come from
PR metadata, workflow inputs, repository files, matrix JSON, or earlier job
outputs. Put it in env: first, validate allowlisted values where possible, and
reference the shell variable with quotes.
4. Restrict pull_request_target Usage
# Only run when a maintainer adds a specific label — prevents untrusted execution
on:
pull_request_target:
types: [labeled]
jobs:
validate:
# Double-guard: check label name AND author_association
if: |
github.event.label.name == 'safe-to-test' &&
(github.event.pull_request.author_association == 'COLLABORATOR' ||
github.event.pull_request.author_association == 'MEMBER' ||
github.event.pull_request.author_association == 'OWNER')
5. Harden with StepSecurity
# Add to every workflow — hardens runner, monitors outbound traffic
- uses: step-security/harden-runner@4d991eb9995541a0b71d1b66f1f98a5f1bef422c # v2.11.0
with:
egress-policy: audit # Start with 'audit', move to 'block' after confirming allowlist
allowed-endpoints: >
api.github.com:443
registry.npmjs.org:443
objects.githubusercontent.com:443
Limitations
- Use this skill only when the task clearly matches the scope described above.
- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.
- Always test reusable workflows in a feature branch before merging to main.
- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.
1---2name: github-actions-advanced3description: Design, debug, and harden GitHub Actions CI/CD workflows, including reusable workflows, matrix builds, self-hosted runners, OIDC authentication, caching, environments, secrets, and release automation.4---567# GitHub Actions Advanced Skill89Expert guidance for designing, writing, debugging, and securing **production-grade** GitHub Actions workflows.1011---1213## Detailed Guide1415Read [the detailed guide](references/detailed-guide.md) before executing this skill. It retains the complete procedure and reference material. Treat its safety, prerequisites, and validation requirements as mandatory. For focused work, load the relevant sections; for end-to-end work, read the guide completely.1617## When to Use This Skill1819- User mentions GitHub Actions, `.github/workflows`, CI/CD pipelines, runners, jobs, steps, or actions20- User wants to automate builds, tests, deployments, or releases via GitHub21- User asks about matrix builds, reusable workflows, composite actions, or self-hosted runners22- User needs help with OIDC authentication, caching strategies, or secrets management23- User says "my GitHub pipeline is failing" or "set up CI for my repo"24- User asks about workflow security, hardening, or environment protection rules2526## When NOT to Use This Skill2728- The user is working with GitLab CI/CD → recommend `gitlab-ci-patterns`29- The user is working with CircleCI, Jenkins, or other CI platforms30- The task is purely about Docker image building without GitHub context → recommend `docker-expert`31- The task is about Kubernetes deployment configuration → recommend `kubernetes-architect`3233---3435## Security Hardening3637### 1. Always Declare Permissions (Least Privilege)3839```yaml40# Workflow-level default — restrict everything41permissions:42 contents: read4344jobs:45 publish:46 # Job-level override — only expand what's needed47 permissions:48 contents: write # Only for release/publish jobs49 packages: write # Only for container push jobs50 pull-requests: write # Only for PR comment jobs51 id-token: write # Only for OIDC auth jobs52```5354### 2. Pin Third-Party Actions to Full Commit SHA5556```yaml57# ❌ UNSAFE — tag can be mutated or hijacked58- uses: actions/checkout@v45960# ✅ SAFE — commit SHA is immutable61- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.26263# Tool to automate SHA pinning:64# npx pin-github-action .github/workflows/*.yml65# or: pip install ratchet && ratchet pin .github/workflows/66```6768### 3. Prevent Script Injection6970```yaml71# ❌ UNSAFE — attacker controls PR title, which gets expanded in shell72- run: echo "${{ github.event.pull_request.title }}"7374# ✅ SAFE — pass through environment variable (shell doesn't evaluate it)75- env:76 PR_TITLE: ${{ github.event.pull_request.title }}77 run: echo "$PR_TITLE"7879# ✅ SAFE — expressions in if: conditions are evaluated by Actions, not shell80- if: github.event.pull_request.draft == false81 run: echo "Not a draft"82```8384Never place `${{ ... }}` directly inside `run:` when the value can come from85PR metadata, workflow inputs, repository files, matrix JSON, or earlier job86outputs. Put it in `env:` first, validate allowlisted values where possible, and87reference the shell variable with quotes.8889### 4. Restrict `pull_request_target` Usage9091```yaml92# Only run when a maintainer adds a specific label — prevents untrusted execution93on:94 pull_request_target:95 types: [labeled]9697jobs:98 validate:99 # Double-guard: check label name AND author_association100 if: |101 github.event.label.name == 'safe-to-test' &&102 (github.event.pull_request.author_association == 'COLLABORATOR' ||103 github.event.pull_request.author_association == 'MEMBER' ||104 github.event.pull_request.author_association == 'OWNER')105```106107### 5. Harden with StepSecurity108109```yaml110# Add to every workflow — hardens runner, monitors outbound traffic111- uses: step-security/harden-runner@4d991eb9995541a0b71d1b66f1f98a5f1bef422c # v2.11.0112 with:113 egress-policy: audit # Start with 'audit', move to 'block' after confirming allowlist114 allowed-endpoints: >115 api.github.com:443116 registry.npmjs.org:443117 objects.githubusercontent.com:443118```119120---121122## Limitations123124- Use this skill only when the task clearly matches the scope described above.125- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.126- Always test reusable workflows in a feature branch before merging to main.127- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.