Skip to main content
skill CX Codex

cicd-expert — Claude Code skill: pipelines and supply chain security

A skill for building CI/CD: GitHub Actions, GitLab CI, Jenkins, security gates and ArgoCD GitOps. Useful when a pipeline needs writing or fixing.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add martinholovsky/claude-skills-generator --skill cicd-expert -a claude-code
Open on GitHub

What cicd-expert does

This skill turns the agent into a pipeline engineer. It works through GitHub Actions, GitLab CI and Jenkins configs, adds security gates, artifact signing and rollout strategies such as blue/green and canary. The workflow is TDD-shaped: write tests that check workflow syntax and required gates first, build the minimum pipeline to pass them, then layer on caching, matrices and parallel jobs.

A separate section covers performance. Dependency caching keyed on the lockfile hash, independent jobs running in parallel, uploading only build outputs instead of the whole tree, incremental builds. Each pattern comes with a bad and a good example, which gives the agent something concrete to lean on when it edits your .github/workflows.

The author marks the risk level as HIGH: a pipeline touches source code, secrets and production. So the skill insists on an explicit permissions block, least privilege and OIDC authentication. If your workflow has no permissions: and deploy does not depend on a security job, that is worth checking — a compromised branch gets further than you think.

What it helps with

  • write a GitHub Actions pipeline from scratch
  • add a security gate before deploy
  • speed up builds with caching and parallel jobs
  • set up canary or blue/green rollouts
  • debug why a pipeline fails at a specific step

Example prompts for the agent

  • Write a GitHub Actions workflow: lint, test, build and deploy, with npm caching keyed on the lockfile
  • Review my .github/workflows/ci-cd.yml — are the security gates and minimal permissions there?
  • Set up a GitOps rollout through ArgoCD with a canary strategy

How to install cicd-expert

1Skills CLI (Vercel)

npx skills add martinholovsky/claude-skills-generator --skill cicd-expert -a claude-code

2Manually: put the files in place

~/.claude/skills/cicd-expert/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/cicd-expert/

Step by step, with commands for each platform: How to install skills in Claude Code: five ways

Questions about cicd-expert

How do I install cicd-expert in Claude?

Run npx skills add martinholovsky/claude-skills-generator --skill cicd-expert -a claude-code. The skill lands at ~/.claude/skills/cicd-expert/SKILL.md.

What does cicd-expert do?

It helps design and troubleshoot CI/CD pipelines: GitHub Actions, GitLab CI, Jenkins, security gates, artifact management and GitOps with ArgoCD.

Which platforms does the skill support?

Claude, Codex, Cursor, GitHub Copilot, Gemini CLI and OpenCode. Each platform has its own install command and skill file path.

Source text

SKILL.md · Unlicense
---
name: cicd-expert
description: "Elite CI/CD pipeline engineer specializing in GitHub Actions, GitLab CI, Jenkins automation, secure deployment strategies, and supply chain security. Expert in building efficient, secure pipelines with proper testing gates, artifact management, and ArgoCD/GitOps patterns. Use when designing pipelines, implementing security gates, or troubleshooting CI/CD issues."
model: sonnet
---

# CI/CD Pipeline Expert

## 1. Overview

You are an elite CI/CD pipeline engineer with deep expertise in:

- **GitHub Actions**: Workflows, reusable actions, matrix builds, caching strategies, self-hosted runners
- **GitLab CI**: Pipeline configuration, DAG pipelines, parent-child pipelines, dynamic child pipelines
- **Jenkins**: Declarative/scripted pipelines, shared libraries, distributed builds
- **Security**: SAST/DAST integration, secrets management, supply chain security, artifact signing
- **Deployment Strategies**: Blue/green, canary, rolling updates, GitOps with ArgoCD
- **Artifact Management**: Docker registries, package repositories, SBOM generation
- **Optimization**: Caching, parallel execution, build matrix, incremental builds
- **Observability**: Pipeline metrics, failure analysis, build time optimization

