Skip to content

Commit

Permalink
Merge dfb5a41 into 9d9d1e9
Browse files Browse the repository at this point in the history
  • Loading branch information
dmuhs committed Feb 12, 2021
2 parents 9d9d1e9 + dfb5a41 commit 0df92ac
Show file tree
Hide file tree
Showing 47 changed files with 520 additions and 217 deletions.
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
2 changes: 1 addition & 1 deletion Makefile
Expand Up @@ -58,7 +58,7 @@ 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
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
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
20 changes: 20 additions & 0 deletions mythx_cli/cli.py
Expand Up @@ -18,6 +18,7 @@
from mythx_cli.group.list import group_list
from mythx_cli.group.open import group_open
from mythx_cli.group.status import group_status
from mythx_cli.project.list import project_list
from mythx_cli.render.command import render
from mythx_cli.util import update_context
from mythx_cli.version.command import version
Expand Down Expand Up @@ -205,6 +206,25 @@ def cli(
cli.add_command(version)


@cli.group()
def project() -> None:
"""Create, modify, and view analysis projects.
\f
This subcommand holds all project-related actions, such as creating,
listing, and managing projects, as well as fetching the status of one
or more groups inside a project.
"""
pass


from mythx_cli.project import project_list

LOGGER.debug("Registering project commands")
project.add_command(project_list)


@cli.group()
def group() -> None:
"""Create, modify, and view analysis groups.
Expand Down
2 changes: 1 addition & 1 deletion mythx_cli/formatter/base.py
Expand Up @@ -34,7 +34,7 @@ def format_analysis_status(resp: AnalysisStatusResponse) -> str:
@abc.abstractmethod
def format_detected_issues(
issues_list: List[
Tuple[DetectedIssuesResponse, Optional[AnalysisInputResponse]]
Tuple[str, DetectedIssuesResponse, Optional[AnalysisInputResponse]]
],
**kwargs,
) -> str:
Expand Down
33 changes: 23 additions & 10 deletions mythx_cli/formatter/json.py
Expand Up @@ -10,6 +10,7 @@
DetectedIssuesResponse,
GroupListResponse,
GroupStatusResponse,
ProjectListResponse,
VersionResponse,
)

Expand All @@ -29,43 +30,49 @@ class JSONFormatter(BaseFormatter):
def format_group_status(resp: GroupStatusResponse) -> str:
"""Format a group status response as compressed JSON."""

return resp.to_json()
return resp.json(by_alias=True)

@staticmethod
def format_project_list(resp: ProjectListResponse):
"""Format a project list response as pretty-printed JSON."""

return resp.json(by_alias=True)

@staticmethod
def format_group_list(resp: GroupListResponse) -> str:
"""Format a group list response as compressed JSON."""

return resp.to_json()
return resp.json(by_alias=True)

@staticmethod
def format_analysis_list(resp: AnalysisListResponse) -> str:
"""Format an analysis list response as compressed JSON."""

return resp.to_json()
return resp.json(by_alias=True)

@staticmethod
def format_analysis_status(resp: AnalysisStatusResponse) -> str:
"""Format an analysis status response as compressed JSON."""

return resp.to_json()
return resp.json(by_alias=True)

@staticmethod
def format_detected_issues(
issues_list: List[
Tuple[DetectedIssuesResponse, Optional[AnalysisInputResponse]]
Tuple[str, DetectedIssuesResponse, Optional[AnalysisInputResponse]]
],
**kwargs,
) -> str:
"""Format an issue report response as compressed JSON."""

output = [resp.to_dict(as_list=True) for resp, _ in issues_list]
output = [resp.dict(by_alias=True) for _, resp, _ in issues_list]
return json.dumps(output)

@staticmethod
def format_version(resp: VersionResponse) -> str:
"""Format a version response as compressed JSON."""

return resp.to_json()
return resp.json(by_alias=True)


class PrettyJSONFormatter(BaseFormatter):
Expand All @@ -85,9 +92,15 @@ def _print_as_json(obj, report_mode=False) -> str:
json_args = {"indent": 2, "sort_keys": True}
if report_mode:
return json.dumps(
[resp.to_dict(as_list=True) for resp, _ in obj], **json_args
[resp.dict(by_alias=True) for _, resp, _ in obj], **json_args
)
return json.dumps(obj.to_dict(), **json_args)
return json.dumps(obj.dict(by_alias=True), **json_args)

@staticmethod
def format_project_list(resp: ProjectListResponse):
"""Format a project list response as pretty-printed JSON."""

return PrettyJSONFormatter._print_as_json(resp)

@staticmethod
def format_group_status(resp: GroupStatusResponse) -> str:
Expand Down Expand Up @@ -116,7 +129,7 @@ def format_analysis_status(obj: AnalysisStatusResponse) -> str:
@staticmethod
def format_detected_issues(
issues_list: List[
Tuple[DetectedIssuesResponse, Optional[AnalysisInputResponse]]
Tuple[str, DetectedIssuesResponse, Optional[AnalysisInputResponse]]
],
**kwargs,
) -> str:
Expand Down
40 changes: 28 additions & 12 deletions mythx_cli/formatter/simple_stdout.py
Expand Up @@ -10,6 +10,7 @@
DetectedIssuesResponse,
GroupListResponse,
GroupStatusResponse,
ProjectListResponse,
VersionResponse,
)

Expand All @@ -33,7 +34,7 @@ def format_analysis_list(resp: AnalysisListResponse) -> str:
"""Format an analysis list response to a simple text representation."""

res = []
for analysis in resp:
for analysis in resp.analyses:
res.append("UUID: {}".format(analysis.uuid))
res.append("Submitted at: {}".format(analysis.submitted_at))
res.append("Status: {}".format(analysis.status))
Expand All @@ -46,10 +47,10 @@ def format_group_status(resp: GroupStatusResponse) -> str:
"""Format a group status response to a simple text representation."""

res = [
"ID: {}".format(resp.group.identifier),
"Name: {}".format(resp.group.name or "<unnamed>"),
"Created on: {}".format(resp.group.created_at),
"Status: {}".format(resp.group.status),
"ID: {}".format(resp.identifier),
"Name: {}".format(resp.name or "<unnamed>"),
"Created on: {}".format(resp.created_at),
"Status: {}".format(resp.status),
"",
]
return "\n".join(res)
Expand All @@ -60,7 +61,7 @@ def format_group_list(resp: GroupListResponse) -> str:
representation."""

res = []
for group in resp:
for group in resp.groups:
res.append("ID: {}".format(group.identifier))
res.append("Name: {}".format(group.name or "<unnamed>"))
res.append("Created on: {}".format(group.created_at))
Expand All @@ -69,6 +70,21 @@ def format_group_list(resp: GroupListResponse) -> str:

return "\n".join(res)

@staticmethod
def format_project_list(resp: ProjectListResponse) -> str:
"""Format an analysis group response to a simple text
representation."""

res = []
for project in resp.projects:
res.append("ID: {}".format(project.id))
res.append("Name: {}".format(project.name or "<unnamed>"))
res.append("Created on: {}".format(project.created))
res.append("Modified: {}".format(project.modified))
res.append("")

return "\n".join(res)

@staticmethod
def format_analysis_status(resp: AnalysisStatusResponse) -> str:
"""Format an analysis status response to a simple text
Expand All @@ -85,7 +101,7 @@ def format_analysis_status(resp: AnalysisStatusResponse) -> str:
@staticmethod
def format_detected_issues(
issues_list: List[
Tuple[DetectedIssuesResponse, Optional[AnalysisInputResponse]]
Tuple[str, DetectedIssuesResponse, Optional[AnalysisInputResponse]]
],
**kwargs,
) -> str:
Expand Down Expand Up @@ -113,10 +129,10 @@ def format_version(resp: VersionResponse) -> str:

return "\n".join(
[
"API: {}".format(resp.api_version),
"Harvey: {}".format(resp.harvey_version),
"Maru: {}".format(resp.maru_version),
"Mythril: {}".format(resp.mythril_version),
"Hashed: {}".format(resp.hashed_version),
"API: {}".format(resp.api),
"Harvey: {}".format(resp.harvey),
"Maru: {}".format(resp.maru),
"Mythril: {}".format(resp.mythril),
"Hashed: {}".format(resp.hash),
]
)

0 comments on commit 0df92ac

Please sign in to comment.