cycode 3.12.1.dev2__tar.gz → 3.12.2__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 (205) hide show
  1. {cycode-3.12.1.dev2 → cycode-3.12.2}/PKG-INFO +1 -1
  2. cycode-3.12.2/cycode/__init__.py +1 -0
  3. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/scan/code_scanner.py +56 -5
  4. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/scan/commit_range_scanner.py +1 -1
  5. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/exceptions/custom_exceptions.py +11 -0
  6. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cyclient/cycode_client_base.py +85 -0
  7. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cyclient/scan_client.py +42 -14
  8. {cycode-3.12.1.dev2 → cycode-3.12.2}/pyproject.toml +1 -1
  9. cycode-3.12.1.dev2/cycode/__init__.py +0 -1
  10. {cycode-3.12.1.dev2 → cycode-3.12.2}/LICENCE +0 -0
  11. {cycode-3.12.1.dev2 → cycode-3.12.2}/README.md +0 -0
  12. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/__main__.py +0 -0
  13. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/__init__.py +0 -0
  14. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/app.py +0 -0
  15. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/__init__.py +0 -0
  16. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/activation_manager.py +0 -0
  17. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/ai_guardrails/__init__.py +0 -0
  18. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/ai_guardrails/command_utils.py +0 -0
  19. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/ai_guardrails/consts.py +0 -0
  20. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/ai_guardrails/ensure_auth_command.py +0 -0
  21. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/ai_guardrails/hooks_manager.py +0 -0
  22. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/ai_guardrails/install_command.py +0 -0
  23. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/ai_guardrails/scan/__init__.py +0 -0
  24. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/ai_guardrails/scan/consts.py +0 -0
  25. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/ai_guardrails/scan/handlers.py +0 -0
  26. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/ai_guardrails/scan/payload.py +0 -0
  27. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/ai_guardrails/scan/policy.py +0 -0
  28. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/ai_guardrails/scan/response_builders.py +0 -0
  29. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/ai_guardrails/scan/scan_command.py +0 -0
  30. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/ai_guardrails/scan/types.py +0 -0
  31. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/ai_guardrails/scan/utils.py +0 -0
  32. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/ai_guardrails/status_command.py +0 -0
  33. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/ai_guardrails/uninstall_command.py +0 -0
  34. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/ai_remediation/__init__.py +0 -0
  35. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/ai_remediation/ai_remediation_command.py +0 -0
  36. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/ai_remediation/apply_fix.py +0 -0
  37. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/ai_remediation/print_remediation.py +0 -0
  38. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/auth/__init__.py +0 -0
  39. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/auth/auth_command.py +0 -0
  40. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/auth/auth_common.py +0 -0
  41. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/auth/auth_manager.py +0 -0
  42. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/auth/models.py +0 -0
  43. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/configure/__init__.py +0 -0
  44. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/configure/configure_command.py +0 -0
  45. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/configure/consts.py +0 -0
  46. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/configure/messages.py +0 -0
  47. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/configure/prompts.py +0 -0
  48. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/ignore/__init__.py +0 -0
  49. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/ignore/ignore_command.py +0 -0
  50. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/mcp/__init__.py +0 -0
  51. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/mcp/mcp_command.py +0 -0
  52. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/report/__init__.py +0 -0
  53. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/report/report_command.py +0 -0
  54. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/report/sbom/__init__.py +0 -0
  55. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/report/sbom/common.py +0 -0
  56. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/report/sbom/path/__init__.py +0 -0
  57. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/report/sbom/path/path_command.py +0 -0
  58. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/report/sbom/repository_url/__init__.py +0 -0
  59. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/report/sbom/repository_url/repository_url_command.py +0 -0
  60. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/report/sbom/sbom_command.py +0 -0
  61. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/report/sbom/sbom_report_file.py +0 -0
  62. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/report_import/__init__.py +0 -0
  63. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/report_import/report_import_command.py +0 -0
  64. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/report_import/sbom/__init__.py +0 -0
  65. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/report_import/sbom/sbom_command.py +0 -0
  66. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/sca_options.py +0 -0
  67. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/scan/__init__.py +0 -0
  68. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/scan/aggregation_report.py +0 -0
  69. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/scan/commit_history/__init__.py +0 -0
  70. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/scan/commit_history/commit_history_command.py +0 -0
  71. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/scan/detection_excluder.py +0 -0
  72. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/scan/path/__init__.py +0 -0
  73. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/scan/path/path_command.py +0 -0
  74. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/scan/pre_commit/__init__.py +0 -0
  75. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/scan/pre_commit/pre_commit_command.py +0 -0
  76. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/scan/pre_push/__init__.py +0 -0
  77. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/scan/pre_push/pre_push_command.py +0 -0
  78. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/scan/pre_receive/__init__.py +0 -0
  79. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/scan/pre_receive/pre_receive_command.py +0 -0
  80. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/scan/remote_url_resolver.py +0 -0
  81. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/scan/repository/__init__.py +0 -0
  82. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/scan/repository/repository_command.py +0 -0
  83. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/scan/scan_ci/__init__.py +0 -0
  84. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/scan/scan_ci/ci_integrations.py +0 -0
  85. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/scan/scan_ci/scan_ci_command.py +0 -0
  86. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/scan/scan_command.py +0 -0
  87. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/scan/scan_parameters.py +0 -0
  88. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/scan/scan_result.py +0 -0
  89. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/status/__init__.py +0 -0
  90. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/status/get_cli_status.py +0 -0
  91. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/status/models.py +0 -0
  92. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/status/status_command.py +0 -0
  93. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/apps/status/version_command.py +0 -0
  94. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/cli_types.py +0 -0
  95. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/config.py +0 -0
  96. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/console.py +0 -0
  97. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/consts.py +0 -0
  98. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/exceptions/__init__.py +0 -0
  99. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/exceptions/handle_ai_remediation_errors.py +0 -0
  100. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/exceptions/handle_auth_errors.py +0 -0
  101. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/exceptions/handle_errors.py +0 -0
  102. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/exceptions/handle_report_sbom_errors.py +0 -0
  103. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/exceptions/handle_scan_errors.py +0 -0
  104. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/files_collector/__init__.py +0 -0
  105. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/files_collector/commit_range_documents.py +0 -0
  106. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/files_collector/documents_walk_ignore.py +0 -0
  107. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/files_collector/file_excluder.py +0 -0
  108. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/files_collector/iac/__init__.py +0 -0
  109. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/files_collector/iac/tf_content_generator.py +0 -0
  110. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/files_collector/models/__init__.py +0 -0
  111. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/files_collector/models/in_memory_zip.py +0 -0
  112. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/files_collector/path_documents.py +0 -0
  113. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/files_collector/repository_documents.py +0 -0
  114. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/files_collector/sca/__init__.py +0 -0
  115. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/files_collector/sca/base_restore_dependencies.py +0 -0
  116. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/files_collector/sca/go/__init__.py +0 -0
  117. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/files_collector/sca/go/restore_go_dependencies.py +0 -0
  118. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/files_collector/sca/maven/__init__.py +0 -0
  119. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/files_collector/sca/maven/restore_gradle_dependencies.py +0 -0
  120. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/files_collector/sca/maven/restore_maven_dependencies.py +0 -0
  121. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/files_collector/sca/npm/__init__.py +0 -0
  122. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/files_collector/sca/npm/restore_deno_dependencies.py +0 -0
  123. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/files_collector/sca/npm/restore_npm_dependencies.py +0 -0
  124. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/files_collector/sca/npm/restore_pnpm_dependencies.py +0 -0
  125. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/files_collector/sca/npm/restore_yarn_dependencies.py +0 -0
  126. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/files_collector/sca/nuget/__init__.py +0 -0
  127. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/files_collector/sca/nuget/restore_nuget_dependencies.py +0 -0
  128. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/files_collector/sca/php/__init__.py +0 -0
  129. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/files_collector/sca/php/restore_composer_dependencies.py +0 -0
  130. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/files_collector/sca/python/__init__.py +0 -0
  131. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/files_collector/sca/python/restore_pipenv_dependencies.py +0 -0
  132. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/files_collector/sca/python/restore_poetry_dependencies.py +0 -0
  133. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/files_collector/sca/ruby/__init__.py +0 -0
  134. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/files_collector/sca/ruby/restore_ruby_dependencies.py +0 -0
  135. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/files_collector/sca/sbt/__init__.py +0 -0
  136. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/files_collector/sca/sbt/restore_sbt_dependencies.py +0 -0
  137. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/files_collector/sca/sca_file_collector.py +0 -0
  138. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/files_collector/walk_ignore.py +0 -0
  139. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/files_collector/zip_documents.py +0 -0
  140. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/logger.py +0 -0
  141. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/main.py +0 -0
  142. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/models.py +0 -0
  143. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/printers/__init__.py +0 -0
  144. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/printers/console_printer.py +0 -0
  145. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/printers/json_printer.py +0 -0
  146. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/printers/printer_base.py +0 -0
  147. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/printers/rich_printer.py +0 -0
  148. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/printers/tables/__init__.py +0 -0
  149. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/printers/tables/sca_table_printer.py +0 -0
  150. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/printers/tables/table.py +0 -0
  151. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/printers/tables/table_models.py +0 -0
  152. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/printers/tables/table_printer.py +0 -0
  153. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/printers/tables/table_printer_base.py +0 -0
  154. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/printers/text_printer.py +0 -0
  155. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/printers/utils/__init__.py +0 -0
  156. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/printers/utils/code_snippet_syntax.py +0 -0
  157. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/printers/utils/detection_data.py +0 -0
  158. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/printers/utils/detection_ordering/__init__.py +0 -0
  159. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/printers/utils/detection_ordering/common_ordering.py +0 -0
  160. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/printers/utils/detection_ordering/sca_ordering.py +0 -0
  161. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/printers/utils/rich_helpers.py +0 -0
  162. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/user_settings/__init__.py +0 -0
  163. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/user_settings/base_file_manager.py +0 -0
  164. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/user_settings/config_file_manager.py +0 -0
  165. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/user_settings/configuration_manager.py +0 -0
  166. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/user_settings/credentials_manager.py +0 -0
  167. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/user_settings/jwt_creator.py +0 -0
  168. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/utils/__init__.py +0 -0
  169. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/utils/binary_utils.py +0 -0
  170. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/utils/enum_utils.py +0 -0
  171. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/utils/get_api_client.py +0 -0
  172. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/utils/git_proxy.py +0 -0
  173. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/utils/ignore_utils.py +0 -0
  174. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/utils/jwt_utils.py +0 -0
  175. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/utils/path_utils.py +0 -0
  176. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/utils/progress_bar.py +0 -0
  177. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/utils/scan_batch.py +0 -0
  178. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/utils/scan_utils.py +0 -0
  179. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/utils/shell_executor.py +0 -0
  180. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/utils/string_utils.py +0 -0
  181. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/utils/task_timer.py +0 -0
  182. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/utils/url_utils.py +0 -0
  183. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/utils/version_checker.py +0 -0
  184. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cli/utils/yaml_utils.py +0 -0
  185. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/config.py +0 -0
  186. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cyclient/__init__.py +0 -0
  187. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cyclient/ai_security_manager_client.py +0 -0
  188. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cyclient/ai_security_manager_service_config.py +0 -0
  189. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cyclient/auth_client.py +0 -0
  190. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cyclient/base_token_auth_client.py +0 -0
  191. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cyclient/cli_activation_client.py +0 -0
  192. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cyclient/client_creator.py +0 -0
  193. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cyclient/config.py +0 -0
  194. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cyclient/config_dev.py +0 -0
  195. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cyclient/cycode_client.py +0 -0
  196. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cyclient/cycode_dev_based_client.py +0 -0
  197. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cyclient/cycode_oidc_based_client.py +0 -0
  198. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cyclient/cycode_token_based_client.py +0 -0
  199. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cyclient/headers.py +0 -0
  200. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cyclient/import_sbom_client.py +0 -0
  201. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cyclient/logger.py +0 -0
  202. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cyclient/models.py +0 -0
  203. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cyclient/report_client.py +0 -0
  204. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/cyclient/scan_config_base.py +0 -0
  205. {cycode-3.12.1.dev2 → cycode-3.12.2}/cycode/logger.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cycode
