From 4f4aaef47fa31ba97fe99d99bb2131aa74ac59e8 Mon Sep 17 00:00:00 2001 From: Ilya Siamionau Date: Wed, 11 Jun 2025 12:36:08 +0200 Subject: [PATCH 1/3] CM-48559 - Fix SAST pre-commit hook --- cycode/cli/apps/scan/code_scanner.py | 34 ++------------------ cycode/cli/apps/scan/commit_range_scanner.py | 2 ++ cycode/cli/apps/scan/scan_result.py | 31 ++++++++++++++++++ 3 files changed, 35 insertions(+), 32 deletions(-) diff --git a/cycode/cli/apps/scan/code_scanner.py b/cycode/cli/apps/scan/code_scanner.py index 19b43733..ad6a6e3e 100644 --- a/cycode/cli/apps/scan/code_scanner.py +++ b/cycode/cli/apps/scan/code_scanner.py @@ -9,6 +9,7 @@ from cycode.cli.apps.scan.scan_parameters import get_scan_parameters from cycode.cli.apps.scan.scan_result import ( create_local_scan_result, + enrich_scan_result_with_data_from_detection_rules, get_scan_result, get_sync_scan_result, print_local_scan_results, @@ -77,37 +78,6 @@ def _should_use_sync_flow(command_scan_type: str, scan_type: str, sync_option: b return True -def _enrich_scan_result_with_data_from_detection_rules( - cycode_client: 'ScanClient', scan_result: ZippedFileScanResult -) -> None: - detection_rule_ids = set() - for detections_per_file in scan_result.detections_per_file: - for detection in detections_per_file.detections: - detection_rule_ids.add(detection.detection_rule_id) - - detection_rules = cycode_client.get_detection_rules(detection_rule_ids) - detection_rules_by_id = {detection_rule.detection_rule_id: detection_rule for detection_rule in detection_rules} - - for detections_per_file in scan_result.detections_per_file: - for detection in detections_per_file.detections: - detection_rule = detection_rules_by_id.get(detection.detection_rule_id) - if not detection_rule: - # we want to make sure that BE returned it. better to not map data instead of failed scan - continue - - if not detection.severity and detection_rule.classification_data: - # it's fine to take the first one, because: - # - for "secrets" and "iac" there is only one classification rule per-detection rule - # - for "sca" and "sast" we get severity from detection service - detection.severity = detection_rule.classification_data[0].severity - - # detection_details never was typed properly. so not a problem for now - detection.detection_details['custom_remediation_guidelines'] = detection_rule.custom_remediation_guidelines - detection.detection_details['remediation_guidelines'] = detection_rule.remediation_guidelines - detection.detection_details['description'] = detection_rule.description - detection.detection_details['policy_display_name'] = detection_rule.display_name - - def _get_scan_documents_thread_func( ctx: typer.Context, is_git_diff: bool, is_commit_range: bool, scan_parameters: dict ) -> Callable[[list[Document]], tuple[str, CliError, LocalScanResult]]: @@ -140,7 +110,7 @@ def _scan_batch_thread_func(batch: list[Document]) -> tuple[str, CliError, Local should_use_sync_flow, ) - _enrich_scan_result_with_data_from_detection_rules(cycode_client, scan_result) + enrich_scan_result_with_data_from_detection_rules(cycode_client, scan_result) local_scan_result = create_local_scan_result( scan_result, batch, command_scan_type, scan_type, severity_threshold diff --git a/cycode/cli/apps/scan/commit_range_scanner.py b/cycode/cli/apps/scan/commit_range_scanner.py index b191611f..64029012 100644 --- a/cycode/cli/apps/scan/commit_range_scanner.py +++ b/cycode/cli/apps/scan/commit_range_scanner.py @@ -13,6 +13,7 @@ from cycode.cli.apps.scan.scan_parameters import get_scan_parameters from cycode.cli.apps.scan.scan_result import ( create_local_scan_result, + enrich_scan_result_with_data_from_detection_rules, init_default_scan_result, print_local_scan_results, ) @@ -120,6 +121,7 @@ def _scan_commit_range_documents( scan_parameters, timeout, ) + enrich_scan_result_with_data_from_detection_rules(cycode_client, scan_result) progress_bar.update(ScanProgressBarSection.SCAN) progress_bar.set_section_length(ScanProgressBarSection.GENERATE_REPORT, 1) diff --git a/cycode/cli/apps/scan/scan_result.py b/cycode/cli/apps/scan/scan_result.py index 88bc6320..31a36368 100644 --- a/cycode/cli/apps/scan/scan_result.py +++ b/cycode/cli/apps/scan/scan_result.py @@ -179,3 +179,34 @@ def print_local_scan_results( printer = ctx.obj.get('console_printer') printer.update_ctx(ctx) printer.print_scan_results(local_scan_results, errors) + + +def enrich_scan_result_with_data_from_detection_rules( + cycode_client: 'ScanClient', scan_result: ZippedFileScanResult +) -> None: + detection_rule_ids = set() + for detections_per_file in scan_result.detections_per_file: + for detection in detections_per_file.detections: + detection_rule_ids.add(detection.detection_rule_id) + + detection_rules = cycode_client.get_detection_rules(detection_rule_ids) + detection_rules_by_id = {detection_rule.detection_rule_id: detection_rule for detection_rule in detection_rules} + + for detections_per_file in scan_result.detections_per_file: + for detection in detections_per_file.detections: + detection_rule = detection_rules_by_id.get(detection.detection_rule_id) + if not detection_rule: + # we want to make sure that BE returned it. better to not map data instead of failed scan + continue + + if not detection.severity and detection_rule.classification_data: + # it's fine to take the first one, because: + # - for "secrets" and "iac" there is only one classification rule per-detection rule + # - for "sca" and "sast" we get severity from detection service + detection.severity = detection_rule.classification_data[0].severity + + # detection_details never was typed properly. so not a problem for now + detection.detection_details['custom_remediation_guidelines'] = detection_rule.custom_remediation_guidelines + detection.detection_details['remediation_guidelines'] = detection_rule.remediation_guidelines + detection.detection_details['description'] = detection_rule.description + detection.detection_details['policy_display_name'] = detection_rule.display_name From 4b6b8c3f4cdaae5e235663fd7a8d541a94fec2f3 Mon Sep 17 00:00:00 2001 From: Ilya Siamionau Date: Wed, 11 Jun 2025 13:28:00 +0200 Subject: [PATCH 2/3] fix line number highlighting --- cycode/cli/apps/scan/commit_range_scanner.py | 7 +++- .../cli/printers/utils/code_snippet_syntax.py | 35 ++++++++++--------- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/cycode/cli/apps/scan/commit_range_scanner.py b/cycode/cli/apps/scan/commit_range_scanner.py index 64029012..5a7893df 100644 --- a/cycode/cli/apps/scan/commit_range_scanner.py +++ b/cycode/cli/apps/scan/commit_range_scanner.py @@ -126,8 +126,13 @@ def _scan_commit_range_documents( progress_bar.update(ScanProgressBarSection.SCAN) progress_bar.set_section_length(ScanProgressBarSection.GENERATE_REPORT, 1) + documents_to_scan = to_documents_to_scan + if scan_type == consts.SAST_SCAN_TYPE: + # actually for SAST from_documents_to_scan is full files and to_documents_to_scan is diff files + documents_to_scan = from_documents_to_scan + local_scan_result = create_local_scan_result( - scan_result, to_documents_to_scan, scan_command_type, scan_type, severity_threshold + scan_result, documents_to_scan, scan_command_type, scan_type, severity_threshold ) set_issue_detected_by_scan_results(ctx, [local_scan_result]) diff --git a/cycode/cli/printers/utils/code_snippet_syntax.py b/cycode/cli/printers/utils/code_snippet_syntax.py index d9ea3af2..20f94d4e 100644 --- a/cycode/cli/printers/utils/code_snippet_syntax.py +++ b/cycode/cli/printers/utils/code_snippet_syntax.py @@ -25,6 +25,20 @@ def get_detection_line(scan_type: str, detection: 'Detection') -> int: ) +def _get_syntax_highlighted_code(code: str, lexer: str, start_line: int, detection_line: int) -> Syntax: + return Syntax( + theme=_SYNTAX_HIGHLIGHT_THEME, + code=code, + lexer=lexer, + line_numbers=True, + word_wrap=True, + dedent=True, + tab_size=2, + start_line=start_line + 1, + highlight_lines={detection_line + 1}, + ) + + def _get_code_snippet_syntax_from_file( scan_type: str, detection: 'Detection', @@ -58,18 +72,11 @@ def _get_code_snippet_syntax_from_file( code_lines_to_render.append(line_content) code_to_render = '\n'.join(code_lines_to_render) - return Syntax( - theme=_SYNTAX_HIGHLIGHT_THEME, + return _get_syntax_highlighted_code( code=code_to_render, lexer=Syntax.guess_lexer(document.path, code=code_to_render), - line_numbers=True, - word_wrap=True, - dedent=True, - tab_size=2, - start_line=start_line_index + 1, - highlight_lines={ - detection_line + 1, - }, + start_line=start_line_index, + detection_line=detection_line, ) @@ -87,15 +94,11 @@ def _get_code_snippet_syntax_from_git_diff( violation = line_content[detection_position_in_line : detection_position_in_line + violation_length] line_content = line_content.replace(violation, obfuscate_text(violation)) - return Syntax( - theme=_SYNTAX_HIGHLIGHT_THEME, + return _get_syntax_highlighted_code( code=line_content, lexer='diff', - line_numbers=True, start_line=detection_line, - dedent=True, - tab_size=2, - highlight_lines={detection_line + 1}, + detection_line=detection_line, ) From b50bfe699472a69fe17480894bd6b19296ead9c5 Mon Sep 17 00:00:00 2001 From: Ilya Siamionau Date: Wed, 11 Jun 2025 13:37:28 +0200 Subject: [PATCH 3/3] update readme --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index f3e57c10..fbc6fba6 100644 --- a/README.md +++ b/README.md @@ -468,6 +468,9 @@ _How to generate a Terraform plan from Terraform configuration file?_ ### Commit History Scan +> [!NOTE] +> Secrets scanning analyzes all commits in the repository history because secrets introduced and later removed can still be leaked or exposed. SCA and SAST scanning focus only on the latest code state and the changes between branches or pull requests. Full commit history scanning is not performed for SCA and SAST. + A commit history scan is limited to a local repository’s previous commits, focused on finding any secrets within the commit history, instead of examining the repository’s current state. To execute a commit history scan, execute the following: