Skip to content
Back to skills

Github Actions

ASecurity

Master GitHub Actions workflow patterns, triggers, optimization, and best practices for CI/CD pipelines.

  • 666 stars
  • 0 votes
  • 0 copies
  • 4 views
  • Added February 8, 2026
devopsbashreactnodetestingdebugginggitapici/cdperformance

Works with

  • api

Security analysis

A96/100
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro shows the line behind each finding and how to fix it

Scanned February 12, 2026

npx -y skills add majiayu000/claude-skill-registry --skill github-actions --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Github Actions?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Github Actions
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/majiayu000-github-actions/badge)](https://www.skillsdirectory.com/skills/majiayu000-github-actions)

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

Download with Pro
SKILL.md
# GitHub Actions Skill

## Purpose

Master GitHub Actions workflow patterns, triggers, optimization, and best practices for CI/CD pipelines.

## Workflow Structure

### Basic Anatomy
```yaml
name: Workflow Name          # Display name in GitHub UI

on:                          # Trigger events
  push:
    branches: [main]

permissions:                 # Required permissions (use minimal)
  contents: read
  pull-requests: write

jobs:                        # One or more jobs
  job-id:                   # Unique job identifier
    runs-on: ubuntu-latest   # Runner environment
    steps:                   # Sequential steps
      - name: Step name
        run: command
```

## Common Triggers

### Push Events
```yaml
# Push to any branch
on: push

# Push to specific branches
on:
  push:
    branches:
      - main
      - develop

# Push to branches matching pattern
on:
  push:
    branches:
      - 'releases/**'
      - 'feature/*'

# Exclude branches
on:
  push:
    branches-ignore:
      - 'docs/**'
```

### Pull Request Events
```yaml
# Any pull request
on: pull_request

# PR to specific branches
on:
  pull_request:
    branches: [main]

# PR types
on:
  pull_request:
    types: [opened, synchronize, reopened, closed]
```

### Manual and Scheduled Triggers
```yaml
# Manual trigger (workflow_dispatch)
on: workflow_dispatch

# With inputs
on:
  workflow_dispatch:
    inputs:
      environment:
        description: 'Environment to deploy to'
        required: true
        type: choice
        options:
          - dev
          - staging
          - production

# Scheduled (cron)
on:
  schedule:
    - cron: '0 0 * * *'  # Daily at midnight UTC
    - cron: '0 */6 * * *'  # Every 6 hours
```

## Optimization Patterns

### Dependency Caching
```yaml
# Automatic npm caching (recommended)
- uses: actions/setup-node@v3
  with:
    node-version: '18'
    cache: 'npm'

# Manual caching (more control)
- uses: actions/cache@v3
  with:
    path: ~/.npm
    key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
    restore-keys: |
      ${{ runner.os }}-node-
```

### Build Artifact Caching
```yaml
- name: Cache build
  uses: actions/cache@v3
  with:
    path: build/
    key: build-${{ github.sha }}

- name: Upload artifacts
  uses: actions/upload-artifact@v3
  with:
    name: build-files
    path: build/
    retention-days: 7
```

### Parallel Jobs
```yaml
jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - run: npm run lint

  test:
    runs-on: ubuntu-latest
    steps:
      - run: npm test

  build:
    runs-on: ubuntu-latest
    needs: [lint, test]  # Wait for lint and test
    steps:
      - run: npm run build
```

## Conditional Execution

### If Conditions
```yaml
# Run only on push to main
- name: Deploy
  if: github.ref == 'refs/heads/main'
  run: npm run deploy

# Run only on pull requests
- name: Preview
  if: github.event_name == 'pull_request'
  run: npm run preview

# Run only on merged PR
- name: Cleanup
  if: github.event.pull_request.merged == true
  run: ./cleanup.sh

# Complex conditions
- name: Deploy to prod
  if: |
    github.ref == 'refs/heads/main' &&
    github.event_name == 'push' &&
    !contains(github.event.head_commit.message, '[skip ci]')
  run: deploy
```

## Environment Variables and Secrets

### Using Secrets
```yaml
env:
  # Global environment variables
  NODE_VERSION: '18'
  API_KEY: ${{ secrets.API_KEY }}

jobs:
  deploy:
    steps:
      - name: Deploy with secrets
        env:
          # Step-specific environment variables
          FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}
          API_URL: ${{ secrets.API_URL }}
        run: |
          echo "Deploying..."
          firebase deploy --token $FIREBASE_TOKEN
```

### GitHub Context Variables
```yaml
# Common context variables
${{ github.repository }}     # owner/repo
${{ github.ref }}            # refs/heads/main
${{ github.sha }}            # commit SHA
${{ github.event_name }}     # push, pull_request, etc.
${{ github.actor }}          # User who triggered workflow
${{ github.run_id }}         # Unique run ID

# Pull request specific
${{ github.event.pull_request.number }}
${{ github.event.pull_request.title }}
${{ github.head_ref }}       # PR source branch
${{ github.base_ref }}       # PR target branch
```

## Matrix Builds

### Test Multiple Versions
```yaml
jobs:
  test:
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-latest, macos-latest, windows-latest]
        node-version: [16, 18, 20]
    steps:
      - uses: actions/setup-node@v3
        with:
          node-version: ${{ matrix.node-version }}
      - run: npm test
```

### Matrix with Exclusions
```yaml
strategy:
  matrix:
    os: [ubuntu-latest, windows-latest]
    node: [16, 18, 20]
    exclude:
      - os: windows-latest
        node: 16  # Skip Windows + Node 16
```

## Common Patterns

### React App CI
```yaml
name: React CI

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Setup Node
        uses: actions/setup-node@v3
        with:
          node-version: '18'
          cache: 'npm'

      - name: Install
        run: npm ci

      - name: Lint
        run: npm run lint

      - name: Test
        run: npm test -- --coverage --watchAll=false
        env:
          CI: true

      - name: Build
        run: npm run build
```

### Deployment with Approval
```yaml
jobs:
  deploy:
    runs-on: ubuntu-latest
    environment:
      name: production
      url: https://myapp.com
    steps:
      - run: npm run deploy
```

### Conditional Deployment
```yaml
jobs:
  deploy:
    if: github.ref == 'refs/heads/main' && github.event_name == 'push'
    runs-on: ubuntu-latest
    steps:
      - name: Deploy to production
        run: ./deploy.sh
```

## Performance Optimization

### Fast npm Install
```yaml
# ✅ Use npm ci (faster, more reliable)
- run: npm ci

# ❌ Don't use npm install in CI
- run: npm install  # Slower, non-deterministic
```

### Caching Strategy
```yaml
# Cache node_modules
- uses: actions/cache@v3
  with:
    path: node_modules
    key: ${{ runner.os }}-npm-${{ hashFiles('package-lock.json') }}

# Cache .npm directory (smaller, faster)
- uses: actions/cache@v3
  with:
    path: ~/.npm
    key: ${{ runner.os }}-npm-${{ hashFiles('package-lock.json') }}
```

### Skip Unnecessary Runs
```yaml
# Skip CI for docs-only changes
on:
  push:
    paths-ignore:
      - '**.md'
      - 'docs/**'

# Run only for specific paths
on:
  push:
    paths:
      - 'src/**'
      - 'package*.json'
```

## Best Practices

### ✅ Do
- Use `npm ci` not `npm install`
- Cache dependencies
- Set specific Node version
- Use latest action versions (`@v3`, `@v4`)
- Set minimal permissions
- Quote strings with special characters
- Use meaningful job and step names

### ❌ Don't
- Hardcode secrets in workflow files
- Use deprecated actions
- Skip dependency caching
- Use `npm install` in CI
- Leave complex workflows undocumented
- Ignore workflow failures

## Debugging Workflows

```bash
# View workflow runs
gh run list --workflow=workflow-name.yml

# View specific run with logs
gh run view RUN_ID --log

# Re-run failed workflow
gh run rerun RUN_ID

# Download logs
gh run download RUN_ID

# Watch workflow in real-time
gh run watch
```

## Common Issues

**Issue**: Workflow not triggering
**Solution**: Check trigger conditions, branch names, path filters

**Issue**: `npm ci` fails
**Solution**: Ensure package-lock.json is committed, check Node version

**Issue**: Secrets not available
**Solution**: Verify secret exists (`gh secret list`), check spelling

**Issue**: Slow builds
**Solution**: Enable caching, use `npm ci`, parallelize jobs

## Project Usage

Music-app workflows:
- `trunk-based-checks.yml`: PR validation, testing, build verification
- `firebase-hosting-merge.yml`: Production deployment (manual trigger)
- `firebase-hosting-pull-request.yml`: PR preview (manual trigger)

All workflows use Node 18, npm caching, and trunk-based development checks.

Attribution

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

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.