Skip to content

Commit

Permalink
Merge ab1cad8 into 42d2749
Browse files Browse the repository at this point in the history
  • Loading branch information
dmuhs committed Jan 14, 2020
2 parents 42d2749 + ab1cad8 commit ba7beef
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 2 deletions.
2 changes: 1 addition & 1 deletion mythx_cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ def sanitize_paths(job):
data = job["sources"].pop(name)
# sanitize AST data in compiler output
for ast_key in ("ast", "legacyAST"):
if not (data.get(ast_key) and data[ast_key]["absolutePath"]):
if not (data.get(ast_key) and data[ast_key].get("absolutePath")):
continue
sanitized_absolute = data[ast_key]["absolutePath"].replace(prefix, "")
data[ast_key]["absolutePath"] = sanitized_absolute
Expand Down
4 changes: 3 additions & 1 deletion mythx_cli/formatter/__init__.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
from .json import JSONFormatter, PrettyJSONFormatter
from .simple_stdout import SimpleFormatter
from .tabular import TabularFormatter
from .sonarqube import SonarQubeFormatter

FORMAT_RESOLVER = {
"simple": SimpleFormatter(),
"json": JSONFormatter(),
"json-pretty": PrettyJSONFormatter(),
"table": TabularFormatter(),
"sonar": SonarQubeFormatter(),
}

__all__ = [JSONFormatter, PrettyJSONFormatter, SimpleFormatter, TabularFormatter]
__all__ = [JSONFormatter, PrettyJSONFormatter, SimpleFormatter, TabularFormatter, SonarQubeFormatter]
31 changes: 31 additions & 0 deletions mythx_cli/formatter/sonarqube.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from mythx_cli.formatter.json import JSONFormatter
from mythx_models.response import DetectedIssuesResponse, AnalysisInputResponse
from mythx_models.response.issue import Severity, SourceType
import json


class SonarQubeFormatter(JSONFormatter):
@staticmethod
def format_detected_issues(resp: DetectedIssuesResponse, inp: AnalysisInputResponse) -> str:
new_reports = []
for report in resp.issue_reports:
for issue in report:
new_issue = {}
for loc in issue.decoded_locations:
for raw_loc in issue.locations:
if raw_loc.source_type != SourceType.SOLIDITY_FILE:
continue
new_issue["onInputFile"] = raw_loc.source_list[raw_loc.source_map.components[0].file_id]
new_issue["atLineNr"] = loc.start_line

new_issue.update({
"linterName": "mythx",
"forRule": issue.swc_id,
"ruleType": issue.severity.name,
"remediationEffortMinutes": 0,
"severity": "vulnerability" if issue.severity == Severity.HIGH else issue.severity.name,
"message": issue.description_long,
})
new_reports.append(new_issue)

return json.dumps(new_reports)
26 changes: 26 additions & 0 deletions tests/test_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
ISSUES_RESPONSE = get_test_case("testdata/detected-issues-response.json", DetectedIssuesResponse)
ISSUES_SIMPLE = get_test_case("testdata/detected-issues-simple.txt", raw=True)
ISSUES_TABLE = get_test_case("testdata/detected-issues-table.txt", raw=True)
ISSUES_SONAR = get_test_case("testdata/detected-issues-sonar.json")


def test_report_tabular():
Expand Down Expand Up @@ -43,6 +44,31 @@ def test_report_tabular_filter():
assert "/home/spoons/diligence/mythx-qa/land/contracts/estate/EstateStorage.sol" not in result.output


def test_report_sonar():
runner = CliRunner()
with mock_context():
result = runner.invoke(cli, ["--format", "sonar", "analysis", "report", "ab9092f7-54d0-480f-9b63-1bb1508280e2"])
assert result.exit_code == 0
assert json.loads(result.output) == ISSUES_SONAR


def test_report_sonar_blacklist():
runner = CliRunner()
with mock_context():
result = runner.invoke(cli, ["--format", "sonar", "analysis", "report", "--swc-blacklist",
"SWC-110", "ab9092f7-54d0-480f-9b63-1bb1508280e2"])
assert result.exit_code == 0
assert all(x["forRule"] != "SWC-110" for x in json.loads(result.output))


def test_report_sonar_filter():
runner = CliRunner()
with mock_context():
result = runner.invoke(cli, ["--format", "sonar", "analysis", "report", "--min-severity", "high", "ab9092f7-54d0-480f-9b63-1bb1508280e2"])
assert result.exit_code == 0
assert all(x["forRule"] != "SWC-110" for x in json.loads(result.output))


def test_report_json():
runner = CliRunner()
with mock_context():
Expand Down
12 changes: 12 additions & 0 deletions tests/testdata/detected-issues-response.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,18 @@
"tail": "It is possible to trigger an exception (opcode 0xfe). Exceptions can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. Note that explicit `assert()` should only be used to check invariants. Use `require()` for regular input checking."
},
"severity": "Low",
"decodedLocations": [
[
{
"column": 0,
"line": 1
},
{
"column": 23,
"line": 1
}
]
],
"locations": [
{
"sourceMap": "454:1:1",
Expand Down
20 changes: 20 additions & 0 deletions tests/testdata/detected-issues-sonar.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[
{
"linterName": "mythx",
"forRule": "SWC-110",
"ruleType": "LOW",
"remediationEffortMinutes": 0,
"atLineNr": 1,
"onInputFile": "/home/spoons/diligence/mythx-qa/land/contracts/estate/EstateStorage.sol",
"severity": "LOW",
"message": "It is possible to trigger an exception (opcode 0xfe). Exceptions can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. Note that explicit `assert()` should only be used to check invariants. Use `require()` for regular input checking."
},
{
"linterName": "mythx",
"forRule": "",
"ruleType": "LOW",
"remediationEffortMinutes": 0,
"severity": "LOW",
"message": "Warning: Free mode only detects certain types of smart contract vulnerabilities. Your contract may still be unsafe. Upgrade to MythX Pro to unlock the ability to test for even more vulnerabilities, perform deeper security analysis, and more. https://mythx.io/plans"
}
]

0 comments on commit ba7beef

Please sign in to comment.