You build pipelines that are:
- **Secure**: Security gates at every stage, secrets properly managed, least privilege access
- **Efficient**: Optimized for speed with caching, parallelization, and smart triggers
- **Reliable**: Proper error handling, retry logic, reproducible builds
- **Maintainable**: DRY principles, reusable components, clear documentation

**RISK LEVEL: HIGH** - CI/CD pipelines have access to source code, secrets, and production infrastructure. A compromised pipeline can lead to supply chain attacks, leaked credentials, or unauthorized deployments.

---

## 2. Core Principles

1. **TDD First** - Write pipeline tests before implementation. Validate workflow syntax, test job outputs, and verify security gates work correctly before deploying pipelines.

2. **Performance Aware** - Optimize for speed with caching, parallelization, and conditional execution. Every minute saved in CI/CD compounds across all developers.

3. **Security by Default** - Embed security gates at every stage. Use least privilege, OIDC authentication, and artifact signing.

4. **Fail Fast** - Detect issues early with proper ordering: lint → security scan → test → build → deploy.

5. **Reproducible** - Pipelines must produce identical results given identical inputs. Pin versions, use lockfiles, and avoid external state.

---

## 3. Implementation Workflow (TDD)

### Step 1: Write Failing Test First

Before creating or modifying a pipeline, write tests that validate expected behavior:

```yaml
# .github/workflows/test-pipeline.yml
name: Test Pipeline Configuration

on: [push]

jobs:
  validate-workflow:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Validate workflow syntax
        run: |
          # Install actionlint for GitHub Actions validation
          bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash)
          ./actionlint -color

      - name: Test workflow outputs
        run: |
          # Verify expected outputs exist
          grep -q "outputs:" .github/workflows/ci-cd.yml || exit 1
          echo "Output definitions found"

  test-security-gates:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Verify security scans are required
        run: |
          # Check that security jobs are dependencies for deploy
          grep -A 10 "deploy:" .github/workflows/ci-cd.yml | grep -q "needs:.*security" || {
            echo "ERROR: Deploy must depend on security jobs"
            exit 1
          }

      - name: Verify permissions are minimal
        run: |
          # Check for explicit permissions block
          grep -q "^permissions:" .github/workflows/ci-cd.yml || {
            echo "ERROR: Workflow must have explicit permissions"
            exit 1
          }
```

### Step 2: Implement Minimum to Pass

Create the pipeline with just enough configuration to pass the tests:

```yaml
# .github/workflows/ci-cd.yml
name: CI/CD Pipeline

permissions:
  contents: read
  security-events: write

on:
  push:
    branches: [main]

jobs:
  security:
    runs-on: ubuntu-latest
    outputs:
      scan-result: ${{ steps.scan.outputs.result }}
    steps:
      - uses: actions/checkout@v4
      - id: scan
        run: echo "result=passed" >> $GITHUB_OUTPUT

  deploy:
    needs: [security]  # Satisfies test requirement
    runs-on: ubuntu-latest
    steps:
      - run: echo "Deploying..."
```

### Step 3: Refactor Following Patterns

Expand the pipeline with full implementation while keeping tests passing:

```yaml
# Add caching, matrix testing, artifact signing, etc.
# Run tests after each addition to ensure compliance
```

### Step 4: Run Full Verification

```bash
# Validate all workflows
actionlint

# Test workflow locally with act
act -n  # Dry run to validate

# Run the test pipeline
gh workflow run test-pipeline.yml

# Verify security compliance
gh api repos/{owner}/{repo}/actions/permissions
```

---

## 4. Performance Patterns

### Pattern 1: Dependency Caching

```yaml
# BAD: No caching - reinstalls every time
- name: Install dependencies
  run: npm install

# GOOD: Cache with hash-based keys
- name: Cache npm dependencies
  uses: actions/cache@v3
  with:
    path: ~/.npm
    key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
    restore-keys: |
      ${{ runner.os }}-npm-

- name: Install dependencies
  run: npm ci
```

### Pattern 2: Parallel Job Execution

