.claude/skills/github-actions-cicd/SKILL.md
Set up GitHub Actions CI/CD pipelines for testing, building, and deploying to Kubernetes. Use when implementing continuous integration and deployment for Phase 5. (project)
npx skillsauth add maneeshanif/todo-spec-driven github-actions-cicdInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
constitution-prompt-phase-5.md.github/workflows/.github/
└── workflows/
├── ci.yaml # Test & build on PR
├── cd-staging.yaml # Deploy to staging
├── cd-production.yaml # Deploy to production
└── security.yaml # Security scanning
Create .github/workflows/ci.yaml:
name: CI Pipeline
on:
pull_request:
branches: [main, develop]
push:
branches: [main, develop]
env:
REGISTRY: ghcr.io
IMAGE_PREFIX: ${{ github.repository }}
jobs:
# Backend Tests
backend-test:
name: Backend Tests
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./backend
services:
postgres:
image: postgres:16-alpine
env:
POSTGRES_USER: test
POSTGRES_PASSWORD: test
POSTGRES_DB: todo_test
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v4
with:
version: "latest"
- name: Set up Python
run: uv python install 3.13
- name: Install dependencies
run: uv sync --frozen
- name: Run linting
run: uv run ruff check .
- name: Run type checking
run: uv run mypy src/
- name: Run tests
env:
DATABASE_URL: postgresql://test:test@localhost:5432/todo_test
BETTER_AUTH_SECRET: test-secret
GEMINI_API_KEY: test-key
run: uv run pytest tests/ -v --cov=src --cov-report=xml
- name: Upload coverage
uses: codecov/codecov-action@v4
with:
files: ./backend/coverage.xml
flags: backend
# Frontend Tests
frontend-test:
name: Frontend Tests
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./frontend
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: './frontend/package-lock.json'
- name: Install dependencies
run: npm ci
- name: Run linting
run: npm run lint
- name: Run type checking
run: npm run type-check
- name: Run tests
run: npm test -- --coverage
- name: Build
run: npm run build
env:
NEXT_PUBLIC_API_URL: http://localhost:8000
# Build Docker Images
build-images:
name: Build Images
runs-on: ubuntu-latest
needs: [backend-test, frontend-test]
if: github.event_name == 'push'
permissions:
contents: read
packages: write
strategy:
matrix:
service:
- name: backend
context: ./backend
dockerfile: ./backend/Dockerfile
- name: frontend
context: ./frontend
dockerfile: ./frontend/Dockerfile
- name: notification-service
context: ./services/notification
dockerfile: ./services/notification/Dockerfile
- name: recurring-service
context: ./services/recurring
dockerfile: ./services/recurring/Dockerfile
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to GHCR
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_PREFIX }}/${{ matrix.service.name }}
tags: |
type=sha,prefix=
type=ref,event=branch
type=semver,pattern={{version}}
- name: Build and push
uses: docker/build-push-action@v5
with:
context: ${{ matrix.service.context }}
file: ${{ matrix.service.dockerfile }}
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
# Helm Chart Validation
helm-lint:
name: Helm Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Helm
uses: azure/setup-helm@v4
with:
version: v3.14.0
- name: Lint charts
run: helm lint ./helm/evolution-todo
- name: Template validation
run: |
helm template evolution-todo ./helm/evolution-todo \
--values ./helm/evolution-todo/values.yaml \
--debug
Create .github/workflows/cd-staging.yaml:
name: CD Staging
on:
push:
branches: [develop]
workflow_dispatch:
env:
REGISTRY: ghcr.io
IMAGE_PREFIX: ${{ github.repository }}
CLUSTER_NAME: todo-staging
NAMESPACE: todo-staging
jobs:
deploy-staging:
name: Deploy to Staging
runs-on: ubuntu-latest
environment: staging
steps:
- uses: actions/checkout@v4
- name: Install doctl
uses: digitalocean/action-doctl@v2
with:
token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}
- name: Save DigitalOcean kubeconfig
run: doctl kubernetes cluster kubeconfig save ${{ env.CLUSTER_NAME }}
- name: Set up Helm
uses: azure/setup-helm@v4
with:
version: v3.14.0
- name: Deploy with Helm
run: |
helm upgrade --install evolution-todo ./helm/evolution-todo \
--namespace ${{ env.NAMESPACE }} \
--create-namespace \
--values ./helm/evolution-todo/values-staging.yaml \
--set global.image.tag=${{ github.sha }} \
--set backend.env.DATABASE_URL=${{ secrets.STAGING_DATABASE_URL }} \
--set backend.env.GEMINI_API_KEY=${{ secrets.GEMINI_API_KEY }} \
--set backend.env.BETTER_AUTH_SECRET=${{ secrets.BETTER_AUTH_SECRET }} \
--wait \
--timeout 10m
- name: Verify deployment
run: |
kubectl rollout status deployment/backend -n ${{ env.NAMESPACE }}
kubectl rollout status deployment/frontend -n ${{ env.NAMESPACE }}
- name: Run smoke tests
run: |
FRONTEND_URL=$(kubectl get svc frontend -n ${{ env.NAMESPACE }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
curl -f http://$FRONTEND_URL/health || exit 1
Create .github/workflows/cd-production.yaml:
name: CD Production
on:
release:
types: [published]
workflow_dispatch:
inputs:
version:
description: 'Version to deploy'
required: true
env:
REGISTRY: ghcr.io
IMAGE_PREFIX: ${{ github.repository }}
CLUSTER_NAME: todo-production
NAMESPACE: todo-app
jobs:
deploy-production:
name: Deploy to Production
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v4
- name: Determine version
id: version
run: |
if [ "${{ github.event_name }}" == "release" ]; then
echo "version=${{ github.event.release.tag_name }}" >> $GITHUB_OUTPUT
else
echo "version=${{ github.event.inputs.version }}" >> $GITHUB_OUTPUT
fi
- name: Install doctl
uses: digitalocean/action-doctl@v2
with:
token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}
- name: Save DigitalOcean kubeconfig
run: doctl kubernetes cluster kubeconfig save ${{ env.CLUSTER_NAME }}
- name: Set up Helm
uses: azure/setup-helm@v4
with:
version: v3.14.0
- name: Deploy with Helm
run: |
helm upgrade --install evolution-todo ./helm/evolution-todo \
--namespace ${{ env.NAMESPACE }} \
--values ./helm/evolution-todo/values-production.yaml \
--set global.image.tag=${{ steps.version.outputs.version }} \
--set backend.env.DATABASE_URL=${{ secrets.PROD_DATABASE_URL }} \
--set backend.env.GEMINI_API_KEY=${{ secrets.GEMINI_API_KEY }} \
--set backend.env.BETTER_AUTH_SECRET=${{ secrets.BETTER_AUTH_SECRET }} \
--set kafka.brokers=${{ secrets.REDPANDA_BROKERS }} \
--wait \
--timeout 15m
- name: Verify deployment
run: |
kubectl rollout status deployment/backend -n ${{ env.NAMESPACE }} --timeout=5m
kubectl rollout status deployment/frontend -n ${{ env.NAMESPACE }} --timeout=5m
- name: Notify success
if: success()
uses: slackapi/slack-github-action@v1
with:
payload: |
{
"text": "Production deployment successful: ${{ steps.version.outputs.version }}"
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}
- name: Rollback on failure
if: failure()
run: |
helm rollback evolution-todo -n ${{ env.NAMESPACE }}
Create .github/workflows/security.yaml:
name: Security Scanning
on:
push:
branches: [main]
pull_request:
branches: [main]
schedule:
- cron: '0 0 * * 0' # Weekly on Sunday
jobs:
trivy-scan:
name: Trivy Vulnerability Scan
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Trivy vulnerability scanner (repo)
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
scan-ref: '.'
format: 'sarif'
output: 'trivy-results.sarif'
- name: Upload Trivy scan results
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: 'trivy-results.sarif'
dependency-review:
name: Dependency Review
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@v4
- name: Dependency Review
uses: actions/dependency-review-action@v4
with:
fail-on-severity: high
Configure in GitHub Settings → Secrets and variables → Actions:
| Secret | Description | Used In |
|--------|-------------|---------|
| DIGITALOCEAN_ACCESS_TOKEN | DO API token | CD pipelines |
| STAGING_DATABASE_URL | Staging Neon DB URL | CD Staging |
| PROD_DATABASE_URL | Production Neon DB URL | CD Production |
| GEMINI_API_KEY | Google AI API key | All deployments |
| BETTER_AUTH_SECRET | Auth secret | All deployments |
| REDPANDA_BROKERS | Redpanda Cloud brokers | Production |
| SLACK_WEBHOOK | Slack notifications | CD Production |
Configure in GitHub Settings → Branches → Branch protection rules:
# For main branch
- Require pull request before merging
- Require status checks to pass:
- backend-test
- frontend-test
- helm-lint
- Require branches to be up to date
- Require signed commits (optional)
- Include administrators
.github/workflows/ directory created| Issue | Cause | Solution |
|-------|-------|----------|
| Tests fail | Missing env vars | Add to workflow env |
| Push denied | No GHCR permission | Check packages: write |
| Helm deploy fails | Bad values | Run helm template locally |
| K8s auth fails | Bad kubeconfig | Check doctl token |
tools
Implement WebSocket service for real-time task synchronization across clients. Use when building real-time updates for Phase 5. (project)
data-ai
Implement Urdu language support with RTL layout, translations, and AI responses in Urdu. Bonus feature (+100 points) for Phase 5. (project)
development
DEPRECATED - Use chatkit-backend skill instead. SSE streaming is now part of the chatkit-backend skill for ChatKit integration.
development
Install and configure Shadcn/ui component library with Radix UI primitives, Aceternity UI effects, set up components, and manage the component registry. Use when adding Shadcn/ui to a Next.js project or installing specific UI components for Phase 2.