# NOTE Github Actions execution environments lack a terminal, needed for
# some integration tests. So we use `script` command to fake a terminal.

name: ci
on:
  push:
    tags:
      - v*
    branches:
      - main
      - release-*
  pull_request:
permissions:
  contents: read

env:
  # Don't ignore C warnings. Note that the output of "go env CGO_CFLAGS" by default is "-g -O2", so we keep them.
  CGO_CFLAGS: -g -O2 -Werror

jobs:
  test:
    timeout-minutes: 30
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-20.04, ubuntu-22.04]
        go-version: [1.20.x, 1.21.x]
        rootless: ["rootless", ""]
        race: ["-race", ""]
        criu: ["", "criu-dev"]
        dmz: ["", "runc_nodmz"]
        exclude:
          - criu: criu-dev
            rootless: rootless
          - criu: criu-dev
            go-version: 1.20.x
          - criu: criu-dev
            race: -race
          - dmz: runc_nodmz
            criu: criu-dev
          - dmz: runc_nodmz
            os: ubuntu-20.04
    runs-on: ${{ matrix.os }}

    steps:

    - name: checkout
      uses: actions/checkout@v4

    - name: install deps
      if: matrix.criu == ''
      env:
        PREFIX: https://download.opensuse.org/repositories/devel:/tools:/criu/xUbuntu
      run: |
        # criu repo
        REPO=${PREFIX}_$(echo ${{ matrix.os }} | sed 's/.*-//')
        curl -fSsLl $REPO/Release.key | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/devel_tools_criu.gpg > /dev/null
        echo "deb $REPO/ /" | sudo tee /etc/apt/sources.list.d/criu.list
        sudo apt update
        sudo apt install libseccomp-dev criu sshfs

    - name: install deps (criu ${{ matrix.criu }})
      if: matrix.criu != ''
      run: |
        sudo apt -q update
        sudo apt -q install libseccomp-dev sshfs \
          libcap-dev libnet1-dev libnl-3-dev \
          libprotobuf-c-dev libprotobuf-dev protobuf-c-compiler protobuf-compiler
        git clone https://github.com/checkpoint-restore/criu.git ~/criu
        (cd ~/criu && git checkout ${{ matrix.criu }} && sudo make install-criu)
        rm -rf ~/criu

    - name: install go ${{ matrix.go-version }}
      uses: actions/setup-go@v5
      with:
        go-version: ${{ matrix.go-version }}

    - name: build
      env:
        EXTRA_BUILDTAGS: ${{ matrix.dmz }}
      run: sudo -E PATH="$PATH" make EXTRA_FLAGS="${{ matrix.race }}" all

    - name: install bats
      uses: mig4/setup-bats@v1
      with:
        bats-version: 1.9.0

    - name: unit test
      if: matrix.rootless != 'rootless'
      env:
        EXTRA_BUILDTAGS: ${{ matrix.dmz }}
      run: sudo -E PATH="$PATH" -- make TESTFLAGS="${{ matrix.race }}" localunittest

    - name: add rootless user
      if: matrix.rootless == 'rootless'
      run: |
        sudo useradd -u2000 -m -d/home/rootless -s/bin/bash rootless
        # Allow root and rootless itself to execute `ssh rootless@localhost` in tests/rootless.sh
        ssh-keygen -t ecdsa -N "" -f $HOME/rootless.key
        sudo mkdir -m 0700 -p /home/rootless/.ssh
        sudo cp $HOME/rootless.key /home/rootless/.ssh/id_ecdsa
        sudo cp $HOME/rootless.key.pub /home/rootless/.ssh/authorized_keys
        sudo chown -R rootless.rootless /home/rootless
        sudo chmod a+X $HOME # for Ubuntu 22.04

    - name: integration test (fs driver)
      run: sudo -E PATH="$PATH" script -e -c 'make local${{ matrix.rootless }}integration'

    - name: integration test (systemd driver)
      # Skip rootless+systemd for ubuntu 20.04 because of cgroup v1.
      if: ${{ !(matrix.os == 'ubuntu-20.04' && matrix.rootless == 'rootless') }}
      run: |
        # Delegate all cgroup v2 controllers to rootless user via --systemd-cgroup.
        # The default (since systemd v252) is "pids memory cpu".
        sudo mkdir -p /etc/systemd/system/user@.service.d
        printf "[Service]\nDelegate=yes\n" | sudo tee /etc/systemd/system/user@.service.d/delegate.conf
        sudo systemctl daemon-reload
        # Run the tests.
        sudo -E PATH="$PATH" script -e -c 'make RUNC_USE_SYSTEMD=yes local${{ matrix.rootless }}integration'

  # We need to continue support for 32-bit ARM.
  # However, we do not have 32-bit ARM CI, so we use i386 for testing 32bit stuff.
  # We are not interested in providing official support for i386.
  cross-i386:
    timeout-minutes: 15
    strategy:
      fail-fast: false
      matrix:
        dmz: ["", "runc_nodmz"]
    runs-on: ubuntu-22.04

    steps:

    - name: checkout
      uses: actions/checkout@v4

    - name: install deps
      run: |
        sudo dpkg --add-architecture i386
        # add criu repo
        sudo add-apt-repository -y ppa:criu/ppa
        # apt-add-repository runs apt update so we don't have to.

        sudo apt -q install libseccomp-dev libseccomp-dev:i386 gcc-multilib libgcc-s1:i386 criu

    - name: install go
      uses: actions/setup-go@v5
      with:
        go-version: 1.x # Latest stable

    - name: unit test
      env:
        EXTRA_BUILDTAGS: ${{ matrix.dmz }}
      run: sudo -E PATH="$PATH" -- make GOARCH=386 localunittest