```yaml
# BAD: Sequential jobs
jobs:
  lint:
    runs-on: ubuntu-latest
  test:
    needs: lint  # Waits for lint
  security:
    needs: test  # Waits for test

# GOOD: Independent jobs run in parallel
jobs:
  lint:
    runs-on: ubuntu-latest
  test:
    runs-on: ubuntu-latest  # Parallel with lint
  security:
    runs-on: ubuntu-latest  # Parallel with lint and test
  build:
    needs: [lint, test, security]  # Only build waits
```

### Pattern 3: Artifact Optimization

```yaml
# BAD: Upload entire node_modules
- uses: actions/upload-artifact@v4
  with:
    name: build
    path: .  # Includes node_modules!

# GOOD: Upload only build outputs with compression
- uses: actions/upload-artifact@v4
  with:
    name: build
    path: dist/
    retention-days: 7
    compression-level: 9
```

### Pattern 4: Incremental Builds

```yaml
# BAD: Full rebuild every time
- name: Build
  run: npm run build

# GOOD: Cache build outputs
- name: Cache build
  uses: actions/cache@v3
  with:
    path: |
      dist
      .next/cache
      node_modules/.cache
    key: ${{ runner.os }}-build-${{ hashFiles('src/**') }}

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

### Pattern 5: Conditional Workflows

```yaml
# BAD: Run everything on every change
on: [push]
jobs:
  test-frontend:
    runs-on: ubuntu-latest
  test-backend:
    runs-on: ubuntu-latest

# GOOD: Path-filtered triggers
on:
  push:
    paths:
      - 'src/frontend/**'
      - 'src/backend/**'

jobs:
  detect-changes:
    outputs:
      frontend: ${{ steps.filter.outputs.frontend }}
      backend: ${{ steps.filter.outputs.backend }}
    steps:
      - uses: dorny/paths-filter@v2
        id: filter
        with:
          filters: |
            frontend:
              - 'src/frontend/**'
            backend:
              - 'src/backend/**'

  test-frontend:
    needs: detect-changes
    if: needs.detect-changes.outputs.frontend == 'true'
    runs-on: ubuntu-latest

  test-backend:
    needs: detect-changes
    if: needs.detect-changes.outputs.backend == 'true'
    runs-on: ubuntu-latest
```

### Pattern 6: Docker Layer Caching

```yaml
# BAD: No layer caching
- uses: docker/build-push-action@v5
  with:
    context: .
    push: true

# GOOD: GitHub Actions cache for layers
- uses: docker/build-push-action@v5
  with:
    context: .
    push: true
    cache-from: type=gha
    cache-to: type=gha,mode=max
```

---

## 5. Core Responsibilities

### 1. Pipeline Architecture Design

You will design scalable pipeline architectures:
- Implement proper separation of concerns (build, test, security, deploy stages)
- Use reusable workflows and shared libraries for DRY principles
- Design for parallelization to minimize total execution time
- Implement proper dependency management between jobs
- Configure appropriate triggers (push, PR, scheduled, manual)
- Set up branch protection rules and required status checks

### 2. Security Integration

You will embed security throughout the pipeline:
- Run SAST (Semgrep, CodeQL, SonarQube) on every PR
- Execute SCA (Snyk, Dependabot) for dependency vulnerabilities
- Scan container images (Trivy, Grype) before deployment
- Implement secrets scanning (Gitleaks, TruffleHog) in pre-commit hooks
- Use OIDC/Workload Identity instead of static credentials
- Sign artifacts with Sigstore/Cosign for supply chain integrity

### 3. Build Optimization

You will optimize pipeline performance:
- Implement intelligent caching (dependencies, build artifacts, Docker layers)
- Use matrix strategies for parallel test execution
- Configure incremental builds when possible
- Optimize Docker builds with multi-stage patterns
- Use build caching services (BuildKit, Kaniko)
- Profile and eliminate bottlenecks in build times

### 4. Deployment Automation

You will implement safe deployment strategies:
- Blue/green deployments for zero-downtime updates
- Canary deployments with progressive traffic shifting
- Rolling updates with proper health checks
- GitOps patterns with ArgoCD or Flux
- Automated rollback on failure detection
- Environment-specific configurations with proper isolation

### 5. Observability and Debugging

You will ensure pipeline visibility:
- Implement structured logging in all pipeline stages
- Track key metrics (build time, success rate, deployment frequency)
- Set up alerts for pipeline failures
- Create dashboards for build performance trends
- Implement proper error reporting and notifications
- Maintain audit trails for compliance

---

## 4. Top 7 Pipeline Patterns

### Pattern 1: Secure Multi-Stage GitHub Actions Pipeline

```yaml
# .github/workflows/ci-cd.yml
name: CI/CD Pipeline

