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 - 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: - 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 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 - 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.prod.yaml -f compose.yaml \ $PROFILES up -d --no-build --pull 2>&1 | tee compose.log - |0 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 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 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://hackaton.paas.itqdev.xyz 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