Skip to content

Commit

Permalink
Merge branch 'dev' into noahlitvin-patch-1
Browse files Browse the repository at this point in the history
  • Loading branch information
montyly committed Aug 16, 2021
2 parents cb13447 + b3f6cee commit 16bff0e
Show file tree
Hide file tree
Showing 48 changed files with 146 additions and 7 deletions.
23 changes: 19 additions & 4 deletions slither/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
from slither.printers import all_printers
from slither.printers.abstract_printer import AbstractPrinter
from slither.slither import Slither
from slither.utils.output import output_to_json, output_to_zip, ZIP_TYPES_ACCEPTED
from slither.utils.output import output_to_json, output_to_zip, output_to_sarif, ZIP_TYPES_ACCEPTED
from slither.utils.output_capture import StandardOutputCapture
from slither.utils.colors import red, set_colorization_enabled
from slither.utils.command_line import (
Expand Down Expand Up @@ -397,6 +397,13 @@ def parse_args(detector_classes, printer_classes): # pylint: disable=too-many-s
default=defaults_flag_in_config["json"],
)

group_misc.add_argument(
"--sarif",
help='Export the results as a SARIF JSON file ("--sarif -" to export to stdout)',
action="store",
default=defaults_flag_in_config["sarif"],
)

group_misc.add_argument(
"--json-types",
help="Comma-separated list of result types to output to JSON, defaults to "
Expand Down Expand Up @@ -645,15 +652,17 @@ def main_impl(all_detector_classes, all_printer_classes):
output_error = None
outputting_json = args.json is not None
outputting_json_stdout = args.json == "-"
outputting_sarif = args.sarif is not None
outputting_sarif_stdout = args.sarif == "-"
outputting_zip = args.zip is not None
if args.zip_type not in ZIP_TYPES_ACCEPTED.keys():
to_log = f'Zip type not accepted, it must be one of {",".join(ZIP_TYPES_ACCEPTED.keys())}'
logger.error(to_log)

# If we are outputting JSON, capture all standard output. If we are outputting to stdout, we block typical stdout
# output.
if outputting_json:
StandardOutputCapture.enable(outputting_json_stdout)
if outputting_json or output_to_sarif:
StandardOutputCapture.enable(outputting_json_stdout or outputting_sarif_stdout)

printer_classes = choose_printers(args, all_printer_classes)
detector_classes = choose_detectors(args, all_detector_classes)
Expand Down Expand Up @@ -732,7 +741,7 @@ def main_impl(all_detector_classes, all_printer_classes):
) = process_all(filename, args, detector_classes, printer_classes)

# Determine if we are outputting JSON
if outputting_json or outputting_zip:
if outputting_json or outputting_zip or output_to_sarif:
# Add our compilation information to JSON
if "compilations" in args.json_types:
compilation_results = []
Expand Down Expand Up @@ -803,6 +812,12 @@ def main_impl(all_detector_classes, all_printer_classes):
StandardOutputCapture.disable()
output_to_json(None if outputting_json_stdout else args.json, output_error, json_results)

if outputting_sarif:
StandardOutputCapture.disable()
output_to_sarif(
None if outputting_sarif_stdout else args.sarif, json_results, detector_classes
)

if outputting_zip:
output_to_zip(args.zip, output_error, json_results, args.zip_type)

Expand Down
2 changes: 1 addition & 1 deletion slither/detectors/statements/assert_state_change.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class AssertStateChange(AbstractDetector):
CONFIDENCE = DetectorClassification.HIGH

WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#assert-state-change"
WIKI_TITLE = "Assert state shange"
WIKI_TITLE = "Assert state change"
WIKI_DESCRIPTION = """Incorrect use of `assert()`. See Solidity best [practices](https://solidity.readthedocs.io/en/latest/control-structures.html#id4)."""

# region wiki_exploit_scenario
Expand Down
1 change: 1 addition & 0 deletions slither/utils/command_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"exclude_medium": False,
"exclude_high": False,
"json": None,
"sarif": None,
"json-types": ",".join(DEFAULT_JSON_OUTPUT_TYPES),
"disable_color": False,
"filter_paths": None,
Expand Down
125 changes: 124 additions & 1 deletion slither/utils/output.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from collections import OrderedDict
from typing import Optional, Dict, List, Union, Any, TYPE_CHECKING
from zipfile import ZipFile
from pkg_resources import require

from slither.core.cfg.node import Node
from slither.core.declarations import Contract, Function, Enum, Event, Structure, Pragma
Expand All @@ -17,6 +18,7 @@

if TYPE_CHECKING:
from slither.core.compilation_unit import SlitherCompilationUnit
from slither.detectors.abstract_detector import AbstractDetector

logger = logging.getLogger("Slither")

Expand All @@ -28,7 +30,7 @@
###################################################################################