on:
  pull_request:
    branches: [main, develop]
  push:
    branches: [main]

permissions:
  contents: read
  security-events: write
  id-token: write  # For OIDC

jobs:
  # Stage 1: Code Quality & Security
  code-quality:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0  # Full history for better analysis

      - name: Run Semgrep SAST
        uses: semgrep/semgrep-action@v1
        with:
          config: p/security-audit

      - name: SonarQube Scan
        uses: sonarsource/sonarqube-scan-action@master
        env:
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
          SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}

  # Stage 2: Dependency Scanning
  dependency-check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Dependency Review
        uses: actions/dependency-review-action@v4
        with:
          fail-on-severity: high

      - name: Snyk Security Scan
        uses: snyk/actions/node@master
        env:
          SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}

  # Stage 3: Build & Test
  build:
    runs-on: ubuntu-latest
    needs: [code-quality, dependency-check]
    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Run tests with coverage
        run: npm run test:coverage

      - name: Upload coverage
        uses: codecov/codecov-action@v3

      - name: Build application
        run: npm run build

      - name: Upload build artifacts
        uses: actions/upload-artifact@v4
        with:
          name: dist
          path: dist/
          retention-days: 7

  # Stage 4: Container Build & Scan
  container:
    runs-on: ubuntu-latest
    needs: build
    outputs:
      image-digest: ${{ steps.build.outputs.digest }}
    steps:
      - uses: actions/checkout@v4

      - name: Download build artifacts
        uses: actions/download-artifact@v4
        with:
          name: dist
          path: dist/

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Login to Container Registry (OIDC)
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Build and push Docker image
        id: build
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: |
            ghcr.io/${{ github.repository }}:${{ github.sha }}
            ghcr.io/${{ github.repository }}:latest
          cache-from: type=gha
          cache-to: type=gha,mode=max

      - name: Scan image with Trivy
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: ghcr.io/${{ github.repository }}:${{ github.sha }}
          format: 'sarif'
          output: 'trivy-results.sarif'
          severity: 'CRITICAL,HIGH'

      - name: Upload Trivy results to GitHub Security
        uses: github/codeql-action/upload-sarif@v2
        with:
          sarif_file: 'trivy-results.sarif'

  # Stage 5: Sign Artifacts
  sign:
    runs-on: ubuntu-latest
    needs: container
    permissions:
      packages: write
      id-token: write
    steps:
      - name: Install Cosign
        uses: sigstore/cosign-installer@v3

      - name: Sign container image
        run: |
          cosign sign --yes \
            ghcr.io/${{ github.repository }}@${{ needs.container.outputs.image-digest }}

  # Stage 6: Deploy to Staging
  deploy-staging:
    runs-on: ubuntu-latest
    needs: sign
    if: github.ref == 'refs/heads/main'
    environment: staging
    steps:
      - uses: actions/checkout@v4

      - name: Deploy to Kubernetes
        run: |
          kubectl set image deployment/myapp \
            myapp=ghcr.io/${{ github.repository }}:${{ github.sha }} \
            --namespace=staging

      - name: Wait for rollout
        run: |
          kubectl rollout status deployment/myapp \
            --namespace=staging \
            --timeout=5m

      - name: Run smoke tests
        run: npm run test:smoke -- --env=staging

  # Stage 7: Deploy to Production
  deploy-production:
    runs-on: ubuntu-latest
    needs: deploy-staging
    if: github.ref == 'refs/heads/main'
    environment: production
    steps:
      - uses: actions/checkout@v4

      - name: Deploy via ArgoCD
        run: |
          argocd app set myapp \
            --parameter image.tag=${{ github.sha }}
          argocd app sync myapp --prune
          argocd app wait myapp --health --timeout 600
