name: "Build and test Drakvuf Sandbox"
on:
  push:
    branches:
    - master
  pull_request:
    branches:
    - master
jobs:
  build_docs:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Set up Python 3.8
        uses: actions/setup-python@v4
        with:
          python-version: 3.8
      - name: Install dependencies
        working-directory: docs
        run: pip install -r requirements.txt
      - name: Build docs
        working-directory: docs
        run: make html
  lint_drakrun_frontend:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Install web dependencies
        working-directory: drakrun/drakrun/web/frontend
        run: npm ci
      - name: Check with prettier
        working-directory: drakrun/drakrun/web/frontend
        run: npx prettier --check src/
  lint_drakrun:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: CERT-Polska/lint-python-action@v2
        with:
          python-version: 3.8
          working-directory: drakrun
  package_drakvuf_bundle:
    strategy:
      fail-fast: false
      matrix:
        include:
          - distro: debian
            version: bullseye
    runs-on: ubuntu-latest
    container: "${{ matrix.distro }}:${{matrix.version}}"
    steps:
      - name: Install git and wget
        run: |
          export DEBIAN_FRONTEND=noninteractive
          apt-get update && apt-get install -y -q git wget
      - uses: actions/checkout@v3
        with:
          submodules: recursive
      - name: Get Drakvuf commit id
        run: |
          # Workaround for fatal: detected dubious ownership
          # https://git-scm.com/docs/git-config/2.35.2#Documentation/git-config.txt-safedirectory
          git config --global --add safe.directory "$(pwd)"
          export DRAKVUF_COMMIT=$(git ls-tree HEAD drakvuf | awk '{ print $3 }')
          echo "Drakvuf commit is ${DRAKVUF_COMMIT}"
          echo "DRAKVUF_COMMIT=$DRAKVUF_COMMIT" >> $GITHUB_ENV
      - name: Restored cached Drakvuf bundle
        id: cache-drakvuf-bundle-restore
        uses: actions/cache/restore@v3
        with:
          path: |
            /out/drakvuf-bundle*.deb 
            /build/usr/lib/libvmi*
            /build/usr/include/libvmi/*
          key: drakvuf-bundle-${{ env.DRAKVUF_COMMIT }}-${{ matrix.distro }}-${{ matrix.version }}
      - if: ${{ steps.cache-drakvuf-bundle-restore.outputs.cache-hit != 'true' }}
        name: Build Drakvuf bundle
        run: |
          cp -ra . /build
          cd /build
          sh drakvuf/package/depends.sh
          bash ci/build_bundle.sh "${{ matrix.distro }}:${{matrix.version}}"
          ls -r /out
      - if: ${{ steps.cache-drakvuf-bundle-restore.outputs.cache-hit != 'true' }}
        name: Save Drakvuf bundle cache
        id: cache-drakvuf-bundle-save
        uses: actions/cache/save@v3
        with:
          path: |
            /out/drakvuf-bundle*.deb 
            /build/usr/lib/libvmi*
            /build/usr/include/libvmi/*
          key: drakvuf-bundle-${{ env.DRAKVUF_COMMIT }}-${{ matrix.distro }}-${{ matrix.version }}
      - name: Build draksetup tools
        run: |
          apt install -y make pkg-config gcc libglib2.0-dev libjson-c-dev
          cp -v /build/usr/lib/libvmi* /usr/lib/
          mkdir /usr/include/libvmi
          cp -v /build/usr/include/libvmi/* /usr/include/libvmi/
          make -C ./drakrun/drakrun/tools
      - uses: actions/upload-artifact@v4
        with:
          name: drakvuf-bundle-debs-${{ matrix.distro }}-${{ matrix.version }}
          path: |
            /out/drakvuf-bundle*.deb
      - uses: actions/upload-artifact@v4
        with:
          name: draksetup-tools-${{ matrix.distro }}-${{ matrix.version }}
          path: |
            drakrun/drakrun/tools/*
  package_drakrun:
    needs: [ package_drakvuf_bundle ]
    runs-on: ubuntu-latest
    container: "python:3.8"
    steps:
      - uses: actions/checkout@v3
        with:
          submodules: recursive
      - name: Use Node.js 16.x
        uses: actions/setup-node@v4
        with:
          node-version: '16'
      - name: Download draksetup compiled tools from artifacts
        uses: actions/download-artifact@v4
        with:
          name: draksetup-tools-debian-bullseye
          path: drakrun/drakrun/tools
      - name: Build drakrun
        run: |
          chmod +x drakrun/drakrun/tools/*  # gh artifacts don't keep file permissions
          cd drakrun
          make DIST=1
      - uses: actions/upload-artifact@v4
        with:
          name: drakvuf-sandbox-whl
          path: ./drakrun/dist/drakvuf_sandbox-*.whl
  test_e2e:
    needs: [ package_drakrun, package_drakvuf_bundle ]
    strategy:
      fail-fast: false
      matrix:
        include:
          - distro: debian
            version: bullseye
            version_number: 11
    runs-on: self-hosted
    container: python:3.8-bullseye
    # Prevent concurrent jobs trying to reach the same VM
    concurrency: ci-${{ github.ref }}-${{ matrix.distro }}-${{ matrix.version_number }}
    steps:
      - uses: actions/checkout@v3
        with:
          submodules: recursive
      - name: Download drakrun debs from artifacts
        uses: actions/download-artifact@v4
        with:
          name: drakvuf-sandbox-whl
          path: /debs
      - name: Download drakvuf-bundle debs from artifacts
        uses: actions/download-artifact@v4
        with:
          name: drakvuf-bundle-debs-${{ matrix.distro }}-${{ matrix.version }}
          path: /debs
      - name: Install git
        run: |
          export DEBIAN_FRONTEND=noninteractive
          apt-get update && apt-get install -y -q git
      - name: Restore cached MinIO server
        id: cache-minio-server-restore
        uses: actions/cache/restore@v3
        with:
          path: |
            /tmp/minio
          key: minio-server-bin
      - if: ${{ steps.cache-minio-server-restore.outputs.cache-hit != 'true' }}
        name: Download MinIO server
        run: |
          wget https://dl.min.io/server/minio/release/linux-amd64/minio -O /tmp/minio
      - if: ${{ steps.cache-minio-server-restore.outputs.cache-hit != 'true' }}
        name: Save cached MinIO server
        id:  cache-minio-server-save
        uses: actions/cache/save@v3
        with:
          path: |
            /tmp/minio
          key: minio-server-bin
      - name: Start tests
        run: |
          git config --global --add safe.directory "$(pwd)"
          cd test
          pip install -r requirements.txt
          pytest -v --capture=no
          python3 -m vm_runner_client destroy
        env:
          DRAKVUF_DEBS_PATH: "/debs"
          BASE_IMAGE: "${{ matrix.distro }}-${{ matrix.version_number }}-generic-amd64"
          SNAPSHOT_VERSION: "win7-20210922"
          MINIO_HOST: "192.168.100.1:8181"
          MINIO_SERVER_BIN_PATH: "/tmp/minio"
          VM_RUNNER_API_URL: "http://127.0.0.1:8080"
          VM_SUFFIX: "${{ matrix.distro }}-${{ matrix.version_number }}"
          # It's local Minio readonly account accessible from local runner
          # I don't really know how to make unauthenticated access so let's
          # keep that dummy account
          MINIO_ACCESS_KEY: "drakvuf-ci-user"
          MINIO_SECRET_KEY: "Ectrj8GnJbfZu4J"
      - name: Job failed - suspending VM (if possible)
        if: ${{ failure() }}
        run: |
          python3 -m vm_runner_client suspend
        env:
          VM_RUNNER_API_URL: "http://127.0.0.1:8080"
          VM_SUFFIX: "${{ matrix.distro }}-${{ matrix.version_number }}"
