| name | ci-cd-patterns |
| skill_category | devops |
| description | CI/CD pipeline patterns, GitHub Actions workflow best practices, build automation, continuous integration, Scorecard and CodeQL security findings, and supply-chain security review — with deterministic pipeline linting script. Covers GitHub Actions, Jenkinsfile, GitLab CI, and Azure Pipelines. Use proactively when reviewing or writing GitHub Actions workflows, debugging slow or flaky pipelines, addressing CI pipeline security findings, or running a supply-chain security review. Run the linter for deterministic issue detection. |
| version | 2.0.0 |
| source | .claude/skills/devops/ci-cd-patterns.md (retired flat file); L3 linter added 2026-05-20 |
| when_to_use | ["Reviewing or writing GitHub Actions workflows","CI pipeline has security findings (Scorecard, CodeQL)","Debugging slow or flaky pipelines","Supply-chain security review of workflows"] |
| allowed-tools | ["Read","Grep","Glob","Bash"] |
| tags | ["ci-cd","github-actions","pipeline","anti-pattern","best-practice","automation","security"] |
| trigger_files | [".github/workflows/*.yml",".github/workflows/*.yaml","Jenkinsfile",".gitlab-ci.yml","azure-pipelines.yml"] |
| trigger_keywords | ["ci/cd","pipeline","github actions","workflow","build","deploy","continuous integration"] |
CI/CD Patterns
Best practices and anti-patterns for CI/CD pipelines, focusing on GitHub Actions but applicable to other CI systems. Run the linter on every workflow file before review; use this prose guidance to explain findings and propose fixes.
Purpose
- Ensure pipelines are fast, reliable, and secure
- Prevent common mistakes that cause build failures or security issues
- Establish patterns for maintainable pipeline configurations
Core Patterns
Pattern 1: Parallel Job Execution
When to use: Multiple independent tasks in pipeline.
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm run lint
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm test
deploy:
needs: [lint, test]
runs-on: ubuntu-latest
steps:
- run: ./deploy.sh
Pattern 2: Dependency Caching
When to use: Repeated dependency installation across runs.
- name: Cache dependencies
uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: Install dependencies
run: npm ci
Pattern 3: Safe Deployments with Health Checks
deploy:
steps:
- name: Deploy
run: kubectl apply -f deployment.yaml
- name: Wait for rollout
run: kubectl rollout status deployment/app --timeout=5m
- name: Health check
run: curl -f https://app.example.com/health || exit 1
- name: Rollback on failure
if: failure()
run: kubectl rollout undo deployment/app
Anti-Patterns
Anti-Pattern 1: Hardcoded Secrets
| Aspect | Description |
|---|
| WHY | Secrets in code are exposed in logs, version history, and forks. Security breach risk. |
| DETECTION | API keys, passwords, tokens directly in workflow files. |
| FIX | Use GitHub Secrets. Reference via ${{ secrets.NAME }}. |
Anti-Pattern 2: Unpinned Action Versions
| Aspect | Description |
|---|
| WHY | Branch refs are mutable — a compromised action repo can inject malicious code into your pipeline without any change to your workflow file. |
| DETECTION | uses: owner/repo@branch or uses: owner/repo@vN without a full SHA. |
| FIX | Pin to full commit SHA: uses: actions/checkout@abc123... # v4.1.0. Check dependabot or Renovate to keep SHAs current. |
Anti-Pattern 3: Missing Timeout
| Aspect | Description |
|---|
| WHY | Hanging builds waste resources and block pipelines. Default 6-hour timeout is too long. |
| DETECTION | No timeout-minutes at job level. |
| FIX | Set explicit timeout-minutes per job (typically 2–3× normal run time). |
Anti-Pattern 4: Missing Permissions Block
| Aspect | Description |
|---|
| WHY | GITHUB_TOKEN defaults to broad write access on many repositories. Overpermissioned tokens are a lateral movement risk if a step is compromised. |
| DETECTION | No permissions block at workflow or job level. Flagged by OSSF Scorecard Token-Permissions check. |
| FIX | Add permissions: read-all at workflow level, then narrow per-job as needed. |
Validation Checklist
Implementation
Invocation — CI/CD Linter (L3 Script)
Run the linter on every workflow file before review. Consume its output only — the script source never enters context.
Input: JSON representation of the GitHub Actions workflow. YAML must be converted to JSON first.
YAML to JSON conversion:
python3 -c "import sys,json,yaml; print(json.dumps(yaml.safe_load(sys.stdin)))" < .github/workflows/ci.yml \
| python .claude/skills/devops/ci-cd-patterns/scripts/cicd_lint.py -
Or with yq:
yq -o json .github/workflows/ci.yml | python .claude/skills/devops/ci-cd-patterns/scripts/cicd_lint.py -
Run via Bash (file argument — JSON):
python .claude/skills/devops/ci-cd-patterns/scripts/cicd_lint.py workflow.json
Input format:
{
"name": "CI",
"on": {"push": {"branches": ["main"]}},
"permissions": "read-all",
"jobs": {
"build": {
"runs-on": "ubuntu-latest",
"timeout-minutes": 30,
"permissions": {"contents": "read"},
"steps": [
{"name": "Checkout", "uses": "actions/checkout@<sha>"},
{"name": "Test", "run": "npm test"}
]
}
}
}
Output:
- JSON object with
findings array (each finding has id, severity, job, title, detail, reference) and summary counts.
- Markdown findings table sorted by severity (CRITICAL → HIGH → MEDIUM).
Findings covered:
| ID | Check | Severity | Source |
|---|
| CICD-001 | Unpinned action (branch = CRITICAL, tag = HIGH) | CRITICAL/HIGH | GitHub Actions Security Hardening Guide |
| CICD-002 | Missing timeout-minutes on job | MEDIUM | GitHub Actions docs |
| CICD-003 | No permissions block (workflow or job level) | HIGH | OSSF Scorecard Token-Permissions |
| CICD-004 | Hardcoded secret in env block or run command | CRITICAL | GitHub Actions encrypted secrets docs |
What to do with the output:
- CRITICAL findings (hardcoded secrets, branch-pinned actions) must be blocked — these are supply-chain and credential exposure risks.
- HIGH findings must be addressed before the workflow is merged to the default branch.
- MEDIUM findings should be addressed; document exceptions.
Error handling: Script exits non-zero on I/O failure or if the input is missing the jobs field (required). Exits 0 for valid input including empty input and finding-present input.
Quick Reference
| Task | Pattern |
|---|
| Speed up builds | Add caching, parallelize jobs |
| Secure secrets | Use ${{ secrets.NAME }} |
| Supply-chain safety | Pin actions to full SHA |
| Least-privilege token | Add permissions block |
| Safe deployments | Health checks + rollback |
| Prevent hangs | Set timeout-minutes |