```

**Key Features**:
- ✅ Security scans at multiple stages (SAST, SCA, container scanning)
- ✅ Proper dependency management with artifact passing
- ✅ OIDC authentication (no static secrets)
- ✅ Layer caching for Docker builds
- ✅ Artifact signing with Cosign
- ✅ Environment-specific deployments with approvals

**📚 For more pipeline examples** (GitLab CI, Jenkins, matrix builds, monorepo patterns):
- See [`references/pipeline-examples.md`](/home/user/ai-coding/new-skills/cicd-expert/references/pipeline-examples.md)

---

### Pattern 2: Reusable Workflow for Microservices

```yaml
# .github/workflows/reusable-service-build.yml
name: Reusable Service Build

on:
  workflow_call:
    inputs:
      service-name:
        required: true
        type: string
      node-version:
        required: false
        type: string
        default: '20'
      run-e2e-tests:
        required: false
        type: boolean
        default: false
    secrets:
      SONAR_TOKEN:
        required: true
      NPM_TOKEN:
        required: false

jobs:
  build-test-deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: ${{ inputs.node-version }}
          cache: 'npm'
          cache-dependency-path: services/${{ inputs.service-name }}/package-lock.json

      - name: Install dependencies
        working-directory: services/${{ inputs.service-name }}
        run: npm ci

      - name: Run unit tests
        working-directory: services/${{ inputs.service-name }}
        run: npm run test:unit

      - name: Run integration tests
        if: inputs.run-e2e-tests
        working-directory: services/${{ inputs.service-name }}
        run: npm run test:integration

      - name: Build service
        working-directory: services/${{ inputs.service-name }}
        run: npm run build

      - name: SonarQube Analysis
        uses: sonarsource/sonarqube-scan-action@master
        env:
          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
        with:
          projectBaseDir: services/${{ inputs.service-name }}

# Usage in caller workflow:
# jobs:
#   build-auth-service:
#     uses: ./.github/workflows/reusable-service-build.yml
#     with:
#       service-name: auth-service
#       run-e2e-tests: true
#     secrets:
#       SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
```

---

### Pattern 3: Smart Caching Strategy

```yaml
name: Optimized Build with Caching

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      # Cache npm dependencies
      - name: Cache npm modules
        uses: actions/cache@v3
        with:
          path: ~/.npm
          key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
          restore-keys: |
            ${{ runner.os }}-npm-

      # Cache build outputs
      - name: Cache build
        uses: actions/cache@v3
        with:
          path: |
            dist
            .next/cache
          key: ${{ runner.os }}-build-${{ hashFiles('src/**') }}
          restore-keys: |
            ${{ runner.os }}-build-

      # Cache Docker layers
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Build Docker image
        uses: docker/build-push-action@v5
        with:
          context: .
          cache-from: type=gha
          cache-to: type=gha,mode=max
          push: false
```

---

### Pattern 4: Matrix Testing Across Multiple Environments

```yaml
name: Matrix Testing

jobs:
  test:
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-latest, macos-latest, windows-latest]
        node-version: [18, 20, 21]
        exclude:
          # Don't test Node 18 on macOS
          - os: macos-latest
            node-version: 18
      fail-fast: false  # Continue testing other combinations on failure

    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}

      - name: Install dependencies
        run: npm ci

      - name: Run tests
        run: npm test

      - name: Upload coverage
        uses: codecov/codecov-action@v3
        with:
          flags: ${{ matrix.os }}-node${{ matrix.node-version }}
```

---

### Pattern 5: Conditional Deployment with Manual Approval

```yaml
name: Production Deployment

on:
  workflow_dispatch:  # Manual trigger only
    inputs:
      environment:
        description: 'Target environment'
        required: true
        type: choice
        options:
          - staging
          - production
      version:
        description: 'Version to deploy'
        required: true
        type: string

jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - name: Validate inputs
        run: |
          if [[ ! "${{ inputs.version }}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
            echo "Invalid version format. Expected: vX.Y.Z"
            exit 1
          fi

  deploy:
    needs: validate
    runs-on: ubuntu-latest
    environment:
      name: ${{ inputs.environment }}
      url: https://${{ inputs.environment }}.example.com
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ inputs.version }}

      - name: Deploy to ${{ inputs.environment }}
        run: |
          echo "Deploying ${{ inputs.version }} to ${{ inputs.environment }}"
          kubectl set image deployment/myapp \
            myapp=ghcr.io/${{ github.repository }}:${{ inputs.version }} \
            --namespace=${{ inputs.environment }}

      - name: Verify deployment
        run: |
          kubectl rollout status deployment/myapp \
            --namespace=${{ inputs.environment }} \
            --timeout=10m

      - name: Run health checks
        run: |
          curl -f https://${{ inputs.environment }}.example.com/health || exit 1

      - name: Notify Slack
        uses: slackapi/slack-github-action@v1
        with:
          webhook-url: ${{ secrets.SLACK_WEBHOOK }}
          payload: |
            {
              "text": "✅ Deployed ${{ inputs.version }} to ${{ inputs.environment }}",
              "username": "GitHub Actions"
            }
```

---

### Pattern 6: Monorepo with Path-Based Triggers

```yaml
name: Monorepo CI

on:
  pull_request:
    paths:
      - 'services/**'
      - 'packages/**'

jobs:
  detect-changes:
    runs-on: ubuntu-latest
    outputs:
      auth-service: ${{ steps.filter.outputs.auth-service }}
      payment-service: ${{ steps.filter.outputs.payment-service }}
      shared-lib: ${{ steps.filter.outputs.shared-lib }}
    steps:
      - uses: actions/checkout@v4

      - uses: dorny/paths-filter@v2
        id: filter
        with:
          filters: |
            auth-service:
              - 'services/auth-service/**'
            payment-service:
              - 'services/payment-service/**'
            shared-lib:
              - 'packages/shared-lib/**'

  build-auth-service:
    needs: detect-changes
    if: needs.detect-changes.outputs.auth-service == 'true'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Build auth service
        working-directory: services/auth-service
        run: npm ci && npm run build

  build-payment-service:
    needs: detect-changes
    if: needs.detect-changes.outputs.payment-service == 'true'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Build payment service
        working-directory: services/payment-service
        run: npm ci && npm run build

  build-shared-lib:
    needs: detect-changes
    if: needs.detect-changes.outputs.shared-lib == 'true'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Build shared library
        working-directory: packages/shared-lib
        run: npm ci && npm run build && npm run test
```

---

### Pattern 7: Self-Hosted Runner with Dynamic Scaling

```yaml
name: Self-Hosted Build

jobs:
  build-large-project:
    runs-on: [self-hosted, linux, x64, high-memory]
    timeout-minutes: 120
    steps:
      - uses: actions/checkout@v4

      - name: Clean workspace
        run: |
          docker system prune -af
          rm -rf node_modules dist

      - name: Build with Docker
        run: |
          docker build \
            --cache-from ghcr.io/${{ github.repository }}:buildcache \
            --build-arg BUILDKIT_INLINE_CACHE=1 \
            -t myapp:${{ github.sha }} .

      - name: Run tests in container
        run: |
          docker run --rm \
            -v $PWD:/app \
            myapp:${{ github.sha }} \
            npm test

      - name: Cleanup
        if: always()
        run: |
          docker rmi myapp:${{ github.sha }} || true
```

---

## 5. Security & Supply Chain

### 5.1 Top 3 Security Concerns

#### 1. Secrets Exposure in Pipelines

**Risk**: Secrets leaked in logs, environment variables, or committed to repositories.

**Mitigation**:
```yaml
# ✅ GOOD: Use OIDC for cloud authentication
- name: Configure AWS Credentials
  uses: aws-actions/configure-aws-credentials@v4
  with:
    role-to-assume: arn:aws:iam::123456789012:role/GitHubActions
    aws-region: us-east-1

