Skip to content
Back to skills

Github Actions Skill

ASecurity

This skill helps write and modify GitHub Actions workflows and custom actions.

  • 43 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added May 30, 2026
developmentpythonrustgojavarubyswiftshellbashnodeexpress

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 May 30, 2026

npx -y skills add ComeOnOliver/skillshub --skill github-actions-skill --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Github Actions Skill?

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

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

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

This skill helps write and modify GitHub Actions workflows and custom actions.

## Workflow Basics

Workflows are YAML files stored in `.github/workflows/`. They define automated processes triggered by events.

### Minimal Workflow Structure

```yaml
name: CI                          # Optional: Display name
on: push                          # Trigger event(s)
jobs:
  build:                          # Job ID (must be unique)
    runs-on: ubuntu-latest        # Runner environment
    steps:
      - uses: actions/checkout@v5 # Use an action
      - run: echo "Hello"         # Run a command
```

## Triggers (on:)

### Common Events

```yaml
on: push                              # Any push
on: [push, pull_request]              # Multiple events
on:
  push:
    branches: [main, 'releases/**']   # Branch filter
    paths: ['src/**']                 # Path filter
  pull_request:
    types: [opened, synchronize]      # Activity types
  workflow_dispatch:                  # Manual trigger
    inputs:
      environment:
        description: 'Deploy target'
        required: true
        type: choice
        options: [dev, staging, prod]
  schedule:
    - cron: '0 0 * * *'               # Daily at midnight UTC
```

### Key Events Reference

| Event | Use Case |
|-------|----------|
| `push` | Commits pushed to branches/tags |
| `pull_request` | PR opened, updated, closed |
| `pull_request_target` | PR from fork (runs in base context) |
| `workflow_dispatch` | Manual trigger with inputs |
| `workflow_call` | Reusable workflow |
| `schedule` | Cron-based scheduling |
| `release` | Release published/created |
| `workflow_run` | After another workflow completes |

## Jobs

### Job Dependencies and Outputs

```yaml
jobs:
  build:
    runs-on: ubuntu-latest
    outputs:
      version: ${{ steps.version.outputs.value }}
    steps:
      - id: version
        run: echo "value=1.0.0" >> "$GITHUB_OUTPUT"

  deploy:
    needs: build                      # Depends on build job
    runs-on: ubuntu-latest
    steps:
      - run: echo "Deploying ${{ needs.build.outputs.version }}"
```

### Job Conditions

```yaml
jobs:
  deploy:
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
```

### Matrix Strategy

```yaml
jobs:
  test:
    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest]
        node: [18, 20]
        exclude:
          - os: windows-latest
            node: 18
        include:
          - os: ubuntu-latest
            node: 20
            coverage: true
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node }}
```

## Steps

### Using Actions

```yaml
steps:
  - uses: actions/checkout@v5           # Public action (owner/repo@ref)
  - uses: actions/checkout@8f4b7f84...  # Pin to commit SHA (most secure)
  - uses: ./.github/actions/my-action   # Local action
  - uses: docker://alpine:3.8           # Docker image
```

### Running Commands

```yaml
steps:
  - run: npm install
  - run: |
      echo "Multi-line"
      echo "commands"
    shell: bash
    working-directory: ./app
```

### Step Conditions

```yaml
steps:
  - run: echo "Always runs"
    if: always()

  - run: echo "On failure"
    if: failure()

  - run: echo "Main branch only"
    if: github.ref == 'refs/heads/main'

  - run: echo "Not cancelled"
    if: ${{ !cancelled() }}
```

## Expressions and Contexts

### Expression Syntax

Use `${{ expression }}` to evaluate expressions. In `if:` conditions, `${{ }}` is optional.

### Common Contexts

