cycode 3.0.1.dev1__tar.gz → 3.0.2.dev2__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 (156) hide show
  1. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/PKG-INFO +1 -1
  2. cycode-3.0.2.dev2/cycode/__init__.py +1 -0
  3. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/apps/scan/code_scanner.py +6 -6
  4. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/apps/scan/pre_commit/pre_commit_command.py +2 -2
  5. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/apps/scan/repository/repository_command.py +2 -2
  6. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/apps/scan/scan_command.py +8 -1
  7. cycode-3.0.2.dev2/cycode/cli/files_collector/excluder.py +174 -0
  8. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/files_collector/models/in_memory_zip.py +18 -8
  9. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/files_collector/path_documents.py +4 -2
  10. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/files_collector/sca/base_restore_dependencies.py +4 -5
  11. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/files_collector/sca/go/restore_go_dependencies.py +0 -3
  12. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/files_collector/sca/maven/restore_maven_dependencies.py +23 -21
  13. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/files_collector/sca/ruby/restore_ruby_dependencies.py +0 -6
  14. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/files_collector/sca/sbt/restore_sbt_dependencies.py +0 -6
  15. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/files_collector/sca/sca_code_scanner.py +12 -9
  16. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cyclient/models.py +16 -0
  17. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cyclient/scan_client.py +32 -2
  18. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/pyproject.toml +1 -1
  19. cycode-3.0.1.dev1/cycode/__init__.py +0 -1
  20. cycode-3.0.1.dev1/cycode/cli/files_collector/excluder.py +0 -161
  21. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/LICENCE +0 -0
  22. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/README.md +0 -0
  23. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/__main__.py +0 -0
  24. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/__init__.py +0 -0
  25. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/app.py +0 -0
  26. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/apps/__init__.py +0 -0
  27. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/apps/ai_remediation/__init__.py +0 -0
  28. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/apps/ai_remediation/ai_remediation_command.py +0 -0
  29. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/apps/ai_remediation/apply_fix.py +0 -0
  30. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/apps/ai_remediation/print_remediation.py +0 -0
  31. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/apps/auth/__init__.py +0 -0
  32. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/apps/auth/auth_command.py +0 -0
  33. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/apps/auth/auth_common.py +0 -0
  34. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/apps/auth/auth_manager.py +0 -0
  35. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/apps/auth/models.py +0 -0
  36. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/apps/configure/__init__.py +0 -0
  37. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/apps/configure/configure_command.py +0 -0
  38. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/apps/configure/consts.py +0 -0
  39. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/apps/configure/messages.py +0 -0
  40. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/apps/configure/prompts.py +0 -0
  41. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/apps/ignore/__init__.py +0 -0
  42. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/apps/ignore/ignore_command.py +0 -0
  43. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/apps/report/__init__.py +0 -0
  44. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/apps/report/report_command.py +0 -0
  45. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/apps/report/sbom/__init__.py +0 -0
  46. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/apps/report/sbom/common.py +0 -0
  47. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/apps/report/sbom/path/__init__.py +0 -0
  48. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/apps/report/sbom/path/path_command.py +0 -0
  49. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/apps/report/sbom/repository_url/__init__.py +0 -0
  50. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/apps/report/sbom/repository_url/repository_url_command.py +0 -0
  51. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/apps/report/sbom/sbom_command.py +0 -0
  52. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/apps/report/sbom/sbom_report_file.py +0 -0
  53. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/apps/scan/__init__.py +0 -0
  54. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/apps/scan/commit_history/__init__.py +0 -0
  55. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/apps/scan/commit_history/commit_history_command.py +0 -0
  56. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/apps/scan/path/__init__.py +0 -0
  57. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/apps/scan/path/path_command.py +0 -0
  58. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/apps/scan/pre_commit/__init__.py +0 -0
  59. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/apps/scan/pre_receive/__init__.py +0 -0
  60. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/apps/scan/pre_receive/pre_receive_command.py +0 -0
  61. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/apps/scan/repository/__init__.py +0 -0
  62. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/apps/scan/scan_ci/__init__.py +0 -0
  63. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/apps/scan/scan_ci/ci_integrations.py +0 -0
  64. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/apps/scan/scan_ci/scan_ci_command.py +0 -0
  65. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/apps/status/__init__.py +0 -0
  66. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/apps/status/get_cli_status.py +0 -0
  67. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/apps/status/models.py +0 -0
  68. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/apps/status/status_command.py +0 -0
  69. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/apps/status/version_command.py +0 -0
  70. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/cli_types.py +0 -0
  71. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/config.py +0 -0
  72. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/console.py +0 -0
  73. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/consts.py +0 -0
  74. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/exceptions/__init__.py +0 -0
  75. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/exceptions/custom_exceptions.py +0 -0
  76. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/exceptions/handle_ai_remediation_errors.py +0 -0
  77. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/exceptions/handle_auth_errors.py +0 -0
  78. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/exceptions/handle_errors.py +0 -0
  79. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/exceptions/handle_report_sbom_errors.py +0 -0
  80. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/exceptions/handle_scan_errors.py +0 -0
  81. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/files_collector/__init__.py +0 -0
  82. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/files_collector/iac/__init__.py +0 -0
  83. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/files_collector/iac/tf_content_generator.py +0 -0
  84. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/files_collector/models/__init__.py +0 -0
  85. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/files_collector/repository_documents.py +0 -0
  86. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/files_collector/sca/__init__.py +0 -0
  87. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/files_collector/sca/go/__init__.py +0 -0
  88. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/files_collector/sca/maven/__init__.py +0 -0
  89. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/files_collector/sca/maven/restore_gradle_dependencies.py +0 -0
  90. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/files_collector/sca/npm/__init__.py +0 -0
  91. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/files_collector/sca/npm/restore_npm_dependencies.py +0 -0
  92. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/files_collector/sca/nuget/__init__.py +0 -0
  93. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/files_collector/sca/nuget/restore_nuget_dependencies.py +0 -0
  94. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/files_collector/sca/ruby/__init__.py +0 -0
  95. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/files_collector/sca/sbt/__init__.py +0 -0
  96. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/files_collector/walk_ignore.py +0 -0
  97. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/files_collector/zip_documents.py +0 -0
  98. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/logger.py +0 -0
  99. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/main.py +0 -0
  100. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/models.py +0 -0
  101. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/printers/__init__.py +0 -0
  102. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/printers/console_printer.py +0 -0
  103. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/printers/json_printer.py +0 -0
  104. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/printers/printer_base.py +0 -0
  105. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/printers/rich_printer.py +0 -0
  106. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/printers/tables/__init__.py +0 -0
  107. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/printers/tables/sca_table_printer.py +0 -0
  108. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/printers/tables/table.py +0 -0
  109. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/printers/tables/table_models.py +0 -0
  110. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/printers/tables/table_printer.py +0 -0
  111. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/printers/tables/table_printer_base.py +0 -0
  112. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/printers/text_printer.py +0 -0
  113. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/printers/utils/__init__.py +0 -0
  114. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/printers/utils/code_snippet_syntax.py +0 -0
  115. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/printers/utils/detection_data.py +0 -0
  116. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/printers/utils/detection_ordering/__init__.py +0 -0
  117. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/printers/utils/detection_ordering/common_ordering.py +0 -0
  118. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/printers/utils/detection_ordering/sca_ordering.py +0 -0
  119. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/printers/utils/rich_helpers.py +0 -0
  120. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/user_settings/__init__.py +0 -0
  121. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/user_settings/base_file_manager.py +0 -0
  122. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/user_settings/config_file_manager.py +0 -0
  123. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/user_settings/configuration_manager.py +0 -0
  124. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/user_settings/credentials_manager.py +0 -0
  125. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/user_settings/jwt_creator.py +0 -0
  126. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/utils/__init__.py +0 -0
  127. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/utils/enum_utils.py +0 -0
  128. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/utils/get_api_client.py +0 -0
  129. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/utils/git_proxy.py +0 -0
  130. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/utils/ignore_utils.py +0 -0
  131. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/utils/jwt_utils.py +0 -0
  132. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/utils/path_utils.py +0 -0
  133. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/utils/progress_bar.py +0 -0
  134. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/utils/scan_batch.py +0 -0
  135. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/utils/scan_utils.py +0 -0
  136. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/utils/sentry.py +0 -0
  137. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/utils/shell_executor.py +0 -0
  138. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/utils/string_utils.py +0 -0
  139. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/utils/task_timer.py +0 -0
  140. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/utils/version_checker.py +0 -0
  141. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cli/utils/yaml_utils.py +0 -0
  142. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/config.py +0 -0
  143. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cyclient/__init__.py +0 -0
  144. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cyclient/auth_client.py +0 -0
  145. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cyclient/client_creator.py +0 -0
  146. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cyclient/config.py +0 -0
  147. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cyclient/config_dev.py +0 -0
  148. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cyclient/cycode_client.py +0 -0
  149. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cyclient/cycode_client_base.py +0 -0
  150. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cyclient/cycode_dev_based_client.py +0 -0
  151. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cyclient/cycode_token_based_client.py +0 -0
  152. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cyclient/headers.py +0 -0
  153. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cyclient/logger.py +0 -0
  154. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cyclient/report_client.py +0 -0
  155. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/cyclient/scan_config_base.py +0 -0
  156. {cycode-3.0.1.dev1 → cycode-3.0.2.dev2}/cycode/logger.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: cycode
3
- Version: 3.0.1.dev1
3
+ Version: 3.0.2.dev2
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__ = '3.0.2.dev2' # DON'T TOUCH. Placeholder. Will be filled automatically on poetry build from Git Tag
@@ -15,7 +15,7 @@ from cycode.cli.config import configuration_manager
15
15
  from cycode.cli.console import console
16
16
  from cycode.cli.exceptions import custom_exceptions
17
17
  from cycode.cli.exceptions.handle_scan_errors import handle_scan_exception
18
- from cycode.cli.files_collector.excluder import exclude_irrelevant_documents_to_scan
18
+ from cycode.cli.files_collector.excluder import excluder
19
19
  from cycode.cli.files_collector.models.in_memory_zip import InMemoryZip
20
20
  from cycode.cli.files_collector.path_documents import get_relevant_documents
21
21
  from cycode.cli.files_collector.repository_documents import (
@@ -56,8 +56,8 @@ def scan_sca_pre_commit(ctx: typer.Context, repo_path: str) -> None:
56
56
  progress_bar_section=ScanProgressBarSection.PREPARE_LOCAL_FILES,
57
57
  repo_path=repo_path,
58
58
  )
59
- git_head_documents = exclude_irrelevant_documents_to_scan(scan_type, git_head_documents)
60
- pre_committed_documents = exclude_irrelevant_documents_to_scan(scan_type, pre_committed_documents)
59
+ git_head_documents = excluder.exclude_irrelevant_documents_to_scan(scan_type, git_head_documents)
60
+ pre_committed_documents = excluder.exclude_irrelevant_documents_to_scan(scan_type, pre_committed_documents)
61
61
  sca_code_scanner.perform_pre_hook_range_scan_actions(repo_path, git_head_documents, pre_committed_documents)
