Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/fuzz #249

Closed
wants to merge 58 commits into from
Closed
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
e2162f8
Add basic projects support
dmuhs Feb 12, 2021
dfb5a41
Bump pythx version
dmuhs Feb 12, 2021
4138a25
Add fuzz subcommand scaffold
dmuhs Feb 22, 2021
a79d728
Add arm subcommand scaffold
dmuhs Feb 22, 2021
ca879cf
Add arm and disarm commands
dmuhs Feb 25, 2021
3cf6431
Fix minor formatting issues
dmuhs Mar 1, 2021
f328a70
Update install make command
dmuhs Mar 1, 2021
46f2705
Add notes on fuzz FaaS commands
dmuhs Mar 1, 2021
7946f2b
sync
joaosantos15 Mar 3, 2021
8b4adcd
creates brownie class
joaosantos15 Mar 9, 2021
dcfdbaa
Add support for --instrumentation-metadata-file for a Scribble invoca…
blitz-1306 Mar 10, 2021
f3cc7f1
feat: adds support for directories as targets and config file paramet…
joaosantos15 Mar 11, 2021
65fc5bb
Merge pull request #246 from dmuhs/feat/fuzz-scribble-meta
joaosantos15 Mar 11, 2021
da61537
feat: adds support for directories as targets on fuzz arm and disarm …
joaosantos15 Mar 12, 2021
d7dcd18
refactor rpc logic into separate class
joaosantos15 Mar 18, 2021
f1c4c5d
fix: issue with __scrible_* file
joaosantos15 Mar 18, 2021
8d5edef
feat: add error messages for bad configs
joaosantos15 Mar 24, 2021
1de182d
Adds comments and custom Exceptions
joaosantos15 Mar 25, 2021
9a91487
initial rewrite
JoranHonig Mar 26, 2021
ed86d9f
rewrite generics
JoranHonig Mar 26, 2021
849a6ff
restructure generics
JoranHonig Mar 26, 2021
aa4c553
traverse nested directories
JoranHonig Mar 29, 2021
2a4d1e7
Merge pull request #248 from JoranHonig/feat/fuzz
joaosantos15 Mar 29, 2021
5e06772
Add error messages, improve error handling
joaosantos15 Mar 30, 2021
61238e3
fix: tests for python >3.6
joaosantos15 Apr 1, 2021
d285248
fix: make targets an array on the config file
joaosantos15 Apr 6, 2021
d23321d
test: add tests for fuzz Carm and disarm commands
joaosantos15 Apr 6, 2021
b84b3c2
remove unused code
joaosantos15 Apr 6, 2021
83bedd4
test: fix broken test
joaosantos15 Apr 6, 2021
9bc0f81
Tweak instrumentation metadata entry in payload to follow API format …
blitz-1306 Apr 7, 2021
0788e6a
Fix affected tests
blitz-1306 Apr 7, 2021
bfff154
Merge pull request #250 from dmuhs/feat/fuzz-tweaks
joaosantos15 Apr 7, 2021
889c51f
qa: code tidy ups
joaosantos15 Apr 14, 2021
520c7c6
Merge branch 'master' into feat/fuzz
joaosantos15 Apr 14, 2021
037091d
Hardhat integration
Nurchik Apr 29, 2021
d6d5e47
Fixed hardhat unit tests
Nurchik Apr 29, 2021
d0c7e97
Fix sourcePaths data format
Nurchik Apr 30, 2021
9182bca
Add corpus target parameter to fuzzing
Nurchik May 4, 2021
83f30fd
Fix errors output
Nurchik May 13, 2021
85eeedd
Merge pull request #252 from dmuhs/feat/fuzz-hardhat
joaosantos15 May 18, 2021
dbb2959
feat: add map_to_original_source flag
joaosantos15 May 18, 2021
6c4832e
Truffle IDE support for fuzz
Nurchik May 19, 2021
2f90ec1
Fix submission logic
Nurchik May 19, 2021
9973ce7
fix: feature broken in brownie
joaosantos15 May 21, 2021
8c90c06
cleanup
joaosantos15 May 21, 2021
bb75d5f
test: adds brownie tests fr map to original source
joaosantos15 May 24, 2021
83aaa45
Fix an issue with relative paths in a target for truffle projects
Nurchik May 24, 2021
51e4bab
Refactor IDE code
Nurchik May 24, 2021
ac6b963
Merge pull request #256 from dmuhs/feat/fuzz-map-original-source
joaosantos15 May 25, 2021
268e755
Remove gql requirement
Nurchik May 28, 2021
bb11a55
feat: adds --dry-run flag
joaosantos15 Jun 25, 2021
80c3bed
Merge pull request #258 from dmuhs/feat/add-dry-run
joaosantos15 Aug 4, 2021
f512d49
feat: add api_key as config file parameter
joaosantos15 Aug 5, 2021
a745721
Merge pull request #259 from dmuhs/feat/faas-auth
joaosantos15 Aug 5, 2021
428827b
update default faas url
joaosantos15 Aug 5, 2021
19d2d86
Merge pull request #260 from dmuhs/feat/faas-auth
joaosantos15 Aug 5, 2021
6b4e466
Merge branch 'feat/fuzz' into feat/fuzz-truffle
Nurchik Aug 6, 2021
81ef764
Merge pull request #261 from dmuhs/feat/fuzz-truffle
Nurchik Aug 6, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Binary file added .DS_Store
Binary file not shown.
49 changes: 49 additions & 0 deletions .github/workflows/main.yml
@@ -0,0 +1,49 @@
name: MythX CLI