| Context | Description |
|---------|-------------|
| `github.*` | Workflow run info (ref, sha, actor, repository) |
| `env.*` | Environment variables |
| `vars.*` | Repository/org variables |
| `secrets.*` | Secrets |
| `steps.<id>.outputs.*` | Step outputs |
| `needs.<job>.outputs.*` | Job outputs |
| `matrix.*` | Matrix values |
| `runner.*` | Runner info (os, arch) |

### Useful Expressions

```yaml
# Context access
${{ github.event_name }}
${{ github.ref_name }}
${{ github.sha }}
${{ github.actor }}

# Conditionals
${{ github.ref == 'refs/heads/main' }}
${{ contains(github.event.head_commit.message, '[skip ci]') }}
${{ startsWith(github.ref, 'refs/tags/') }}

# Default values
${{ github.head_ref || github.run_id }}

# JSON manipulation
${{ toJSON(github.event) }}
${{ fromJSON(needs.job1.outputs.matrix) }}
```

### Built-in Functions

| Function | Example |
|----------|---------|
| `contains(search, item)` | `contains(github.event.issue.labels.*.name, 'bug')` |
| `startsWith(str, value)` | `startsWith(github.ref, 'refs/tags/')` |
| `endsWith(str, value)` | `endsWith(github.repository, '-demo')` |
| `format(str, ...)` | `format('Hello {0}', github.actor)` |
| `join(array, sep)` | `join(matrix.os, ', ')` |
| `toJSON(value)` | `toJSON(steps.test.outputs)` |
| `fromJSON(str)` | `fromJSON(needs.setup.outputs.matrix)` |
| `hashFiles(path)` | `hashFiles('**/package-lock.json')` |

## Secrets and Variables

### Accessing Secrets

```yaml
steps:
  - run: echo "Token: $TOKEN"
    env:
      TOKEN: ${{ secrets.MY_TOKEN }}

  - uses: some-action@v1
    with:
      api-key: ${{ secrets.API_KEY }}
```

### Environment Variables

```yaml
env:                              # Workflow-level
  NODE_ENV: production

jobs:
  build:
    env:                          # Job-level
      CI: true
    steps:
      - run: echo $MY_VAR
        env:                      # Step-level
          MY_VAR: value
```

### Setting Outputs

```yaml
steps:
  - id: set-output
    run: echo "result=success" >> "$GITHUB_OUTPUT"

  - run: echo "${{ steps.set-output.outputs.result }}"
```

## Runners

Common labels: `ubuntu-latest`, `windows-latest`, `macos-latest`. Self-hosted: `runs-on: [self-hosted, linux, x64]`. See `references/RUNNERS.md` for full specs.

## Permissions

```yaml
permissions:
  contents: read
  pull-requests: write
  id-token: write         # Required for OIDC

# Or disable all
permissions: {}
```

## Concurrency

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

## Artifacts and Caching

### Upload/Download Artifacts

```yaml
- uses: actions/upload-artifact@v4
  with:
    name: build-output
    path: dist/

- uses: actions/download-artifact@v4
  with:
    name: build-output
```

### Dependency Caching

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

## Environments

```yaml
jobs:
  deploy:
    environment:
      name: production
      url: https://example.com
    runs-on: ubuntu-latest
```

## Reusable Workflows

### Calling a Reusable Workflow

```yaml
jobs:
  call-workflow:
    uses: owner/repo/.github/workflows/reusable.yml@main
    with:
      input1: value
    secrets:
      token: ${{ secrets.TOKEN }}
```

### Creating a Reusable Workflow

```yaml
on:
  workflow_call:
    inputs:
      environment:
        required: true
        type: string
    secrets:
      token:
        required: true

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - run: echo "Deploying to ${{ inputs.environment }}"
        env:
          TOKEN: ${{ secrets.token }}
```

## Common Patterns

### Checkout and Setup

```yaml
steps:
  - uses: actions/checkout@v5
  - uses: actions/setup-node@v4
    with:
      node-version: '20'
      cache: 'npm'
  - run: npm ci
```

### Conditional on File Changes

