Skip to main content

github-actions-advanced

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.

Jump to install

Source facts

Repository
alpertuncortak/crypto-data-pipeline
Last source activity
June 3, 2026 at 12:03
Detected SKILL.md language
English
Stars
2
Forks
0

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
github-actions-advanced
description
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.
category
devops
risk
safe
source
community
date_added
2026-05-30
# GitHub Actions Advanced Skill Expert guidance for designing, writing, debugging, and securing **production-grade** GitHub Actions workflows. --- ## 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` --- ## Step 1: Understand Context Before Responding When invoked, first gather context: ```bash # Discover existing workflows in the repo find .github/workflows -name "*.yml" -o -name "*.yaml" 2>/dev/null | head -20 # Check for composite actions find .github/actions -name "action.yml" 2>/dev/null # Detect tech stack (influences runner OS, language setup actions) ls package.json requirements.txt Gemfile go.mod Cargo.toml pom.xml 2>/dev/null ``` Then adapt recommendations to: - Existing workflow patterns in the repo - The tech stack and language runtime - Whether this is a monorepo or single-project repo - Whether self-hosted or GitHub-hosted runners are in use --- ## Workflow Structure Reference ```yaml name: Workflow Name on: # Triggers (see Triggers section) push: branches: [main] permissions: # Always declare — principle of least privilege contents: read env: # Workflow-level env vars NODE_VERSION: '20' concurrency: # Prevent duplicate runs group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true # Cancel older runs for same branch jobs: job-id: name: Human-readable name runs-on: ubuntu-24.04 # Pin OS version — never use -latest in prod timeout-minutes: 15 # Always set — prevents runaway jobs environment: production # Links to GitHub Environment (approvals/secrets) steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Step name run: echo "hello" ``` --- ## Triggers (`on:`) ### Common Patterns ```yaml on: push: branches: [main, 'release/**'] paths-ignore: ['**.md', 'docs/**'] # Skip docs-only changes pull_request: types: [opened, synchronize, reopened] branches: [main] workflow_dispatch: # Manual trigger with inputs inputs: environment: description: 'Deploy target' required: true type: choice options: [staging, production] dry-run: description: 'Dry run only?' type: boolean default: false schedule: - cron: '0 2 * * 1' # Monday 2am UTC workflow_call: # Called by other workflows (reusable) inputs: image-tag: type: string required: true secrets: deploy-token: required: true release: types: [published] # Trigger only on published releases pull_request_target: # Runs with repo secrets — use with care! types: [labeled] # Gate with label + author_association check ``` > **Security Warning:** `pull_request_target` runs with repo secrets. Only use after a maintainer labels the PR. Never check out fork code without explicit sandboxing. --- ## Reusable Workflows Split large pipelines into composable units stored in `.github/workflows/`. **Convention:** Prefix internal/reusable workflows with `_` (e.g., `_build.yml`). ### Caller (`.github/workflows/deploy.yml`) ```yaml jobs: call-build: uses: ./.github/workflows/_build.yml # Same-repo reusable # uses: org/repo/.github/workflows/build.yml@main # Cross-repo with: image-tag: ${{ github.sha }} secrets: inherit # Pass all caller secrets down call-test: uses: ./.github/workflows/_test.yml with: node-version: '20' secrets: NPM_TOKEN: ${{ secrets.NPM_TOKEN }} # Explicit secret passing ``` ### Reusable Workflow (`.github/workflows/_build.yml`) ```yaml on: workflow_call: inputs: image-tag: type: string required: true push: type: boolean default: false secrets: registry-token: required: false outputs: digest: description: "Image digest" value: ${{ jobs.build.outputs.digest }} jobs: build: runs-on: ubuntu-24.04 timeout-minutes: 20 outputs: digest: ${{ steps.build.outputs.digest }} steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - id: build uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6.9.0 with: push: ${{ inputs.push }} tags: myapp:${{ inputs.image-tag }} ``` --- ## Matrix Builds ```yaml jobs: test: strategy: fail-fast: false # Don't cancel others if one fails max-parallel: 4 # Limit concurrent runners matrix: os: [ubuntu-24.04, windows-2022, macos-14] node: ['18', '20', '22'] exclude: - os: windows-2022 node: '18' include: - os: ubuntu-24.04 node: '22' experimental: true # Custom matrix variable runs-on: ${{ matrix.os }} timeout-minutes: 20 steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 with: node-version: ${{ matrix.node }} cache: 'npm' - run: npm ci - run: npm test continue-on-error: ${{ matrix.experimental == true }} ``` ### Dynamic Matrix via Script ```yaml jobs: generate-matrix: runs-on: ubuntu-24.04 outputs: matrix: ${{ steps.set-matrix.outputs.matrix }} steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - id: set-matrix run: | SERVICES=$(ls services/ | jq -R -s -c 'split("\n")[:-1]') echo "matrix={\"service\":$SERVICES}" >> $GITHUB_OUTPUT build: needs: generate-matrix strategy: matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }} runs-on: ubuntu-24.04 steps: - run: echo "Building ${{ matrix.service }}" ``` --- ## Caching Strategies ### Language Setup Actions (Preferred — No Extra Step Needed) ```yaml # Node.js - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 with: node-version: '20' cache: 'npm' # or 'yarn' or 'pnpm' # Python - uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0 with: python-version: '3.12' cache: 'pip' # Go - uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0 with: go-version: '1.23' cache: true # Java / Gradle / Maven - uses: actions/setup-java@7a6d8a8234af8eb26422e24052f73b12b0e46a27 # v4.6.0 with: distribution: 'temurin' java-version: '21' cache: 'maven' # or 'gradle' ``` ### Manual Cache (Any Tool) ```yaml - uses: actions/cache@6849a6489940f00c2f30c0fb92c6274307ccb58a # v4.1.2 id: cache-deps with: path: | ~/.cache/pip .venv key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements*.txt') }} restore-keys: | ${{ runner.os }}-pip-${{ hashFiles('**/requirements*.txt') }} ${{ runner.os }}-pip- - name: Install deps (only on cache miss) if: steps.cache-deps.outputs.cache-hit != 'true' run: pip install -r requirements.txt ``` ### Docker Layer Caching ```yaml - uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6.9.0 with: cache-from: type=gha cache-to: type=gha,mode=max # For registry-backed cache (cross-branch): # cache-from: type=registry,ref=ghcr.io/myorg/myapp:buildcache # cache-to: type=registry,ref=ghcr.io/myorg/myapp:buildcache,mode=max ``` --- ## OIDC Authentication (Keyless Cloud Auth) **Never store long-lived cloud credentials as secrets.** Use OIDC to get short-lived tokens that expire automatically. ### AWS ```yaml permissions: id-token: write contents: read steps: - uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2 with: role-to-assume: arn:aws:iam::123456789012:role/GitHubActionsRole aws-region: us-east-1 role-session-name: GitHubActions-${{ github.run_id }} # Trust policy on the IAM role must include: # "token.actions.githubusercontent.com" as OIDC provider # Condition: "repo:org/repo:ref:refs/heads/main" (restrict to branch) ``` ### GCP (Workload Identity Federation) ```yaml permissions: id-token: write contents: read steps: - uses: google-github-actions/auth@6fc4af4b145ae7821d527454aa9bd537d1f2dc5f # v2.1.7 with: workload_identity_provider: projects/123456789/locations/global/workloadIdentityPools/github-pool/providers/github-provider service_account: github-actions@my-project.iam.gserviceaccount.com token_format: access_token # or 'id_token' ``` ### Azure (Federated Identity) ```yaml permissions: id-token: write contents: read steps: - uses: azure/login@a65d910e8af852a8061c627c456678983e180302 # v2.2.0 with: client-id: ${{ secrets.AZURE_CLIENT_ID }} tenant-id: ${{ secrets.AZURE_TENANT_ID }} subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} # No client secret needed! Uses OIDC federated credentials ``` --- ## Environments & Deployment Protection ```yaml jobs: deploy-staging: environment: name: staging url: https://staging.myapp.com runs-on: ubuntu-24.04 timeout-minutes: 30 steps: - run: ./scripts/deploy.sh staging deploy-production: needs: deploy-staging environment: name: production url: https://myapp.com # Shown in the GitHub UI deployment panel runs-on: ubuntu-24.04 timeout-minutes: 30 steps: - run: ./scripts/deploy.sh production ``` **Configure in Settings → Environments:** - **Required reviewers** — manual approval gate before run - **Wait timer** — delay after approval (e.g., 10-minute buffer) - **Branch/tag restrictions** — only `main` or `v*` tags can deploy to prod - **Environment-specific secrets** — override repo-level secrets per environment - **Deployment branches** — whitelist which branches can target this environment --- ## Secrets Management ```yaml # Access repo/org/environment secrets env: DB_PASSWORD: ${{ secrets.DB_PASSWORD }} # Auto-provided token — no setup needed - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 with: github-token: ${{ secrets.GITHUB_TOKEN }} # Hierarchy (most specific wins): # environment secret > repo secret > org secret ``` ### Masking Dynamic Values ```yaml - name: Generate and mask dynamic token run: | TOKEN=$(./scripts/generate-token.sh) echo "::add-mask::$TOKEN" # Mask in all subsequent logs echo "DEPLOY_TOKEN=$TOKEN" >> $GITHUB_ENV ``` ### Secrets in Composite Actions ```yaml # Secrets cannot be passed as inputs to composite actions # Pass them as env vars instead: - uses: ./.github/actions/my-action env: SECRET_VALUE: ${{ secrets.MY_SECRET }} ``` --- ## Composite Actions Package reusable step sequences into local actions. No container spin-up, no separate workflow file needed. ### Action Definition (`.github/actions/setup-app/action.yml`) ```yaml name: Setup App description: Install and configure application dependencies inputs: node-version: description: 'Node.js version' required: false default: '20' install-flags: description: 'Additional npm install flags' required: false default: '' outputs: cache-hit: description: 'Whether the dependency cache was hit' value: ${{ steps.cache.outputs.cache-hit }} runs: using: composite steps: - uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0 with: node-version: ${{ inputs.node-version }} cache: npm
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub