diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a5a3b9f..c354353 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -147,7 +147,7 @@ cache: 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 @@ -191,13 +191,14 @@ ansible-initvm: ANSIBLE_HOST_KEY_CHECKING: false before_script: - 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 apps.yaml + - ansible-playbook -i inventory/hosts site.yaml when: manual build-runtime: @@ -235,61 +236,70 @@ lint: - if: $CI_PIPELINE_SOURCE == 'merge_request_event' - if: $CI_COMMIT_TAG -# test: -# <<: *docker-job -# stage: test -# variables: -# COMPOSE_PROFILES: | -# --profile migrations -# --profile tests -# script: -# - apk add --no-cache docker-compose -# - export PROFILES="$(printf '%s ' $COMPOSE_PROFILES)" -# - cp "$TEST_STAGE_FIREBASE_CONF" ./infrastructure/configs/backend/firebase.json -# - | -# ( -# while true; do -# docker compose -f compose.yaml $PROFILES logs -f 2>&1 -# sleep 1 -# done -# ) | tee -a compose.log & -# - LOGS_PID=$! -# - | -# REGISTRY_PREFIX=$CI_REGISTRY_IMAGE IMAGE_TAG=$CI_COMMIT_SHA \ -# docker compose -f compose.yaml -f compose.prod.yaml \ -# $PROFILES up -d --quiet-pull --quiet-build 2>&1 | tee compose.log -# - | -# TEST_CONTAINER_ID=$(docker compose -f compose.yaml $PROFILES ps -q tests -a) -# timeout 600 docker wait $TEST_CONTAINER_ID -# TEST_EXIT_CODE=$(docker inspect --format "{{.State.ExitCode}}" $TEST_CONTAINER_ID) +test: + <<: *buildah-job + stage: test + variables: + COMPOSE_PROFILES: | + --profile migrations + --profile tests + script: + - apk add --no-cache podman podman-compose + - export PROFILES="$(printf '%s ' $COMPOSE_PROFILES)" + - cp "$TEST_STAGE_FIREBASE_CONF" ./infrastructure/configs/backend/firebase.json + - | + ( + while true; do + podman-compose -f compose.yaml $PROFILES logs -f 2>&1 + sleep 1 + done + ) | tee -a compose.log & + - LOGS_PID=$! + - | + REGISTRY_PREFIX=$CI_REGISTRY_IMAGE IMAGE_TAG=$CI_COMMIT_SHA \ + podman-compose -f compose.yaml -f compose.prod.yaml \ + $PROFILES up -d 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 [ $TEST_EXIT_CODE -eq 0 ]; then -# echo "Tests passed." -# else -# echo "Tests failed with exit code $TEST_EXIT_CODE." -# exit 1 -# fi -# - | -# docker 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 + 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 diff --git a/compose.yaml b/compose.yaml index eefa828..93ac88b 100644 --- a/compose.yaml +++ b/compose.yaml @@ -27,6 +27,13 @@ services: required: true - path: ./infrastructure/configs/backend/.env required: false + healthcheck: + test: [ "CMD", "curl", "-fsS", "http://localhost:8080/healthcheck" ] + interval: 5s + timeout: 4s + start_period: 5s + start_interval: 2s + retries: 5 networks: - default ports: @@ -44,13 +51,13 @@ services: target: /app/config.toml read_only: true bind: - selinux: Z + selinux: z - type: bind source: ./infrastructure/configs/backend/firebase.json target: /app/firebase.json read_only: true bind: - selinux: Z + selinux: z tests: build: @@ -60,28 +67,35 @@ services: tags: - template-project-tests:latest pull: true - # depends_on: - # backend: - # restart: false - # condition: service_healthy - # required: true - # migrations: - # restart: false - # condition: service_completed_successfully - # required: true - # postgres: - # restart: false - # condition: service_healthy - # required: true - # redis: - # restart: false - # condition: service_healthy - # required: true + depends_on: + backend: + restart: false + condition: service_healthy + required: true + migrations: + restart: false + condition: service_completed_successfully + required: true + postgres: + restart: false + condition: service_healthy + required: true + redis: + restart: false + condition: service_healthy + required: true env_file: - path: ./infrastructure/configs/backend/.env.template required: true - path: ./infrastructure/configs/backend/.env required: false + healthcheck: + test: [ "CMD", "pg_isready", "-U", "postgres", "--dbname=postgres" ] + interval: 5s + timeout: 4s + start_period: 5s + start_interval: 2s + retries: 5 networks: - default profiles: @@ -91,12 +105,15 @@ services: - type: bind source: ./infrastructure/configs/backend/config.toml target: /app/config.toml - read_only: false + read_only: true bind: - selinux: Z + selinux: z - type: bind source: ./.cov target: /app/cov + read_only: false + bind: + selinux: z migrations: build: @@ -127,13 +144,13 @@ services: target: /app/config.toml read_only: false bind: - selinux: Z + selinux: z - type: bind source: ./alembic.ini target: /app/alembic.ini read_only: true bind: - selinux: Z + selinux: z postgres: image: docker.io/postgres:17-alpine @@ -160,7 +177,7 @@ services: target: /etc/postgresql/postgresql.conf read_only: true bind: - selinux: Z + selinux: z - type: volume source: postgres_data target: /var/lib/postgresql/data @@ -203,7 +220,7 @@ services: target: /pgadmin4/servers.json read_only: true bind: - selinux: Z + selinux: z - type: volume source: pgadmin_data target: /var/lib/pgadmin @@ -233,7 +250,7 @@ services: target: /usr/local/etc/redis/redis.conf read_only: true bind: - selinux: Z + selinux: z - type: volume source: redis_data target: /data