Files
RekomenciBackend/.gitlab-ci.yml
T
2025-11-22 16:43:06 +03:00

407 lines
10 KiB
YAML

stages:
- iac
- build
- test
- security
- tag
- deploy
variables:
BASE_IMAGE_NAME: $CI_REGISTRY_IMAGE
TRIVY_CACHE_DIR: .cache/trivy
TRIVY_NO_PROGRESS: "true"
TRIVY_TIMEOUT: "10m0s"
TRIVY_USERNAME: $CI_REGISTRY_USER
TRIVY_PASSWORD: $CI_REGISTRY_PASSWORD
TRIVY_REGISTRY: $CI_REGISTRY
UV_PROJECT_ENVIRONMENT: .venv
UV_CACHE_DIR: .cache/uv
BUILDAH_ISOLATION: oci
STORAGE_DRIVER: vfs
cache:
key: "${CI_COMMIT_REF_SLUG}"
paths:
- $TRIVY_CACHE_DIR
- $UV_CACHE_DIR
- $UV_PROJECT_ENVIRONMENT
policy: pull-push
.buildah-job: &buildah-job
image: quay.io/containers/buildah:latest
variables:
STORAGE_DRIVER: vfs
before_script:
- buildah login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
.trivy-fs-template: &trivy-fs-scan
stage: security
image:
name: aquasec/trivy:latest
entrypoint: [""]
cache:
paths:
- $TRIVY_CACHE_DIR
policy: pull-push
before_script:
- mkdir -p $TRIVY_CACHE_DIR
script:
- trivy filesystem --skip-files $TRIVY_CACHE_DIR --format cyclonedx --output fs-sbom.json .
- trivy filesystem --skip-files $TRIVY_CACHE_DIR --format sarif --output gl-sast-fs-report.json .
allow_failure: true
artifacts:
reports:
sast: gl-sast-fs-report.json
paths:
- fs-sbom.json
- gl-sast-fs-report.json
expire_in: 1 week
when: always
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_COMMIT_TAG
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'
- if: $SAST_DISABLED
when: never
.trivy-image-template: &trivy-image-scan
stage: security
image:
name: aquasec/trivy:latest
entrypoint: [""]
cache:
paths:
- $TRIVY_CACHE_DIR
policy: pull-push
before_script:
- mkdir -p $TRIVY_CACHE_DIR
script:
- |
trivy image \
--scanners vuln \
--format cyclonedx \
--output image-sbom-${IMAGE_TYPE}.json \
$IMAGE_NAME:$CI_COMMIT_SHA
- |
trivy image \
--format sarif \
--output gl-sast-image-${IMAGE_TYPE}-report.json \
$IMAGE_NAME:$CI_COMMIT_SHA
allow_failure: true
artifacts:
reports:
sast: gl-sast-image-${IMAGE_TYPE}-report.json
paths:
- image-sbom-${IMAGE_TYPE}.json
- gl-sast-image-${IMAGE_TYPE}-report.json
expire_in: 1 week
when: always
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_COMMIT_TAG
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'
- if: $SAST_DISABLED
when: never
.webhook-template: &webhook-config
image: curlimages/curl:latest
script:
- |
curl -sf -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $WEBHOOK_SECRET_TOKEN" \
-H "Webhook-Identifier: $WEBHOOK_BYPASS_TOKEN" \
"$WEBHOOK_URL"
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
when: on_success
.build-template: &build-config
<<: *buildah-job
stage: build
script:
- |
buildah bud \
--tag $IMAGE_NAME:$CI_COMMIT_SHA \
--file $CONTAINERFILE \
--target $BUILDTARGET \
--layers \
--cache-from $IMAGE_NAME-cache \
--cache-to $IMAGE_NAME-cache \
.
- buildah push $IMAGE_NAME:$CI_COMMIT_SHA
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
when: always
- if: $CI_COMMIT_TAG
when: always
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'
when: manual
allow_failure: true
.tag-template: &tag-config
<<: *buildah-job
stage: tag
script:
- |
set -euo pipefail
buildah pull $IMAGE_NAME:$CI_COMMIT_SHA
if [ -n "${CI_COMMIT_TAG:-}" ]; then
buildah tag $IMAGE_NAME:$CI_COMMIT_SHA $IMAGE_NAME:$CI_COMMIT_TAG
buildah push $IMAGE_NAME:$CI_COMMIT_TAG
fi
if [ -n "${CI_COMMIT_BRANCH:-}" ]; then
buildah tag $IMAGE_NAME:$CI_COMMIT_SHA $IMAGE_NAME:$CI_COMMIT_REF_SLUG
buildah push $IMAGE_NAME:$CI_COMMIT_REF_SLUG
if [ "$CI_COMMIT_BRANCH" = "$CI_DEFAULT_BRANCH" ]; then
buildah tag $IMAGE_NAME:$CI_COMMIT_SHA $IMAGE_NAME:latest
buildah push $IMAGE_NAME:latest
fi
fi
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_COMMIT_TAG
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'
when: manual
allow_failure: true
.uv-job: &uv-job
image: debian:trixie-slim
cache:
key: "${CI_JOB_NAME}-${CI_COMMIT_REF_SLUG}"
paths:
- $UV_PROJECT_ENVIRONMENT
- $UV_CACHE_DIR
policy: pull-push
before_script:
- apt-get update
- apt-get install -y --no-install-recommends ca-certificates curl just git
- update-ca-certificates
- curl -LsSf https://astral.sh/uv/install.sh | sh
- export PATH="$HOME/.local/bin:$PATH"
ansible-initvm:
stage: iac
image: alpine/ansible:2.18.6
variables:
ANSIBLE_HOST_KEY_CHECKING: false
before_script:
- apk add openssl
- echo $ENV_PRIVATE_KEY_BASE64 | base64 -d > /id.pem
- chmod 0600 /id.pem
- mv "$INVENTORY_ALPHA_VM" ./infrastructure/iac/ansible/inventory/host_vars/alpha.yaml
- printf "[servers]\nalpha\n" > infrastructure/iac/ansible/inventory/hosts
script:
- cd ./infrastructure/iac/ansible
- ansible-galaxy collection install -r requirements.yaml
- ansible-galaxy install -r requirements.yaml
- ansible-playbook -i inventory/hosts site.yaml
when: manual
build-runtime:
<<: *build-config
variables:
IMAGE_NAME: $BASE_IMAGE_NAME/backend
CONTAINERFILE: Containerfile
BUILDTARGET: runtime
build-tests:
<<: *build-config
variables:
IMAGE_NAME: $BASE_IMAGE_NAME/backend-tests
CONTAINERFILE: Containerfile
BUILDTARGET: tests
build-migrations:
<<: *build-config
variables:
IMAGE_NAME: $BASE_IMAGE_NAME/backend-migrations
CONTAINERFILE: Containerfile
BUILDTARGET: migrations
build-ml:
<<: *build-config
variables:
IMAGE_NAME: $BASE_IMAGE_NAME/ml
CONTAINERFILE: Containerfile.ml
BUILDTARGET: ml
lint:
<<: *uv-job
stage: test
script:
- source $HOME/.local/bin/env
- uv sync --group linters --frozen
- source $UV_PROJECT_ENVIRONMENT/bin/activate
- just lint
allow_failure: true
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'
- if: $CI_COMMIT_TAG
test:
<<: *buildah-job
stage: test
variables:
COMPOSE_PROFILES: |
--profile migrations
--profile tests
PODMAN_IGNORE_CGROUPSV1_WARNING: True
script:
- dnf -y install podman podman-compose
# - cp ./infrastructure/configs/podman/ci.conf /etc/containers/containers.conf
- cp "$TEST_STAGE_FIREBASE_CONF" ./infrastructure/configs/backend/firebase.json
- podman info --format '{{.Host.EventLogger}}'
- export PROFILES="$(printf '%s ' $COMPOSE_PROFILES)"
- |
(
while true; do
podman-compose -f compose.yaml $PROFILES logs 2>&1
sleep 30
done
) | grep "Error: no container" -v | tee -a compose.log &
- LOGS_PID=$!
- |
(
while true; do
echo "Containers $(date)"
podman ps -a
sleep 10
done
) &
- |
REGISTRY_PREFIX=$CI_REGISTRY_IMAGE IMAGE_TAG=$CI_COMMIT_SHA \
podman-compose -f compose.yaml -f compose.prod.yaml \
$PROFILES up -d --no-build --pull 2>&1 | tee compose.log
TEST_CONTAINER_ID=$(
podman-compose ps --all --format json \
| jq -r '.[] | select(.Labels["io.podman.compose.service"] == "tests") | .Id'
)
if [ -z "$TEST_CONTAINER_ID" ]; then
echo "Tests container not found."
exit 1
fi
timeout 600 podman wait "$TEST_CONTAINER_ID"
TEST_EXIT_CODE=$(podman inspect --format "{{.State.ExitCode}}" "$TEST_CONTAINER_ID")
if [ "$TEST_EXIT_CODE" -eq 0 ]; then
echo "Tests passed."
else
echo "Tests failed with exit code $TEST_EXIT_CODE."
exit 1
fi
- |
podman-compose -f compose.yaml $PROFILES down
- cat .cov/coverage.txt
artifacts:
paths:
- ./.cov
- ./compose.log
reports:
coverage_report:
coverage_format: cobertura
path: .cov/coverage.xml
expire_in: 1 week
when: always
coverage: /TOTAL.*? (100(?:\.0+)?\%|[1-9]?\d(?:\.\d+)?\%)$/
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'
dependencies:
- build-runtime
- build-tests
- build-migrations
sast-filesystem:
<<: *trivy-fs-scan
sast-image-runtime:
<<: *trivy-image-scan
variables:
IMAGE_NAME: $BASE_IMAGE_NAME/backend
IMAGE_TYPE: runtime
dependencies:
- build-runtime
sast-image-tests:
<<: *trivy-image-scan
variables:
IMAGE_NAME: $BASE_IMAGE_NAME/backend-tests
IMAGE_TYPE: tests
dependencies:
- build-tests
sast-image-migrations:
<<: *trivy-image-scan
variables:
IMAGE_NAME: $BASE_IMAGE_NAME/backend-migrations
IMAGE_TYPE: migrations
dependencies:
- build-migrations
sast-image-ml:
<<: *trivy-image-scan
variables:
IMAGE_NAME: $BASE_IMAGE_NAME/ml
IMAGE_TYPE: ml
dependencies:
- build-ml
tag-runtime:
<<: *tag-config
variables:
IMAGE_NAME: $BASE_IMAGE_NAME/backend
tag-tests:
<<: *tag-config
variables:
IMAGE_NAME: $BASE_IMAGE_NAME/backend-tests
tag-migrations:
<<: *tag-config
variables:
IMAGE_NAME: $BASE_IMAGE_NAME/backend-migrations
tag-ml:
<<: *tag-config
variables:
IMAGE_NAME: $BASE_IMAGE_NAME/ml
webhook-migrations-deploy:
<<: *webhook-config
stage: deploy
variables:
WEBHOOK_URL: $WEBHOOK_URL_MIGRATIONS
resource_group: staging
dependencies:
- build-migrations
- sast-image-migrations
webhook-backend-deploy:
<<: *webhook-config
stage: deploy
variables:
WEBHOOK_URL: $WEBHOOK_URL_BACKEND
environment:
name: staging
url: https://team-39-alpha-gm5qjkou.hack.prodcontest.ru
resource_group: staging
dependencies:
- build-runtime
- sast-image-runtime
workflow:
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_COMMIT_TAG