name: Проверка, сборка и развёртывание Magistr

on:
  push:
    branches:
      - main
    tags:
      - 'v*'

concurrency:
  group: magistr-production
  cancel-in-progress: false

env:
  REGISTRY: gitea.zuev.company
  BACKEND_IMAGE: zuev/magistr-backend
  FRONTEND_IMAGE: zuev/magistr-frontend
  MAVEN_IMAGE: maven:3.9.9-eclipse-temurin-17@sha256:f58d59b6273e785ac0a4477f6e9b5ba1d7731c75b906c0f7b34076f1851318cc
  NODE_IMAGE: node:22-alpine3.23@sha256:8516dce0483394d5708d4b2ee6cacb79fb1d617ea4e2787c2120bcca92ce372e
  TRIVY_IMAGE: aquasec/trivy:0.63.0@sha256:6fb0646988fcd2fdf7bf123f7174945ebc2c9c72d1fa1567c8d7daeeb70f8037

jobs:
  checks:
    name: Обязательные проверки
    runs-on: ubuntu-latest
    timeout-minutes: 20
    steps:
      - name: Получить исходный код
        uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1

      - name: Backend unit и component tests
        run: >-
          docker run --rm
          -v "${{ github.workspace }}/backend:/workspace"
          -w /workspace
          "${{ env.MAVEN_IMAGE }}"
          mvn -Dapi.version=1.44 '-Dtest=!*IntegrationTest' test

      - name: Frontend static и unit tests
        run: >-
          docker run --rm
          -v "${{ github.workspace }}/frontend:/workspace"
          -w /workspace
          "${{ env.NODE_IMAGE }}"
          sh -c "npm ci && npm run check"

      - name: Проверить Docker Compose
        env:
          POSTGRES_PASSWORD: ci-config-only
          JWT_SECRET: ci-only-secret-not-for-runtime-0123456789abcdef0123456789abcdef
        run: docker compose config --quiet

      - name: Проверить сценарий immutable rollout и rollback
        run: bash scripts/test-deploy-images.sh

      - name: Проверить закрепление артефактов и supply-chain gates
        run: bash scripts/test-artifact-pinning.sh

  build-and-push-backend:
    name: Собрать backend image
    needs: checks
    runs-on: ubuntu-latest
    timeout-minutes: 30
    outputs:
      digest: ${{ steps.build.outputs.digest }}
    steps:
      - name: Получить исходный код
        uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1

      - name: Войти в Container Registry
        uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.ZUEV_TOKEN }}

      - name: Сформировать immutable tags и labels
        id: meta
        uses: docker/metadata-action@318604b99e75e41977312d83839a89be02ca4893 # v5.9.0
        with:
          images: ${{ env.REGISTRY }}/${{ env.BACKEND_IMAGE }}
          flavor: latest=false
          tags: |
            type=sha,format=long,prefix=sha-
            type=ref,event=tag

      - name: Собрать и опубликовать backend image
        id: build
        uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2
        with:
          context: ./backend
          push: true
          provenance: mode=max
          sbom: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: |
            ${{ steps.meta.outputs.labels }}
            org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}
            org.opencontainers.image.revision=${{ github.sha }}

  build-and-push-frontend:
    name: Собрать frontend image
    needs: checks
    runs-on: ubuntu-latest
    timeout-minutes: 20
    outputs:
      digest: ${{ steps.build.outputs.digest }}
    steps:
      - name: Получить исходный код
        uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1

      - name: Войти в Container Registry
        uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.ZUEV_TOKEN }}

      - name: Сформировать immutable tags и labels
        id: meta
        uses: docker/metadata-action@318604b99e75e41977312d83839a89be02ca4893 # v5.9.0
        with:
          images: ${{ env.REGISTRY }}/${{ env.FRONTEND_IMAGE }}
          flavor: latest=false
          tags: |
            type=sha,format=long,prefix=sha-
            type=ref,event=tag

      - name: Собрать и опубликовать frontend image
        id: build
        uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2
        with:
          context: ./frontend
          push: true
          provenance: mode=max
          sbom: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: |
            ${{ steps.meta.outputs.labels }}
            org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}
            org.opencontainers.image.revision=${{ github.sha }}

  security-scan:
    name: Проверить опубликованные образы
    needs: [build-and-push-backend, build-and-push-frontend]
    runs-on: ubuntu-latest
    timeout-minutes: 20
    env:
      BACKEND_REF: ${{ env.REGISTRY }}/${{ env.BACKEND_IMAGE }}@${{ needs.build-and-push-backend.outputs.digest }}
      FRONTEND_REF: ${{ env.REGISTRY }}/${{ env.FRONTEND_IMAGE }}@${{ needs.build-and-push-frontend.outputs.digest }}
    steps:
      - name: Войти в Container Registry
        uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.ZUEV_TOKEN }}

      - name: Проверить backend на HIGH и CRITICAL уязвимости
        run: >-
          docker run --rm
          -v "$HOME/.docker:/root/.docker:ro"
          "${{ env.TRIVY_IMAGE }}"
          image --scanners vuln --exit-code 1 --severity HIGH,CRITICAL --ignore-unfixed
          "$BACKEND_REF"

      - name: Проверить frontend на HIGH и CRITICAL уязвимости
        run: >-
          docker run --rm
          -v "$HOME/.docker:/root/.docker:ro"
          "${{ env.TRIVY_IMAGE }}"
          image --scanners vuln --exit-code 1 --severity HIGH,CRITICAL --ignore-unfixed
          "$FRONTEND_REF"

  deploy-to-k8s:
    name: Развернуть проверенные digests
    needs: [build-and-push-backend, build-and-push-frontend, security-scan]
    runs-on: ubuntu-latest
    timeout-minutes: 15
    environment: production
    env:
      BACKEND_REF: ${{ env.REGISTRY }}/${{ env.BACKEND_IMAGE }}@${{ needs.build-and-push-backend.outputs.digest }}
      FRONTEND_REF: ${{ env.REGISTRY }}/${{ env.FRONTEND_IMAGE }}@${{ needs.build-and-push-frontend.outputs.digest }}
      KUBECTL_VERSION: v1.33.12
      KUBECTL_SHA256: fe80ae4133b44fa2077db4af144e80765eb1b3b2eede55fbff6933c4374d8c6e
    steps:
      - name: Получить deploy-скрипт
        uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1

      - name: Создать kubeconfig
        env:
          KUBECONFIG_DATA: ${{ secrets.KUBECONFIG_DATA }}
        run: |
          install -d -m 700 "$HOME/.kube"
          printf '%s' "$KUBECONFIG_DATA" | base64 --decode > "$HOME/.kube/config"
          chmod 600 "$HOME/.kube/config"

      - name: Установить проверенный kubectl
        run: |
          curl --fail --show-error --silent --location --retry 3 \
            --output kubectl \
            "https://dl.k8s.io/release/${KUBECTL_VERSION}/bin/linux/amd64/kubectl"
          echo "${KUBECTL_SHA256}  kubectl" | sha256sum --check --strict
          sudo install -m 0755 kubectl /usr/local/bin/kubectl

      - name: Применить digests и проверить rollout
        run: bash scripts/deploy-images.sh "$BACKEND_REF" "$FRONTEND_REF"