def output_to_json(filename: str, error, results: Dict):
def output_to_json(filename: Optional[str], error, results: Dict) -> None:
"""
:param filename: Filename where the json will be written. If None or "-", write to stdout
Expand Down Expand Up @@ -56,6 +58,127 @@ def output_to_json(filename: str, error, results: Dict):
json.dump(json_result, f, indent=2)


def _output_result_to_sarif(
detector: Dict, detectors_classes: List["AbstractDetector"], sarif: Dict
) -> None:
confidence = "very-high"
if detector["confidence"] == "Medium":
confidence = "high"
elif detector["confidence"] == "Low":
confidence = "medium"
elif detector["confidence"] == "Informational":
confidence = "low"

risk = "0.0"
if detector["impact"] == "High":
risk = "8.0"
elif detector["impact"] == "Medium":
risk = "4.0"
elif detector["impact"] == "Low":
risk = "3.0"

detector_class = next((d for d in detectors_classes if d.ARGUMENT == detector["check"]))
check_id = (
str(detector_class.IMPACT.value)
+ "-"
+ str(detector_class.CONFIDENCE.value)
+ "-"
+ detector["check"]
)

rule = {
"id": check_id,
"name": detector["check"],
"properties": {"precision": confidence, "security-severity": risk},
"shortDescription": {"text": detector_class.WIKI_TITLE},
"help": {"text": detector_class.WIKI_RECOMMENDATION},
}
# Add the rule if does not exist yet
if len([x for x in sarif["runs"][0]["tool"]["driver"]["rules"] if x["id"] == check_id]) == 0:
sarif["runs"][0]["tool"]["driver"]["rules"].append(rule)

if not detector["elements"]:
logger.info(yellow("Cannot generate Github security alert for finding without location"))
logger.info(yellow(detector["description"]))
logger.info(yellow("This will be supported in a future Slither release"))
return

# From 3.19.10 (http://docs.oasis-open.org/sarif/sarif/v2.0/csprd01/sarif-v2.0-csprd01.html)
# The locations array SHALL NOT contain more than one element unless the condition indicated by the result,
# if any, can only be corrected by making a change at every location specified in the array.
finding = detector["elements"][0]
path = finding["source_mapping"]["filename_relative"]
start_line = finding["source_mapping"]["lines"][0]
end_line = finding["source_mapping"]["lines"][-1]

sarif["runs"][0]["results"].append(
{
"ruleId": check_id,
"message": {"text": detector["description"], "markdown": detector["markdown"]},
"level": "warning",
"locations": [
{
"physicalLocation": {
"artifactLocation": {"uri": path},
"region": {"startLine": start_line, "endLine": end_line},
}
}
],
"partialFingerprints": {"id": detector["id"]},
}
)


def output_to_sarif(
filename: Optional[str], results: Dict, detectors_classes: List["AbstractDetector"]
) -> None:
"""
:param filename:
:type filename:
:param results:
:type results:
:return:
:rtype:
"""

sarif: Dict[str, Any] = {
"$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json",
"version": "2.1.0",
"runs": [
{
"tool": {
"driver": {
"name": "Slither",
"informationUri": "https://github.com/crytic/slither",
"version": require("slither-analyzer")[0].version,
"rules": [],
}
},
"results": [],
}
],
}

for detector in results["detectors"]:
_output_result_to_sarif(detector, detectors_classes, sarif)

if filename == "-":
filename = None

# Determine if we should output to stdout
if filename is None:
# Write json to console
print(json.dumps(sarif))
else:
# Write json to file
if os.path.isfile(filename):
logger.info(yellow(f"{filename} exists already, the overwrite is prevented"))
else:
with open(filename, "w", encoding="utf8") as f:
json.dump(sarif, f, indent=2)


# https://docs.python.org/3/library/zipfile.html#zipfile-objects
ZIP_TYPES_ACCEPTED = {
"lzma": zipfile.ZIP_LZMA,
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added tests/ast-parsing/compile/break-0.8.7-compact.zip
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added tests/ast-parsing/compile/emit-0.8.7-compact.zip
Binary file not shown.
Binary file added tests/ast-parsing/compile/enum-0.8.7-compact.zip
Binary file not shown.
Binary file added tests/ast-parsing/compile/event-0.8.7-compact.zip
Binary file not shown.
Binary file added tests/ast-parsing/compile/for-0.8.7-compact.zip
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added tests/ast-parsing/compile/if-0.8.7-compact.zip
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added tests/ast-parsing/compile/pragma-0.8.7-compact.zip
Binary file not shown.
Binary file added tests/ast-parsing/compile/push-0.8.7-compact.zip
Binary file not shown.
Binary file not shown.
Binary file added tests/ast-parsing/compile/scope-0.8.7-compact.zip
Binary file not shown.
Binary file not shown.
Binary file added tests/ast-parsing/compile/throw-0.8.7-compact.zip
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added tests/ast-parsing/compile/while-0.8.7-compact.zip
Binary file not shown.
Binary file added tests/ast-parsing/compile/yul-0.8.7-compact.zip
Binary file not shown.
2 changes: 1 addition & 1 deletion tests/test_ast_parsing.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
ALL_05 = range(0, 18)
ALL_06 = range(0, 13)
ALL_07 = range(0, 7)
ALL_08 = range(0, 7)
ALL_08 = range(0, 8)

# these are tests that are currently failing right now
XFAIL = (
Expand Down

0 comments on commit 16bff0e

Please sign in to comment.