From a7d7c1eef2fa3e92f6848f4a943d42f8887a51cf Mon Sep 17 00:00:00 2001 From: Feist Josselin Date: Thu, 12 Oct 2023 14:47:31 +0200 Subject: [PATCH] Minor improvements --- slither/__main__.py | 19 ++++++++++ slither/core/slither_core.py | 22 +++++++++++ slither/utils/command_line.py | 2 + slither/utils/sarif.py | 71 +++++++++++++++++++++++++++++++++++ 4 files changed, 114 insertions(+) create mode 100644 slither/utils/sarif.py diff --git a/slither/__main__.py b/slither/__main__.py index c639200362..f4fca54937 100644 --- a/slither/__main__.py +++ b/slither/__main__.py @@ -79,6 +79,11 @@ def process_single( ast = "--ast-json" slither = Slither(target, ast_format=ast, **vars(args)) + if args.sarif_input: + slither.sarif_input = args.sarif_input + if args.sarif_triage: + slither.sarif_triage = args.sarif_triage + return _process(slither, detector_classes, printer_classes) @@ -469,6 +474,20 @@ def parse_args( default=defaults_flag_in_config["sarif"], ) + group_misc.add_argument( + "--sarif-input", + help="Sarif input (beta)", + action="store", + default=defaults_flag_in_config["sarif_input"], + ) + + group_misc.add_argument( + "--sarif-triage", + help="Sarif triage (beta)", + action="store", + default=defaults_flag_in_config["sarif_triage"], + ) + group_misc.add_argument( "--json-types", help="Comma-separated list of result types to output to JSON, defaults to " diff --git a/slither/core/slither_core.py b/slither/core/slither_core.py index 798008707f..e6bbef8ff4 100644 --- a/slither/core/slither_core.py +++ b/slither/core/slither_core.py @@ -21,6 +21,7 @@ from slither.core.source_mapping.source_mapping import SourceMapping, Source from slither.slithir.variables import Constant from slither.utils.colors import red +from slither.utils.sarif import read_triage_info from slither.utils.source_mapping import get_definition, get_references, get_implementation logger = logging.getLogger("Slither") @@ -48,6 +49,10 @@ def __init__(self) -> None: self._source_code_to_line: Optional[Dict[str, List[str]]] = None self._previous_results_filename: str = "slither.db.json" + + # TODO: add cli flag to set these variables + self.sarif_input: str = "export.sarif" + self.sarif_triage: str = "export.sarif.sarifexplorer" self._results_to_hide: List = [] self._previous_results: List = [] # From triaged result @@ -444,6 +449,8 @@ def valid_result(self, r: Dict) -> bool: return True def load_previous_results(self) -> None: + self.load_previous_results_from_sarif() + filename = self._previous_results_filename try: if os.path.isfile(filename): @@ -453,9 +460,24 @@ def load_previous_results(self) -> None: for r in self._previous_results: if "id" in r: self._previous_results_ids.add(r["id"]) + except json.decoder.JSONDecodeError: logger.error(red(f"Impossible to decode {filename}. Consider removing the file")) + def load_previous_results_from_sarif(self) -> None: + sarif = pathlib.Path(self.sarif_input) + triage = pathlib.Path(self.sarif_triage) + + if not sarif.exists(): + return + if not triage.exists(): + return + + triaged = read_triage_info(sarif, triage) + + for id_triaged in triaged: + self._previous_results_ids.add(id_triaged) + def write_results_to_hide(self) -> None: if not self._results_to_hide: return diff --git a/slither/utils/command_line.py b/slither/utils/command_line.py index 0824725821..6c50fcab93 100644 --- a/slither/utils/command_line.py +++ b/slither/utils/command_line.py @@ -68,6 +68,8 @@ class FailOnLevel(enum.Enum): "zip_type": "lzma", "show_ignored_findings": False, "no_fail": False, + "sarif_input": "export.sarif", + "sarif_triage": "export.sarif.sarifexplorer", **DEFAULTS_FLAG_IN_CONFIG_CRYTIC_COMPILE, } diff --git a/slither/utils/sarif.py b/slither/utils/sarif.py new file mode 100644 index 0000000000..600ac35c76 --- /dev/null +++ b/slither/utils/sarif.py @@ -0,0 +1,71 @@ +""" +Various utils for sarif/vscode +""" +import json +from pathlib import Path +from typing import List, Dict, Optional, Tuple, Any + + +def _parse_index(key: str) -> Optional[Tuple[int, int]]: + if key.count(":") != 2: + return None + + try: + run = int(key[key.find(":") + 1 : key.rfind(":")]) + index = int(key[key.rfind(":") + 1 :]) + return run, index + except ValueError: + return None + + +def _get_indexes(path_to_triage: Path) -> List[Tuple[int, int]]: + try: + with open(path_to_triage, encoding="utf8") as file_desc: + triage = json.load(file_desc) + except json.decoder.JSONDecodeError: + return [] + + resultIdToNotes: Dict[str, Dict] = triage.get("resultIdToNotes", {}) + + indexes: List[Tuple[int, int]] = [] + for key, data in resultIdToNotes.items(): + if "status" in data and data["status"] == 1: + parsed = _parse_index(key) + if parsed: + indexes.append(parsed) + + return indexes + + +def read_triage_info(path_to_sarif: Path, path_to_triage: Path) -> List[str]: + try: + with open(path_to_sarif, encoding="utf8") as file_desc: + sarif = json.load(file_desc) + except json.decoder.JSONDecodeError: + return [] + + runs: List[Dict[str, Any]] = sarif.get("runs", []) + + # Don't support multiple runs for now + if len(runs) != 1: + return [] + + run_results: List[Dict] = runs[0].get("results", []) + + indexes = _get_indexes(path_to_triage) + + ids: List[str] = [] + for run, index in indexes: + + # We dont support multiple runs for now + if run != 0: + continue + try: + elem = run_results[index] + except KeyError: + continue + if "partialFingerprints" in elem: + if "id" in elem["partialFingerprints"]: + ids.append(elem["partialFingerprints"]["id"]) + + return ids