```yaml
on:
  push:
    paths:
      - 'src/**'
      - '!src/**/*.md'
```

### Run on Tag Push

```yaml
on:
  push:
    tags:
      - 'v*'
```

## Workflow Commands Quick Reference

```bash
# Step outputs (use in later steps via steps.<id>.outputs.<name>)
echo "name=value" >> "$GITHUB_OUTPUT"

# Set environment variable for subsequent steps
echo "VAR_NAME=value" >> "$GITHUB_ENV"

# Job summary (supports markdown)
echo "### Build Results :rocket:" >> "$GITHUB_STEP_SUMMARY"
echo "| Test | Status |" >> "$GITHUB_STEP_SUMMARY"
echo "| --- | --- |" >> "$GITHUB_STEP_SUMMARY"
echo "| Unit | Passed |" >> "$GITHUB_STEP_SUMMARY"

# Add to PATH for subsequent steps
echo "/path/to/tool" >> "$GITHUB_PATH"

# Log annotations
echo "::error file=app.js,line=10::Something failed"
echo "::warning::Deprecation notice"
echo "::notice::FYI message"

# Mask a value from logs
echo "::add-mask::$SECRET_VALUE"
```

See `references/WORKFLOW-COMMANDS.md` for full details including `::group::`, `::debug::`, multiline values, and GITHUB_STATE.

## Key Limits

| Limit | Value |
|-------|-------|
| Workflow run time | 35 days |
| Job execution time | 6 hours (self-hosted: unlimited) |
| Matrix combinations | 256 per workflow |
| Concurrent jobs (Free) | 20 (macOS: 5) |
| Concurrent jobs (Team/Enterprise) | 60 (macOS: 5) |
| Workflow file size | 512 KB |
| Caches total per repo | 10 GB |
| Artifact retention | 90 days (configurable) |
| Log retention | 400 days (configurable to 90) |

See `references/LIMITS.md` for full limits including API rates and storage quotas.

## Troubleshooting

1. **Workflow not triggering**: Check branch/path filters, verify file is in `.github/workflows/`
2. **Permission denied**: Add required `permissions:` block
3. **Secret not found**: Verify secret name matches exactly (case-sensitive)
4. **Step output empty**: Ensure using `>> "$GITHUB_OUTPUT"` (not deprecated set-output)
5. **Matrix job failing**: Check `exclude`/`include` syntax and values
6. **Debug logging**: Re-run workflow with `ACTIONS_RUNNER_DEBUG: true` or `ACTIONS_STEP_DEBUG: true`

## References

Core:
- `references/WORKFLOW-SYNTAX.md` - Full workflow YAML syntax
- `references/EXPRESSIONS.md` - Contexts, functions, operators
- `references/TRIGGERS.md` - Event types and filtering
- `references/WORKFLOW-COMMANDS.md` - GITHUB_OUTPUT, GITHUB_ENV, annotations, job summaries
- `references/LIMITS.md` - Time limits, quotas, rate limits by plan

Build and deploy:
- `references/ACTIONS.md` - Creating custom actions (JS, Docker, composite)
- `references/RUNNERS.md` - Runner specs, self-hosted configuration
- `references/PATTERNS.md` - Common workflow patterns
- `references/LANGUAGE-CI.md` - CI setup per language (Node, Python, Java, Go, Rust, Ruby, .NET, Swift)
- `references/PUBLISHING.md` - Publish to npm, PyPI, Docker Hub, GHCR, Maven Central
- `references/CLOUD-DEPLOYMENTS.md` - Deploy to AWS, Azure, GCP with OIDC

Security and ops:
- `references/SECURITY.md` - Secrets, OIDC (AWS/Azure/GCP), attestations, script injection
- `references/MIGRATION.md` - Migrate from Jenkins, Travis CI, CircleCI, GitLab, Azure DevOps
- `references/ENTERPRISE.md` - ARC, runner groups, larger runners, billing, private networking

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…