3
- Version: 3.12.1.dev2
3
+ Version: 3.12.2
4
4
  Summary: Boost security in your dev lifecycle via SAST, SCA, Secrets & IaC scanning.
5
5
  License-Expression: MIT
6
6
  License-File: LICENCE
@@ -0,0 +1 @@
1
+ __version__ = '3.12.2' # DON'T TOUCH. Placeholder. Will be filled automatically on poetry build from Git Tag
@@ -47,6 +47,36 @@ start_scan_time = time.time()
47
47
  logger = get_logger('Code Scanner')
48
48
 
49
49
 
50
+ class _UploadProgressAggregator:
51
+ """Aggregates upload progress across parallel batch uploads for display in the progress bar."""
52
+
53
+ def __init__(self, progress_bar: 'BaseProgressBar') -> None:
54
+ self._progress_bar = progress_bar
55
+ self._slots: list[list[int]] = []
56
+
57
+ def create_callback(self) -> Callable[[int, int], None]:
58
+ """Create a progress callback for one batch upload. Each batch gets its own slot."""
59
+ slot = [0, 0]
60
+ self._slots.append(slot)
61
+
62
+ def on_upload_progress(bytes_read: int, total_bytes: int) -> None:
63
+ slot[0] = bytes_read
64
+ slot[1] = total_bytes
65
+
66
+ # Sum across all batch slots to show combined progress
67
+ total_read = sum(s[0] for s in self._slots)
68
+ total_size = sum(s[1] for s in self._slots)
69
+
70
+ if total_read >= total_size:
71
+ self._progress_bar.update_right_side_label(None)
72
+ else:
73
+ mb_read = total_read / (1024 * 1024)
74
+ mb_total = total_size / (1024 * 1024)
75
+ self._progress_bar.update_right_side_label(f'Uploading {mb_read:.1f} / {mb_total:.1f} MB')
76
+
77
+ return on_upload_progress
78
+
79
+
50
80
  def scan_disk_files(ctx: typer.Context, paths: tuple[str, ...]) -> None:
51
81
  scan_type = ctx.obj['scan_type']
52
82
  progress_bar = ctx.obj['progress_bar']
@@ -121,6 +151,9 @@ def _get_scan_documents_thread_func(
121
151
  severity_threshold = ctx.obj['severity_threshold']
122
152
  sync_option = ctx.obj['sync']
123
153
  command_scan_type = ctx.info_name
154
+ progress_bar = ctx.obj['progress_bar']
155
+
156
+ aggregator = _UploadProgressAggregator(progress_bar)
124
157
 
125
158
  def _scan_batch_thread_func(batch: list[Document]) -> tuple[str, CliError, LocalScanResult]:
126
159
  local_scan_result = error = error_message = None
@@ -143,6 +176,7 @@ def _get_scan_documents_thread_func(
143
176
  is_commit_range,
144
177
  scan_parameters,
145
178
  should_use_sync_flow,
179
+ on_upload_progress=aggregator.create_callback(),
146
180
  )
147
181
 
148
182
  enrich_scan_result_with_data_from_detection_rules(cycode_client, scan_result)
@@ -268,15 +302,18 @@ def _perform_scan_v4_async(
268
302
  scan_parameters: dict,
269
303
  is_git_diff: bool,
270
304
  is_commit_range: bool,
305
+ on_upload_progress: Optional[Callable] = None,
271
306
  ) -> ZippedFileScanResult:
272
307
  upload_link = cycode_client.get_upload_link(scan_type)
273
308
  logger.debug('Got upload link, %s', {'upload_id': upload_link.upload_id})
274
309
 
275
- cycode_client.upload_to_presigned_post(upload_link.url, upload_link.presigned_post_fields, zipped_documents)
310
+ cycode_client.upload_to_presigned_post(
311
+ upload_link.url, upload_link.presigned_post_fields, zipped_documents, on_upload_progress
312
+ )
276
313
  logger.debug('Uploaded zip to presigned URL')
277
314
 
278
315
  scan_async_result = cycode_client.scan_repository_from_upload_id(
279
- scan_type, upload_link.upload_id, scan_parameters, is_git_diff, is_commit_range
316
+ scan_type, upload_link.upload_id, zipped_documents, scan_parameters, is_git_diff, is_commit_range
280
317
  )
281
318
  logger.debug(
282
319
  'Presigned upload scan request triggered, %s',
@@ -292,9 +329,14 @@ def _perform_scan_async(
292
329
  scan_type: str,
293
330
  scan_parameters: dict,
294
331
  is_commit_range: bool,
332
+ on_upload_progress: Optional[Callable] = None,
295
333
  ) -> ZippedFileScanResult:
296
334
  scan_async_result = cycode_client.zipped_file_scan_async(
297
- zipped_documents, scan_type, scan_parameters, is_commit_range=is_commit_range
335
+ zipped_documents,
336
+ scan_type,
337
+ scan_parameters,
338
+ is_commit_range=is_commit_range,
339
+ on_upload_progress=on_upload_progress,
298
340
  )
299
341
  logger.debug('Async scan request has been triggered successfully, %s', {'scan_id': scan_async_result.scan_id})
300
342
 
@@ -326,6 +368,7 @@ def _perform_scan(
326
368
  is_commit_range: bool,
327
369
  scan_parameters: dict,
328
370
  should_use_sync_flow: bool = False,
371
+ on_upload_progress: Optional[Callable] = None,
329
372
  ) -> ZippedFileScanResult:
330
373
  if should_use_sync_flow:
331
374
  # it does not support commit range scans; should_use_sync_flow handles it
@@ -334,12 +377,20 @@ def _perform_scan(
334
377
  if should_use_presigned_upload(scan_type):
335
378
  try:
336
379
  return _perform_scan_v4_async(
337
- cycode_client, zipped_documents, scan_type, scan_parameters, is_git_diff, is_commit_range
380
+ cycode_client,
381
+ zipped_documents,
382
+ scan_type,
383
+ scan_parameters,
384
+ is_git_diff,
385
+ is_commit_range,
386
+ on_upload_progress,
338
387
  )
339
388
  except requests.exceptions.RequestException:
340
389
  logger.warning('Direct upload to object storage failed. Falling back to upload via Cycode API. ')
341
390
 
342
- return _perform_scan_async(cycode_client, zipped_documents, scan_type, scan_parameters, is_commit_range)
391
+ return _perform_scan_async(
392
+ cycode_client, zipped_documents, scan_type, scan_parameters, is_commit_range, on_upload_progress
393
+ )
343
394
 
344
395
 
345
396
  def poll_scan_results(
@@ -113,7 +113,7 @@ def _perform_commit_range_scan_v4_async(
113
113
  logger.debug('Uploaded to-commit zip')
114
114
 
115
115
  scan_async_result = cycode_client.commit_range_scan_from_upload_ids(
116
- scan_type, from_upload_link.upload_id, to_upload_link.upload_id, scan_parameters
116
+ scan_type, from_upload_link.upload_id, to_upload_link.upload_id, from_commit_zipped_documents, scan_parameters
117
117
  )
118
118
  logger.debug('V4 commit range scan request triggered, %s', {'scan_id': scan_async_result.scan_id})
119
119
 
@@ -55,6 +55,11 @@ class HttpUnauthorizedError(RequestHttpError):
55
55
  return f'HTTP unauthorized error occurred during the request. Message: {self.error_message}'
56
56
 
57
57
 
58
+ class SlowUploadConnectionError(CycodeError):
59
+ def __str__(self) -> str:
60
+ return 'Upload was interrupted mid-transfer, indicating a slow or unstable network connection.'
61
+
62
+
58
63
  class ZipTooLargeError(CycodeError):
59
64
  def __init__(self, size_limit: int) -> None:
60
65
  self.size_limit = size_limit
@@ -102,6 +107,12 @@ KNOWN_USER_FRIENDLY_REQUEST_ERRORS: CliErrors = {
102
107
  code='timeout_error',
103
108
  message='The request timed out. Please try again by executing the `cycode scan` command',
104
109
  ),
110
+ SlowUploadConnectionError: CliError(
111
+ soft_fail=True,
112
+ code='slow_upload_error',
113
+ message='The scan upload was interrupted. This is likely due to a slow or unstable network connection. '
114
+ 'Please try again by executing the `cycode scan` command',
115
+ ),
105
116
  HttpUnauthorizedError: CliError(
106
117
  soft_fail=True,
107
118
  code='auth_error',
@@ -1,6 +1,7 @@
1
1
  import os
2
2
  import platform
3
3
  import ssl
4
+ from io import BytesIO
4
5
  from typing import TYPE_CHECKING, Callable, ClassVar, Optional
5
6
 
6
7
  import requests
@@ -15,6 +16,7 @@ from cycode.cli.exceptions.custom_exceptions import (
15
16
  RequestHttpError,
16
17
  RequestSslError,
17
18
  RequestTimeoutError,
19
+ SlowUploadConnectionError,
18
20
  )
19
21
  from cycode.cyclient import config
20
22
  from cycode.cyclient.headers import get_cli_user_agent, get_correlation_id
@@ -90,6 +92,23 @@ def _should_retry_exception(exception: BaseException) -> bool:
90
92
  return is_request_error or is_server_error
91
93
 
92
94
 
95
+ class UploadProgressTracker:
96
+ """File-like wrapper that tracks bytes read during upload and fires a progress callback."""
97
+
98
+ def __init__(self, data: bytes, callback: Optional[Callable[[int, int], None]]) -> None:
99
+ self._io = BytesIO(data)
100
+ self._callback = callback
101
+ self.bytes_read = 0
102
+ self.len = len(data)
103
+
104
+ def read(self, size: int = -1) -> bytes:
105
+ chunk = self._io.read(size)
106
+ self.bytes_read += len(chunk)
107
+ if self._callback and chunk:
108
+ self._callback(self.bytes_read, self.len)
109
+ return chunk
110
+
111
+
93
112
  class CycodeClientBase:
94
113
  MANDATORY_HEADERS: ClassVar[dict[str, str]] = {
95
114
  'User-Agent': get_cli_user_agent(),
@@ -117,6 +136,72 @@ class CycodeClientBase:
117
136
  def get(self, url_path: str, headers: Optional[dict] = None, **kwargs) -> Response:
118
137
  return self._execute(method='get', endpoint=url_path, headers=headers, **kwargs)
119
138
 
139
+ def post_multipart(
140
+ self,
141
+ url_path: str,
142
+ form_fields: dict,
143
+ files: dict,
144
+ on_upload_progress: Optional[Callable[[int, int], None]] = None,
145
+ hide_response_content_log: bool = False,
146
+ ) -> Response:
147
+ """POST a multipart form body with optional upload progress tracking and retry."""
148
+ url = self.build_full_url(self.api_url, url_path)
149
+ logger.debug('Executing request, %s', {'method': 'POST', 'url': url})
150
+
151
+ # Encode the multipart body once up front so we can reuse the same bytes across retries.
152
+ # A dummy URL is used because requests.Request requires one, but only the encoded body matters here.
153
+ prepared = requests.Request('POST', 'https://dummy', data=form_fields, files=files).prepare()
154
+
155
+ return self._send_multipart(
156
+ url=url,
157
+ body=prepared.body,
158
+ content_type=prepared.headers['Content-Type'],
159
+ on_upload_progress=on_upload_progress,
160
+ hide_response_content_log=hide_response_content_log,
161
+ )
162
+
163
+ @retry(
164
+ retry=retry_if_exception(_should_retry_exception),
165
+ stop=_RETRY_STOP_STRATEGY,
166
+ wait=_RETRY_WAIT_STRATEGY,
167
+ reraise=True,
168
+ before_sleep=_retry_before_sleep,
169
+ )
170
+ def _send_multipart(
171
+ self,
172
+ url: str,
173
+ body: bytes,
174
+ content_type: str,
175
+ on_upload_progress: Optional[Callable[[int, int], None]],
176
+ hide_response_content_log: bool,
177
+ ) -> Response:
178
+ # Wrap the body in a fresh tracker each attempt so bytes_read starts from zero.
179
+ tracker = UploadProgressTracker(body, on_upload_progress)
180
+ headers = self.get_request_headers({'Content-Type': content_type})
181
+ try:
182
+ response = _get_request_function()(
183
+ method='post', url=url, data=tracker, headers=headers, timeout=self.timeout
184
+ )
185
+
186
+ content = 'HIDDEN' if hide_response_content_log else response.text
187
+ logger.debug(
188
+ 'Receiving response, %s',
189
+ {'status_code': response.status_code, 'url': url, 'content': content},
190
+ )
191
+
192
+ response.raise_for_status()
193
+ return response
194
+ except (exceptions.ChunkedEncodingError, exceptions.ConnectionError) as e:
195
+ # A connection drop before the full body was sent indicates a slow/unstable network.
196
+ if tracker.bytes_read < tracker.len:
197
+ raise SlowUploadConnectionError from e
198
+ # Full body was sent — map to our types so _should_retry_exception handles retry logic.
199
+ if isinstance(e, exceptions.ConnectionError):
200
+ raise RequestConnectionError from e
201
+ raise
202
+ except Exception as e:
203
+ self._handle_exception(e)
204
+
120
205
  @retry(
121
206
  retry=retry_if_exception(_should_retry_exception),
122
207
  stop=_RETRY_STOP_STRATEGY,
@@ -1,6 +1,6 @@
1
1
  import json
2
2
  from copy import deepcopy
3
- from typing import TYPE_CHECKING, Optional, Union
3
+ from typing import TYPE_CHECKING, Callable, Optional, Union
4
4
  from uuid import UUID
5
5
 
6
6
  import requests
@@ -8,10 +8,14 @@ from requests import Response
8
8
 
9
9
  from cycode.cli import consts
10
10
  from cycode.cli.config import configuration_manager
11
- from cycode.cli.exceptions.custom_exceptions import CycodeError, RequestHttpError
11
+ from cycode.cli.exceptions.custom_exceptions import (
12
+ CycodeError,
13
+ RequestHttpError,
14
+ SlowUploadConnectionError,
15
+ )
12
16
  from cycode.cli.files_collector.models.in_memory_zip import InMemoryZip
13
17
  from cycode.cyclient import models
14
- from cycode.cyclient.cycode_client_base import CycodeClientBase
18
+ from cycode.cyclient.cycode_client_base import CycodeClientBase, UploadProgressTracker
15
19
  from cycode.cyclient.logger import logger
16
20
 
17
21
  if TYPE_CHECKING:
@@ -114,18 +118,18 @@ class ScanClient:
114
118
  scan_parameters: dict,
115
119
  is_git_diff: bool = False,
116
120
  is_commit_range: bool = False,
121
+ on_upload_progress: Optional[Callable[[int, int], None]] = None,
117
122
  ) -> models.ScanInitializationResponse:
118
- files = {'file': ('multiple_files_scan.zip', zip_file.read())}
119
-
120
- response = self.scan_cycode_client.post(
123
+ response = self.scan_cycode_client.post_multipart(
121
124
  url_path=self.get_zipped_file_scan_async_url_path(scan_type),
122
- data={
125
+ form_fields={
123
126
  'is_git_diff': is_git_diff,
124
127
  'scan_parameters': json.dumps(scan_parameters),
125
128
  'is_commit_range': is_commit_range,
126
129
  'compression_manifest': self._create_compression_manifest_string(zip_file),
127
130
  },
128
- files=files,
131
+ files={'file': ('multiple_files_scan.zip', zip_file.read(), 'application/octet-stream')},
132
+ on_upload_progress=on_upload_progress,
129
133
  )
130
134
  return models.ScanInitializationResponseSchema().load(response.json())
131
135
 
@@ -135,17 +139,38 @@ class ScanClient:
135
139
  response = self.scan_cycode_client.get(url_path=url_path, hide_response_content_log=self._hide_response_log)
136
140
  return models.UploadLinkResponseSchema().load(response.json())
137
141
 
138
- def upload_to_presigned_post(self, url: str, fields: dict[str, str], zip_file: 'InMemoryZip') -> None:
139
- multipart = {key: (None, value) for key, value in fields.items()}
140
- multipart['file'] = (None, zip_file.read())
141
- # We are not using Cycode client, as we are calling aws S3.
142
- response = requests.post(url, files=multipart, timeout=self.scan_cycode_client.timeout)
143
- response.raise_for_status()
142
+ def upload_to_presigned_post(
143
+ self,
144
+ url: str,
145
+ fields: dict[str, str],
146
+ zip_file: 'InMemoryZip',
147
+ on_upload_progress: Optional[Callable[[int, int], None]] = None,
148
+ ) -> None:
149
+ all_files = {key: (None, value) for key, value in fields.items()}
150
+ all_files['file'] = ('multiple_files_scan.zip', zip_file.read(), 'application/octet-stream')
151
+
152
+ prepared = requests.Request('POST', 'https://dummy', files=all_files).prepare()
153
+ tracker = UploadProgressTracker(prepared.body, on_upload_progress)
154
+
155
+ try:
156
+ # We are not using Cycode client, as we are calling aws S3.
157
+ response = requests.post(
158
+ url,
159
+ data=tracker,
160
+ headers={'Content-Type': prepared.headers['Content-Type']},
161
+ timeout=self.scan_cycode_client.timeout,
162
+ )
163
+ response.raise_for_status()
164
+ except (requests.exceptions.ChunkedEncodingError, requests.exceptions.ConnectionError) as e:
165
+ if tracker.bytes_read < tracker.len:
166
+ raise SlowUploadConnectionError from e
167
+ raise
144
168
 
145
169
  def scan_repository_from_upload_id(
146
170
  self,
147
171
  scan_type: str,
148
172
  upload_id: str,
173
+ zip_file: InMemoryZip,
149
174
  scan_parameters: dict,
150
175
  is_git_diff: bool = False,
151
176
  is_commit_range: bool = False,
@@ -159,6 +184,7 @@ class ScanClient:
159
184
  'is_git_diff': is_git_diff,
160
185
  'is_commit_range': is_commit_range,
161
186
  'scan_parameters': json.dumps(scan_parameters),
187
+ 'compression_manifest': self._create_compression_manifest_string(zip_file),
162
188
  },
163
189
  )
164
190
  return models.ScanInitializationResponseSchema().load(response.json())
@@ -206,6 +232,7 @@ class ScanClient:
206
232
  scan_type: str,
207
233
  from_commit_upload_id: str,
208
234
  to_commit_upload_id: str,
235
+ from_commit_zip_file: InMemoryZip,
209
236
  scan_parameters: dict,
210
237
  is_git_diff: bool = False,
211
238
  ) -> models.ScanInitializationResponse:
@@ -218,6 +245,7 @@ class ScanClient:
218
245
  'to_commit_upload_id': to_commit_upload_id,
219
246
  'is_git_diff': is_git_diff,
220
247
  'scan_parameters': json.dumps(scan_parameters),
248
+ 'compression_manifest': self._create_compression_manifest_string(from_commit_zip_file),
221
249
  },
222
250
  )
223
251
  return models.ScanInitializationResponseSchema().load(response.json())
@@ -21,7 +21,7 @@ classifiers = [
21
21
  "Programming Language :: Python :: 3.14",
22
22
  ]
23
23
  dynamic = ["dependencies"]
24
- version = "3.12.1.dev2"
24
+ version = "3.12.2"
25
25
 
26
26
  [project.scripts]
27
27
  cycode = "cycode.cli.app:app"
@@ -1 +0,0 @@
1
- __version__ = '3.12.1.dev2' # DON'T TOUCH. Placeholder. Will be filled automatically on poetry build from Git Tag
File without changes
File without changes
File without changes
File without changes