diff --git a/README.md b/README.md index 24e2b742..9f48da38 100644 --- a/README.md +++ b/README.md @@ -287,7 +287,7 @@ The Cycode CLI application offers several types of scans so that you can choose | `--client-id TEXT` | Specify a Cycode client ID for this specific scan execution | | `--show-secret BOOLEAN` | Show secrets in plain text. See [Show/Hide Secrets](#showhide-secrets) section for more details. | | `--soft-fail BOOLEAN` | Run scan without failing, always return a non-error status code. See [Soft Fail](#soft-fail) section for more details. | -| `--severity-threshold [INFO\|LOW\|MEDIUM\|HIGH\|CRITICAL]` | Show only violations at the specified level or higher (supported for the SCA scan type only). | +| `--severity-threshold [INFO\|LOW\|MEDIUM\|HIGH\|CRITICAL]` | Show only violations at the specified level or higher. | | `--sca-scan` | Specify the SCA scan you wish to execute (`package-vulnerabilities`/`license-compliance`). The default is both | | `--monitor` | When specified, the scan results will be recorded in the knowledge graph. Please note that when working in `monitor` mode, the knowledge graph will not be updated as a result of SCM events (Push, Repo creation). (Supported for SCA scan type only). | | `--report` | When specified, a violations report will be generated. A URL link to the report will be printed as an output to the command execution | diff --git a/cycode/cli/commands/scan/code_scanner.py b/cycode/cli/commands/scan/code_scanner.py index 4f9772e2..47d017b0 100644 --- a/cycode/cli/commands/scan/code_scanner.py +++ b/cycode/cli/commands/scan/code_scanner.py @@ -713,20 +713,26 @@ def exclude_irrelevant_detections( ) -> List[Detection]: relevant_detections = _exclude_detections_by_exclusions_configuration(detections, scan_type) relevant_detections = _exclude_detections_by_scan_type(relevant_detections, scan_type, command_scan_type) - return _exclude_detections_by_severity(relevant_detections, scan_type, severity_threshold) + return _exclude_detections_by_severity(relevant_detections, severity_threshold) -def _exclude_detections_by_severity( - detections: List[Detection], scan_type: str, severity_threshold: str -) -> List[Detection]: - if scan_type != consts.SCA_SCAN_TYPE or severity_threshold is None: +def _exclude_detections_by_severity(detections: List[Detection], severity_threshold: str) -> List[Detection]: + if severity_threshold is None: return detections relevant_detections = [] for detection in detections: severity = detection.detection_details.get('advisory_severity') + if not severity: + severity = detection.severity + if _does_severity_match_severity_threshold(severity, severity_threshold): relevant_detections.append(detection) + else: + logger.debug( + 'Going to ignore violations because they are below the severity threshold, %s', + {'severity': severity, 'severity_threshold': severity_threshold}, + ) return relevant_detections @@ -861,10 +867,11 @@ def _generate_unique_id() -> UUID: def _does_severity_match_severity_threshold(severity: str, severity_threshold: str) -> bool: detection_severity_value = Severity.try_get_value(severity) - if detection_severity_value is None: + severity_threshold_value = Severity.try_get_value(severity_threshold) + if detection_severity_value is None or severity_threshold_value is None: return True - return detection_severity_value >= Severity.try_get_value(severity_threshold) + return detection_severity_value >= severity_threshold_value def _get_scan_result( diff --git a/cycode/cli/commands/scan/scan_command.py b/cycode/cli/commands/scan/scan_command.py index d394f8c7..a428a87a 100644 --- a/cycode/cli/commands/scan/scan_command.py +++ b/cycode/cli/commands/scan/scan_command.py @@ -66,7 +66,7 @@ @click.option( '--severity-threshold', default=None, - help='Show violations only for the specified level or higher (supported for SCA scan types only).', + help='Show violations only for the specified level or higher.', type=click.Choice([e.name for e in Severity]), required=False, ) diff --git a/cycode/cli/models.py b/cycode/cli/models.py index 4d4d241c..39c07e44 100644 --- a/cycode/cli/models.py +++ b/cycode/cli/models.py @@ -43,6 +43,7 @@ class Severity(Enum): @staticmethod def try_get_value(name: str) -> any: + name = name.upper() if name not in Severity.__members__: return None diff --git a/tests/cli/commands/scan/test_code_scanner.py b/tests/cli/commands/scan/test_code_scanner.py index 7b739a82..2c15dd3d 100644 --- a/tests/cli/commands/scan/test_code_scanner.py +++ b/tests/cli/commands/scan/test_code_scanner.py @@ -1,6 +1,7 @@ import os from cycode.cli import consts +from cycode.cli.commands.scan.code_scanner import _does_severity_match_severity_threshold from cycode.cli.files_collector.excluder import _is_file_relevant_for_sca_scan from cycode.cli.files_collector.path_documents import _generate_document from cycode.cli.models import Document @@ -72,3 +73,24 @@ def test_generate_document() -> None: assert isinstance(generated_tfplan_document, Document) assert generated_tfplan_document.path.endswith('.tf') assert generated_tfplan_document.is_git_diff_format == is_git_diff + + +def test_does_severity_match_severity_threshold() -> None: + assert _does_severity_match_severity_threshold('INFO', 'LOW') is False + + assert _does_severity_match_severity_threshold('LOW', 'LOW') is True + assert _does_severity_match_severity_threshold('LOW', 'MEDIUM') is False + + assert _does_severity_match_severity_threshold('MEDIUM', 'LOW') is True + assert _does_severity_match_severity_threshold('MEDIUM', 'MEDIUM') is True + assert _does_severity_match_severity_threshold('MEDIUM', 'HIGH') is False + + assert _does_severity_match_severity_threshold('HIGH', 'MEDIUM') is True + assert _does_severity_match_severity_threshold('HIGH', 'HIGH') is True + assert _does_severity_match_severity_threshold('HIGH', 'CRITICAL') is False + + assert _does_severity_match_severity_threshold('CRITICAL', 'HIGH') is True + assert _does_severity_match_severity_threshold('CRITICAL', 'CRITICAL') is True + + assert _does_severity_match_severity_threshold('NON_EXISTENT', 'LOW') is True + assert _does_severity_match_severity_threshold('LOW', 'NON_EXISTENT') is True diff --git a/tests/cli/models/__init__.py b/tests/cli/models/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/cli/models/test_severity.py b/tests/cli/models/test_severity.py new file mode 100644 index 00000000..332f987c --- /dev/null +++ b/tests/cli/models/test_severity.py @@ -0,0 +1,24 @@ +from cycode.cli.models import Severity + + +def test_try_get_value() -> None: + assert Severity.try_get_value('info') == -1 + assert Severity.try_get_value('iNfO') == -1 + + assert Severity.try_get_value('INFO') == -1 + assert Severity.try_get_value('LOW') == 0 + assert Severity.try_get_value('MEDIUM') == 1 + assert Severity.try_get_value('HIGH') == 2 + assert Severity.try_get_value('CRITICAL') == 3 + + assert Severity.try_get_value('NON_EXISTENT') is None + + +def test_get_member_weight() -> None: + assert Severity.get_member_weight('INFO') == -1 + assert Severity.get_member_weight('LOW') == 0 + assert Severity.get_member_weight('MEDIUM') == 1 + assert Severity.get_member_weight('HIGH') == 2 + assert Severity.get_member_weight('CRITICAL') == 3 + + assert Severity.get_member_weight('NON_EXISTENT') == -2