dotclaude

Skill in engineering

github-actions-pipeline

Design, write, or fix GitHub Actions workflows for a project: a CI pipeline with the right triggers, concurrency, caching, matrix, and least-privilege permissions; pinned actions; reusable workflows and composite actions; deploy workflows with environments and OIDC instead of long-lived secrets; and the debugging moves for slow, flaky, or failing runs. Use when adding CI to a repository, when a pipeline is slow or flaky, when a workflow needs deploy or release steps, or when a security review flags workflow permissions.

Arguments
(optional) the project type, what the pipeline must do, or the failing workflow

Install

As a plugin

Bundled in the engineering plugin. Add the marketplace once, then install the bundle; it updates with the marketplace.

/plugin marketplace add KhaledSaeed18/dotclaude
/plugin install engineering@dotclaude

As a single item

Run from the project root; the skill lands under .claude/. Copy it to ~/.claude/ to make it global.

npx shadcn@latest add KhaledSaeed18/dotclaude/github-actions-pipeline

Files installed

  • .claude/skills/github-actions-pipeline/SKILL.md

What it does

A pipeline is trusted when it is fast enough to run on every push, deterministic enough that a red is a real failure, and locked down enough that a compromised dependency cannot use it. Design for those three before adding steps.

A CI workflow skeleton

name: ci
on:
  pull_request:
  push:
    branches: [main]

permissions:
  contents: read            # top-level default; widen per job only

concurrency:
  group: ci-${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: ${{ github.event_name == 'pull_request' }}

jobs:
  test:
    runs-on: ubuntu-latest
    timeout-minutes: 15
    strategy:
      fail-fast: false
      matrix:
        node: [20, 22]
    steps:
      - uses: actions/checkout@v4      # pin to a SHA in security-sensitive repos
      - uses: pnpm/action-setup@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node }}
          cache: pnpm
      - run: pnpm install --frozen-lockfile
      - run: pnpm lint
      - run: pnpm typecheck
      - run: pnpm test -- --reporter=junit --outputFile=junit.xml
      - uses: actions/upload-artifact@v4
        if: always()
        with: { name: test-results-${{ matrix.node }}, path: junit.xml }

Rules

Triggers

  • pull_request for validation, push to the default branch for post-merge and deploy, workflow_dispatch for manual runs, schedule for nightly or dependency checks. Path filters (paths:) to skip irrelevant runs, remembering that a required check that is skipped blocks merging unless the branch rule allows it.
  • Never pull_request_target with a checkout of the PR head unless you understand it: it runs with write permissions on untrusted code.

Permissions

  • Top-level permissions: contents: read; each job adds only what it needs (pull-requests: write to comment, id-token: write for OIDC, packages: write to publish).
  • No long-lived cloud keys in secrets; use OIDC federation (aws-actions/configure-aws-credentials with a role, google-github-actions/auth, Azure federated credentials).
  • Secrets never printed; ::add-mask:: for derived values; no set -x in steps that touch them.

Pinning

  • Third-party actions pinned to a full commit SHA with a version comment, bumped by Dependabot (package-ecosystem: github-actions). First-party actions/* at a major tag is an acceptable compromise in low-risk repos.
  • Tool versions from the repo's own files (.nvmrc, .tool-versions, package.json engines), not hard-coded twice.

Speed

  • Cache the package manager store via the setup action's cache: input; cache build outputs (actions/cache keyed on lockfile hash plus source hash) only when the build is expensive and the cache is safe.
  • Split into jobs that run in parallel (lint, typecheck, test, build) when each takes over a minute; keep one job when they are all fast, because job startup costs 20 to 40 seconds.
  • timeout-minutes on every job so a hang fails instead of consuming the runner for six hours.
  • concurrency with cancel-in-progress on pull requests so pushes supersede stale runs.

Determinism

  • --frozen-lockfile / npm ci / pip install -r with hashes; no latest tags; pinned runner images when the OS matters (ubuntu-24.04 over ubuntu-latest for reproducibility).
  • Retries only for steps with known transient failure (network installs), via a retry action with a small count; a retried test is a flaky test to fix, not to hide.

Reuse

  • A reusable workflow (on: workflow_call) for a pipeline shared across repos; a composite action (action.yml with runs: using: composite) for a bundle of steps shared across jobs. Version them by tag.

Deploy workflows

jobs:
  deploy:
    needs: [test]
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    environment:
      name: production
      url: https://app.example.com
    permissions: { id-token: write, contents: read }
    steps:
      - uses: actions/checkout@v4
      - uses: aws-actions/configure-aws-credentials@v4
        with: { role-to-assume: arn:aws:iam::123456789012:role/gh-deploy, aws-region: eu-west-1 }
      - run: ./scripts/deploy.sh

Environments carry the protection rules (required reviewers, wait timers, branch restrictions) and the environment-scoped secrets. Deploy from an artifact built in the tested job (actions/download-artifact), not from a fresh build, so what was tested is what ships.

Releases

Tag-triggered (on: push: tags: ['v*']), build, create the release with gh release create or softprops/action-gh-release, attach artifacts, publish packages with provenance (npm publish --provenance needs id-token: write).

Debugging

  • Re-run with debug logging (ACTIONS_STEP_DEBUG secret or the "enable debug logging" checkbox) and read the raw log; gh run view <id> --log-failed gets the failing step's log locally (the fix-ci skill covers the loop).
  • Reproduce locally with the same commands and the same tool versions; act for a rough approximation of the runner.
  • For a flaky test, capture the seed and the artifact, and quarantine with a tracked issue rather than a retry.
  • Timing: the run summary shows per-step durations; the slowest step is usually dependency install without cache or a test suite that should be sharded.

Review checklist

Least-privilege permissions; no pull_request_target misuse; actions pinned; frozen installs; caching keyed correctly; timeouts; concurrency; artifacts uploaded on failure; deploy from tested artifact with an environment and OIDC; no secrets in logs.

This is the skill as installed, rendered from its source on GitHub. Read it as Markdown.

  • adversarial-reviewerReview code through three hostile personas - the Saboteur, the New Hire, and the Security Auditor - each required to find at least one issue. Use when a...
  • api-design-reviewReview an API contract (REST or GraphQL) before or while it is implemented, checking resource naming, HTTP semantics, status codes, error shape...
  • code-review-responseProcess code-review feedback with technical rigour. Understand each point, check it against the actual codebase, and respond with reasoning or...
  • create-agentAuthor a new subagent for this repository end to end by scaffolding it with pnpm new, curating its tool allowlist, setting model, color, and memory in...
  • create-commandAuthor a new slash command for this repository end to end by scaffolding it with pnpm new, writing the frontmatter and argument handling, drafting the...
  • create-hookAuthor a new Claude Code hook for this repository end to end by scaffolding it with pnpm new, writing the hook script and its settings.json wiring...