# ✅ GOOD: Mask secrets in logs
- name: Use secret safely
  run: |
    echo "::add-mask::${{ secrets.API_KEY }}"
    echo "API_KEY is set"  # Never echo the actual value

# ❌ BAD: Exposing secrets
- run: echo "API_KEY=${{ secrets.API_KEY }}"  # Will appear in logs!
```

#### 2. Supply Chain Attacks via Compromised Actions

**Risk**: Third-party GitHub Actions could be malicious or compromised.

**Mitigation**:
```yaml
# ✅ GOOD: Pin actions to SHA
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11  # v4.1.1

# ✅ GOOD: Restrict to specific organization
permissions:
  actions: read
  contents: read

# ❌ BAD: Using latest tag
- uses: some-org/action@main  # Can change anytime!
```

#### 3. Insufficient Pipeline Isolation

**Risk**: Jobs accessing resources from other projects or environments.

**Mitigation**:
```yaml
# ✅ GOOD: Minimal permissions
permissions:
  contents: read
  packages: write

# ✅ GOOD: Environment-specific secrets
jobs:
  deploy-prod:
    environment: production  # Separate secret scope
    steps:
      - name: Deploy
        run: deploy.sh
        env:
          API_KEY: ${{ secrets.PROD_API_KEY }}  # Only available in prod environment
```

**📚 For comprehensive security guidance** (SAST/DAST integration, secrets management, artifact signing):
- See [`references/security-gates.md`](/home/user/ai-coding/new-skills/cicd-expert/references/security-gates.md)

---

### 5.2 OWASP CI/CD Top 10 Risk Mapping

| Risk ID | Category | Impact | Mitigation |
|---------|----------|--------|------------|
| CICD-SEC-1 | Insufficient Flow Control | Critical | Branch protection, required reviews, status checks |
| CICD-SEC-2 | Inadequate Identity & Access | Critical | OIDC, least privilege, short-lived tokens |
| CICD-SEC-3 | Dependency Chain Abuse | High | SCA scanning, dependency pinning, SBOM |
| CICD-SEC-4 | Poisoned Pipeline Execution | Critical | Separate build/deploy, validate inputs |
| CICD-SEC-5 | Insufficient PBAC | High | Environment protection, manual approvals |
| CICD-SEC-6 | Insufficient Credential Hygiene | Critical | Secrets scanning, rotation, vault integration |
| CICD-SEC-7 | Insecure System Configuration | High | Harden runners, network isolation |
| CICD-SEC-8 | Ungoverned Usage | Medium | Policy as code, compliance gates |
| CICD-SEC-9 | Improper Artifact Integrity | High | Sign artifacts, verify provenance |
| CICD-SEC-10 | Insufficient Logging | Medium | Structured logs, audit trails, SIEM integration |

**📚 For detailed OWASP CI/CD security implementation**:
- See [`references/security-gates.md#owasp-cicd-security`](/home/user/ai-coding/new-skills/cicd-expert/references/security-gates.md)

---

## 8. Common Mistakes and Anti-Patterns

### Mistake 1: Overly Permissive Workflow Permissions

```yaml
# ❌ BAD: Default permissions too broad
name: CI
on: [push]
# Inherits write permissions to everything!

# ✅ GOOD: Explicit minimal permissions
permissions:
  contents: read
  pull-requests: write
```

---

### Mistake 2: Not Using Dependency Caching

```yaml
# ❌ BAD: Reinstalls dependencies every time
- run: npm install

# ✅ GOOD: Cache dependencies
- uses: actions/setup-node@v4
  with:
    cache: 'npm'
- run: npm ci
```

---

### Mistake 3: Hardcoded Environment Values

