name: concrete-compiler publish docker images

on:
  workflow_dispatch:
  push:
    branches:
      - 'main'
      - 'force-docker-images'

env:
  ACTION_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
  SLACK_CHANNEL: ${{ secrets.SLACK_CHANNEL }}
  SLACK_USERNAME: ${{ secrets.BOT_USERNAME }}
  SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
  THIS_FILE: .github/workflows/concrete_compiler_publish_docker_images.yml
  TRIVY_DB_REPOSITORY: public.ecr.aws/aquasecurity/trivy-db:2
  TRIVY_JAVA_DB_REPOSITORY: public.ecr.aws/aquasecurity/trivy-java-db:1

concurrency:
  group: concrete_compiler_publish_docker_images
  cancel-in-progress: true

jobs:
  setup-instance:
    runs-on: ubuntu-latest
    outputs:
      runner-name: ${{ steps.start-instance.outputs.label }}
    steps:
      - name: Start instance
        id: start-instance
        uses: zama-ai/slab-github-runner@f26b8d611b2e695158fb0a6980834f0612f65ef8 # v1.4.0
        with:
          mode: start
          github-token: ${{ secrets.SLAB_ACTION_TOKEN }}
          slab-url: ${{ secrets.SLAB_BASE_URL }}
          job-secret: ${{ secrets.JOB_SECRET }}
          backend: aws
          profile: cpu-test

  # Not sure what to do about this one...
  hpx-image:
    needs: [setup-instance]
    runs-on: ${{ needs.setup-instance.outputs.runner-name }}
    env:
      image: ghcr.io/zama-ai/hpx
      dockerfile: docker/Dockerfile.hpx-env
    steps:
      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
        with:
          fetch-depth: 0
      - name: Get changed files
        id: changed-files
        uses: tj-actions/changed-files@bab30c2299617f6615ec02a68b9a40d10bd21366 # v44.5.24
      - name: Login
        id: login
        if: contains(steps.changed-files.outputs.modified_files, env.dockerfile) || contains(steps.changed-files.outputs.modified_files, env.THIS_FILE)
        run: echo "${{ secrets.GHCR_PASSWORD }}" | docker login -u ${{ secrets.GHCR_LOGIN }} --password-stdin ghcr.io
      - name: Build
        if: ${{ steps.login.conclusion != 'skipped' }}
        run: docker build -t "${{ env.image }}" -f ${{ env.dockerfile }} .
      - name: Run Trivy vulnerability scanner
        if: ${{ steps.login.conclusion != 'skipped' }}
        uses: aquasecurity/trivy-action@18f2510ee396bbf400402947b394f2dd8c87dbb0 # 0.29.0
        with:
          image-ref: '${{ env.image }}'
          format: 'sarif'
          scanners: vuln,secret
          output: trivy-out-docker.sarif
      - name: Upload Trivy scan results to GitHub Security tab
        if: ${{ steps.login.conclusion != 'skipped' }}
        uses: github/codeql-action/upload-sarif@86b04fb0e47484f7282357688f21d5d0e32175fe # v3.27.6
        with:
          sarif_file: trivy-out-docker.sarif
          category: trivy-docker
      - name: Publish
        if: ${{ steps.login.conclusion != 'skipped' }}
        run: docker push "${{ env.image }}:latest"
      - name: Slack Notification
        if: ${{ failure() && github.ref == 'refs/heads/main' }}
        continue-on-error: true
        uses: rtCamp/action-slack-notify@c33737706dea87cd7784c687dadc9adf1be59990
        env:
          SLACK_COLOR: ${{ job.status }}
          SLACK_MESSAGE: "hpx-image finished with status: ${{ job.status }}. (${{ env.ACTION_RUN_URL }})"

  cuda-image:
    needs: [setup-instance]
    runs-on: ${{ needs.setup-instance.outputs.runner-name }}
    env:
      image: ghcr.io/zama-ai/cuda
    strategy:
      matrix:
        include:
          - name: cuda-12-3
            tag: 12-3
            dockerfile: docker/Dockerfile.cuda-123-env
          - name: cuda-11-8
            tag: 11-8
            dockerfile: docker/Dockerfile.cuda-118-env
    steps:
      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
        with:
          fetch-depth: 0
      - name: Set up env
        run: |
          echo "HOME=/home/ubuntu" >> "${GITHUB_ENV}"
      - name: Get changed files
        id: changed-files
        uses: tj-actions/changed-files@bab30c2299617f6615ec02a68b9a40d10bd21366 # v44.5.24
      - name: Login
        id: login
        # from the docs: The jobs.<job_id>.if condition is evaluated before jobs.<job_id>.strategy.matrix is applied. So we can't just use matrix.dockerfile
        # so we have to build both images if one of the two files change, or we will have to split this into two
        # https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#jobsjob_idif
        if: contains(steps.changed-files.outputs.modified_files, 'docker/Dockerfile.cuda-118-env') || contains(steps.changed-files.outputs.modified_files, 'docker/Dockerfile.cuda-123-env') || contains(steps.changed-files.outputs.modified_files, env.THIS_FILE)
        run: echo "${{ secrets.GHCR_PASSWORD }}" | docker login -u ${{ secrets.GHCR_LOGIN }} --password-stdin ghcr.io
      - name: Build Tag and Publish
        if: ${{ steps.login.conclusion != 'skipped' }}
        run: |
          docker build -t "${{ env.image }}" -f ${{ matrix.dockerfile }} .
          docker image tag "${{ env.image }}" "${{ env.image }}:${{ matrix.tag }}"
          docker push "${{ env.image }}:${{ matrix.tag }}"
      - name: Run Trivy vulnerability scanner
        if: ${{ steps.login.conclusion != 'skipped' }}
        uses: aquasecurity/trivy-action@18f2510ee396bbf400402947b394f2dd8c87dbb0 # 0.29.0
        with:
          image-ref: '${{ env.image }}'
          format: 'sarif'
          scanners: vuln,secret
          output: trivy-out-docker.sarif
      - name: Upload Trivy scan results to GitHub Security tab
        if: ${{ steps.login.conclusion != 'skipped' }}
        uses: github/codeql-action/upload-sarif@86b04fb0e47484f7282357688f21d5d0e32175fe # v3.27.6
        with:
          sarif_file: trivy-out-docker.sarif
          category: trivy-docker
      - name: Push Latest Image
        if: ${{ steps.login.conclusion != 'skipped' && matrix.tag == '11-8' }}
        run: docker push "${{ env.image }}:latest"
      - name: Slack Notification
        if: ${{ failure() && github.ref == 'refs/heads/main' }}
        continue-on-error: true
        uses: rtCamp/action-slack-notify@c33737706dea87cd7784c687dadc9adf1be59990
        env:
          SLACK_COLOR: ${{ job.status }}
          SLACK_MESSAGE: "cuda-image finished with status: ${{ job.status }}. (${{ env.ACTION_RUN_URL }})"

  compiler-image:
    needs: [setup-instance, hpx-image, cuda-image]
    runs-on: ${{ needs.setup-instance.outputs.runner-name }}
    env:
      image: ghcr.io/zama-ai/concrete-compiler
      dockerfile: docker/Dockerfile.concrete-compiler-env
    steps:
      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
        with:
          fetch-depth: 0
          submodules: recursive
      - name: Get changed files
        id: changed-files
        uses: tj-actions/changed-files@bab30c2299617f6615ec02a68b9a40d10bd21366 # v44.5.24
        with:
          files: |
            backends/**
            compilers/**
            third_party/**
            tools/**
            docker/**
      - name: Login to Registry
        id: login
        if: steps.changed-files.outputs.any_changed == 'true'
        run: echo "${{ secrets.GHCR_PASSWORD }}" | docker login -u ${{ secrets.GHCR_LOGIN }} --password-stdin ghcr.io
      - name: Build Image
        if: steps.login.conclusion != 'skipped'
        run: |
          DOCKER_BUILDKIT=1 docker build --no-cache \
            --label "commit-sha=${{ github.sha }}" -t ${{ env.image }} -f ${{ env.dockerfile }} .
      - name: Run Trivy vulnerability scanner
        uses: aquasecurity/trivy-action@18f2510ee396bbf400402947b394f2dd8c87dbb0 # 0.29.0
        if: steps.login.conclusion != 'skipped'
        with:
          image-ref: '${{ env.image }}'
          format: 'sarif'
          scanners: vuln,secret
          output: trivy-out-docker.sarif
      - name: Upload Trivy scan results to GitHub Security tab
        if: steps.login.conclusion != 'skipped'
        uses: github/codeql-action/upload-sarif@86b04fb0e47484f7282357688f21d5d0e32175fe # v3.27.6
        with:
          sarif_file: trivy-out-docker.sarif
          category: trivy-docker
      - name: Tag and Publish Image
        if: steps.login.conclusion != 'skipped'
        run: |
          docker image tag ${{ env.image }} ${{ env.image }}:${{ github.sha }}
          docker image push ${{ env.image }}:latest
          docker image push ${{ env.image }}:${{ github.sha }}
      - name: Tag and Publish Release Image
        if: steps.login.conclusion != 'skipped' && startsWith(github.ref, 'refs/tags/v')
        run: |
          docker image tag ${{ env.image }} ${{ env.image }}:${{ github.ref_name }}
          docker image push ${{ env.image }}:${{ github.ref_name }}
      - name: Slack Notification
        if: ${{ failure() && github.ref == 'refs/heads/main' }}
        continue-on-error: true
        uses: rtCamp/action-slack-notify@c33737706dea87cd7784c687dadc9adf1be59990
        env:
          SLACK_COLOR: ${{ job.status }}
          SLACK_MESSAGE: "compiler-image finished with status: ${{ job.status }}. (${{ env.ACTION_RUN_URL }})"

  teardown-instance:
    name: Teardown instance
    needs: [ setup-instance, compiler-image ]
    if: ${{ always() && needs.setup-instance.result != 'skipped' }}
    runs-on: ubuntu-latest
    steps:
      - name: Stop instance
        id: stop-instance
        uses: zama-ai/slab-github-runner@f26b8d611b2e695158fb0a6980834f0612f65ef8 # v1.4.0
        with:
          mode: stop
          github-token: ${{ secrets.SLAB_ACTION_TOKEN }}
          slab-url: ${{ secrets.SLAB_BASE_URL }}
          job-secret: ${{ secrets.JOB_SECRET }}
          label: ${{ needs.setup-instance.outputs.runner-name }}
      - name: Slack Notification
        if: ${{ failure() }}
        continue-on-error: true
        uses: rtCamp/action-slack-notify@c33737706dea87cd7784c687dadc9adf1be59990
        env:
          SLACK_COLOR: ${{ job.status }}
          SLACK_MESSAGE: "Instance teardown finished with status: ${{ job.status }}. (${{ env.ACTION_RUN_URL }})"
