From 114983c17daafcfed62b96ad8999075f38bb062c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20L=C3=B3pez?= <2642849+elopez@users.noreply.github.com> Date: Fri, 1 Apr 2022 09:31:31 -0300 Subject: [PATCH] Windows CI for Slither (#1137) * workflows: parser: use solc-select from pip The hardcoded, manually-installed version is out of date. This updates the workflow to install directly from pip now that it is available there. * workflows: parser: Run tests also on Windows * workflows: parser: bump solc-select to >=v1.0.0b1 This version introduces Windows support. * workflows: parser: FIXME: install patched crytic-compile * workflows: features: enable Windows runs This enables runs on windows-2022 and updates solc-select to support running on Windows. * workflows: features: FIXME: install patched crytic-compile * workflows: detectors: enable Windows runs This enables runs on windows-2022 and updates solc-select to support running on Windows. * workflows: detectors, features, parser: disable fail-fast Disable fail-fast so failures in one platform do not hide failures in the other OS. * tests: detectors: adjust GENERIC_PATH replacement for Windows Backslashes are escaped in the string representation, so we need to double them before replacing. Also change generic path to a constant string to avoid it being converted to "\GENERIC_PATH" in Windows and getting an invalid escape error from the JSON decoder later on. * tests: use lf endings for test code If autocrlf is enabled on Windows, it will rewrite solc code with CRLF file endings and break tests that depend on byte offsets in the code files. * workflows: detectors: FIXME: install patched crytic-compile * workflows: ci: enable Windows runs This enables runs on windows-2022 and updates solc-select to support running on Windows. Some tests with Linux requirements are excluded. * workflows: ci: FIXME: install patched crytic-compile * workflows: *: update actions/setup-python to v3 v1 does not install Python correctly on Windows. While at it, update all instances to v3. * workflows: ci: add msys2 tools to path * workflows: ci: disable broken Windows workflows * workflows: apply linter fixes * workflows: ci: enable dapp test * tests: dapp: fix test * core: normalize paths on POSIX style * workflows: ci: enable printers tests on Windows --- .github/ISSUE_TEMPLATE/feature_request.yml | 1 + .github/workflows/black.yml | 4 +- .github/workflows/ci.yml | 88 +++++++++++++++------- .github/workflows/detectors.yml | 17 +++-- .github/workflows/features.yml | 17 +++-- .github/workflows/linter.yml | 4 +- .github/workflows/parser.yml | 23 +++--- .github/workflows/pip-audit.yml | 29 +++---- .github/workflows/pylint.yml | 4 +- scripts/ci_test_dapp.sh | 13 ++-- slither/core/slither_core.py | 5 +- tests/.gitattributes | 3 + tests/test_detectors.py | 17 ++--- 13 files changed, 141 insertions(+), 84 deletions(-) create mode 100644 tests/.gitattributes diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index 3356bea03..651f78037 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -1,3 +1,4 @@ +--- name: Feature request description: Suggest a feature labels: ["enhancement"] diff --git a/.github/workflows/black.yml b/.github/workflows/black.yml index eddac1480..1f54bfd3e 100644 --- a/.github/workflows/black.yml +++ b/.github/workflows/black.yml @@ -11,7 +11,7 @@ on: branches: [master, dev] schedule: # run CI every day even if no PRs/merges occur - - cron: '0 12 * * *' + - cron: '0 12 * * *' jobs: build: @@ -23,7 +23,7 @@ jobs: uses: actions/checkout@v2 - name: Set up Python 3.6 - uses: actions/setup-python@v2 + uses: actions/setup-python@v3 with: python-version: 3.6 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5ccd15dd9..dbe540ea2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,3 +1,4 @@ +--- name: CI defaults: @@ -13,46 +14,81 @@ on: pull_request: schedule: # run CI every day even if no PRs/merges occur - - cron: '0 12 * * *' + - cron: '0 12 * * *' jobs: tests: - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} strategy: + fail-fast: false matrix: + os: ["ubuntu-latest", "windows-2022"] type: ["cli", + "dapp", "data_dependency", # "embark", "erc", "etherlime", + # "etherscan" "find_paths", + "flat", "kspec", "printers", + # "prop" "simil", "slither_config", "truffle", - "upgradability", - # "prop", - "flat"] + "upgradability"] + exclude: + # Requires nix + - os: windows-2022 + type: dapp + # Requires nvm + - os: windows-2022 + type: etherlime + # Requires nvm + - os: windows-2022 + type: truffle steps: - - uses: actions/checkout@v1 - - name: Set up Python 3.6 - uses: actions/setup-python@v1 - with: - python-version: 3.6 - - name: Install dependencies - run: | - python setup.py install - # Used by ci_test.sh - pip install deepdiff - - pip install solc-select - solc-select install all - solc-select use 0.5.1 - - - name: Run Tests - env: - TEST_TYPE: ${{ matrix.type }} - GITHUB_ETHERSCAN: ${{ secrets.GITHUB_ETHERSCAN }} - run: | - bash "scripts/ci_test_${TEST_TYPE}.sh" + - uses: actions/checkout@v1 + + - name: Set up shell + if: runner.os == 'Windows' + run: | + echo 'C:\msys64\mingw64\bin' >> "$GITHUB_PATH" + echo 'C:\msys64\usr\bin' >> "$GITHUB_PATH" + + - name: Set up Python 3.6 + uses: actions/setup-python@v3 + with: + python-version: 3.6 + - name: Install dependencies + run: | + # FIXME: patched crytic-compile is used to support Windows. + # Install from pip once branch is merged and crytic-compile released + pip install "crytic-compile@https://github.com/crytic/crytic-compile/archive/refs/heads/dev-windows-long-paths.zip" + + python setup.py install + # Used by ci_test.sh + pip install deepdiff + + pip install "solc-select>=v1.0.0b1" + solc-select install all + solc-select use 0.5.1 + + - name: Set up nix + if: matrix.type == 'dapp' + uses: cachix/install-nix-action@v16 + + - name: Set up cachix + if: matrix.type == 'dapp' + uses: cachix/cachix-action@v10 + with: + name: dapp + + - name: Run Tests + env: + TEST_TYPE: ${{ matrix.type }} + GITHUB_ETHERSCAN: ${{ secrets.GITHUB_ETHERSCAN }} + run: | + bash "scripts/ci_test_${TEST_TYPE}.sh" diff --git a/.github/workflows/detectors.yml b/.github/workflows/detectors.yml index 13f4ca6ff..46c3ffcbd 100644 --- a/.github/workflows/detectors.yml +++ b/.github/workflows/detectors.yml @@ -11,32 +11,39 @@ on: branches: [master, dev] schedule: # run CI every day even if no PRs/merges occur - - cron: '0 12 * * *' + - cron: '0 12 * * *' jobs: build: name: Detectors tests - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-2022] steps: - name: Checkout Code uses: actions/checkout@v2 - name: Set up Python 3.6 - uses: actions/setup-python@v2 + uses: actions/setup-python@v3 with: python-version: 3.6 - name: Install dependencies run: | + # FIXME: patched crytic-compile is used to support Windows. + # Install from pip once branch is merged and crytic-compile released + pip install "crytic-compile@https://github.com/crytic/crytic-compile/archive/refs/heads/dev-windows-long-paths.zip" + python setup.py install pip install deepdiff pip install pytest - pip install solc-select + pip install "solc-select>=v1.0.0b1" solc-select install all solc-select use 0.7.3 - name: Test with pytest run: | pytest tests/test_detectors.py - diff --git a/.github/workflows/features.yml b/.github/workflows/features.yml index 72aeec986..ffef3d537 100644 --- a/.github/workflows/features.yml +++ b/.github/workflows/features.yml @@ -11,29 +11,37 @@ on: branches: [master, dev] schedule: # run CI every day even if no PRs/merges occur - - cron: '0 12 * * *' + - cron: '0 12 * * *' jobs: build: name: Features tests - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-2022] steps: - name: Checkout Code uses: actions/checkout@v2 - name: Set up Python 3.6 - uses: actions/setup-python@v2 + uses: actions/setup-python@v3 with: python-version: 3.6 - name: Install dependencies run: | + # FIXME: patched crytic-compile is used to support Windows. + # Install from pip once branch is merged and crytic-compile released + pip install "crytic-compile@https://github.com/crytic/crytic-compile/archive/refs/heads/dev-windows-long-paths.zip" + python setup.py install pip install deepdiff pip install pytest - pip install solc-select + pip install "solc-select>=v1.0.0b1" solc-select install all solc-select use 0.8.0 @@ -45,4 +53,3 @@ jobs: run: | pytest tests/test_features.py pytest tests/test_constant_folding_unary.py - diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index 94bc3a97b..2fb81477b 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -11,7 +11,7 @@ on: branches: [master, dev] schedule: # run CI every day even if no PRs/merges occur - - cron: '0 12 * * *' + - cron: '0 12 * * *' jobs: build: @@ -23,7 +23,7 @@ jobs: uses: actions/checkout@v2 - name: Set up Python 3.6 - uses: actions/setup-python@v2 + uses: actions/setup-python@v3 with: python-version: 3.6 diff --git a/.github/workflows/parser.yml b/.github/workflows/parser.yml index a06e895ae..dbe10bac2 100644 --- a/.github/workflows/parser.yml +++ b/.github/workflows/parser.yml @@ -11,37 +11,42 @@ on: branches: [master, dev] schedule: # run CI every day even if no PRs/merges occur - - cron: '0 12 * * *' + - cron: '0 12 * * *' jobs: build: name: Parser tests - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-2022] steps: - name: Checkout Code uses: actions/checkout@v2 - name: Set up Python 3.6 - uses: actions/setup-python@v2 + uses: actions/setup-python@v3 with: python-version: 3.6 - name: Install dependencies run: | + # FIXME: patched crytic-compile is used to support Windows. + # Install from pip once branch is merged and crytic-compile released + pip install "crytic-compile@https://github.com/crytic/crytic-compile/archive/refs/heads/dev-windows-long-paths.zip" + python setup.py install pip install deepdiff pip install pytest + pip install "solc-select>=v1.0.0b1" - git clone https://github.com/crytic/solc-select.git - cd solc-select - git checkout 119dd05f58341811cb02b546f25269a7e8a10875 - python setup.py install + - name: Install solc + run: | solc-select install all solc-select use 0.8.0 - cd .. - name: Test with pytest run: | pytest tests/test_ast_parsing.py - diff --git a/.github/workflows/pip-audit.yml b/.github/workflows/pip-audit.yml index f6360056c..c14674ce7 100644 --- a/.github/workflows/pip-audit.yml +++ b/.github/workflows/pip-audit.yml @@ -1,3 +1,4 @@ +--- name: pip-audit on: @@ -11,17 +12,17 @@ jobs: audit: runs-on: ubuntu-latest steps: - - name: Checkout repository - uses: actions/checkout@v2 - - name: Set up Python 3.10 - uses: actions/setup-python@v2 - with: - python-version: "3.10" - - name: Install pip-audit - run: | - python -m pip install --upgrade pip - python -m pip install pip-audit - - name: Run pip-audit - run: | - python -m pip install . - pip-audit --desc -v + - name: Checkout repository + uses: actions/checkout@v2 + - name: Set up Python 3.10 + uses: actions/setup-python@v3 + with: + python-version: "3.10" + - name: Install pip-audit + run: | + python -m pip install --upgrade pip + python -m pip install pip-audit + - name: Run pip-audit + run: | + python -m pip install . + pip-audit --desc -v diff --git a/.github/workflows/pylint.yml b/.github/workflows/pylint.yml index c4b7c36df..b5e5b25b0 100644 --- a/.github/workflows/pylint.yml +++ b/.github/workflows/pylint.yml @@ -11,7 +11,7 @@ on: branches: [master, dev] schedule: # run CI every day even if no PRs/merges occur - - cron: '0 12 * * *' + - cron: '0 12 * * *' jobs: build: @@ -23,7 +23,7 @@ jobs: uses: actions/checkout@v2 - name: Set up Python 3.6 - uses: actions/setup-python@v2 + uses: actions/setup-python@v3 with: python-version: 3.6 diff --git a/scripts/ci_test_dapp.sh b/scripts/ci_test_dapp.sh index bc2c92607..d353d8f23 100755 --- a/scripts/ci_test_dapp.sh +++ b/scripts/ci_test_dapp.sh @@ -8,23 +8,20 @@ cd test_dapp || exit 255 git config --global user.email "ci@trailofbits.com" git config --global user.name "CI User" -curl https://nixos.org/nix/install | sh -# shellcheck disable=SC1090,SC1091 -. "$HOME/.nix-profile/etc/profile.d/nix.sh" -nix-env -iA nixpkgs.cachix -cachix use dapp +which nix-env || exit 255 git clone --recursive https://github.com/dapphub/dapptools "$HOME/.dapp/dapptools" nix-env -f "$HOME/.dapp/dapptools" -iA dapp seth solc hevm ethsign dapp init -slither . +slither . --detect external-function -if [ $? -eq 21 ] +# TODO: make more elaborate test +if [ $? -eq 3 ] then exit 0 fi -echo "Truffle test failed" +echo "Dapp test failed" exit 255 diff --git a/slither/core/slither_core.py b/slither/core/slither_core.py index 78ff30ca5..2a76f3e6e 100644 --- a/slither/core/slither_core.py +++ b/slither/core/slither_core.py @@ -4,6 +4,7 @@ import json import logging import os +import posixpath import re from typing import Optional, Dict, List, Set, Union @@ -172,7 +173,7 @@ class SlitherCore(Context): return False mapping_elements_with_lines = ( ( - os.path.normpath(elem["source_mapping"]["filename_absolute"]), + posixpath.normpath(elem["source_mapping"]["filename_absolute"]), elem["source_mapping"]["lines"], ) for elem in r["elements"] @@ -218,7 +219,7 @@ class SlitherCore(Context): if "source_mapping" in elem ] source_mapping_elements = map( - lambda x: os.path.normpath(x) if x else x, source_mapping_elements + lambda x: posixpath.normpath(x) if x else x, source_mapping_elements ) matching = False diff --git a/tests/.gitattributes b/tests/.gitattributes new file mode 100644 index 000000000..e6e5f7d87 --- /dev/null +++ b/tests/.gitattributes @@ -0,0 +1,3 @@ +# Always checkout test solidity code with lf endings +# autocrlf breaks file offsets in tests. +*.sol text eol=lf diff --git a/tests/test_detectors.py b/tests/test_detectors.py index f8374e1c9..30999389c 100644 --- a/tests/test_detectors.py +++ b/tests/test_detectors.py @@ -1314,11 +1314,10 @@ def test_detector(test_item: Test): for additional_file in test_item.additional_files: additional_path = str(pathlib.Path(test_dir_path, additional_file).absolute()) - results_as_string = results_as_string.replace( - additional_path, str(pathlib.Path(GENERIC_PATH)) - ) - results_as_string = results_as_string.replace(test_file_path, str(pathlib.Path(GENERIC_PATH))) - + additional_path = additional_path.replace("\\", "\\\\") + results_as_string = results_as_string.replace(additional_path, GENERIC_PATH) + test_file_path = test_file_path.replace("\\", "\\\\") + results_as_string = results_as_string.replace(test_file_path, GENERIC_PATH) results = json.loads(results_as_string) diff = DeepDiff(results, expected_result, ignore_order=True, verbose_level=2) @@ -1358,13 +1357,13 @@ def _generate_test(test_item: Test, skip_existing=False): results = sl.run_detectors() results_as_string = json.dumps(results) - results_as_string = results_as_string.replace(test_file_path, str(pathlib.Path(GENERIC_PATH))) + test_file_path = test_file_path.replace("\\", "\\\\") + results_as_string = results_as_string.replace(test_file_path, GENERIC_PATH) for additional_file in test_item.additional_files: additional_path = str(pathlib.Path(test_dir_path, additional_file).absolute()) - results_as_string = results_as_string.replace( - additional_path, str(pathlib.Path(GENERIC_PATH)) - ) + additional_path = additional_path.replace("\\", "\\\\") + results_as_string = results_as_string.replace(additional_path, GENERIC_PATH) results = json.loads(results_as_string) with open(expected_result_path, "w", encoding="utf8") as f: