cycode 2.3.1.dev2__tar.gz → 2.3.2.dev1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/PKG-INFO +1 -1
  2. cycode-2.3.2.dev1/cycode/__init__.py +1 -0
  3. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/commands/scan/code_scanner.py +68 -60
  4. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/commands/scan/pre_commit/pre_commit_command.py +2 -2
  5. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/commands/scan/repository/repository_command.py +1 -2
  6. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/consts.py +4 -0
  7. cycode-2.3.2.dev1/cycode/cli/utils/scan_batch.py +138 -0
  8. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/pyproject.toml +1 -1
  9. cycode-2.3.1.dev2/cycode/__init__.py +0 -1
  10. cycode-2.3.1.dev2/cycode/cli/utils/scan_batch.py +0 -75
  11. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/LICENCE +0 -0
  12. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/README.md +0 -0
  13. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/__init__.py +0 -0
  14. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/commands/__init__.py +0 -0
  15. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/commands/ai_remediation/__init__.py +0 -0
  16. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/commands/ai_remediation/ai_remediation_command.py +0 -0
  17. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/commands/auth/__init__.py +0 -0
  18. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/commands/auth/auth_command.py +0 -0
  19. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/commands/auth/auth_manager.py +0 -0
  20. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/commands/auth_common.py +0 -0
  21. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/commands/configure/__init__.py +0 -0
  22. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/commands/configure/configure_command.py +0 -0
  23. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/commands/ignore/__init__.py +0 -0
  24. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/commands/ignore/ignore_command.py +0 -0
  25. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/commands/main_cli.py +0 -0
  26. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/commands/report/__init__.py +0 -0
  27. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/commands/report/report_command.py +0 -0
  28. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/commands/report/sbom/__init__.py +0 -0
  29. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/commands/report/sbom/common.py +0 -0
  30. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/commands/report/sbom/path/__init__.py +0 -0
  31. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/commands/report/sbom/path/path_command.py +0 -0
  32. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/commands/report/sbom/repository_url/__init__.py +0 -0
  33. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/commands/report/sbom/repository_url/repository_url_command.py +0 -0
  34. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/commands/report/sbom/sbom_command.py +0 -0
  35. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/commands/report/sbom/sbom_report_file.py +0 -0
  36. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/commands/scan/__init__.py +0 -0
  37. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/commands/scan/commit_history/__init__.py +0 -0
  38. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/commands/scan/commit_history/commit_history_command.py +0 -0
  39. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/commands/scan/path/__init__.py +0 -0
  40. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/commands/scan/path/path_command.py +0 -0
  41. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/commands/scan/pre_commit/__init__.py +0 -0
  42. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/commands/scan/pre_receive/__init__.py +0 -0
  43. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/commands/scan/pre_receive/pre_receive_command.py +0 -0
  44. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/commands/scan/repository/__init__.py +0 -0
  45. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/commands/scan/scan_ci/__init__.py +0 -0
  46. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/commands/scan/scan_ci/ci_integrations.py +0 -0
  47. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/commands/scan/scan_ci/scan_ci_command.py +0 -0
  48. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/commands/scan/scan_command.py +0 -0
  49. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/commands/status/__init__.py +0 -0
  50. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/commands/status/status_command.py +0 -0
  51. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/commands/version/__init__.py +0 -0
  52. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/commands/version/version_checker.py +0 -0
  53. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/commands/version/version_command.py +0 -0
  54. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/config.py +0 -0
  55. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/config.yaml +0 -0
  56. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/exceptions/__init__.py +0 -0
  57. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/exceptions/common.py +0 -0
  58. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/exceptions/custom_exceptions.py +0 -0
  59. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/exceptions/handle_ai_remediation_errors.py +0 -0
  60. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/exceptions/handle_report_sbom_errors.py +0 -0
  61. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/exceptions/handle_scan_errors.py +0 -0
  62. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/files_collector/__init__.py +0 -0
  63. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/files_collector/excluder.py +0 -0
  64. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/files_collector/iac/__init__.py +0 -0
  65. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/files_collector/iac/tf_content_generator.py +0 -0
  66. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/files_collector/models/__init__.py +0 -0
  67. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/files_collector/models/in_memory_zip.py +0 -0
  68. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/files_collector/path_documents.py +0 -0
  69. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/files_collector/repository_documents.py +0 -0
  70. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/files_collector/sca/__init__.py +0 -0
  71. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/files_collector/sca/base_restore_dependencies.py +0 -0
  72. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/files_collector/sca/go/__init__.py +0 -0
  73. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/files_collector/sca/go/restore_go_dependencies.py +0 -0
  74. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/files_collector/sca/maven/__init__.py +0 -0
  75. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/files_collector/sca/maven/restore_gradle_dependencies.py +0 -0
  76. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/files_collector/sca/maven/restore_maven_dependencies.py +0 -0
  77. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/files_collector/sca/npm/__init__.py +0 -0
  78. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/files_collector/sca/npm/restore_npm_dependencies.py +0 -0
  79. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/files_collector/sca/nuget/__init__.py +0 -0
  80. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/files_collector/sca/nuget/restore_nuget_dependencies.py +0 -0
  81. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/files_collector/sca/ruby/__init__.py +0 -0
  82. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/files_collector/sca/ruby/restore_ruby_dependencies.py +0 -0
  83. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/files_collector/sca/sbt/__init__.py +0 -0
  84. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/files_collector/sca/sbt/restore_sbt_dependencies.py +0 -0
  85. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/files_collector/sca/sca_code_scanner.py +0 -0
  86. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/files_collector/walk_ignore.py +0 -0
  87. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/files_collector/zip_documents.py +0 -0
  88. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/main.py +0 -0
  89. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/models.py +0 -0
  90. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/printers/__init__.py +0 -0
  91. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/printers/console_printer.py +0 -0
  92. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/printers/json_printer.py +0 -0
  93. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/printers/printer_base.py +0 -0
  94. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/printers/tables/__init__.py +0 -0
  95. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/printers/tables/sca_table_printer.py +0 -0
  96. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/printers/tables/table.py +0 -0
  97. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/printers/tables/table_models.py +0 -0
  98. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/printers/tables/table_printer.py +0 -0
  99. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/printers/tables/table_printer_base.py +0 -0
  100. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/printers/text_printer.py +0 -0
  101. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/sentry.py +0 -0
  102. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/user_settings/__init__.py +0 -0
  103. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/user_settings/base_file_manager.py +0 -0
  104. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/user_settings/config_file_manager.py +0 -0
  105. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/user_settings/configuration_manager.py +0 -0
  106. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/user_settings/credentials_manager.py +0 -0
  107. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/user_settings/jwt_creator.py +0 -0
  108. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/utils/__init__.py +0 -0
  109. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/utils/enum_utils.py +0 -0
  110. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/utils/get_api_client.py +0 -0
  111. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/utils/git_proxy.py +0 -0
  112. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/utils/ignore_utils.py +0 -0
  113. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/utils/jwt_utils.py +0 -0
  114. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/utils/path_utils.py +0 -0
  115. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/utils/progress_bar.py +0 -0
  116. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/utils/scan_utils.py +0 -0
  117. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/utils/shell_executor.py +0 -0
  118. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/utils/string_utils.py +0 -0
  119. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/utils/task_timer.py +0 -0
  120. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cli/utils/yaml_utils.py +0 -0
  121. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cyclient/__init__.py +0 -0
  122. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cyclient/auth_client.py +0 -0
  123. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cyclient/client_creator.py +0 -0
  124. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cyclient/config.py +0 -0
  125. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cyclient/config.yaml +0 -0
  126. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cyclient/config_dev.py +0 -0
  127. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cyclient/cycode_client.py +0 -0
  128. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cyclient/cycode_client_base.py +0 -0
  129. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cyclient/cycode_dev_based_client.py +0 -0
  130. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cyclient/cycode_token_based_client.py +0 -0
  131. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cyclient/headers.py +0 -0
  132. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cyclient/models.py +0 -0
  133. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cyclient/report_client.py +0 -0
  134. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cyclient/scan_client.py +0 -0
  135. {cycode-2.3.1.dev2 → cycode-2.3.2.dev1}/cycode/cyclient/scan_config_base.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cycode
3
- Version: 2.3.1.dev2
3
+ Version: 2.3.2.dev1
4
4
  Summary: Boost security in your dev lifecycle via SAST, SCA, Secrets & IaC scanning.
5
5
  Home-page: https://github.com/cycodehq/cycode-cli
6
6
  License: MIT
@@ -0,0 +1 @@
1
+ __version__ = '2.3.2.dev1' # DON'T TOUCH. Placeholder. Will be filled automatically on poetry build from Git Tag
@@ -45,7 +45,7 @@ start_scan_time = time.time()
45
45
 
46
46
  def scan_sca_pre_commit(context: click.Context) -> None:
47
47
  scan_type = context.obj['scan_type']
48
- scan_parameters = get_default_scan_parameters(context)
48
+ scan_parameters = get_scan_parameters(context)
49
49
  git_head_documents, pre_committed_documents = get_pre_commit_modified_documents(
50
50
  context.obj['progress_bar'], ScanProgressBarSection.PREPARE_LOCAL_FILES
51
51
  )
@@ -80,14 +80,13 @@ def scan_sca_commit_range(context: click.Context, path: str, commit_range: str)
80
80
 
81
81
 
82
82
  def scan_disk_files(context: click.Context, paths: Tuple[str]) -> None:
83
- scan_parameters = get_scan_parameters(context, paths)
84
83
  scan_type = context.obj['scan_type']
85
84
  progress_bar = context.obj['progress_bar']
86
85
 
87
86
  try:
88
87
  documents = get_relevant_documents(progress_bar, ScanProgressBarSection.PREPARE_LOCAL_FILES, scan_type, paths)
89
88
  perform_pre_scan_documents_actions(context, scan_type, documents)
90
- scan_documents(context, documents, scan_parameters=scan_parameters)
89
+ scan_documents(context, documents, get_scan_parameters(context, paths))
91
90
  except Exception as e:
92
91
  handle_scan_exception(context, e)
93
92
 
@@ -151,14 +150,12 @@ def _enrich_scan_result_with_data_from_detection_rules(
151
150
 
152
151
  def _get_scan_documents_thread_func(
153
152
  context: click.Context, is_git_diff: bool, is_commit_range: bool, scan_parameters: dict
154
- ) -> Tuple[Callable[[List[Document]], Tuple[str, CliError, LocalScanResult]], str]:
153
+ ) -> Callable[[List[Document]], Tuple[str, CliError, LocalScanResult]]:
155
154
  cycode_client = context.obj['client']
156
155
  scan_type = context.obj['scan_type']
157
156
  severity_threshold = context.obj['severity_threshold']
158
157
  sync_option = context.obj['sync']
159
158
  command_scan_type = context.info_name
160
- aggregation_id = str(_generate_unique_id())
161
- scan_parameters['aggregation_id'] = aggregation_id
162
159
 
163
160
  def _scan_batch_thread_func(batch: List[Document]) -> Tuple[str, CliError, LocalScanResult]:
164
161
  local_scan_result = error = error_message = None
@@ -171,7 +168,7 @@ def _get_scan_documents_thread_func(
171
168
  should_use_sync_flow = _should_use_sync_flow(command_scan_type, scan_type, sync_option, scan_parameters)
172
169
 
173
170
  try:
174
- logger.debug('Preparing local files, %s', {'batch_size': len(batch)})
171
+ logger.debug('Preparing local files, %s', {'batch_files_count': len(batch)})
175
172
  zipped_documents = zip_documents(scan_type, batch)
176
173
  zip_file_size = zipped_documents.size
177
174
  scan_result = perform_scan(
@@ -227,7 +224,7 @@ def _get_scan_documents_thread_func(
227
224
 
228
225
  return scan_id, error, local_scan_result
229
226
 
230
- return _scan_batch_thread_func, aggregation_id
227
+ return _scan_batch_thread_func
231
228
 
232
229
 
233
230
  def scan_commit_range(
@@ -287,20 +284,19 @@ def scan_commit_range(
287
284
  logger.debug('List of commit ids to scan, %s', {'commit_ids': commit_ids_to_scan})
288
285
  logger.debug('Starting to scan commit range (it may take a few minutes)')
289
286
 
290
- scan_documents(context, documents_to_scan, is_git_diff=True, is_commit_range=True)
287
+ scan_documents(
288
+ context, documents_to_scan, get_scan_parameters(context, (path,)), is_git_diff=True, is_commit_range=True
289
+ )
291
290
  return None
292
291
 
293
292
 
294
293
  def scan_documents(
295
294
  context: click.Context,
296
295
  documents_to_scan: List[Document],
296
+ scan_parameters: dict,
297
297
  is_git_diff: bool = False,
298
298
  is_commit_range: bool = False,
299
- scan_parameters: Optional[dict] = None,
300
299
  ) -> None:
301
- if not scan_parameters:
302
- scan_parameters = get_default_scan_parameters(context)
303
-
304
300
  scan_type = context.obj['scan_type']
305
301
  progress_bar = context.obj['progress_bar']
306
302
 
@@ -315,19 +311,15 @@ def scan_documents(
315
311
  )
316
312
  return
317
313
 
318
- scan_batch_thread_func, aggregation_id = _get_scan_documents_thread_func(
319
- context, is_git_diff, is_commit_range, scan_parameters
320
- )
314
+ scan_batch_thread_func = _get_scan_documents_thread_func(context, is_git_diff, is_commit_range, scan_parameters)
321
315
  errors, local_scan_results = run_parallel_batched_scan(
322
316
  scan_batch_thread_func, scan_type, documents_to_scan, progress_bar=progress_bar
323
317
  )
324
318
 
325
- if len(local_scan_results) > 1:
326
- # if we used more than one batch, we need to fetch aggregate report url
327
- aggregation_report_url = _try_get_aggregation_report_url_if_needed(
328
- scan_parameters, context.obj['client'], scan_type
329
- )
330
- set_aggregation_report_url(context, aggregation_report_url)
319
+ aggregation_report_url = _try_get_aggregation_report_url_if_needed(
320
+ scan_parameters, context.obj['client'], scan_type
321
+ )
322
+ _set_aggregation_report_url(context, aggregation_report_url)
331
323
 
332
324
  progress_bar.set_section_length(ScanProgressBarSection.GENERATE_REPORT, 1)
333
325
  progress_bar.update(ScanProgressBarSection.GENERATE_REPORT)
@@ -337,25 +329,6 @@ def scan_documents(
337
329
  print_results(context, local_scan_results, errors)
338
330
 
339
331
 
340
- def set_aggregation_report_url(context: click.Context, aggregation_report_url: Optional[str] = None) -> None:
341
- context.obj['aggregation_report_url'] = aggregation_report_url
342
-
343
-
344
- def _try_get_aggregation_report_url_if_needed(
345
- scan_parameters: dict, cycode_client: 'ScanClient', scan_type: str
346
- ) -> Optional[str]:
347
- aggregation_id = scan_parameters.get('aggregation_id')
348
- if not scan_parameters.get('report'):
349
- return None
350
- if aggregation_id is None:
351
- return None
352
- try:
353
- report_url_response = cycode_client.get_scan_aggregation_report_url(aggregation_id, scan_type)
354
- return report_url_response.report_url
355
- except Exception as e:
356
- logger.debug('Failed to get aggregation report url: %s', str(e))
357
-
358
-
359
332
  def scan_commit_range_documents(
360
333
  context: click.Context,
361
334
  from_documents_to_scan: List[Document],
@@ -380,7 +353,7 @@ def scan_commit_range_documents(
380
353
  try:
381
354
  progress_bar.set_section_length(ScanProgressBarSection.SCAN, 1)
382
355
 
383
- scan_result = init_default_scan_result(cycode_client, scan_id, scan_type)
356
+ scan_result = init_default_scan_result(scan_id)
384
357
  if should_scan_documents(from_documents_to_scan, to_documents_to_scan):
385
358
  logger.debug('Preparing from-commit zip')
386
359
  from_commit_zipped_documents = zip_documents(scan_type, from_documents_to_scan)
@@ -518,7 +491,7 @@ def perform_scan_async(
518
491
  cycode_client,
519
492
  scan_async_result.scan_id,
520
493
  scan_type,
521
- scan_parameters.get('report'),
494
+ scan_parameters,
522
495
  )
523
496
 
524
497
 
@@ -553,16 +526,14 @@ def perform_commit_range_scan_async(
553
526
  logger.debug(
554
527
  'Async commit range scan request has been triggered successfully, %s', {'scan_id': scan_async_result.scan_id}
555
528
  )
556
- return poll_scan_results(
557
- cycode_client, scan_async_result.scan_id, scan_type, scan_parameters.get('report'), timeout
558
- )
529
+ return poll_scan_results(cycode_client, scan_async_result.scan_id, scan_type, scan_parameters, timeout)
559
530
 
560
531
 
561
532
  def poll_scan_results(
562
533
  cycode_client: 'ScanClient',
563
534
  scan_id: str,
564
535
  scan_type: str,
565
- should_get_report: bool = False,
536
+ scan_parameters: dict,
566
537
  polling_timeout: Optional[int] = None,
567
538
  ) -> ZippedFileScanResult:
568
539
  if polling_timeout is None:
@@ -579,7 +550,7 @@ def poll_scan_results(
579
550
  print_debug_scan_details(scan_details)
580
551
 
581
552
  if scan_details.scan_status == consts.SCAN_STATUS_COMPLETED:
582
- return _get_scan_result(cycode_client, scan_type, scan_id, scan_details, should_get_report)
553
+ return _get_scan_result(cycode_client, scan_type, scan_id, scan_details, scan_parameters)
583
554
 
584
555
  if scan_details.scan_status == consts.SCAN_STATUS_ERROR:
585
556
  raise custom_exceptions.ScanAsyncError(
@@ -671,18 +642,19 @@ def parse_pre_receive_input() -> str:
671
642
  return pre_receive_input.splitlines()[0]
672
643
 
673
644
 
674
- def get_default_scan_parameters(context: click.Context) -> dict:
645
+ def _get_default_scan_parameters(context: click.Context) -> dict:
675
646
  return {
676
647
  'monitor': context.obj.get('monitor'),
677
648
  'report': context.obj.get('report'),
678
649
  'package_vulnerabilities': context.obj.get('package-vulnerabilities'),
679
650
  'license_compliance': context.obj.get('license-compliance'),
680
651
  'command_type': context.info_name,
652
+ 'aggregation_id': str(_generate_unique_id()),
681
653
  }
682
654
 
683
655
 
684
- def get_scan_parameters(context: click.Context, paths: Tuple[str]) -> dict:
685
- scan_parameters = get_default_scan_parameters(context)
656
+ def get_scan_parameters(context: click.Context, paths: Optional[Tuple[str]] = None) -> dict:
657
+ scan_parameters = _get_default_scan_parameters(context)
686
658
 
687
659
  if not paths:
688
660
  return scan_parameters
@@ -890,10 +862,10 @@ def _get_scan_result(
890
862
  scan_type: str,
891
863
  scan_id: str,
892
864
  scan_details: 'ScanDetailsResponse',
893
- should_get_report: bool = False,
865
+ scan_parameters: dict,
894
866
  ) -> ZippedFileScanResult:
895
867
  if not scan_details.detections_count:
896
- return init_default_scan_result(cycode_client, scan_id, scan_type, should_get_report)
868
+ return init_default_scan_result(scan_id)
897
869
 
898
870
  scan_raw_detections = cycode_client.get_scan_raw_detections(scan_type, scan_id)
899
871
 
@@ -901,25 +873,40 @@ def _get_scan_result(
901
873
  did_detect=True,
902
874
  detections_per_file=_map_detections_per_file_and_commit_id(scan_type, scan_raw_detections),
903
875
  scan_id=scan_id,
904
- report_url=_try_get_report_url_if_needed(cycode_client, should_get_report, scan_id, scan_type),
876
+ report_url=_try_get_any_report_url_if_needed(cycode_client, scan_id, scan_type, scan_parameters),
905
877
  )
906
878
 
907
879
 
908
- def init_default_scan_result(
909
- cycode_client: 'ScanClient', scan_id: str, scan_type: str, should_get_report: bool = False
910
- ) -> ZippedFileScanResult:
880
+ def init_default_scan_result(scan_id: str) -> ZippedFileScanResult:
911
881
  return ZippedFileScanResult(
912
882
  did_detect=False,
913
883
  detections_per_file=[],
914
884
  scan_id=scan_id,
915
- report_url=_try_get_report_url_if_needed(cycode_client, should_get_report, scan_id, scan_type),
916
885
  )
917
886
 
918
887
 
888
+ def _try_get_any_report_url_if_needed(
889
+ cycode_client: 'ScanClient',
890
+ scan_id: str,
891
+ scan_type: str,
892
+ scan_parameters: dict,
893
+ ) -> Optional[str]:
894
+ """Tries to get aggregation report URL if needed, otherwise tries to get report URL."""
895
+ aggregation_report_url = None
896
+ if scan_parameters:
897
+ _try_get_report_url_if_needed(cycode_client, scan_id, scan_type, scan_parameters)
898
+ aggregation_report_url = _try_get_aggregation_report_url_if_needed(scan_parameters, cycode_client, scan_type)
899
+
900
+ if aggregation_report_url:
901
+ return aggregation_report_url
902
+
903
+ return _try_get_report_url_if_needed(cycode_client, scan_id, scan_type, scan_parameters)
904
+
905
+
919
906
  def _try_get_report_url_if_needed(
920
- cycode_client: 'ScanClient', should_get_report: bool, scan_id: str, scan_type: str
907
+ cycode_client: 'ScanClient', scan_id: str, scan_type: str, scan_parameters: dict
921
908
  ) -> Optional[str]:
922
- if not should_get_report:
909
+ if not scan_parameters.get('report', False):
923
910
  return None
924
911
 
925
912
  try:
@@ -929,6 +916,27 @@ def _try_get_report_url_if_needed(
929
916
  logger.debug('Failed to get report URL', exc_info=e)
930
917
 
931
918
 
919
+ def _set_aggregation_report_url(context: click.Context, aggregation_report_url: Optional[str] = None) -> None:
920
+ context.obj['aggregation_report_url'] = aggregation_report_url
921
+
922
+
923
+ def _try_get_aggregation_report_url_if_needed(
924
+ scan_parameters: dict, cycode_client: 'ScanClient', scan_type: str
925
+ ) -> Optional[str]:
926
+ if not scan_parameters.get('report', False):
927
+ return None
928
+
929
+ aggregation_id = scan_parameters.get('aggregation_id')
930
+ if aggregation_id is None:
931
+ return None
932
+
933
+ try:
934
+ report_url_response = cycode_client.get_scan_aggregation_report_url(aggregation_id, scan_type)
935
+ return report_url_response.report_url
936
+ except Exception as e:
937
+ logger.debug('Failed to get aggregation report url: %s', str(e))
938
+
939
+
932
940
  def _map_detections_per_file_and_commit_id(scan_type: str, raw_detections: List[dict]) -> List[DetectionsPerFile]:
933
941
  """Converts list of detections (async flow) to list of DetectionsPerFile objects (sync flow).
934
942
 
@@ -4,7 +4,7 @@ from typing import List
4
4
  import click
5
5
 
6
6
  from cycode.cli import consts
7
- from cycode.cli.commands.scan.code_scanner import scan_documents, scan_sca_pre_commit
7
+ from cycode.cli.commands.scan.code_scanner import get_scan_parameters, scan_documents, scan_sca_pre_commit
8
8
  from cycode.cli.files_collector.excluder import exclude_irrelevant_documents_to_scan
9
9
  from cycode.cli.files_collector.repository_documents import (
10
10
  get_diff_file_content,
@@ -44,4 +44,4 @@ def pre_commit_command(context: click.Context, ignored_args: List[str]) -> None:
44
44
  documents_to_scan.append(Document(get_path_by_os(get_diff_file_path(file)), get_diff_file_content(file)))
45
45
 
46
46
  documents_to_scan = exclude_irrelevant_documents_to_scan(scan_type, documents_to_scan)
47
- scan_documents(context, documents_to_scan, is_git_diff=True)
47
+ scan_documents(context, documents_to_scan, get_scan_parameters(context), is_git_diff=True)
@@ -63,7 +63,6 @@ def repository_command(context: click.Context, path: str, branch: str) -> None:
63
63
  perform_pre_scan_documents_actions(context, scan_type, documents_to_scan)
64
64
 
65
65
  logger.debug('Found all relevant files for scanning %s', {'path': path, 'branch': branch})
66
- scan_parameters = get_scan_parameters(context, (path,))
67
- scan_documents(context, documents_to_scan, scan_parameters=scan_parameters)
66
+ scan_documents(context, documents_to_scan, get_scan_parameters(context, (path,)))
68
67
  except Exception as e:
69
68
  handle_scan_exception(context, e)
@@ -145,7 +145,11 @@ ZIP_MAX_SIZE_LIMIT_IN_BYTES = {
145
145
  # scan in batches
146
146
  DEFAULT_SCAN_BATCH_MAX_SIZE_IN_BYTES = 9 * 1024 * 1024
147
147
  SCAN_BATCH_MAX_SIZE_IN_BYTES = {SAST_SCAN_TYPE: 50 * 1024 * 1024}
148
+ SCAN_BATCH_MAX_SIZE_IN_BYTES_ENV_VAR_NAME = 'SCAN_BATCH_MAX_SIZE_IN_BYTES'
149
+
148
150
  DEFAULT_SCAN_BATCH_MAX_FILES_COUNT = 1000
151
+ SCAN_BATCH_MAX_FILES_COUNT_ENV_VAR_NAME = 'SCAN_BATCH_MAX_FILES_COUNT'
152
+
149
153
  # if we increase this values, the server doesn't allow connecting (ConnectionError)
150
154
  SCAN_BATCH_MAX_PARALLEL_SCANS = 5
151
155
  SCAN_BATCH_SCANS_PER_CPU = 1
@@ -0,0 +1,138 @@
1
+ import os
2
+ from multiprocessing.pool import ThreadPool
3
+ from typing import TYPE_CHECKING, Callable, Dict, List, Tuple
4
+
5
+ from cycode.cli import consts
6
+ from cycode.cli.models import Document
7
+ from cycode.cli.utils.progress_bar import ScanProgressBarSection
8
+ from cycode.cyclient import logger
9
+
10
+ if TYPE_CHECKING:
11
+ from cycode.cli.models import CliError, LocalScanResult
12
+ from cycode.cli.utils.progress_bar import BaseProgressBar
13
+
14
+
15
+ def _get_max_batch_size(scan_type: str) -> int:
16
+ logger.debug(
17
+ 'You can customize the batch size by setting the environment variable "%s"',
18
+ consts.SCAN_BATCH_MAX_SIZE_IN_BYTES_ENV_VAR_NAME,
19
+ )
20
+
21
+ custom_size = os.environ.get(consts.SCAN_BATCH_MAX_SIZE_IN_BYTES_ENV_VAR_NAME)
22
+ if custom_size:
23
+ logger.debug('Custom batch size is set, %s', {'custom_size': custom_size})
24
+ return int(custom_size)
25
+
26
+ return consts.SCAN_BATCH_MAX_SIZE_IN_BYTES.get(scan_type, consts.DEFAULT_SCAN_BATCH_MAX_SIZE_IN_BYTES)
27
+
28
+
29
+ def _get_max_batch_files_count(_: str) -> int:
30
+ logger.debug(
31
+ 'You can customize the batch files count by setting the environment variable "%s"',
32
+ consts.SCAN_BATCH_MAX_FILES_COUNT_ENV_VAR_NAME,
33
+ )
34
+
35
+ custom_files_count = os.environ.get(consts.SCAN_BATCH_MAX_FILES_COUNT_ENV_VAR_NAME)
36
+ if custom_files_count:
37
+ logger.debug('Custom batch files count is set, %s', {'custom_files_count': custom_files_count})
38
+ return int(custom_files_count)
39
+
40
+ return consts.DEFAULT_SCAN_BATCH_MAX_FILES_COUNT
41
+
42
+
43
+ def split_documents_into_batches(
44
+ scan_type: str,
45
+ documents: List[Document],
46
+ ) -> List[List[Document]]:
47
+ max_size = _get_max_batch_size(scan_type)
48
+ max_files_count = _get_max_batch_files_count(scan_type)
49
+
50
+ logger.debug(
51
+ 'Splitting documents into batches, %s',
52
+ {'document_count': len(documents), 'max_batch_size': max_size, 'max_files_count': max_files_count},
53
+ )
54
+
55
+ batches = []
56
+
57
+ current_size = 0
58
+ current_batch = []
59
+ for document in documents:
60
+ document_size = len(document.content.encode('UTF-8'))
61
+
62
+ exceeds_max_size = current_size + document_size > max_size
63
+ if exceeds_max_size:
64
+ logger.debug(
65
+ 'Going to create new batch because current batch size exceeds the limit, %s',
66
+ {
67
+ 'batch_index': len(batches),
68
+ 'current_batch_size': current_size + document_size,
69
+ 'max_batch_size': max_size,
70
+ },
71
+ )
72
+
73
+ exceeds_max_files_count = len(current_batch) >= max_files_count
74
+ if exceeds_max_files_count:
75
+ logger.debug(
76
+ 'Going to create new batch because current batch files count exceeds the limit, %s',
77
+ {
78
+ 'batch_index': len(batches),
79
+ 'current_batch_files_count': len(current_batch),
80
+ 'max_batch_files_count': max_files_count,
81
+ },
82
+ )
83
+
84
+ if exceeds_max_size or exceeds_max_files_count:
85
+ batches.append(current_batch)
86
+
87
+ current_batch = [document]
88
+ current_size = document_size
89
+ else:
90
+ current_batch.append(document)
91
+ current_size += document_size
92
+
93
+ if current_batch:
94
+ batches.append(current_batch)
95
+
96
+ logger.debug('Documents were split into batches %s', {'batches_count': len(batches)})
97
+
98
+ return batches
99
+
100
+
101
+ def _get_threads_count() -> int:
102
+ cpu_count = os.cpu_count() or 1
103
+ return min(cpu_count * consts.SCAN_BATCH_SCANS_PER_CPU, consts.SCAN_BATCH_MAX_PARALLEL_SCANS)
104
+
105
+
106
+ def run_parallel_batched_scan(
107
+ scan_function: Callable[[List[Document]], Tuple[str, 'CliError', 'LocalScanResult']],
108
+ scan_type: str,
109
+ documents: List[Document],
110
+ progress_bar: 'BaseProgressBar',
111
+ ) -> Tuple[Dict[str, 'CliError'], List['LocalScanResult']]:
112
+ # batching is disabled for SCA; requested by Mor
113
+ batches = [documents] if scan_type == consts.SCA_SCAN_TYPE else split_documents_into_batches(scan_type, documents)
114
+
115
+ progress_bar.set_section_length(ScanProgressBarSection.SCAN, len(batches)) # * 3
116
+ # TODO(MarshalX): we should multiply the count of batches in SCAN section because each batch has 3 steps:
117
+ # 1. scan creation
118
+ # 2. scan completion
119
+ # 3. detection creation
120
+ # it's not possible yet because not all scan types moved to polling mechanism
121
+ # the progress bar could be significant improved (be more dynamic) in the future
122
+
123
+ threads_count = _get_threads_count()
124
+ local_scan_results: List['LocalScanResult'] = []
125
+ cli_errors: Dict[str, 'CliError'] = {}
126
+
127
+ logger.debug('Running parallel batched scan, %s', {'threads_count': threads_count, 'batches_count': len(batches)})
128
+
129
+ with ThreadPool(processes=threads_count) as pool:
130
+ for scan_id, err, result in pool.imap(scan_function, batches):
131
+ if result:
132
+ local_scan_results.append(result)
133
+ if err:
134
+ cli_errors[scan_id] = err
135
+
136
+ progress_bar.update(ScanProgressBarSection.SCAN)
137
+
138
+ return cli_errors, local_scan_results
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "cycode"
3
- version = "2.3.1.dev2" # DON'T TOUCH. Placeholder. Will be filled automatically on poetry build from Git Tag
3
+ version = "2.3.2.dev1" # DON'T TOUCH. Placeholder. Will be filled automatically on poetry build from Git Tag
4
4
  description = "Boost security in your dev lifecycle via SAST, SCA, Secrets & IaC scanning."
5
5
  keywords=["secret-scan", "cycode", "devops", "token", "secret", "security", "cycode", "code"]
6
6
  authors = ["Cycode <support@cycode.com>"]
@@ -1 +0,0 @@
1
- __version__ = '2.3.1.dev2' # DON'T TOUCH. Placeholder. Will be filled automatically on poetry build from Git Tag
@@ -1,75 +0,0 @@
1
- import os
2
- from multiprocessing.pool import ThreadPool
3
- from typing import TYPE_CHECKING, Callable, Dict, List, Tuple
4
-
5
- from cycode.cli import consts
6
- from cycode.cli.models import Document
7
- from cycode.cli.utils.progress_bar import ScanProgressBarSection
8
-
9
- if TYPE_CHECKING:
10
- from cycode.cli.models import CliError, LocalScanResult
11
- from cycode.cli.utils.progress_bar import BaseProgressBar
12
-
13
-
14
- def split_documents_into_batches(
15
- documents: List[Document],
16
- max_size: int = consts.DEFAULT_SCAN_BATCH_MAX_SIZE_IN_BYTES,
17
- max_files_count: int = consts.DEFAULT_SCAN_BATCH_MAX_FILES_COUNT,
18
- ) -> List[List[Document]]:
19
- batches = []
20
-
21
- current_size = 0
22
- current_batch = []
23
- for document in documents:
24
- document_size = len(document.content.encode('UTF-8'))
25
-
26
- if (current_size + document_size > max_size) or (len(current_batch) >= max_files_count):
27
- batches.append(current_batch)
28
-
29
- current_batch = [document]
30
- current_size = document_size
31
- else:
32
- current_batch.append(document)
33
- current_size += document_size
34
-
35
- if current_batch:
36
- batches.append(current_batch)
37
-
38
- return batches
39
-
40
-
41
- def _get_threads_count() -> int:
42
- cpu_count = os.cpu_count() or 1
43
- return min(cpu_count * consts.SCAN_BATCH_SCANS_PER_CPU, consts.SCAN_BATCH_MAX_PARALLEL_SCANS)
44
-
45
-
46
- def run_parallel_batched_scan(
47
- scan_function: Callable[[List[Document]], Tuple[str, 'CliError', 'LocalScanResult']],
48
- scan_type: str,
49
- documents: List[Document],
50
- progress_bar: 'BaseProgressBar',
51
- ) -> Tuple[Dict[str, 'CliError'], List['LocalScanResult']]:
52
- max_size = consts.SCAN_BATCH_MAX_SIZE_IN_BYTES.get(scan_type, consts.DEFAULT_SCAN_BATCH_MAX_SIZE_IN_BYTES)
53
-
54
- batches = [documents] if scan_type == consts.SCA_SCAN_TYPE else split_documents_into_batches(documents, max_size)
55
-
56
- progress_bar.set_section_length(ScanProgressBarSection.SCAN, len(batches)) # * 3
57
- # TODO(MarshalX): we should multiply the count of batches in SCAN section because each batch has 3 steps:
58
- # 1. scan creation
59
- # 2. scan completion
60
- # 3. detection creation
61
- # it's not possible yet because not all scan types moved to polling mechanism
62
- # the progress bar could be significant improved (be more dynamic) in the future
63
-
64
- local_scan_results: List['LocalScanResult'] = []
65
- cli_errors: Dict[str, 'CliError'] = {}
66
- with ThreadPool(processes=_get_threads_count()) as pool:
67
- for scan_id, err, result in pool.imap(scan_function, batches):
68
- if result:
69
- local_scan_results.append(result)
70
- if err:
71
- cli_errors[scan_id] = err
72
-
73
- progress_bar.update(ScanProgressBarSection.SCAN)
74
-
75
- return cli_errors, local_scan_results
File without changes
File without changes