name: CI

on:
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]

# save workspaces to speed up testing
env:
  CAPA_SAVE_WORKSPACE: "True"

jobs:
  changelog_format:
    runs-on: ubuntu-20.04
    steps:
    - name: Checkout capa
      uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
    # The sync GH action in capa-rules relies on a single '- *$' in the CHANGELOG file
    - name: Ensure CHANGELOG has '- *$'
      run: |
        number=$(grep '\- *$' CHANGELOG.md | wc -l)
        if [ $number != 1 ]; then exit 1; fi

  code_style:
    runs-on: ubuntu-20.04
    steps:
    - name: Checkout capa
      uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
    - name: Set up Python 3.8
      uses: actions/setup-python@d27e3f3d7c64b4bbf8e4abfb9b63b83e846e0435 # v4.5.0
      with:
        python-version: "3.8"
    - name: Install dependencies
      run: pip install -e .[dev]
    - name: Lint with ruff
      run: ruff --config .github/ruff.toml check .
    - name: Lint with isort
      run: isort --profile black --length-sort --line-width 120 --skip-glob "*_pb2.py" -c .
    - name: Lint with black
      run: black -l 120 --extend-exclude ".*_pb2.py" --check .
    - name: Lint with pycodestyle
      run: pycodestyle --exclude="*_pb2.py" --show-source capa/ scripts/ tests/
    - name: Check types with mypy
      run: mypy --config-file .github/mypy/mypy.ini --check-untyped-defs capa/ scripts/ tests/

  rule_linter:
    runs-on: ubuntu-20.04
    steps:
    - name: Checkout capa with submodules
      uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
      with:
        submodules: recursive
    - name: Set up Python 3.8
      uses: actions/setup-python@d27e3f3d7c64b4bbf8e4abfb9b63b83e846e0435 # v4.5.0
      with:
        python-version: "3.8"
    - name: Install capa
      run: pip install -e .
    - name: Run rule linter
      run: python scripts/lint.py rules/

  tests:
    name: Tests in ${{ matrix.python-version }} on ${{ matrix.os }}
    runs-on: ${{ matrix.os }}
    needs: [code_style, rule_linter]
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-20.04, windows-2019, macos-11]
        # across all operating systems
        python-version: ["3.7", "3.11"]
        include:
          # on Ubuntu run these as well
          - os: ubuntu-20.04
            python-version: "3.8"
          - os: ubuntu-20.04
            python-version: "3.9"
          - os: ubuntu-20.04
            python-version: "3.10"
    steps:
    - name: Checkout capa with submodules
      uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
      with:
        submodules: recursive
    - name: Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@d27e3f3d7c64b4bbf8e4abfb9b63b83e846e0435 # v4.5.0
      with:
        python-version: ${{ matrix.python-version }}
    - name: Install pyyaml
      if: matrix.os == 'ubuntu-20.04'
      run: sudo apt-get install -y libyaml-dev
    - name: Install capa
      run: pip install -e .[dev]
    - name: Run tests
      run: pytest -v tests/

  binja-tests:
    name: Binary Ninja tests for ${{ matrix.python-version }} on ${{ matrix.os }}
    runs-on: ubuntu-20.04
    needs: [code_style, rule_linter]
    strategy:
      fail-fast: false
      matrix:
        python-version: ["3.7", "3.11"]
    steps:
    - name: Checkout capa with submodules
      uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
      with:
        submodules: recursive
    - name: Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@d27e3f3d7c64b4bbf8e4abfb9b63b83e846e0435 # v4.5.0
      with:
        python-version: ${{ matrix.python-version }}
    - name: Install pyyaml
      run: sudo apt-get install -y libyaml-dev
    - name: Install capa
      run: pip install -e .[dev]
    - name: install Binary Ninja
      env:
        BN_SERIAL: ${{ secrets.BN_SERIAL }}
      run: |
        mkdir ./.github/binja
        curl "https://raw.githubusercontent.com/Vector35/binaryninja-api/6812c97/scripts/download_headless.py" -o ./.github/binja/download_headless.py
        python ./.github/binja/download_headless.py --serial $BN_SERIAL --output .github/binja/BinaryNinja-headless.zip
        unzip .github/binja/BinaryNinja-headless.zip -d .github/binja/
        python .github/binja/binaryninja/scripts/install_api.py --install-on-root --silent
    - name: Run tests
      env:
        BN_LICENSE: ${{ secrets.BN_LICENSE }}
      run: pytest -v tests/test_binja_features.py  # explicitly refer to the binja tests for performance. other tests run above.
