Skip to content

Commit

Permalink
Merge a745721 into d4a9f42
Browse files Browse the repository at this point in the history
  • Loading branch information
joaosantos15 committed Aug 5, 2021
2 parents d4a9f42 + a745721 commit b8aa90a
Show file tree
Hide file tree
Showing 75 changed files with 45,502 additions and 228 deletions.
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
4 changes: 3 additions & 1 deletion .gitignore
Expand Up @@ -101,4 +101,6 @@ ENV/
# mypy
.mypy_cache/
.idea/
.vscode/
.vscode/

.mythx.yml
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))
9 changes: 4 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,7 @@ def analyze(
swc_whitelist=swc_whitelist,
)
# extend response with job UUID to keep formatter logic isolated
resp.uuid = uuid
issues_list.append((resp, inp))
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

0 comments on commit b8aa90a

Please sign in to comment.