ci-cd
SkillCloud & infraCI/CD pipeline design: GitHub Actions, GitLab CI, multi-stage Docker builds, image scanning, SBOM attestation (Cosign keyless), and environment promotion. Layered by complexity — Level 0 (all projects), Level 1 (containerized), Level 2 (Kubernetes). GitOps and Kubernetes deployment patterns in references/gitops-kubernetes.md.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the ci-cd skill
What this skill tells your AI
The instructions your AI receives, as published by irahardianto/awesome-agv in .agents/skills/ci-cd/SKILL.md and read by ahel’s review.
CI/CD Principles
Agent scope: This rule applies when writing CI/CD manifests (Dockerfile, docker-compose, GitHub Actions, GitLab CI, etc.). It is layered by deployment complexity — apply only the levels relevant to the project.
Deployment Complexity Levels
| Level | Applies When | Key Additions |
|---|---|---|
| 0 — All projects | Always | Lint, test, security scan, secrets management |
| 1 — Containerized | Docker image is the artifact | Multi-stage build, image scan, SBOM attestation |
| 2 — Orchestrated | Kubernetes or managed container platform | Deployment strategies, GitOps |
Load supplementary rules when reaching Level 2:
- Deployment strategies + GitOps → references/gitops-kubernetes.md
Level 0 — Universal Pipeline Design
Pipeline Stages (in order):
- Lint — static analysis, formatting checks
- Build — compile, bundle, generate artifacts
- Unit Test — fast tests with mocked dependencies
- Integration Test — tests against real dependencies (Testcontainers)
- Security Scan — dependency audit, SAST, secrets detection
- Deploy — push to target environment
Rules:
- Fail fast — run cheapest checks first (lint before build, build before test)
- Pipeline must be deterministic — same input = same output, every time
- Keep pipelines under 15 minutes — optimize slow stages
- Never skip failing steps — fix the pipeline, don't bypass it
- Build once, deploy many — same artifact promotes through all environments
Level 0 — Deploy Target Examples
The deploy stage varies by target. The pipeline stages before it are identical.
Docker Compose (local / staging):
docker compose up --build
Cloud Run:
gcloud run deploy myapp \
--image gcr.io/project/myapp:$GIT_SHA \
--region us-central1
Vercel (frontend SPA):
vercel deploy --prod
Kubernetes: Use GitOps — see references/gitops-kubernetes.md.
Level 0 — Manifest Patterns
GitHub Actions
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: go.mod # Pin via go.mod
cache: true # Cache dependencies
- run: gofumpt -l -e -d .
- run: go vet ./...
- run: staticcheck ./...
test:
needs: lint # Fail fast: lint before test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: go.mod
cache: true
- run: go test -race -cover ./...
security:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Scan for secrets
uses: trufflesecurity/trufflehog@v3 # Pin to release tag
- name: Audit dependencies
run: go run golang.org/x/vuln/cmd/govulncheck@latest ./...
Rules:
- Pin action versions (
@v4, not@latestor@main) - Use
needs:to enforce stage ordering - Cache dependencies (
cache: truein setup actions) - Use
go-version-file/node-version-fileinstead of hardcoding versions - Never put secrets in workflow files — use
${{ secrets.NAME }}
Level 1 — Containerized Projects
Dockerfile (Multi-Stage Build)
# Stage 1: Build
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download # Cache dependencies
COPY . .
RUN CGO_ENABLED=0 go build -o /bin/api ./cmd/api
# Stage 2: Runtime (minimal image)
FROM gcr.io/distroless/static-debian12
COPY --from=builder /bin/api /bin/api
EXPOSE 8080
CMD ["/bin/api"]
Rules:
- Always use multi-stage builds (build → runtime)
- Pin base image versions (never use
:latest) - Copy dependency files first, then source (layer caching)
- Use minimal runtime images (distroless, alpine, scratch)
- Never copy
.env, secrets, or.gitinto images
Docker Compose (Local Development)
services:
backend:
build:
context: ./apps/backend # Path per project-structure.md
ports:
- "8080:8080"
env_file: .env # Environment config
depends_on:
postgres:
condition: service_healthy
postgres:
image: postgres:16-alpine # Pin versions
environment:
POSTGRES_DB: ${DB_NAME}
POSTGRES_USER: ${DB_USER}
POSTGRES_PASSWORD: ${DB_PASSWORD}
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DB_USER}"]
interval: 5s
timeout: 5s
retries: 5
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:
Rules:
- Always define health checks for dependencies
- Use
depends_onwithcondition: service_healthy - Pin all image versions
- Use volumes for persistent data
- Never hardcode credentials — use env_file or environment variables
Image Scan + SBOM Attestation
After building and pushing a container image, scan it and attach a signed SBOM attestation.
Preferred approach: Cosign keyless signing (no key management required)
Cosign integrates with your CI provider's OIDC token (GitHub Actions, GitLab CI) to sign images and attestations without storing or rotating cryptographic keys. The signature is anchored to a transparency log (Rekor), making it auditable and policy-enforceable.
build:
needs: security
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
id-token: write # Required for Cosign keyless signing
steps:
- uses: actions/checkout@v4
- name: Install Cosign
uses: sigstore/cosign-installer@v3
- name: Build and push image
id: build
run: |
docker build -t ghcr.io/${{ github.repository }}:${{ github.sha }} .
docker push ghcr.io/${{ github.repository }}:${{ github.sha }}
- name: Scan container image
run: |
trivy image \
--severity HIGH,CRITICAL \
--exit-code 1 \
ghcr.io/${{ github.repository }}:${{ github.sha }}
- name: Generate SBOM
run: |
syft ghcr.io/${{ github.repository }}:${{ github.sha }} \
-o cyclonedx-json > sbom.json
- name: Attest SBOM to image (keyless, OIDC-backed)
run: |
cosign attest \
--predicate sbom.json \
--type cyclonedx \
ghcr.io/${{ github.repository }}:${{ github.sha }}
# Cosign uses the GitHub Actions OIDC token automatically.
# No COSIGN_PASSWORD or secret keys required.
How the SBOM travels with the image:
The SBOM attestation is stored as an OCI reference in the same container registry alongside the image digest. It requires no additional infrastructure — any registry that supports OCI artifacts (ghcr.io, Google Artifact Registry, AWS ECR, Docker Hub) works out of the box.
To verify the attestation at any time:
cosign verify-attestation \
--type cyclonedx \
ghcr.io/org/app@sha256:<digest>
Use ORAS instead of Cosign when:
- You need to attach arbitrary supply chain artifacts (scan reports, provenance JSON, build logs) that go beyond what Cosign's attestation model covers.
oras attach ghcr.io/org/app@sha256:<digest> scan-report.json
Rules:
- Prefer Cosign keyless signing — eliminates secret key management overhead
- SBOM is attached to the image in the OCI registry — not stored as a CI artifact
- Scan BEFORE attesting — the SBOM reflects the scanned image
- For non-containerized apps (Vercel, Netlify frontend), use
npm audit/yarn auditinstead; no SBOM attachment applies
Deployment vs Release (Feature Flags)
Code deployment and feature release are separate concerns. When the PRD or technical architecture explicitly requires gradual rollout, A/B testing, or kill switches, feature flags can decouple them.
Agent rule: Do NOT implement feature flags unless explicitly required by the PRD or technical architecture document. See @.agents/skills/feature-flags/SKILL.md for implementation guidance when they are required.
Environment Promotion
dev → staging → production
- Dev: Deployed on every push to feature branch
- Staging: Deployed on merge to main/develop
- Production: Deployed via manual approval or automated release
Rules:
- Same artifacts promote through environments (build once, deploy many)
- Environment-specific config via environment variables, not build flags
- Never deploy directly to production without staging validation
CI/CD Checklist
Always (all projects):
- Pipeline stages run in correct order (lint → build → test → security → deploy)?
- All versions pinned (base images, CI actions, tool versions)?
- Dependency caching enabled?
- No secrets in config files (use env vars or secrets manager)?
- Secret scanning in CI?
- Health checks defined for all service dependencies?
- Pipeline completes in under 15 minutes?
If building container images (Level 1):
- Multi-stage Docker builds used?
- Container image scanned for HIGH/CRITICAL CVEs?
- SBOM generated and attested to image via Cosign (keyless)?
If deploying to Kubernetes (Level 2):
- Deployment strategy defined (blue-green, canary, or rolling)?
- GitOps in place — no direct
kubectl applyin production? - Secrets reference external store, not plaintext in git?
- See references/gitops-kubernetes.md for full checklist
If feature flags are required by PRD/architecture:
- Flag infrastructure specified in tech architecture document?
- Every flag has an owner and expiry date?
- See @.agents/skills/feature-flags/SKILL.md for full checklist
Related Principles
- Code Idioms and Conventions @code-idioms-and-conventions.md (validation before ship)
- Security Mandate @security-mandate.md (secrets management)
- Security Principles @security-principles.md (image scanning, SBOM)
- Git Workflow Principles @git-workflow-principles.md (branch strategy)
- Project Structure @project-structure.md (service paths)
- Testing Strategy @testing-strategy.md (unit and integration test stages)
- GitOps + Kubernetes Deployment references/gitops-kubernetes.md
- Feature Flags @.agents/skills/feature-flags/SKILL.md
- Rule Priority @.agents/rules/rule-priority.md
Signals
- GitHub stars
- 156
- Forks
- 53
- Last commit
- Aug 2026
Advanced
- Catalog kind
- skill
- Gateway key
ci-cd-irahardianto- Source
- github.com/irahardianto/awesome-agv