Skip to content

CM-48559 - Fix SAST pre-commit hook #318

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jun 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
34 changes: 2 additions & 32 deletions cycode/cli/apps/scan/code_scanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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]]:
Expand Down Expand Up @@ -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
Expand Down
9 changes: 8 additions & 1 deletion cycode/cli/apps/scan/commit_range_scanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
)
Expand Down Expand Up @@ -120,12 +121,18 @@ 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)

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])

Expand Down
31 changes: 31 additions & 0 deletions cycode/cli/apps/scan/scan_result.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
35 changes: 19 additions & 16 deletions cycode/cli/printers/utils/code_snippet_syntax.py
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -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,
)


Expand All @@ -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,
)


Expand Down