on: [push, pull_request]

jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.6, 3.7, 3.8, pypy3]

steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install Python dependencies
uses: py-actions/py-dependency-install@v2
with:
path: "requirements_dev.txt"
- name: Setup tox for GH actions
run: pip install tox-gh-actions
- name: Test with tox
run: make test
- name: Upload to Coveralls
run: coveralls
env:
COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}

deploy:
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags')
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: "3.7"
- name: Install Python dependencies
uses: py-actions/py-dependency-install@v2
with:
path: "requirements_dev.txt"
- name: Build and publish
env:
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
run: make release
7 changes: 7 additions & 0 deletions .mythx.yml
@@ -0,0 +1,7 @@
fuzz:
deployed_contract_address: "0x7277646075fa72737e1F6114654C5d9949a67dF2"
number_of_cores: 1
campaign_name_prefix: "brownie_test"
rpc_url: "http://localhost:9898"
faas_url: "http://localhost:9899"
build_directory: /private/var/folders/w9/36q5pfw94rz6bh0062p2j8p40000gn/T/pytest-of-boss/pytest-105/test_fuzz_run_deployedSourceMa1/build/contracts
9 changes: 5 additions & 4 deletions Makefile
Expand Up @@ -51,14 +51,14 @@ clean-test: ## remove test and coverage artifacts
rm -fr .pytest_cache

format:
isort -rc mythx_cli tests
black -t py37 mythx_cli tests
isort mythx_cli tests
black -t py38 mythx_cli tests

lint: ## check style with flake8
flake8 mythx_cli tests

test: ## run tests quickly with the default Python
py.test -vv
pytest --cov-report html --cov-report term --cov mythx_cli tests/

test-all: ## run tests on every Python version with tox
tox
Expand Down Expand Up @@ -89,4 +89,5 @@ dist: clean ## builds source and wheel package
ls -l dist

install: clean ## install the package to the active Python's site-packages
python setup.py install
pip install -r requirements_dev.txt
pip install -e .
37 changes: 37 additions & 0 deletions docs/mythx_cli.fuzz.rst
@@ -0,0 +1,37 @@
mythx\_cli.fuzz package
=======================

Submodules
----------

mythx\_cli.fuzz.run module
--------------------------

.. automodule:: mythx_cli.fuzz.run
:members:
:undoc-members:
:show-inheritance:

mythx\_cli.fuzz.setup module
----------------------------

.. automodule:: mythx_cli.fuzz.setup
:members:
:undoc-members:
:show-inheritance:

mythx\_cli.fuzz.arm module
----------------------------

.. automodule:: mythx_cli.fuzz.arm
:members:
:undoc-members:
:show-inheritance:

Module contents
---------------

.. automodule:: mythx_cli.fuzz
:members:
:undoc-members:
:show-inheritance:
45 changes: 45 additions & 0 deletions docs/mythx_cli.project.rst
@@ -0,0 +1,45 @@
mythx\_cli.project package
==========================

Submodules
----------

mythx\_cli.project.delete module
--------------------------------

.. automodule:: mythx_cli.project.delete
:members:
:undoc-members:
:show-inheritance:

mythx\_cli.project.details module
---------------------------------

.. automodule:: mythx_cli.project.details
:members:
:undoc-members:
:show-inheritance:

mythx\_cli.project.list module
------------------------------

.. automodule:: mythx_cli.project.list
:members:
:undoc-members:
:show-inheritance:

mythx\_cli.project.open module
------------------------------

.. automodule:: mythx_cli.project.open
:members:
:undoc-members:
:show-inheritance:

Module contents
---------------

.. automodule:: mythx_cli.project
:members:
:undoc-members:
:show-inheritance:
2 changes: 2 additions & 0 deletions docs/mythx_cli.rst
Expand Up @@ -10,7 +10,9 @@ Subpackages
mythx_cli.analysis
mythx_cli.analyze
mythx_cli.formatter
mythx_cli.fuzz
mythx_cli.group
mythx_cli.project
mythx_cli.render
mythx_cli.version

Expand Down
2 changes: 1 addition & 1 deletion mythx_cli/analysis/list.py
Expand Up @@ -44,5 +44,5 @@ def analysis_list(ctx, number: int) -> None:

# trim result to desired result number
LOGGER.debug(f"Got {len(result.analyses)} analyses, trimming to {number}")
result = AnalysisListResponse(analyses=result[:number], total=resp.total)
result = AnalysisListResponse(analyses=result.analyses[:number], total=resp.total)
write_or_print(FORMAT_RESOLVER[ctx["fmt"]].format_analysis_list(result))
7 changes: 4 additions & 3 deletions mythx_cli/analysis/report.py
Expand Up @@ -4,6 +4,7 @@

import click
from mythx_models.response import AnalysisInputResponse, DetectedIssuesResponse
from pythx import Client

from mythx_cli.formatter import FORMAT_RESOLVER, util
from mythx_cli.formatter.base import BaseFormatter
Expand Down Expand Up @@ -54,9 +55,10 @@ def analysis_report(
"""

issues_list: List[
Tuple[DetectedIssuesResponse, Optional[AnalysisInputResponse]]
Tuple[str, DetectedIssuesResponse, Optional[AnalysisInputResponse]]
] = []
formatter: BaseFormatter = FORMAT_RESOLVER[ctx["fmt"]]
ctx["client"]: Client
for uuid in uuids:
LOGGER.debug(f"{uuid}: Fetching report")
resp = ctx["client"].report(uuid)
Expand All @@ -74,8 +76,7 @@ def analysis_report(
swc_blacklist=swc_blacklist,
swc_whitelist=swc_whitelist,
)
resp.uuid = uuid
issues_list.append((resp, inp))
issues_list.append((uuid, resp, inp))

LOGGER.debug(
f"{uuid}: Printing report for {len(issues_list)} issue items with sort key \"{ctx['table_sort_key']}\""
Expand Down
2 changes: 1 addition & 1 deletion mythx_cli/analysis/status.py
Expand Up @@ -22,6 +22,6 @@ def analysis_status(ctx, uuids: List[str]) -> None:
"""
for uuid in uuids:
LOGGER.debug(f"{uuid}: Fetching status")
resp = ctx["client"].status(uuid)
resp = ctx["client"].analysis_status(uuid)
LOGGER.debug(f"{uuid}: Printing status information")
write_or_print(FORMAT_RESOLVER[ctx["fmt"]].format_analysis_status(resp))
10 changes: 5 additions & 5 deletions mythx_cli/analyze/command.py
Expand Up @@ -206,8 +206,8 @@ def analyze(

if create_group:
resp: GroupCreationResponse = ctx["client"].create_group(group_name=group_name)
group_id = resp.group.identifier
group_name = resp.group.name or ""
group_id = resp.identifier
group_name = resp.name or ""

if group_id:
# associate all following analyses to the passed or newly created group
Expand Down Expand Up @@ -308,7 +308,7 @@ def analyze(
return

issues_list: List[
Tuple[DetectedIssuesResponse, Optional[AnalysisInputResponse]]
Tuple[str, DetectedIssuesResponse, Optional[AnalysisInputResponse]]
] = []
formatter: BaseFormatter = FORMAT_RESOLVER[ctx["fmt"]]
for uuid in uuids:
Expand All @@ -331,8 +331,8 @@ def analyze(
swc_whitelist=swc_whitelist,
)
# extend response with job UUID to keep formatter logic isolated
resp.uuid = uuid
issues_list.append((resp, inp))
# resp.uuid = uuid
joaosantos15 marked this conversation as resolved.
Show resolved Hide resolved
issues_list.append((uuid, resp, inp))

LOGGER.debug(
f"Printing report for {len(issues_list)} issue items with sort key \"{ctx['table_sort_key']}\""
Expand Down
104 changes: 104 additions & 0 deletions mythx_cli/analyze/scribble.py
@@ -1,11 +1,16 @@
import json
import os
import subprocess
import sys
from collections import defaultdict
from typing import List

import click

from mythx_cli.util import sol_files_by_directory

SCRIBBLE_ARMING_META_FILE = ".scribble-arming.meta.json"


class ScribbleMixin:
"""A mixing for job objects to instrument code with Scribble."""
Expand All @@ -27,6 +32,7 @@ def _handle_scribble_error(process: subprocess.CompletedProcess) -> None:
click.echo(process.stderr.decode())
click.echo("=====STDOUT=====")
click.echo(process.stdout.decode())

sys.exit(process.returncode)

def instrument_truffle_artifacts(
Expand All @@ -49,6 +55,7 @@ def instrument_truffle_artifacts(
"source": file_data["source"],
"id": payload["source_list"].index(filename),
}

stdin["contracts"][filename][payload["contract_name"]] = {
"evm": {
"bytecode": {
Expand All @@ -72,6 +79,7 @@ def instrument_truffle_artifacts(
)

self._handle_scribble_error(process)

return json.loads(process.stdout.decode())

def instrument_solc_file(
Expand All @@ -91,5 +99,101 @@ def instrument_solc_file(
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)

self._handle_scribble_error(process)

return json.loads(process.stdout.decode())

@staticmethod
def instrument_solc_in_place(
file_list: List[str],
scribble_path: str,
remappings: List[str] = None,
solc_version: str = None,
) -> None:
"""Instrument a collection of Solidity files in place.

:param file_list: List of paths to Solidity files to instrument
:param scribble_path: The path to the scribble executable
:param remappings: List of import remappings to pass to solc
:param solc_version: The solc compiler version to use
"""
command = [
scribble_path,
"--arm",
"--output-mode=files",
f"--instrumentation-metadata-file={SCRIBBLE_ARMING_META_FILE}",
]

if remappings:
command.append(f"--path-remapping={';'.join(remappings)}")

if solc_version:
command.append(f"--compiler-version={solc_version}")

# Scribble doesnt currently support directories as inputs
# so we create a list of all solidity files inside each of the targets
# and submit that to Scribble.

sol_files = []
for file in file_list:
target_files = sol_files_by_directory(file)
sol_files = [*sol_files, *target_files]

command.extend(sol_files)

process = subprocess.run(
command, stdout=subprocess.PIPE, stderr=subprocess.PIPE
)

ScribbleMixin._handle_scribble_error(process)

@staticmethod
def disarm_solc_in_place(
file_list: List[str],
scribble_path: str,
remappings: List[str] = None,
solc_version: str = None,
) -> None:
"""Un-instrument a collection of Solidity files in place.

:param file_list: List of paths to Solidity files to instrument
:param scribble_path: The path to the scribble executable
:param remappings: List of import remappings to pass to solc
:param solc_version: The solc compiler version to use
"""
command = [scribble_path, "--disarm"]

if remappings:
command.append(f"--path-remapping={';'.join(remappings)}")

if solc_version:
command.append(f"--compiler-version={solc_version}")

# Scribble doesnt currently support directories as inputs
# so we create a list of all solidity files inside each of the targets
# and submit that to Scribble.

sol_files = []
for file in file_list:
target_files = sol_files_by_directory(file)
sol_files = [*sol_files, *target_files]

command.extend(sol_files)

if os.path.isfile(SCRIBBLE_ARMING_META_FILE):
os.remove(SCRIBBLE_ARMING_META_FILE)

process = subprocess.run(
command, stdout=subprocess.PIPE, stderr=subprocess.PIPE
)

ScribbleMixin._handle_scribble_error(process)

@staticmethod
def get_arming_instr_meta():
if os.path.exists(SCRIBBLE_ARMING_META_FILE):
with open(SCRIBBLE_ARMING_META_FILE, "r") as f:
return json.load(f)

return None