62
62
  scan_commit_range_documents(
63
63
  ctx,
@@ -77,8 +77,8 @@ def scan_sca_commit_range(ctx: typer.Context, path: str, commit_range: str) -> N
77
77
  from_commit_documents, to_commit_documents = get_commit_range_modified_documents(
78
78
  progress_bar, ScanProgressBarSection.PREPARE_LOCAL_FILES, path, from_commit_rev, to_commit_rev
79
79
  )
80
- from_commit_documents = exclude_irrelevant_documents_to_scan(scan_type, from_commit_documents)
81
- to_commit_documents = exclude_irrelevant_documents_to_scan(scan_type, to_commit_documents)
80
+ from_commit_documents = excluder.exclude_irrelevant_documents_to_scan(scan_type, from_commit_documents)
81
+ to_commit_documents = excluder.exclude_irrelevant_documents_to_scan(scan_type, to_commit_documents)
82
82
  sca_code_scanner.perform_pre_commit_range_scan_actions(
83
83
  path, from_commit_documents, from_commit_rev, to_commit_documents, to_commit_rev
84
84
  )
@@ -288,7 +288,7 @@ def scan_commit_range(
288
288
  {'path': path, 'commit_range': commit_range, 'commit_id': commit_id},
289
289
  )
290
290
 
291
- documents_to_scan.extend(exclude_irrelevant_documents_to_scan(scan_type, commit_documents_to_scan))
291
+ documents_to_scan.extend(excluder.exclude_irrelevant_documents_to_scan(scan_type, commit_documents_to_scan))
292
292
 
293
293
  logger.debug('List of commit ids to scan, %s', {'commit_ids': commit_ids_to_scan})
294
294
  logger.debug('Starting to scan commit range (it may take a few minutes)')
@@ -5,7 +5,7 @@ import typer
5
5
 
6
6
  from cycode.cli import consts
7
7
  from cycode.cli.apps.scan.code_scanner import get_scan_parameters, scan_documents, scan_sca_pre_commit
8
- from cycode.cli.files_collector.excluder import exclude_irrelevant_documents_to_scan
8
+ from cycode.cli.files_collector.excluder import excluder
9
9
  from cycode.cli.files_collector.repository_documents import (
10
10
  get_diff_file_content,
11
11
  get_diff_file_path,
@@ -45,5 +45,5 @@ def pre_commit_command(
45
45
  progress_bar.update(ScanProgressBarSection.PREPARE_LOCAL_FILES)
46
46
  documents_to_scan.append(Document(get_path_by_os(get_diff_file_path(file)), get_diff_file_content(file)))
47
47
 
48
- documents_to_scan = exclude_irrelevant_documents_to_scan(scan_type, documents_to_scan)
48
+ documents_to_scan = excluder.exclude_irrelevant_documents_to_scan(scan_type, documents_to_scan)
49
49
  scan_documents(ctx, documents_to_scan, get_scan_parameters(ctx), is_git_diff=True)
@@ -7,7 +7,7 @@ import typer
7
7
  from cycode.cli import consts
8
8
  from cycode.cli.apps.scan.code_scanner import get_scan_parameters, scan_documents
9
9
  from cycode.cli.exceptions.handle_scan_errors import handle_scan_exception
10
- from cycode.cli.files_collector.excluder import exclude_irrelevant_documents_to_scan
10
+ from cycode.cli.files_collector.excluder import excluder
11
11
  from cycode.cli.files_collector.repository_documents import get_git_repository_tree_file_entries
12
12
  from cycode.cli.files_collector.sca.sca_code_scanner import perform_pre_scan_documents_actions
13
13
  from cycode.cli.logger import logger
@@ -57,7 +57,7 @@ def repository_command(
57
57
  )
58
58
  )
59
59
 
60
- documents_to_scan = exclude_irrelevant_documents_to_scan(scan_type, documents_to_scan)
60
+ documents_to_scan = excluder.exclude_irrelevant_documents_to_scan(scan_type, documents_to_scan)
61
61
 
62
62
  perform_pre_scan_documents_actions(ctx, scan_type, documents_to_scan)
63
63
 
@@ -9,6 +9,7 @@ from cycode.cli.consts import (
9
9
  ISSUE_DETECTED_STATUS_CODE,
10
10
  NO_ISSUES_STATUS_CODE,
11
11
  )
12
+ from cycode.cli.files_collector.excluder import excluder
12
13
  from cycode.cli.utils import scan_utils
13
14
  from cycode.cli.utils.get_api_client import get_scan_cycode_client
14
15
  from cycode.cli.utils.sentry import add_breadcrumb
@@ -138,13 +139,19 @@ def scan_command(
138
139
 
139
140
  ctx.obj['show_secret'] = show_secret
140
141
  ctx.obj['soft_fail'] = soft_fail
141
- ctx.obj['client'] = get_scan_cycode_client(ctx)
142
142
  ctx.obj['scan_type'] = scan_type
143
143
  ctx.obj['sync'] = sync
144
144
  ctx.obj['severity_threshold'] = severity_threshold
145
145
  ctx.obj['monitor'] = monitor
146
146
  ctx.obj['report'] = report
147
147
 
148
+ scan_client = get_scan_cycode_client(ctx)
149
+ ctx.obj['client'] = scan_client
150
+
151
+ remote_scan_config = scan_client.get_scan_configuration_safe(scan_type)
152
+ if remote_scan_config:
153
+ excluder.apply_scan_config(str(scan_type), remote_scan_config)
154
+
148
155
  if export_type and export_file:
149
156
  console_printer = ctx.obj['console_printer']
150
157
  console_printer.enable_recording(export_type, export_file)
@@ -0,0 +1,174 @@
1
+ from typing import TYPE_CHECKING
2
+
3
+ from cycode.cli import consts
4
+ from cycode.cli.config import configuration_manager
5
+ from cycode.cli.user_settings.config_file_manager import ConfigFileManager
6
+ from cycode.cli.utils.path_utils import get_file_size, is_binary_file, is_sub_path
7
+ from cycode.cli.utils.string_utils import get_content_size, is_binary_content
8
+ from cycode.logger import get_logger
9
+
10
+ if TYPE_CHECKING:
11
+ from cycode.cli.models import Document
12
+ from cycode.cli.utils.progress_bar import BaseProgressBar, ProgressBarSection
13
+ from cycode.cyclient import models
14
+
15
+
16
+ logger = get_logger('File Excluder')
17
+
18
+
19
+ def _is_subpath_of_cycode_configuration_folder(filename: str) -> bool:
20
+ return (
21
+ is_sub_path(configuration_manager.global_config_file_manager.get_config_directory_path(), filename)
22
+ or is_sub_path(configuration_manager.local_config_file_manager.get_config_directory_path(), filename)
23
+ or filename.endswith(ConfigFileManager.get_config_file_route())
24
+ )
25
+
26
+
27
+ def _is_path_configured_in_exclusions(scan_type: str, file_path: str) -> bool:
28
+ exclusions_by_path = configuration_manager.get_exclusions_by_scan_type(scan_type).get(
29
+ consts.EXCLUSIONS_BY_PATH_SECTION_NAME, []
30
+ )
31
+ return any(is_sub_path(exclusion_path, file_path) for exclusion_path in exclusions_by_path)
32
+
33
+
34
+ def _does_file_exceed_max_size_limit(filename: str) -> bool:
35
+ return get_file_size(filename) > consts.FILE_MAX_SIZE_LIMIT_IN_BYTES
36
+
37
+
38
+ def _does_document_exceed_max_size_limit(content: str) -> bool:
39
+ return get_content_size(content) > consts.FILE_MAX_SIZE_LIMIT_IN_BYTES
40
+
41
+
42
+ def _is_file_relevant_for_sca_scan(filename: str) -> bool:
43
+ if any(sca_excluded_path in filename for sca_excluded_path in consts.SCA_EXCLUDED_PATHS):
44
+ logger.debug(
45
+ 'The file is irrelevant because it is from the inner path of node_modules, %s', {'filename': filename}
46
+ )
47
+ return False
48
+
49
+ return True
50
+
51
+
52
+ class Excluder:
53
+ def __init__(self) -> None:
54
+ self._scannable_extensions: dict[str, tuple[str, ...]] = {
55
+ consts.IAC_SCAN_TYPE: consts.IAC_SCAN_SUPPORTED_FILES,
56
+ consts.SCA_SCAN_TYPE: consts.SCA_CONFIGURATION_SCAN_SUPPORTED_FILES,
57
+ }
58
+ self._non_scannable_extensions: dict[str, tuple[str, ...]] = {
59
+ consts.SECRET_SCAN_TYPE: consts.SECRET_SCAN_FILE_EXTENSIONS_TO_IGNORE,
60
+ }
61
+
62
+ def apply_scan_config(self, scan_type: str, scan_config: 'models.ScanConfiguration') -> None:
63
+ if scan_config.scannable_extensions:
64
+ self._scannable_extensions[scan_type] = tuple(scan_config.scannable_extensions)
65
+
66
+ def _is_file_extension_supported(self, scan_type: str, filename: str) -> bool:
67
+ filename = filename.lower()
68
+
69
+ scannable_extensions = self._scannable_extensions.get(scan_type)
70
+ if scannable_extensions:
71
+ return filename.endswith(scannable_extensions)
72
+
73
+ non_scannable_extensions = self._non_scannable_extensions.get(scan_type)
74
+ if non_scannable_extensions:
75
+ return not filename.endswith(non_scannable_extensions)
76
+
77
+ return True
78
+
79
+ def _is_relevant_file_to_scan_common(self, scan_type: str, filename: str) -> bool:
80
+ if _is_subpath_of_cycode_configuration_folder(filename):
81
+ logger.debug(
82
+ 'The document is irrelevant because it is in the Cycode configuration directory, %s',
83
+ {'filename': filename, 'configuration_directory': consts.CYCODE_CONFIGURATION_DIRECTORY},
84
+ )
85
+ return False
86
+
87
+ if _is_path_configured_in_exclusions(scan_type, filename):
88
+ logger.debug(
89
+ 'The document is irrelevant because its path is in the ignore paths list, %s', {'filename': filename}
90
+ )
91
+ return False
92
+
93
+ if not self._is_file_extension_supported(scan_type, filename):
94
+ logger.debug(
95
+ 'The document is irrelevant because its extension is not supported, %s',
96
+ {'scan_type': scan_type, 'filename': filename},
97
+ )
98
+ return False
99
+
100
+ return True
101
+
102
+ def _is_relevant_file_to_scan(self, scan_type: str, filename: str) -> bool:
103
+ if not self._is_relevant_file_to_scan_common(scan_type, filename):
104
+ return False
105
+
106
+ if is_binary_file(filename):
107
+ logger.debug('The file is irrelevant because it is a binary file, %s', {'filename': filename})
108
+ return False
109
+
110
+ if scan_type != consts.SCA_SCAN_TYPE and _does_file_exceed_max_size_limit(filename):
111
+ logger.debug(
112
+ 'The file is irrelevant because it has exceeded the maximum size limit, %s',
113
+ {
114
+ 'max_file_size': consts.FILE_MAX_SIZE_LIMIT_IN_BYTES,
115
+ 'file_size': get_file_size(filename),
116
+ 'filename': filename,
117
+ },
118
+ )
119
+ return False
120
+
121
+ return not (scan_type == consts.SCA_SCAN_TYPE and not _is_file_relevant_for_sca_scan(filename))
122
+
123
+ def _is_relevant_document_to_scan(self, scan_type: str, filename: str, content: str) -> bool:
124
+ if not self._is_relevant_file_to_scan_common(scan_type, filename):
125
+ return False
126
+
127
+ if is_binary_content(content):
128
+ logger.debug('The document is irrelevant because it is a binary file, %s', {'filename': filename})
129
+ return False
130
+
131
+ if scan_type != consts.SCA_SCAN_TYPE and _does_document_exceed_max_size_limit(content):
132
+ logger.debug(
133
+ 'The document is irrelevant because it has exceeded the maximum size limit, %s',
134
+ {
135
+ 'max_document_size': consts.FILE_MAX_SIZE_LIMIT_IN_BYTES,
136
+ 'document_size': get_content_size(content),
137
+ 'filename': filename,
138
+ },
139
+ )
140
+ return False
141
+
142
+ return True
143
+
144
+ def exclude_irrelevant_files(
145
+ self,
146
+ progress_bar: 'BaseProgressBar',
147
+ progress_bar_section: 'ProgressBarSection',
148
+ scan_type: str,
149
+ filenames: list[str],
150
+ ) -> list[str]:
151
+ relevant_files = []
152
+ for filename in filenames:
153
+ progress_bar.update(progress_bar_section)
154
+ if self._is_relevant_file_to_scan(scan_type, filename):
155
+ relevant_files.append(filename)
156
+
157
+ is_sub_path.cache_clear() # free up memory
158
+
159
+ return relevant_files
160
+
161
+ def exclude_irrelevant_documents_to_scan(
162
+ self, scan_type: str, documents_to_scan: list['Document']
163
+ ) -> list['Document']:
164
+ logger.debug('Excluding irrelevant documents to scan')
165
+
166
+ relevant_documents = []
167
+ for document in documents_to_scan:
168
+ if self._is_relevant_document_to_scan(scan_type, document.path, document.content):
169
+ relevant_documents.append(document)
170
+
171
+ return relevant_documents
172
+
173
+
174
+ excluder = Excluder()
@@ -1,25 +1,28 @@
1
+ from collections import defaultdict
1
2
  from io import BytesIO
3
+ from pathlib import Path
2
4
  from sys import getsizeof
3
- from typing import TYPE_CHECKING, Optional
5
+ from typing import Optional
4
6
  from zipfile import ZIP_DEFLATED, ZipFile
5
7
 
6
8
  from cycode.cli.user_settings.configuration_manager import ConfigurationManager
7
9
  from cycode.cli.utils.path_utils import concat_unique_id
8
10
 
9
- if TYPE_CHECKING:
10
- from pathlib import Path
11
-
12
11
 
13
12
  class InMemoryZip:
14
13
  def __init__(self) -> None:
15
14
  self.configuration_manager = ConfigurationManager()
16
15
 
17
- # Create the in-memory file-like object
18
16
  self.in_memory_zip = BytesIO()
19
- self.zip = ZipFile(self.in_memory_zip, 'a', ZIP_DEFLATED, False)
17
+ self.zip = ZipFile(self.in_memory_zip, mode='a', compression=ZIP_DEFLATED, allowZip64=False)
18
+
19
+ self._files_count = 0
20
+ self._extension_statistics = defaultdict(int)
20
21
 
21
22
  def append(self, filename: str, unique_id: Optional[str], content: str) -> None:
22
- # Write the file to the in-memory zip
23
+ self._files_count += 1
24
+ self._extension_statistics[Path(filename).suffix] += 1
25
+
23
26
  if unique_id:
24
27
  filename = concat_unique_id(filename, unique_id)
25
28
 
@@ -28,7 +31,6 @@ class InMemoryZip:
28
31
  def close(self) -> None:
29
32
  self.zip.close()
30
33
 
31
- # to bytes
32
34
  def read(self) -> bytes:
33
35
  self.in_memory_zip.seek(0)
34
36
  return self.in_memory_zip.read()
@@ -40,3 +42,11 @@ class InMemoryZip:
40
42
  @property
41
43
  def size(self) -> int:
42
44
  return getsizeof(self.in_memory_zip)
45
+
46
+ @property
47
+ def files_count(self) -> int:
48
+ return self._files_count
49
+
50
+ @property
51
+ def extension_statistics(self) -> dict[str, int]:
52
+ return dict(self._extension_statistics)
@@ -1,7 +1,7 @@
1
1
  import os
2
2
  from typing import TYPE_CHECKING
3
3
 
4
- from cycode.cli.files_collector.excluder import exclude_irrelevant_files
4
+ from cycode.cli.files_collector.excluder import excluder
5
5
  from cycode.cli.files_collector.iac.tf_content_generator import (
6
6
  generate_tf_content_from_tfplan,
7
7
  generate_tfplan_document_name,
@@ -54,7 +54,9 @@ def _get_relevant_files(
54
54
  progress_bar_section_len = len(all_files_to_scan) * 2
55
55
  progress_bar.set_section_length(progress_bar_section, progress_bar_section_len)
56
56
 
57
- relevant_files_to_scan = exclude_irrelevant_files(progress_bar, progress_bar_section, scan_type, all_files_to_scan)
57
+ relevant_files_to_scan = excluder.exclude_irrelevant_files(
58
+ progress_bar, progress_bar_section, scan_type, all_files_to_scan
59
+ )
58
60
 
59
61
  # after finishing the first processing (excluding),
60
62
  # we must update the progress bar stage with respect of excluded files.
@@ -59,14 +59,13 @@ class BaseRestoreDependencies(ABC):
59
59
  manifest_file_path = self.get_manifest_file_path(document)
60
60
  restore_file_path = build_dep_tree_path(document.absolute_path, self.get_lock_file_name())
61
61
  relative_restore_file_path = build_dep_tree_path(document.path, self.get_lock_file_name())
62
- working_directory_path = self.get_working_directory(document)
63
62
 
64
63
  if not self.verify_restore_file_already_exist(restore_file_path):
65
64
  output = execute_commands(
66
- self.get_commands(manifest_file_path),
67
- self.command_timeout,
65
+ commands=self.get_commands(manifest_file_path),
66
+ timeout=self.command_timeout,
68
67
  output_file_path=restore_file_path if self.create_output_file_manually else None,
69
- working_directory=working_directory_path,
68
+ working_directory=self.get_working_directory(document),
70
69
  )
71
70
  if output is None: # one of the commands failed
72
71
  return None
@@ -75,7 +74,7 @@ class BaseRestoreDependencies(ABC):
75
74
  return Document(relative_restore_file_path, restore_file_content, self.is_git_diff)
76
75
 
77
76
  def get_working_directory(self, document: Document) -> Optional[str]:
78
- return None
77
+ return os.path.dirname(document.absolute_path)
79
78
 
80
79
  @staticmethod
81
80
  def verify_restore_file_already_exist(restore_file_path: str) -> bool:
@@ -43,6 +43,3 @@ class RestoreGoDependencies(BaseRestoreDependencies):
43
43
 
44
44
  def get_lock_file_name(self) -> str:
45
45
  return GO_RESTORE_FILE_NAME
46
-
47
- def get_working_directory(self, document: Document) -> Optional[str]:
48
- return os.path.dirname(document.absolute_path)
@@ -30,34 +30,36 @@ class RestoreMavenDependencies(BaseRestoreDependencies):
30
30
  return join_paths('target', MAVEN_CYCLONE_DEP_TREE_FILE_NAME)
31
31
 
32
32
  def try_restore_dependencies(self, document: Document) -> Optional[Document]:
33
- restore_dependencies_document = super().try_restore_dependencies(document)
34
33
  manifest_file_path = self.get_manifest_file_path(document)
35
34
  if document.content is None:
36
- restore_dependencies_document = self.restore_from_secondary_command(
37
- document, manifest_file_path, restore_dependencies_document
38
- )
39
- else:
40
- restore_dependencies_document.content = get_file_content(
41
- join_paths(get_file_dir(manifest_file_path), self.get_lock_file_name())
42
- )
35
+ return self.restore_from_secondary_command(document, manifest_file_path)
36
+
37
+ restore_dependencies_document = super().try_restore_dependencies(document)
38
+ if restore_dependencies_document is None:
39
+ return None
40
+
41
+ restore_dependencies_document.content = get_file_content(
42
+ join_paths(get_file_dir(manifest_file_path), self.get_lock_file_name())
43
+ )
43
44
 
44
45
  return restore_dependencies_document
45
46
 
46
- def restore_from_secondary_command(
47
- self, document: Document, manifest_file_path: str, restore_dependencies_document: Optional[Document]
48
- ) -> Optional[Document]:
49
- # TODO(MarshalX): does it even work? Ignored restore_dependencies_document arg
50
- secondary_restore_command = create_secondary_restore_commands(manifest_file_path)
51
- backup_restore_content = execute_commands(secondary_restore_command, self.command_timeout)
52
- restore_dependencies_document = Document(
53
- build_dep_tree_path(document.path, MAVEN_DEP_TREE_FILE_NAME), backup_restore_content, self.is_git_diff
47
+ def restore_from_secondary_command(self, document: Document, manifest_file_path: str) -> Optional[Document]:
48
+ restore_content = execute_commands(
49
+ commands=create_secondary_restore_commands(manifest_file_path),
50
+ timeout=self.command_timeout,
51
+ working_directory=self.get_working_directory(document),
54
52
  )
55
- restore_dependencies = None
56
- if restore_dependencies_document.content is not None:
57
- restore_dependencies = restore_dependencies_document
58
- restore_dependencies.content = get_file_content(MAVEN_DEP_TREE_FILE_NAME)
53
+ if restore_content is None:
54
+ return None
59
55
 
60
- return restore_dependencies
56
+ restore_file_path = build_dep_tree_path(document.absolute_path, MAVEN_DEP_TREE_FILE_NAME)
57
+ return Document(
58
+ path=build_dep_tree_path(document.path, MAVEN_DEP_TREE_FILE_NAME),
59
+ content=get_file_content(restore_file_path),
60
+ is_git_diff_format=self.is_git_diff,
61
+ absolute_path=restore_file_path,
62
+ )
61
63
 
62
64
 
63
65
  def create_secondary_restore_commands(manifest_file_path: str) -> list[list[str]]:
@@ -1,6 +1,3 @@
1
- import os
2
- from typing import Optional
3
-
4
1
  from cycode.cli.files_collector.sca.base_restore_dependencies import BaseRestoreDependencies
5
2
  from cycode.cli.models import Document
6
3
 
@@ -17,6 +14,3 @@ class RestoreRubyDependencies(BaseRestoreDependencies):
17
14
 
18
15
  def get_lock_file_name(self) -> str:
19
16
  return RUBY_LOCK_FILE_NAME
20
-
21
- def get_working_directory(self, document: Document) -> Optional[str]:
22
- return os.path.dirname(document.absolute_path)
@@ -1,6 +1,3 @@
1
- import os
2
- from typing import Optional
3
-
4
1
  from cycode.cli.files_collector.sca.base_restore_dependencies import BaseRestoreDependencies
5
2
  from cycode.cli.models import Document
6
3
 
@@ -17,6 +14,3 @@ class RestoreSbtDependencies(BaseRestoreDependencies):
17
14
 
18
15
  def get_lock_file_name(self) -> str:
19
16
  return SBT_LOCK_FILE_NAME
20
-
21
- def get_working_directory(self, document: Document) -> Optional[str]:
22
- return os.path.dirname(document.absolute_path)
@@ -92,17 +92,16 @@ def get_project_file_ecosystem(document: Document) -> Optional[str]:
92
92
 
93
93
  def try_restore_dependencies(
94
94
  ctx: typer.Context,
95
- documents_to_add: dict[str, Document],
96
95
  restore_dependencies: 'BaseRestoreDependencies',
97
96
  document: Document,
98
- ) -> None:
97
+ ) -> Optional[Document]:
99
98
  if not restore_dependencies.is_project(document):
100
- return
99
+ return None
101
100
 
102
101
  restore_dependencies_document = restore_dependencies.restore(document)
103
102
  if restore_dependencies_document is None:
104
103
  logger.warning('Error occurred while trying to generate dependencies tree, %s', {'filename': document.path})
105
- return
104
+ return None
106
105
 
107
106
  if restore_dependencies_document.content is None:
108
107
  logger.warning('Error occurred while trying to generate dependencies tree, %s', {'filename': document.path})
@@ -114,10 +113,7 @@ def try_restore_dependencies(
114
113
  manifest_file_path = get_manifest_file_path(document, is_monitor_action, project_path)
115
114
  logger.debug('Succeeded to generate dependencies tree on path: %s', manifest_file_path)
116
115
 
117
- if restore_dependencies_document.path in documents_to_add:
118
- logger.debug('Duplicate document on restore for path: %s', restore_dependencies_document.path)
119
- else:
120
- documents_to_add[restore_dependencies_document.path] = restore_dependencies_document
116
+ return restore_dependencies_document
121
117
 
122
118
 
123
119
  def add_dependencies_tree_document(
@@ -128,7 +124,14 @@ def add_dependencies_tree_document(
128
124
 
129
125
  for restore_dependencies in restore_dependencies_list:
130
126
  for document in documents_to_scan:
131
- try_restore_dependencies(ctx, documents_to_add, restore_dependencies, document)
127
+ restore_dependencies_document = try_restore_dependencies(ctx, restore_dependencies, document)
128
+ if restore_dependencies_document is None:
129
+ continue
130
+
131
+ if restore_dependencies_document.path in documents_to_add:
132
+ logger.debug('Duplicate document on restore for path: %s', restore_dependencies_document.path)
133
+ else:
134
+ documents_to_add[restore_dependencies_document.path] = restore_dependencies_document
132
135
 
133
136
  # mutate original list using slice assignment
134
137
  documents_to_scan[:] = list(documents_to_add.values())
@@ -500,3 +500,19 @@ class SupportedModulesPreferencesSchema(Schema):
500
500
  @post_load
501
501
  def build_dto(self, data: dict[str, Any], **_) -> 'SupportedModulesPreferences':
502
502
  return SupportedModulesPreferences(**data)
503
+
504
+
505
+ @dataclass
506
+ class ScanConfiguration:
507
+ scannable_extensions: list[str]
508
+
509
+
510
+ class ScanConfigurationSchema(Schema):
511
+ class Meta:
512
+ unknown = EXCLUDE
513
+
514
+ scannable_extensions = fields.List(fields.String(), allow_none=True)
515
+
516
+ @post_load
517
+ def build_dto(self, data: dict[str, Any], **_) -> 'ScanConfiguration':
518
+ return ScanConfiguration(**data)
@@ -1,16 +1,17 @@
1
1
  import json
2
2
  from copy import deepcopy
3
- from typing import TYPE_CHECKING, Union
3
+ from typing import TYPE_CHECKING, Optional, Union
4
4
  from uuid import UUID
5
5
 
6
6
  from requests import Response
7
7
 
8
8
  from cycode.cli import consts
9
9
  from cycode.cli.config import configuration_manager
10
- from cycode.cli.exceptions.custom_exceptions import CycodeError
10
+ from cycode.cli.exceptions.custom_exceptions import CycodeError, RequestHttpError
11
11
  from cycode.cli.files_collector.models.in_memory_zip import InMemoryZip
12
12
  from cycode.cyclient import models
13
13
  from cycode.cyclient.cycode_client_base import CycodeClientBase
14
+ from cycode.cyclient.logger import logger
14
15
 
15
16
  if TYPE_CHECKING:
16
17
  from cycode.cyclient.scan_config_base import ScanConfigBase
@@ -100,12 +101,19 @@ class ScanClient:
100
101
  is_commit_range: bool = False,
101
102
  ) -> models.ScanInitializationResponse:
102
103
  files = {'file': ('multiple_files_scan.zip', zip_file.read())}
104
+
105
+ compression_manifest = {
106
+ 'file_count_by_extension': zip_file.extension_statistics,
107
+ 'file_count': zip_file.files_count,
108
+ }
109
+
103
110
  response = self.scan_cycode_client.post(
104
111
  url_path=self.get_zipped_file_scan_async_url_path(scan_type),
105
112
  data={
106
113
  'is_git_diff': is_git_diff,
107
114
  'scan_parameters': json.dumps(scan_parameters),
108
115
  'is_commit_range': is_commit_range,
116
+ 'compression_manifest': json.dumps(compression_manifest),
109
117
  },
110
118
  files=files,
111
119
  )
@@ -245,3 +253,25 @@ class ScanClient:
245
253
  @staticmethod
246
254
  def parse_scan_response(response: Response) -> models.ScanResult:
247
255
  return models.ScanResultSchema().load(response.json())
256
+
257
+ def get_scan_configuration_path(self, scan_type: str) -> str:
258
+ correct_scan_type = self.scan_config.get_async_scan_type(scan_type)
259
+ return f'{self.get_scan_service_url_path(scan_type)}/{correct_scan_type}/configuration'
260
+
261
+ def get_scan_configuration(self, scan_type: str) -> models.ScanConfiguration:
262
+ response = self.scan_cycode_client.get(
263
+ url_path=self.get_scan_configuration_path(scan_type),
264
+ hide_response_content_log=self._hide_response_log,
265
+ )
266
+ return models.ScanConfigurationSchema().load(response.json())
267
+
268
+ def get_scan_configuration_safe(self, scan_type: str) -> Optional['models.ScanConfiguration']:
269
+ try:
270
+ return self.get_scan_configuration(scan_type)
271
+ except RequestHttpError as e:
272
+ if e.status_code == 404:
273
+ logger.debug(
274
+ 'Remote scan configuration is not supported for this scan type: %s', {'scan_type': scan_type}
275
+ )
276
+ else:
277
+ logger.debug('Failed to get remote scan configuration: %s', {'scan_type': scan_type}, exc_info=e)
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "cycode"
3
- version = "3.0.1.dev1" # DON'T TOUCH. Placeholder. Will be filled automatically on poetry build from Git Tag
3
+ version = "3.0.2.dev2" # 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__ = '3.0.1.dev1' # DON'T TOUCH. Placeholder. Will be filled automatically on poetry build from Git Tag