| name | gitlab-ci-patterns |
| type | skill |
| description | GitLab CI/CD pipelines — include templates, environments, OIDC auth, caching, protected runners, deployment gates. |
| related-rules | ["pipeline-standards.md","quality-gates.md"] |
| allowed-tools | Read, Write, Edit |
Skill: GitLab CI Patterns
Expertise: GitLab CI YAML, include/extends, environments, DAST, protected runners, Kubernetes deploy.
When to load
When creating or reviewing .gitlab-ci.yml files for build, test, or deployment pipelines.
Standard Pipeline Structure
stages:
- validate
- build
- scan
- deploy-staging
- smoke-test
- deploy-production
variables:
IMAGE_NAME: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
DOCKER_BUILDKIT: "1"
lint:
stage: validate
image: python:3.12-slim
cache:
key: pip-$CI_COMMIT_REF_SLUG
paths: [.cache/pip]
script:
- pip install ruff mypy --cache-dir .cache/pip
- ruff check src/ tests/
- mypy src/ --strict
test:
stage: validate
image: python:3.12-slim
cache:
key: pip-$CI_COMMIT_REF_SLUG
paths: [.cache/pip]
script:
- pip install -r requirements.txt -r requirements-dev.txt --cache-dir .cache/pip
- pytest tests/ --cov=src --cov-report=xml --cov-fail-under=80
coverage: '/TOTAL.*\s+(\d+%)$/'
artifacts:
reports:
coverage_report:
coverage_format: cobertura
path: coverage.xml
build-image:
stage: build
image: docker:24
services: [docker:24-dind]
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
script:
- docker build --cache-from $CI_REGISTRY_IMAGE:cache
--build-arg BUILDKIT_INLINE_CACHE=1
-t $IMAGE_NAME
-t $CI_REGISTRY_IMAGE:cache .
- docker push $IMAGE_NAME
- docker push $CI_REGISTRY_IMAGE:cache
only: [main, tags]
container-scan:
stage: scan
image:
name: aquasec/trivy:latest
entrypoint: [""]
script:
- trivy image --exit-code 1 --severity CRITICAL,HIGH $IMAGE_NAME
needs: [build-image]
sast:
stage: scan
include:
- template: Security/SAST.gitlab-ci.yml
deploy-staging:
stage: deploy-staging
environment:
name: staging
url: https://staging.example.com
script:
- helm upgrade --install my-service charts/my-service
--set image.tag=$CI_COMMIT_SHA
--namespace staging
--atomic --timeout 5m
only: [main]
smoke-staging:
stage: smoke-test
script:
- curl -f https://staging.example.com/health
needs: [deploy-staging]
only: [main]
deploy-production:
stage: deploy-production
environment:
name: production
url: https://app.example.com
when: manual
allow_failure: false
script:
- helm upgrade --install my-service charts/my-service
--set image.tag=$CI_COMMIT_SHA
--namespace production
--atomic --timeout 5m
only: [main]
needs: [smoke-staging]
Include & Extends (DRY pipelines)
include:
- project: 'infra/ci-templates'
file: '/templates/docker-build.yml'
ref: v1.2.0
- template: Security/SAST.gitlab-ci.yml
.base-deploy:
image: bitnami/helm:3
before_script:
- echo $KUBECONFIG_B64 | base64 -d > /tmp/kubeconfig
- export KUBECONFIG=/tmp/kubeconfig
deploy-staging:
extends: .base-deploy
environment: staging
script: helm upgrade --install ...
Protected Runners (bare-metal / internal registry)
build-internal:
tags:
- self-hosted
- bare-metal
- docker
script: ...
Configure in GitLab → Settings → CI/CD → Runners:
- Protected runners only run on protected branches (main, tags)
- Untagged jobs run on shared runners only