Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsBlogPro
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Authors
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges
  • Chrome Extension
  • Skill Manager

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

ProTermsPrivacyRefunds
Back to skills

Github Actions Matrix Patterns

ASecurity

Use when designing matrix builds (OS x version x dimension), composing reusable workflows, gating jobs on conditions, doing OIDC to AWS/GCP/Cloudflare without long-lived secrets, sharding tests across runners, or fixing cache invalidation. Triggers: workflow_call between repos, fail-fast: false tradeoffs, exclude/include matrix surgery, environment protection rules, OIDC trust policy setup, concurrency cancellation on duplicate pushes, artifact reuse across jobs, conditional job matrices comp...

2 stars
0 votes
0 copies
0 views
Added 9/24/2026
devopsrustgobashnodedockerawsgcpgitdevopssecurity

Security Analysis

A100/100

Pro scans all 5 files and shows the line behind each finding

Scanned 9/24/2026

$npx -y skills add curiositech/port-daddy --skill github-actions-matrix-patterns --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Github Actions Matrix Patterns?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Github Actions Matrix Patterns
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/curiositech-github-actions-matrix-patterns-port-daddy/badge)](https://www.skillsdirectory.com/skills/curiositech-github-actions-matrix-patterns-port-daddy)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
Files
SKILL.md
---
license: Apache-2.0
name: github-actions-matrix-patterns
allowed-tools: Read,Write,Edit,Bash,Glob,Grep,WebSearch,WebFetch
description: 'Use when designing matrix builds (OS x version x dimension), composing reusable workflows, gating jobs on conditions, doing OIDC to AWS/GCP/Cloudflare without long-lived secrets, sharding tests across runners, or fixing cache invalidation. Triggers: workflow_call between repos, fail-fast: false tradeoffs, exclude/include matrix surgery, environment protection rules, OIDC trust policy setup, concurrency cancellation on duplicate pushes, artifact reuse across jobs, conditional job matrices computed at runtime. NOT for GitLab CI / CircleCI / Jenkins (different yaml dialects), self-hosted runner administration, or local act dev.'
metadata:
  category: DevOps & Infrastructure
  tags:
    - github-actions
    - ci-cd
    - matrix
    - oidc
    - reusable-workflows
    - automation
  provenance:
    kind: first-party
    owners: [port-daddy]
  pairs-with:
    - skill: git-best-practices
      reason: Pinned workflow refs, tag discipline, and branch protection that release CI depends on live in the git workflow itself
    - skill: agent-pr-authoring
      reason: The PR checks these matrix workflows gate are the same checks an agent-authored PR must be written to pass
  io-contract:
    kind: deliverable
    consumes:
      - kind: ci-requirement
        format: markdown
        description: A description of what the pipeline must build/test/deploy -- target OSes, runtimes, cloud provider, and gating rules -- from a human or another agent.
      - kind: workflow-plan
        format: json
        description: A structured plan of the workflow's matrix shape, pinning policy, permissions, auth mode, and cache/concurrency settings, matching schemas/github-actions-matrix-patterns-plan.schema.json.
    produces:
      - kind: workflow-design
        format: markdown
        description: The workflow YAML plus the rationale for matrix shape, OIDC trust policy, and cache keys, following this skill's patterns.
      - kind: workflow-audit-report
        format: json
        description: A deterministic pass/fail audit of the workflow-plan against this skill's Quality Gates, as produced by scripts/github_actions_matrix_patterns_audit.mjs.
---

# GitHub Actions Matrix Patterns

Hello-world Actions are easy. Real CI gets stuck on three things: matrix expansion that runs the wrong cells, OIDC trust policies that reject your cloud auth, and cache keys that never invalidate (or invalidate on every commit). This skill catalogs those.

## When to use

- Building across OS x runtime version x dimension (e.g., ubuntu/macos/windows × Node 20/22).
- Sharing a workflow between repos via `workflow_call`.
- Authenticating to AWS/GCP/Cloudflare without storing long-lived keys.
- Sharding a slow test suite across N runners.
- Cancelling outdated CI runs when a new commit lands on the same branch.

## Core capabilities

### Basic matrix

```yaml
strategy:
  fail-fast: false
  matrix:
    os: [ubuntu-latest, macos-latest, windows-latest]
    node: [20, 22]
    include:
      - os: ubuntu-latest
        node: 22
        coverage: true        # extra dimension only on this cell
    exclude:
      - os: windows-latest
        node: 20              # known broken combination
```

`fail-fast: true` cancels the rest of the matrix on the first failure — fine for dev speed, bad for "tell me everything that's broken." Default to `false` for release CI.

### Reusable workflows (`workflow_call`)

```yaml
# .github/workflows/test.yml
on:
  workflow_call:
    inputs:
      node-version: { type: string, required: false, default: '22' }
      coverage: { type: boolean, required: false, default: false }
    secrets:
      CODECOV_TOKEN: { required: false }
    outputs:
      coverage-pct:
        value: ${{ jobs.test.outputs.coverage-pct }}

jobs:
  test:
    runs-on: ubuntu-latest
    outputs:
      coverage-pct: ${{ steps.report.outputs.pct }}
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: ${{ inputs.node-version }} }
      - run: pnpm test
      - if: inputs.coverage
        id: report
        run: echo "pct=$(node scripts/coverage-pct.js)" >> "$GITHUB_OUTPUT"
```

Caller:

```yaml
jobs:
  call-test:
    uses: ./.github/workflows/test.yml
    with: { node-version: '22', coverage: true }
    secrets: inherit
```

For cross-repo: `uses: org/repo/.github/workflows/test.yml@v1` and pin to a tag, never `@main`.

### OIDC to a cloud provider

GitHub mints a short-lived OIDC token. The cloud trusts it via a trust policy. No long-lived AWS keys in your secrets.

```yaml
permissions:
  id-token: write           # mint OIDC
  contents: read

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/github-deploy
          aws-region: us-west-2
      - run: aws s3 sync ./out s3://my-bucket/
```

AWS trust policy on `github-deploy`:

```json
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": { "Federated": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com" },
    "Action": "sts:AssumeRoleWithWebIdentity",
    "Condition": {
      "StringEquals": { "token.actions.githubusercontent.com:aud": "sts.amazonaws.com" },
      "StringLike":  { "token.actions.githubusercontent.com:sub": "repo:myorg/myrepo:ref:refs/heads/main" }
    }
  }]
}
```

The `sub` condition is the security boundary. Tighten it to `repo:org/repo:environment:production` for additional protection from a malicious PR.

### Concurrency

Cancel outdated runs when a new commit lands on a branch:

```yaml
concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true
```

For deploy jobs you don't want to cancel mid-flight, scope to PRs only:

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

### Conditional matrices

Compute a matrix at runtime when the dimensions depend on the changed files:

```yaml
jobs:
  changed:
    runs-on: ubuntu-latest
    outputs:
      packages: ${{ steps.set.outputs.packages }}
    steps:
      - uses: actions/checkout@v4
        with: { fetch-depth: 0 }
      - id: set
        run: |
          PKGS=$(git diff --name-only origin/main...HEAD | grep '^packages/' | cut -d/ -f2 | sort -u | jq -R . | jq -sc .)
          echo "packages=$PKGS" >> "$GITHUB_OUTPUT"

  test:
    needs: changed
    if: ${{ needs.changed.outputs.packages != '[]' }}
    runs-on: ubuntu-latest
    strategy:
      matrix:
        package: ${{ fromJson(needs.changed.outputs.packages) }}
    steps:
      - run: pnpm --filter @myorg/${{ matrix.package }} test
```

### Caching with stable keys

```yaml
- uses: actions/cache@v4
  with:
    path: ~/.pnpm-store
    key: pnpm-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
    restore-keys: |
      pnpm-${{ runner.os }}-
```

`key` invalidates when the lockfile changes. `restore-keys` is the partial-hit fallback — restores the latest matching prefix.

For language toolchains, prefer the setup-* actions' built-in caching (`actions/setup-node@v4 with: cache: 'pnpm'`); they handle key construction.

### Sharding tests across runners

```yaml
strategy:
  fail-fast: false
  matrix:
    shard: [1, 2, 3, 4]
steps:
  - run: pnpm test --shard=${{ matrix.shard }}/4
```

Most test runners (vitest, jest, playwright) accept `--shard=K/N`. Distribute by file count and rotate the assignment seed weekly to prevent a slow file always landing on shard 1.

### Environments + protection rules

```yaml
jobs:
  deploy-prod:
    environment: production
    runs-on: ubuntu-latest
```

`environment: production` triggers required reviewers, deployment branches policy, wait timer, and environment-scoped secrets. Use this for the production deploy step rather than baking approvals into the workflow logic.

## Anti-patterns

### Pinning to `@main` for third-party actions

**Symptom:** Workflow that worked yesterday fails today; no commits to your repo.
**Diagnosis:** Floating tag — upstream pushed a breaking change.
**Fix:** Pin to a SHA: `uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab`. Or at minimum a major tag your security team has reviewed.

### `secrets.GITHUB_TOKEN` for cross-repo writes

**Symptom:** Workflow fails to push to another repo even with `permissions: contents: write`.
**Diagnosis:** `GITHUB_TOKEN` only has scope to the current repo.
**Fix:** Use a deploy key, fine-grained PAT, or GitHub App token (preferred for orgs).

### Matrix `exclude` without `include`

**Symptom:** Matrix balloons to 30 cells; you exclude 25 of them.
**Diagnosis:** Inverting the polarity. Exclude is for trimming a small handful; include is for adding cells.
**Fix:** Build the small list explicitly with `include` only.

### Cache key that never invalidates

**Symptom:** Stale dependencies on every run; "works locally" recurring.
**Diagnosis:** Key uses only `runner.os`, no hash of the lockfile.
**Fix:** Always `hashFiles('lockfile.path')` in the key. `restore-keys` is fallback, not primary.

### OIDC `sub` claim too permissive

**Symptom:** A fork PR triggers a deploy.
**Diagnosis:** Trust policy `sub: repo:org/repo:*` matches PR refs from forks.
**Fix:** Pin to specific refs: `repo:org/repo:ref:refs/heads/main`, or use environment claims: `repo:org/repo:environment:production`.

### Implicit `permissions: write-all`

**Symptom:** A compromised action exfiltrates a token with full repo write.
**Diagnosis:** Workflow inherits the default permissions, which historically were write-all.
**Fix:** Set top-level `permissions: read-all` and grant per-job: `permissions: { contents: read, id-token: write }`.

## Quality gates

- [ ] Every third-party action pinned to a SHA or audited major version.
- [ ] Top-level `permissions: read-all`; per-job grants minimal.
- [ ] OIDC used instead of long-lived cloud secrets where the provider supports it.
- [ ] Production deploys behind `environment:` with required reviewers.
- [ ] `concurrency` set on PR workflows to cancel outdated runs.
- [ ] Cache keys include a hash of the lockfile they cover.
- [ ] `fail-fast: false` on release CI matrices.
- [ ] Test sharding seed rotated weekly so slow files don't pin a shard.
- [ ] No `secrets: inherit` to forks.

## Deterministic Audit

Before shipping (or reviewing) a workflow, write its shape as a JSON plan matching
`schemas/github-actions-matrix-patterns-plan.schema.json` and run it through the
deterministic auditor:

```bash
node scripts/github_actions_matrix_patterns_audit.mjs --input examples/sample-input.json
```

`auditGithubActionsMatrixPatterns(plan)` (in `scripts/github_actions_matrix_patterns_audit.mjs`)
turns this skill's Quality Gates into machine-checkable rules over structured fields — no
keyword matching: floating action refs, `write-all` (or inherited) permissions, long-lived
cloud secrets where OIDC works, a repo-wildcard OIDC `sub` claim (the fork-PR deploy hole),
`fail-fast` on release CI, inverted exclude polarity, cache keys with no lockfile hash,
missing PR concurrency cancellation, deploys outside an `environment:`, and secrets inherited
by fork PRs. It returns `{ pass, score, findings, recommendations }` and exits 1 on failure,
so a CI gate can reject a workflow plan without re-deriving the reasoning.
`examples/sample-input.json` is a correctly hardened OIDC deploy plan (`pass: true`, zero
findings). See `CHANGELOG.md` for the bundle's history.

## NOT for

- **GitLab CI / CircleCI / Jenkins** — different DSLs, different runners.
- **Self-hosted runner administration** — different domain (autoscaling, security hardening).
- **`act` local development** — local-only quirks not worth conflating.
- **GitHub Apps** beyond their use as token issuers — separate skill (no dedicated skill yet).
- **pnpm workspace filtering, catalogs, hoisting** — once the matrix is fine and the workspace is broken, → `pnpm-workspace-monorepo`.
- **Docker image build cache strategy from CI** — → `dockerfile-build-cache-mastery` for the Dockerfile/buildx side.

Attribution

curiositechcuriositech
View sourceSee grades on GitHubMore from curiositech →
SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Related Skills

Terraform Module Library

Build reusable Terraform modules for AWS, Azure, and GCP infrastructure following infrastructure-as-code best practices. Use when creating infrastructure modules, standardizing cloud provisioning, or implementing reusable IaC components.

401991 votes

sematext-otel

Wire a service's OpenTelemetry output to Sematext Cloud. Walks through region, App-type, instrumentation flow (managed OTLP endpoint vs Sematext Agent), and signal selection (traces/metrics/logs), then produces the exact env-var block and points at a runnable reference example in this repo. Invoke when instrumenting a new app for Sematext.

01 votes

Deployment Patterns

Deployment workflows, CI/CD pipeline patterns, Docker containerization, health checks, rollback strategies, and production readiness checklists for web applications. Use when setting up deployment infrastructure or planning releases.

2699140 votes

Babysit

Watch a pull request or review cycle until it is ready to merge. Use when asked to babysit, monitor, or keep checking PR comments, reviews, and CI until all actionable issues are resolved.

971540 votes

V7 Roster

Interact with the Paperclip control plane API for task coordination and governance. Use when checking assignments, updating issue status, posting comments, delegating work, managing routines, or calling Paperclip API endpoints.

953190 votes
View all in devops →