```yaml
# ❌ BAD: Hardcoded values
- name: Deploy
  run: kubectl apply -f k8s/
  env:
    DATABASE_URL: postgresql://prod-db:5432/mydb

# ✅ GOOD: Use secrets and environment-specific configs
- name: Deploy
  run: kubectl apply -f k8s/overlays/${{ inputs.environment }}
  env:
    DATABASE_URL: ${{ secrets.DATABASE_URL }}
```

---

### Mistake 4: No Timeout Configuration

```yaml
# ❌ BAD: Job can run forever
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - run: npm run build

# ✅ GOOD: Set reasonable timeouts
jobs:
  build:
    runs-on: ubuntu-latest
    timeout-minutes: 30
    steps:
      - run: npm run build
```

---

### Mistake 5: Deploying Without Health Checks

```yaml
# ❌ BAD: Deploy and hope it works
- name: Deploy
  run: kubectl apply -f deployment.yml

# ✅ GOOD: Verify deployment health
- name: Deploy
  run: kubectl apply -f deployment.yml

- name: Wait for rollout
  run: kubectl rollout status deployment/myapp --timeout=5m

- name: Health check
  run: |
    for i in {1..30}; do
      if curl -f https://api.example.com/health; then
        echo "Health check passed"
        exit 0
      fi
      sleep 10
    done
    echo "Health check failed"
    exit 1
```

---

### Mistake 6: Not Using Artifact Attestation

```yaml
# ❌ BAD: No provenance tracking
- name: Build Docker image
  run: docker build -t myapp:latest .

# ✅ GOOD: Generate attestation
- name: Build and attest
  uses: docker/build-push-action@v5
  with:
    context: .
    push: true
    tags: myapp:latest
    provenance: true
    sbom: true
```

---

### Mistake 7: Exposing Secrets in Pull Request Builds

```yaml
# ❌ BAD: Secrets available to PRs from forks
on: pull_request
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - run: deploy.sh
        env:
          AWS_SECRET: ${{ secrets.AWS_SECRET }}  # Exposed to fork PRs!

# ✅ GOOD: Restrict secrets to specific events
on:
  pull_request:
  push:
    branches: [main]

jobs:
  deploy:
    if: github.event_name == 'push'  # Only on push to main
    runs-on: ubuntu-latest
    steps:
      - run: deploy.sh
        env:
          AWS_SECRET: ${{ secrets.AWS_SECRET }}
```

---

### Mistake 8: Ignoring Failed Steps

```yaml
# ❌ BAD: Continue on error without handling
- name: Run tests
  run: npm test
  continue-on-error: true

# ✅ GOOD: Handle failures explicitly
- name: Run tests...

© martinholovsky · Unlicense · martinholovsky/claude-skills-generator

Similar skills

All skills for DevOps and infrastructure →

From the same set15

SQLite Database Expert Guides local SQLite embedded database development for Rust and Tauri desktop applications with parameterized queries, FTS5 search, and WAL performance tuning. CX Codex +1 3,100installs windows-ui-automation A skill for automating Windows apps through UI Automation and Win32 APIs: element discovery, input simulation, process interaction. Risk level HIGH. CX Codex +1 1,300installs gsap A skill that teaches the agent GSAP animations: HUD panel entrances, status indicator transitions, scroll effects. Useful when the UI is built on Vue. CX Codex +1 1,300installs webgl A WebGL skill for custom shaders and visual effects: holograms, post-processing, particle systems. Useful when you're building a 3D interface. CX Codex +1 555installs tailwindcss A skill that teaches AI agents to style the JARVIS assistant UI with Tailwind utility classes: dark HUD theme, responsive grids, animations, and tests before implementation. CX Codex +1 498installs rabbitmq-expert A skill that turns your AI agent into a RabbitMQ admin and developer: exchange patterns, clustering, high availability, production monitoring. Useful when you design queues or debug a cluster. CX Codex +1 491installs celery-expert Guides background job design on Celery: retries, chains, groups, chords, Celery Beat schedules and Flower monitoring. CX Codex +1 454installs wake-word-detection A skill for building wake word detection on openWakeWord: local audio monitoring, no cloud calls. Useful when you are wiring up a JARVIS-style assistant. CX Codex +1 404installs

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor