GitHub Actions CI/CD Engineering Standards

SkillDocs & knowledge

Master GitHub Actions CI/CD workflows with production-grade security and performance patterns. Use ONLY when explicitly setting up CI/CD pipelines specifically via GitHub Actions, setting up matrix strategies, caching dependencies, managing artifacts, or implementing reusable workflows. For deployment requests, use ONLY when the deploy step is inside a .github/workflows file. NOT for GitLab or autonomous-dev. NOT for Render, AWS, Azure, or GCP deployments unless explicitly triggered from within a CI/CD workflow context. Do NOT trigger for generic "deploy my app" requests without clarifying the target platform.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the GitHub Actions CI/CD Engineering Standards skill

What this skill tells your AI

The instructions your AI receives, as published by neverinfamous/memory-journal-mcp in skills/github-actions/SKILL.md and read by ahel’s review.

This skill codifies 2026 GitHub Actions best practices — secure supply chains, efficient caching, reusable workflows, and hardened permission models.

1. Security: SHA Pinning (Mandatory)

Pin Every Third-Party Action to a Commit SHA

# ✅ Good: SHA-pinned (immutable, auditable)
- uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.2.2
- uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde8c81c89c3166c0 # v4.2.0

# ❌ Bad: Tag-pinned (mutable, vulnerable to supply chain attacks)
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
  • ALWAYS pin to full-length commit SHAs — tags are mutable and can be hijacked
  • ALWAYS add a trailing comment with the version for human readability
  • Use tools like step-security/harden-runner or pin-github-action CLI to automate SHA resolution
  • Resolve SHA Manually: See templates.md for the gh api command to resolve SHAs.
  • Audit quarterly — review all pinned SHAs when updating workflow dependencies

Permission Hardening

# Set restrictive defaults at the workflow level
permissions:
  contents: read

jobs:
  build:
    runs-on: ubuntu-latest
    # Grant specific permissions per-job
    permissions:
      contents: read
      packages: write
  • ALWAYS set permissions: at the workflow level — use read-all or specify individually
  • NEVER use permissions: write-all — it grants maximum privileges
  • Grant write only where needed — per-job, not per-workflow

2. Workflow Structure

Standard CI Template

See templates.md for a complete, production-ready CI workflow template.

Key Structural Rules

  • ALWAYS set concurrency with cancel-in-progress: true to prevent stale runs
  • Use needs: to create a dependency chain: lint → test → build → deploy
  • Use .node-version or .python-version files — never hardcode versions in workflows
  • Use --frozen-lockfile — never let CI modify the lock file

3. Caching

Package Manager Caching

# Node.js (pnpm)
- uses: actions/setup-node@<sha>
  with:
    node-version-file: .node-version
    cache: pnpm

# Python (uv)
- uses: actions/setup-python@<sha>
  with:
    python-version-file: .python-version
- run: pip install uv
- uses: actions/cache@<sha>
  with:
    path: ~/.cache/uv
    key: uv-${{ runner.os }}-${{ hashFiles('uv.lock') }}
    restore-keys: uv-${{ runner.os }}-

# Go
- uses: actions/setup-go@<sha>
  with:
    go-version-file: go.mod
    cache: true

Custom Caching Rules

  • Key on lock file hash${{ hashFiles('pnpm-lock.yaml') }}
  • Use restore-keys for fallback to partial cache hits
  • Cache the package manager's global cache, not node_modules directly
  • Don't cache everything — simplicity trumps marginal speedup

4. Matrix Strategy

Basic Matrix

jobs:
  test:
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-latest, macos-latest, windows-latest]
        node: [20, 22]
        exclude:
          - os: windows-latest
            node: 20
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/setup-node@<sha>
        with:
          node-version: ${{ matrix.node }}

Dynamic Matrix

jobs:
  prepare:
    runs-on: ubuntu-latest
    outputs:
      matrix: ${{ steps.set.outputs.matrix }}
    steps:
      - id: set
        run: |
          echo 'matrix={"include":[{"project":"api"},{"project":"web"}]}' >> "$GITHUB_OUTPUT"

  build:
    needs: prepare
    strategy:
      matrix: ${{ fromJSON(needs.prepare.outputs.matrix) }}
    runs-on: ubuntu-latest
    steps:
      - run: echo "Building ${{ matrix.project }}"

Rules

  • Use fail-fast: false for test matrices — you want to see all failures, not just the first
  • Use include/exclude to fine-tune — don't generate invalid combinations
  • Use max-parallel if jobs contend for shared resources (APIs, databases)

5. Reusable Workflows

Defining a Reusable Workflow

# .github/workflows/reusable-build.yml
name: Reusable Build

on:
  workflow_call:
    inputs:
      node-version:
        type: string
        default: '22'
    secrets:
      NPM_TOKEN:
        required: true

permissions:
  contents: read

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@<sha>
      - uses: actions/setup-node@<sha>
        with:
          node-version: ${{ inputs.node-version }}
          registry-url: https://registry.npmjs.org
      - run: pnpm install --frozen-lockfile
      - run: pnpm build
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

Calling a Reusable Workflow

jobs:
  build:
    uses: ./.github/workflows/reusable-build.yml
    with:
      node-version: '22'
    secrets:
      NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

Rules

  • Pass secrets explicitly — avoid secrets: inherit (grants broader access than needed)
  • Pin reusable workflows to SHA or tag in production
  • Use workflow_call inputs for all configuration — don't rely on env or file conventions
  • Separate concerns: reusable workflows = entire jobs; composite actions = reusable steps

6. Artifacts (v4)

# Upload
- uses: actions/upload-artifact@<sha> # v4
  with:
    name: build-output
    path: dist/
    retention-days: 7
    compression-level: 6

# Download (in a different job)
- uses: actions/download-artifact@<sha> # v4
  with:
    name: build-output
    path: dist/

Rules

  • v4 artifacts are immutable — you cannot overwrite the same artifact name
  • Use unique names per job — don't upload from parallel matrix jobs to the same name
  • Set retention-days — don't rely on org defaults (storage costs add up)
  • Use compression-level: 0 for already-compressed files (.zip, .tar.gz)
  • v3 and v4 are incompatible — do not mix upload-artifact@v3 with download-artifact@v4

7. Environment Protection

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment:
      name: production
      url: https://myapp.example.com
    steps:
      - run: echo "Deploying to production"
  • Use environment: for production deployments — enables approval gates
  • Configure required reviewers in repo Settings → Environments
  • Use environment-scoped secrets — production secrets should not be accessible in CI

8. Anti-Patterns (Never Do These)

Anti-PatternWhy It's WrongDo This Instead
uses: action@v4Mutable tag, supply chain riskPin to full commit SHA
permissions: write-allMaximum privilege, dangerousExplicit per-job permissions
continue-on-error: true on security stepsSuppresses critical failuresHard-fail on security gates
secrets: inheritOver-broad secret accessPass secrets explicitly
Hardcoded node-version: 22Version drift across workflowsUse .node-version file
No concurrency:Stale runs waste minutesAlways set with cancel-in-progress
if: always() on non-cleanup stepsRuns even after critical failuresUse if: success() (default)
Caching node_modules directlyFragile, platform-specificCache package manager global cache

Signals

GitHub stars
20
Forks
5
Last commit
Jul 2026

ahel review

  • S4info
    community integration — published by neverinfamous, not github

Automated review, not a security audit. Ruleset v1.

Advanced
Catalog kind
skill
Gateway key
github-actions-neverinfamous
Source
github.com/neverinfamous/memory-journal-mcp