Skip to content

Commit aadb590

Browse files
authored
CM-46731 - Make all flows use scan service (#296)
1 parent dad7859 commit aadb590

File tree

12 files changed

+127
-398
lines changed

12 files changed

+127
-398
lines changed

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,6 @@ The Cycode CLI application offers several types of scans so that you can choose
303303
| `--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). |
304304
| `--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. |
305305
| `--no-restore` | When specified, Cycode will not run restore command. Will scan direct dependencies ONLY! |
306-
| `--sync` | Run scan synchronously (the default is asynchronous). |
307306
| `--gradle-all-sub-projects` | When specified, Cycode will run gradle restore command for all sub projects. Should run from root project directory ONLY! |
308307
| `--help` | Show options for given command. |
309308

cycode/cli/apps/scan/code_scanner.py

Lines changed: 25 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -100,24 +100,30 @@ def set_issue_detected_by_scan_results(ctx: typer.Context, scan_results: List[Lo
100100
set_issue_detected(ctx, any(scan_result.issue_detected for scan_result in scan_results))
101101

102102

103-
def _should_use_scan_service(scan_type: str, scan_parameters: dict) -> bool:
104-
return scan_type == consts.SECRET_SCAN_TYPE and scan_parameters.get('report') is True
103+
def _should_use_sync_flow(command_scan_type: str, scan_type: str, sync_option: bool) -> bool:
104+
"""Decide whether to use sync flow or async flow for the scan.
105105
106+
Note:
107+
Passing `--sync` option does not mean that sync flow will be used in all cases.
106108
107-
def _should_use_sync_flow(
108-
command_scan_type: str, scan_type: str, sync_option: bool, scan_parameters: Optional[dict] = None
109-
) -> bool:
110-
if not sync_option:
109+
The logic:
110+
- for IAC scan, sync flow is always used
111+
- for SAST scan, sync flow is not supported
112+
- for SCA and Secrets scan, sync flow is supported only for path/repository scan
113+
"""
114+
if not sync_option and scan_type != consts.IAC_SCAN_TYPE:
111115
return False
112116

113117
if command_scan_type not in {'path', 'repository'}:
114-
raise ValueError(f'Sync flow is not available for "{command_scan_type}" command type. Remove --sync option.')
118+
return False
115119

116-
if scan_type is consts.SAST_SCAN_TYPE:
117-
raise ValueError('Sync scan is not available for SAST scan type.')
120+
if scan_type == consts.IAC_SCAN_TYPE:
121+
# sync in the only available flow for IAC scan; we do not use detector directly anymore
122+
return True
118123

119-
if scan_parameters.get('report') is True:
120-
raise ValueError('You can not use sync flow with report option. Either remove "report" or "sync" option.')
124+
if scan_type is consts.SAST_SCAN_TYPE: # noqa: SIM103
125+
# SAST does not support sync flow
126+
return False
121127

122128
return True
123129

@@ -169,8 +175,7 @@ def _scan_batch_thread_func(batch: List[Document]) -> Tuple[str, CliError, Local
169175
scan_id = str(_generate_unique_id())
170176
scan_completed = False
171177

172-
should_use_scan_service = _should_use_scan_service(scan_type, scan_parameters)
173-
should_use_sync_flow = _should_use_sync_flow(command_scan_type, scan_type, sync_option, scan_parameters)
178+
should_use_sync_flow = _should_use_sync_flow(command_scan_type, scan_type, sync_option)
174179

175180
try:
176181
logger.debug('Preparing local files, %s', {'batch_files_count': len(batch)})
@@ -180,11 +185,9 @@ def _scan_batch_thread_func(batch: List[Document]) -> Tuple[str, CliError, Local
180185
cycode_client,
181186
zipped_documents,
182187
scan_type,
183-
scan_id,
184188
is_git_diff,
185189
is_commit_range,
186190
scan_parameters,
187-
should_use_scan_service,
188191
should_use_sync_flow,
189192
)
190193

@@ -224,7 +227,6 @@ def _scan_batch_thread_func(batch: List[Document]) -> Tuple[str, CliError, Local
224227
zip_file_size,
225228
command_scan_type,
226229
error_message,
227-
should_use_scan_service or should_use_sync_flow, # sync flow implies scan service
228230
)
229231

230232
return scan_id, error, local_scan_result
@@ -456,24 +458,16 @@ def perform_scan(
456458
cycode_client: 'ScanClient',
457459
zipped_documents: 'InMemoryZip',
458460
scan_type: str,
459-
scan_id: str,
460461
is_git_diff: bool,
461462
is_commit_range: bool,
462463
scan_parameters: dict,
463-
should_use_scan_service: bool = False,
464464
should_use_sync_flow: bool = False,
465465
) -> ZippedFileScanResult:
466466
if should_use_sync_flow:
467467
# it does not support commit range scans; should_use_sync_flow handles it
468468
return perform_scan_sync(cycode_client, zipped_documents, scan_type, scan_parameters, is_git_diff)
469469

470-
if scan_type in (consts.SCA_SCAN_TYPE, consts.SAST_SCAN_TYPE) or should_use_scan_service:
471-
return perform_scan_async(cycode_client, zipped_documents, scan_type, scan_parameters, is_commit_range)
472-
473-
if is_commit_range:
474-
return cycode_client.commit_range_zipped_file_scan(scan_type, zipped_documents, scan_id)
475-
476-
return cycode_client.zipped_file_scan(scan_type, zipped_documents, scan_id, scan_parameters, is_git_diff)
470+
return perform_scan_async(cycode_client, zipped_documents, scan_type, scan_parameters, is_commit_range)
477471

478472

479473
def perform_scan_async(
@@ -823,7 +817,6 @@ def _report_scan_status(
823817
zip_size: int,
824818
command_scan_type: str,
825819
error_message: Optional[str],
826-
should_use_scan_service: bool = False,
827820
) -> None:
828821
try:
829822
end_scan_time = time.time()
@@ -840,12 +833,15 @@ def _report_scan_status(
840833
'scan_type': scan_type,
841834
}
842835

843-
cycode_client.report_scan_status(scan_type, scan_id, scan_status, should_use_scan_service)
836+
cycode_client.report_scan_status(scan_type, scan_id, scan_status)
844837
except Exception as e:
845838
logger.debug('Failed to report scan status', exc_info=e)
846839

847840

848841
def _generate_unique_id() -> UUID:
842+
if 'PYTEST_TEST_UNIQUE_ID' in os.environ:
843+
return UUID(os.environ['PYTEST_TEST_UNIQUE_ID'])
844+
849845
return uuid4()
850846

851847

@@ -868,13 +864,13 @@ def _get_scan_result(
868864
if not scan_details.detections_count:
869865
return init_default_scan_result(scan_id)
870866

871-
scan_raw_detections = cycode_client.get_scan_raw_detections(scan_type, scan_id)
867+
scan_raw_detections = cycode_client.get_scan_raw_detections(scan_id)
872868

873869
return ZippedFileScanResult(
874870
did_detect=True,
875871
detections_per_file=_map_detections_per_file_and_commit_id(scan_type, scan_raw_detections),
876872
scan_id=scan_id,
877-
report_url=_try_get_any_report_url_if_needed(cycode_client, scan_id, scan_type, scan_parameters),
873+
report_url=_try_get_aggregation_report_url_if_needed(scan_parameters, cycode_client, scan_type),
878874
)
879875

880876

@@ -886,37 +882,6 @@ def init_default_scan_result(scan_id: str) -> ZippedFileScanResult:
886882
)
887883

888884

889-
def _try_get_any_report_url_if_needed(
890-
cycode_client: 'ScanClient',
891-
scan_id: str,
892-
scan_type: str,
893-
scan_parameters: dict,
894-
) -> Optional[str]:
895-
"""Tries to get aggregation report URL if needed, otherwise tries to get report URL."""
896-
aggregation_report_url = None
897-
if scan_parameters:
898-
_try_get_report_url_if_needed(cycode_client, scan_id, scan_type, scan_parameters)
899-
aggregation_report_url = _try_get_aggregation_report_url_if_needed(scan_parameters, cycode_client, scan_type)
900-
901-
if aggregation_report_url:
902-
return aggregation_report_url
903-
904-
return _try_get_report_url_if_needed(cycode_client, scan_id, scan_type, scan_parameters)
905-
906-
907-
def _try_get_report_url_if_needed(
908-
cycode_client: 'ScanClient', scan_id: str, scan_type: str, scan_parameters: dict
909-
) -> Optional[str]:
910-
if not scan_parameters.get('report', False):
911-
return None
912-
913-
try:
914-
report_url_response = cycode_client.get_scan_report_url(scan_id, scan_type)
915-
return report_url_response.report_url
916-
except Exception as e:
917-
logger.debug('Failed to get report URL', exc_info=e)
918-
919-
920885
def _set_aggregation_report_url(ctx: typer.Context, aggregation_report_url: Optional[str] = None) -> None:
921886
ctx.obj['aggregation_report_url'] = aggregation_report_url
922887

cycode/cli/apps/scan/scan_command.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,9 @@ def scan_command(
5454
] = SeverityOption.INFO,
5555
sync: Annotated[
5656
bool,
57-
typer.Option('--sync', help='Run scan synchronously.', show_default='asynchronously'),
57+
typer.Option(
58+
'--sync', help='Run scan synchronously (INTERNAL FOR IDEs).', show_default='asynchronously', hidden=True
59+
),
5860
] = False,
5961
report: Annotated[
6062
bool,

cycode/cyclient/models.py

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -59,19 +59,6 @@ def __init__(self, file_name: str, detections: List[Detection], commit_id: Optio
5959
self.commit_id = commit_id
6060

6161

62-
class DetectionsPerFileSchema(Schema):
63-
class Meta:
64-
unknown = EXCLUDE
65-
66-
file_name = fields.String()
67-
detections = fields.List(fields.Nested(DetectionSchema))
68-
commit_id = fields.String(allow_none=True)
69-
70-
@post_load
71-
def build_dto(self, data: Dict[str, Any], **_) -> 'DetectionsPerFile':
72-
return DetectionsPerFile(**data)
73-
74-
7562
class ZippedFileScanResult(Schema):
7663
def __init__(
7764
self,
@@ -89,21 +76,6 @@ def __init__(
8976
self.err = err
9077

9178

92-
class ZippedFileScanResultSchema(Schema):
93-
class Meta:
94-
unknown = EXCLUDE
95-
96-
did_detect = fields.Boolean()
97-
scan_id = fields.String()
98-
report_url = fields.String(allow_none=True)
99-
detections_per_file = fields.List(fields.Nested(DetectionsPerFileSchema))
100-
err = fields.String()
101-
102-
@post_load
103-
def build_dto(self, data: Dict[str, Any], **_) -> 'ZippedFileScanResult':
104-
return ZippedFileScanResult(**data)
105-
106-
10779
class ScanResult(Schema):
10880
def __init__(
10981
self,

0 commit comments

Comments
 (0)