2929 generate_unique_scan_id ,
3030 is_cycodeignore_allowed_by_scan_config ,
3131 set_issue_detected_by_scan_results ,
32+ should_use_presigned_upload ,
3233)
3334from cycode .cyclient .models import ZippedFileScanResult
3435from cycode .logger import get_logger
3536
3637if TYPE_CHECKING :
3738 from cycode .cli .files_collector .models .in_memory_zip import InMemoryZip
39+ from cycode .cli .printers .console_printer import ConsolePrinter
40+ from cycode .cli .utils .progress_bar import BaseProgressBar
3841 from cycode .cyclient .scan_client import ScanClient
3942
4043start_scan_time = time .time ()
@@ -106,7 +109,10 @@ def _should_use_sync_flow(command_scan_type: str, scan_type: str, sync_option: b
106109
107110
108111def _get_scan_documents_thread_func (
109- ctx : typer .Context , is_git_diff : bool , is_commit_range : bool , scan_parameters : dict
112+ ctx : typer .Context ,
113+ is_git_diff : bool ,
114+ is_commit_range : bool ,
115+ scan_parameters : dict ,
110116) -> Callable [[list [Document ]], tuple [str , CliError , LocalScanResult ]]:
111117 cycode_client = ctx .obj ['client' ]
112118 scan_type = ctx .obj ['scan_type' ]
@@ -180,6 +186,36 @@ def _scan_batch_thread_func(batch: list[Document]) -> tuple[str, CliError, Local
180186 return _scan_batch_thread_func
181187
182188
189+ def _run_presigned_upload_scan (
190+ scan_batch_thread_func : Callable ,
191+ scan_type : str ,
192+ documents_to_scan : list [Document ],
193+ progress_bar : 'BaseProgressBar' ,
194+ printer : 'ConsolePrinter' ,
195+ ) -> tuple :
196+ try :
197+ # Try to zip all documents as a single batch; ZipTooLargeError raised if it exceeds the scan type's limit
198+ zip_documents (scan_type , documents_to_scan )
199+ # It fits: skip batching and upload everything as one ZIP
200+ return run_parallel_batched_scan (
201+ scan_batch_thread_func ,
202+ scan_type ,
203+ documents_to_scan ,
204+ progress_bar = progress_bar ,
205+ skip_batching = True ,
206+ )
207+ except custom_exceptions .ZipTooLargeError :
208+ printer .print_warning (
209+ 'The scan is too large to upload as a single file. This may result in corrupted scan results.'
210+ )
211+ return run_parallel_batched_scan (
212+ scan_batch_thread_func ,
213+ scan_type ,
214+ documents_to_scan ,
215+ progress_bar = progress_bar ,
216+ )
217+
218+
183219def scan_documents (
184220 ctx : typer .Context ,
185221 documents_to_scan : list [Document ],
@@ -203,9 +239,15 @@ def scan_documents(
203239 return
204240
205241 scan_batch_thread_func = _get_scan_documents_thread_func (ctx , is_git_diff , is_commit_range , scan_parameters )
206- errors , local_scan_results = run_parallel_batched_scan (
207- scan_batch_thread_func , scan_type , documents_to_scan , progress_bar = progress_bar
208- )
242+
243+ if should_use_presigned_upload (scan_type ):
244+ errors , local_scan_results = _run_presigned_upload_scan (
245+ scan_batch_thread_func , scan_type , documents_to_scan , progress_bar , printer
246+ )
247+ else :
248+ errors , local_scan_results = run_parallel_batched_scan (
249+ scan_batch_thread_func , scan_type , documents_to_scan , progress_bar = progress_bar
250+ )
209251
210252 try_set_aggregation_report_url_if_needed (ctx , scan_parameters , ctx .obj ['client' ], scan_type )
211253
@@ -217,6 +259,31 @@ def scan_documents(
217259 print_local_scan_results (ctx , local_scan_results , errors )
218260
219261
262+ def _perform_scan_v4_async (
263+ cycode_client : 'ScanClient' ,
264+ zipped_documents : 'InMemoryZip' ,
265+ scan_type : str ,
266+ scan_parameters : dict ,
267+ is_git_diff : bool ,
268+ is_commit_range : bool ,
269+ ) -> ZippedFileScanResult :
270+ upload_link = cycode_client .get_upload_link (scan_type )
271+ logger .debug ('Got upload link, %s' , {'upload_id' : upload_link .upload_id })
272+
273+ cycode_client .upload_to_presigned_post (upload_link .url , upload_link .presigned_post_fields , zipped_documents )
274+ logger .debug ('Uploaded zip to presigned URL' )
275+
276+ scan_async_result = cycode_client .scan_repository_from_upload_id (
277+ scan_type , upload_link .upload_id , scan_parameters , is_git_diff , is_commit_range
278+ )
279+ logger .debug (
280+ 'Presigned upload scan request triggered, %s' ,
281+ {'scan_id' : scan_async_result .scan_id , 'upload_id' : upload_link .upload_id },
282+ )
283+
284+ return poll_scan_results (cycode_client , scan_async_result .scan_id , scan_type , scan_parameters )
285+
286+
220287def _perform_scan_async (
221288 cycode_client : 'ScanClient' ,
222289 zipped_documents : 'InMemoryZip' ,
@@ -262,6 +329,11 @@ def _perform_scan(
262329 # it does not support commit range scans; should_use_sync_flow handles it
263330 return _perform_scan_sync (cycode_client , zipped_documents , scan_type , scan_parameters , is_git_diff )
264331
332+ if should_use_presigned_upload (scan_type ):
333+ return _perform_scan_v4_async (
334+ cycode_client , zipped_documents , scan_type , scan_parameters , is_git_diff , is_commit_range
335+ )
336+
265337 return _perform_scan_async (cycode_client , zipped_documents , scan_type , scan_parameters , is_commit_range )
266338
267339
0 commit comments