cycode 2.1.1.dev1__tar.gz → 2.1.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 (133) hide show
  1. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/PKG-INFO +1 -2
  2. cycode-2.1.2.dev2/cycode/__init__.py +1 -0
  3. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/commands/ignore/ignore_command.py +53 -23
  4. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/commands/scan/code_scanner.py +37 -27
  5. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/consts.py +1 -0
  6. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/files_collector/path_documents.py +9 -17
  7. cycode-2.1.2.dev2/cycode/cli/files_collector/walk_ignore.py +42 -0
  8. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/user_settings/configuration_manager.py +2 -1
  9. cycode-2.1.2.dev2/cycode/cli/utils/ignore_utils.py +459 -0
  10. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/pyproject.toml +2 -2
  11. cycode-2.1.1.dev1/cycode/__init__.py +0 -1
  12. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/LICENCE +0 -0
  13. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/README.md +0 -0
  14. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/__init__.py +0 -0
  15. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/commands/__init__.py +0 -0
  16. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/commands/ai_remediation/__init__.py +0 -0
  17. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/commands/ai_remediation/ai_remediation_command.py +0 -0
  18. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/commands/auth/__init__.py +0 -0
  19. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/commands/auth/auth_command.py +0 -0
  20. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/commands/auth/auth_manager.py +0 -0
  21. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/commands/auth_common.py +0 -0
  22. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/commands/configure/__init__.py +0 -0
  23. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/commands/configure/configure_command.py +0 -0
  24. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/commands/ignore/__init__.py +0 -0
  25. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/commands/main_cli.py +0 -0
  26. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/commands/report/__init__.py +0 -0
  27. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/commands/report/report_command.py +0 -0
  28. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/commands/report/sbom/__init__.py +0 -0
  29. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/commands/report/sbom/common.py +0 -0
  30. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/commands/report/sbom/path/__init__.py +0 -0
  31. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/commands/report/sbom/path/path_command.py +0 -0
  32. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/commands/report/sbom/repository_url/__init__.py +0 -0
  33. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/commands/report/sbom/repository_url/repository_url_command.py +0 -0
  34. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/commands/report/sbom/sbom_command.py +0 -0
  35. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/commands/report/sbom/sbom_report_file.py +0 -0
  36. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/commands/scan/__init__.py +0 -0
  37. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/commands/scan/commit_history/__init__.py +0 -0
  38. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/commands/scan/commit_history/commit_history_command.py +0 -0
  39. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/commands/scan/path/__init__.py +0 -0
  40. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/commands/scan/path/path_command.py +0 -0
  41. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/commands/scan/pre_commit/__init__.py +0 -0
  42. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/commands/scan/pre_commit/pre_commit_command.py +0 -0
  43. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/commands/scan/pre_receive/__init__.py +0 -0
  44. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/commands/scan/pre_receive/pre_receive_command.py +0 -0
  45. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/commands/scan/repository/__init__.py +0 -0
  46. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/commands/scan/repository/repository_command.py +0 -0
  47. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/commands/scan/scan_ci/__init__.py +0 -0
  48. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/commands/scan/scan_ci/ci_integrations.py +0 -0
  49. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/commands/scan/scan_ci/scan_ci_command.py +0 -0
  50. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/commands/scan/scan_command.py +0 -0
  51. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/commands/status/__init__.py +0 -0
  52. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/commands/status/status_command.py +0 -0
  53. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/commands/version/__init__.py +0 -0
  54. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/commands/version/version_command.py +0 -0
  55. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/config.py +0 -0
  56. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/config.yaml +0 -0
  57. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/exceptions/__init__.py +0 -0
  58. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/exceptions/common.py +0 -0
  59. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/exceptions/custom_exceptions.py +0 -0
  60. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/exceptions/handle_ai_remediation_errors.py +0 -0
  61. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/exceptions/handle_report_sbom_errors.py +0 -0
  62. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/exceptions/handle_scan_errors.py +0 -0
  63. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/files_collector/__init__.py +0 -0
  64. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/files_collector/excluder.py +0 -0
  65. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/files_collector/iac/__init__.py +0 -0
  66. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/files_collector/iac/tf_content_generator.py +0 -0
  67. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/files_collector/models/__init__.py +0 -0
  68. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/files_collector/models/in_memory_zip.py +0 -0
  69. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/files_collector/repository_documents.py +0 -0
  70. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/files_collector/sca/__init__.py +0 -0
  71. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/files_collector/sca/base_restore_dependencies.py +0 -0
  72. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/files_collector/sca/go/__init__.py +0 -0
  73. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/files_collector/sca/go/restore_go_dependencies.py +0 -0
  74. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/files_collector/sca/maven/__init__.py +0 -0
  75. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/files_collector/sca/maven/restore_gradle_dependencies.py +0 -0
  76. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/files_collector/sca/maven/restore_maven_dependencies.py +0 -0
  77. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/files_collector/sca/npm/__init__.py +0 -0
  78. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/files_collector/sca/npm/restore_npm_dependencies.py +0 -0
  79. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/files_collector/sca/nuget/__init__.py +0 -0
  80. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/files_collector/sca/nuget/restore_nuget_dependencies.py +0 -0
  81. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/files_collector/sca/ruby/__init__.py +0 -0
  82. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/files_collector/sca/ruby/restore_ruby_dependencies.py +0 -0
  83. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/files_collector/sca/sbt/__init__.py +0 -0
  84. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/files_collector/sca/sbt/restore_sbt_dependencies.py +0 -0
  85. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/files_collector/sca/sca_code_scanner.py +0 -0
  86. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/files_collector/zip_documents.py +0 -0
  87. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/main.py +0 -0
  88. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/models.py +0 -0
  89. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/printers/__init__.py +0 -0
  90. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/printers/console_printer.py +0 -0
  91. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/printers/json_printer.py +0 -0
  92. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/printers/printer_base.py +0 -0
  93. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/printers/tables/__init__.py +0 -0
  94. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/printers/tables/sca_table_printer.py +0 -0
  95. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/printers/tables/table.py +0 -0
  96. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/printers/tables/table_models.py +0 -0
  97. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/printers/tables/table_printer.py +0 -0
  98. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/printers/tables/table_printer_base.py +0 -0
  99. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/printers/text_printer.py +0 -0
  100. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/sentry.py +0 -0
  101. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/user_settings/__init__.py +0 -0
  102. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/user_settings/base_file_manager.py +0 -0
  103. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/user_settings/config_file_manager.py +0 -0
  104. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/user_settings/credentials_manager.py +0 -0
  105. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/user_settings/jwt_creator.py +0 -0
  106. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/utils/__init__.py +0 -0
  107. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/utils/enum_utils.py +0 -0
  108. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/utils/get_api_client.py +0 -0
  109. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/utils/git_proxy.py +0 -0
  110. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/utils/jwt_utils.py +0 -0
  111. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/utils/path_utils.py +0 -0
  112. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/utils/progress_bar.py +0 -0
  113. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/utils/scan_batch.py +0 -0
  114. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/utils/scan_utils.py +0 -0
  115. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/utils/shell_executor.py +0 -0
  116. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/utils/string_utils.py +0 -0
  117. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/utils/task_timer.py +0 -0
  118. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cli/utils/yaml_utils.py +0 -0
  119. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cyclient/__init__.py +0 -0
  120. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cyclient/auth_client.py +0 -0
  121. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cyclient/client_creator.py +0 -0
  122. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cyclient/config.py +0 -0
  123. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cyclient/config.yaml +0 -0
  124. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cyclient/config_dev.py +0 -0
  125. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cyclient/cycode_client.py +0 -0
  126. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cyclient/cycode_client_base.py +0 -0
  127. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cyclient/cycode_dev_based_client.py +0 -0
  128. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cyclient/cycode_token_based_client.py +0 -0
  129. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cyclient/headers.py +0 -0
  130. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cyclient/models.py +0 -0
  131. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cyclient/report_client.py +0 -0
  132. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/cycode/cyclient/scan_client.py +0 -0
  133. {cycode-2.1.1.dev1 → cycode-2.1.2.dev2}/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.1.1.dev1
3
+ Version: 2.1.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
@@ -29,7 +29,6 @@ Requires-Dist: colorama (>=0.4.3,<0.5.0)
29
29
  Requires-Dist: gitpython (>=3.1.30,<3.2.0)
30
30
  Requires-Dist: marshmallow (>=3.15.0,<3.23.0)
31
31
  Requires-Dist: patch-ng (==1.18.1)
32
- Requires-Dist: pathspec (>=0.11.1,<0.13.0)
33
32
  Requires-Dist: pyjwt (>=2.8.0,<3.0)
34
33
  Requires-Dist: pyyaml (>=6.0,<7.0)
35
34
  Requires-Dist: requests (>=2.32.2,<3.0)
@@ -0,0 +1 @@
1
+ __version__ = '2.1.2.dev2' # DON'T TOUCH. Placeholder. Will be filled automatically on poetry build from Git Tag
@@ -1,20 +1,16 @@
1
- import os
2
1
  import re
2
+ from typing import Optional
3
3
 
4
4
  import click
5
5
 
6
6
  from cycode.cli import consts
7
7
  from cycode.cli.config import config, configuration_manager
8
8
  from cycode.cli.sentry import add_breadcrumb
9
- from cycode.cli.utils.path_utils import get_absolute_path
9
+ from cycode.cli.utils.path_utils import get_absolute_path, is_path_exists
10
10
  from cycode.cli.utils.string_utils import hash_string_to_sha256
11
11
  from cycode.cyclient import logger
12
12
 
13
13
 
14
- def _is_path_to_ignore_exists(path: str) -> bool:
15
- return os.path.exists(path)
16
-
17
-
18
14
  def _is_package_pattern_valid(package: str) -> bool:
19
15
  return re.search('^[^@]+@[^@]+$', package) is not None
20
16
 
@@ -47,10 +43,16 @@ def _is_package_pattern_valid(package: str) -> bool:
47
43
  required=False,
48
44
  help='Ignore scanning a specific package version while running an SCA scan. Expected pattern: name@version.',
49
45
  )
46
+ @click.option(
47
+ '--by-cve',
48
+ type=click.STRING,
49
+ required=False,
50
+ help='Ignore scanning a specific CVE while running an SCA scan. Expected pattern: CVE-YYYY-NNN.',
51
+ )
50
52
  @click.option(
51
53
  '--scan-type',
52
54
  '-t',
53
- default='secret',
55
+ default=consts.SECRET_SCAN_TYPE,
54
56
  help='Specify the type of scan you wish to execute (the default is Secrets).',
55
57
  type=click.Choice(config['scans']['supported_scans']),
56
58
  required=False,
@@ -64,40 +66,68 @@ def _is_package_pattern_valid(package: str) -> bool:
64
66
  required=False,
65
67
  help='Add an ignore rule to the global CLI config.',
66
68
  )
67
- def ignore_command(
68
- by_value: str, by_sha: str, by_path: str, by_rule: str, by_package: str, scan_type: str, is_global: bool
69
+ def ignore_command( # noqa: C901
70
+ by_value: Optional[str],
71
+ by_sha: Optional[str],
72
+ by_path: Optional[str],
73
+ by_rule: Optional[str],
74
+ by_package: Optional[str],
75
+ by_cve: Optional[str],
76
+ scan_type: str = consts.SECRET_SCAN_TYPE,
77
+ is_global: bool = False,
69
78
  ) -> None:
70
79
  """Ignores a specific value, path or rule ID."""
71
80
  add_breadcrumb('ignore')
72
81
 
73
- if not by_value and not by_sha and not by_path and not by_rule and not by_package:
74
- raise click.ClickException('ignore by type is missing')
82
+ all_by_values = [by_value, by_sha, by_path, by_rule, by_package, by_cve]
83
+ if all(by is None for by in all_by_values):
84
+ raise click.ClickException('Ignore by type is missing')
85
+ if len([by for by in all_by_values if by is not None]) != 1:
86
+ raise click.ClickException('You must specify only one ignore by type')
75
87
 
76
88
  if any(by is not None for by in [by_value, by_sha]) and scan_type != consts.SECRET_SCAN_TYPE:
77
- raise click.ClickException('this exclude is supported only for secret scan type')
89
+ raise click.ClickException('This exclude is supported only for Secret scan type')
90
+ if (by_cve or by_package) and scan_type != consts.SCA_SCAN_TYPE:
91
+ raise click.ClickException('This exclude is supported only for SCA scan type')
92
+
93
+ # only one of the by values must be set
94
+ # at least one of the by values must be set
95
+ exclusion_type = exclusion_value = None
78
96
 
79
- if by_value is not None:
97
+ if by_value:
80
98
  exclusion_type = consts.EXCLUSIONS_BY_VALUE_SECTION_NAME
81
99
  exclusion_value = hash_string_to_sha256(by_value)
82
- elif by_sha is not None:
100
+
101
+ if by_sha:
83
102
  exclusion_type = consts.EXCLUSIONS_BY_SHA_SECTION_NAME
84
103
  exclusion_value = by_sha
85
- elif by_path is not None:
104
+
105
+ if by_path:
86
106
  absolute_path = get_absolute_path(by_path)
87
- if not _is_path_to_ignore_exists(absolute_path):
88
- raise click.ClickException('the provided path to ignore by is not exist')
107
+ if not is_path_exists(absolute_path):
108
+ raise click.ClickException('The provided path to ignore by does not exist')
109
+
89
110
  exclusion_type = consts.EXCLUSIONS_BY_PATH_SECTION_NAME
90
111
  exclusion_value = get_absolute_path(absolute_path)
91
- elif by_package is not None:
92
- if scan_type != consts.SCA_SCAN_TYPE:
93
- raise click.ClickException('exclude by package is supported only for sca scan type')
112
+
113
+ if by_rule:
114
+ exclusion_type = consts.EXCLUSIONS_BY_RULE_SECTION_NAME
115
+ exclusion_value = by_rule
116
+
117
+ if by_package:
94
118
  if not _is_package_pattern_valid(by_package):
95
119
  raise click.ClickException('wrong package pattern. should be name@version.')
120
+
96
121
  exclusion_type = consts.EXCLUSIONS_BY_PACKAGE_SECTION_NAME
97
122
  exclusion_value = by_package
98
- else:
99
- exclusion_type = consts.EXCLUSIONS_BY_RULE_SECTION_NAME
100
- exclusion_value = by_rule
123
+
124
+ if by_cve:
125
+ exclusion_type = consts.EXCLUSIONS_BY_CVE_SECTION_NAME
126
+ exclusion_value = by_cve
127
+
128
+ if not exclusion_type or not exclusion_value:
129
+ # should never happen
130
+ raise click.ClickException('Invalid ignore by type')
101
131
 
102
132
  configuration_scope = 'global' if is_global else 'local'
103
133
  logger.debug(
@@ -764,58 +764,68 @@ def _exclude_detections_by_exclusions_configuration(detections: List[Detection],
764
764
 
765
765
 
766
766
  def _should_exclude_detection(detection: Detection, exclusions: Dict) -> bool:
767
+ # FIXME(MarshalX): what the difference between by_value and by_sha?
767
768
  exclusions_by_value = exclusions.get(consts.EXCLUSIONS_BY_VALUE_SECTION_NAME, [])
768
769
  if _is_detection_sha_configured_in_exclusions(detection, exclusions_by_value):
769
770
  logger.debug(
770
- 'Going to ignore violations because they are on the values-to-ignore list, %s',
771
- {'value_sha': detection.detection_details.get('sha512', '')},
771
+ 'Ignoring violation because its value is on the ignore list, %s',
772
+ {'value_sha': detection.detection_details.get('sha512')},
772
773
  )
773
774
  return True
774
775
 
775
776
  exclusions_by_sha = exclusions.get(consts.EXCLUSIONS_BY_SHA_SECTION_NAME, [])
776
777
  if _is_detection_sha_configured_in_exclusions(detection, exclusions_by_sha):
777
778
  logger.debug(
778
- 'Going to ignore violations because they are on the SHA ignore list, %s',
779
- {'sha': detection.detection_details.get('sha512', '')},
779
+ 'Ignoring violation because its SHA value is on the ignore list, %s',
780
+ {'sha': detection.detection_details.get('sha512')},
780
781
  )
781
782
  return True
782
783
 
783
784
  exclusions_by_rule = exclusions.get(consts.EXCLUSIONS_BY_RULE_SECTION_NAME, [])
784
- if exclusions_by_rule:
785
- detection_rule = detection.detection_rule_id
786
- if detection_rule in exclusions_by_rule:
787
- logger.debug(
788
- 'Going to ignore violations because they are on the Rule ID ignore list, %s',
789
- {'detection_rule': detection_rule},
790
- )
791
- return True
785
+ detection_rule_id = detection.detection_rule_id
786
+ if detection_rule_id in exclusions_by_rule:
787
+ logger.debug(
788
+ 'Ignoring violation because its Detection Rule ID is on the ignore list, %s',
789
+ {'detection_rule_id': detection_rule_id},
790
+ )
791
+ return True
792
792
 
793
793
  exclusions_by_package = exclusions.get(consts.EXCLUSIONS_BY_PACKAGE_SECTION_NAME, [])
794
- if exclusions_by_package:
795
- package = _get_package_name(detection)
796
- if package in exclusions_by_package:
797
- logger.debug(
798
- 'Going to ignore violations because they are on the packages-to-ignore list, %s', {'package': package}
799
- )
800
- return True
794
+ package = _get_package_name(detection)
795
+ if package and package in exclusions_by_package:
796
+ logger.debug('Ignoring violation because its package@version is on the ignore list, %s', {'package': package})
797
+ return True
798
+
799
+ exclusions_by_cve = exclusions.get(consts.EXCLUSIONS_BY_CVE_SECTION_NAME, [])
800
+ cve = _get_cve_identifier(detection)
801
+ if cve and cve in exclusions_by_cve:
802
+ logger.debug('Ignoring violation because its CVE is on the ignore list, %s', {'cve': cve})
803
+ return True
801
804
 
802
805
  return False
803
806
 
804
807
 
805
808
  def _is_detection_sha_configured_in_exclusions(detection: Detection, exclusions: List[str]) -> bool:
806
- detection_sha = detection.detection_details.get('sha512', '')
809
+ detection_sha = detection.detection_details.get('sha512')
807
810
  return detection_sha in exclusions
808
811
 
809
812
 
810
- def _get_package_name(detection: Detection) -> str:
811
- package_name = detection.detection_details.get('vulnerable_component', '')
812
- package_version = detection.detection_details.get('vulnerable_component_version', '')
813
+ def _get_package_name(detection: Detection) -> Optional[str]:
814
+ package_name = detection.detection_details.get('vulnerable_component')
815
+ package_version = detection.detection_details.get('vulnerable_component_version')
816
+
817
+ if package_name is None:
818
+ package_name = detection.detection_details.get('package_name')
819
+ package_version = detection.detection_details.get('package_version')
820
+
821
+ if package_name and package_version:
822
+ return f'{package_name}@{package_version}'
823
+
824
+ return None
813
825
 
814
- if package_name == '':
815
- package_name = detection.detection_details.get('package_name', '')
816
- package_version = detection.detection_details.get('package_version', '')
817
826
 
818
- return f'{package_name}@{package_version}'
827
+ def _get_cve_identifier(detection: Detection) -> Optional[str]:
828
+ return detection.detection_details.get('alert', {}).get('cve_identifier')
819
829
 
820
830
 
821
831
  def _get_document_by_file_name(
@@ -131,6 +131,7 @@ EXCLUSIONS_BY_SHA_SECTION_NAME = 'shas'
131
131
  EXCLUSIONS_BY_PATH_SECTION_NAME = 'paths'
132
132
  EXCLUSIONS_BY_RULE_SECTION_NAME = 'rules'
133
133
  EXCLUSIONS_BY_PACKAGE_SECTION_NAME = 'packages'
134
+ EXCLUSIONS_BY_CVE_SECTION_NAME = 'cves'
134
135
 
135
136
  # 5MB in bytes (in decimal)
136
137
  FILE_MAX_SIZE_LIMIT_IN_BYTES = 5000000
@@ -1,7 +1,5 @@
1
1
  import os
2
- from typing import TYPE_CHECKING, Iterable, List, Tuple
3
-
4
- import pathspec
2
+ from typing import TYPE_CHECKING, List, Tuple
5
3
 
6
4
  from cycode.cli.files_collector.excluder import exclude_irrelevant_files
7
5
  from cycode.cli.files_collector.iac.tf_content_generator import (
@@ -10,6 +8,7 @@ from cycode.cli.files_collector.iac.tf_content_generator import (
10
8
  is_iac,
11
9
  is_tfplan_file,
12
10
  )
11
+ from cycode.cli.files_collector.walk_ignore import walk_ignore
13
12
  from cycode.cli.models import Document
14
13
  from cycode.cli.utils.path_utils import get_absolute_path, get_file_content
15
14
  from cycode.cyclient import logger
@@ -18,17 +17,18 @@ if TYPE_CHECKING:
18
17
  from cycode.cli.utils.progress_bar import BaseProgressBar, ProgressBarSection
19
18
 
20
19
 
21
- def _get_all_existing_files_in_directory(path: str) -> List[str]:
20
+ def _get_all_existing_files_in_directory(path: str, *, walk_with_ignore_patterns: bool = True) -> List[str]:
22
21
  files: List[str] = []
23
22
 
24
- for root, _, filenames in os.walk(path):
23
+ walk_func = walk_ignore if walk_with_ignore_patterns else os.walk
24
+ for root, _, filenames in walk_func(path):
25
25
  for filename in filenames:
26
26
  files.append(os.path.join(root, filename))
27
27
 
28
28
  return files
29
29
 
30
30
 
31
- def _get_relevant_files_in_path(path: str, exclude_patterns: Iterable[str]) -> List[str]:
31
+ def _get_relevant_files_in_path(path: str) -> List[str]:
32
32
  absolute_path = get_absolute_path(path)
33
33
 
34
34
  if not os.path.isfile(absolute_path) and not os.path.isdir(absolute_path):
@@ -37,14 +37,8 @@ def _get_relevant_files_in_path(path: str, exclude_patterns: Iterable[str]) -> L
37
37
  if os.path.isfile(absolute_path):
38
38
  return [absolute_path]
39
39
 
40
- all_file_paths = set(_get_all_existing_files_in_directory(absolute_path))
41
-
42
- path_spec = pathspec.PathSpec.from_lines(pathspec.patterns.GitWildMatchPattern, exclude_patterns)
43
- excluded_file_paths = set(path_spec.match_files(all_file_paths))
44
-
45
- relevant_file_paths = all_file_paths - excluded_file_paths
46
-
47
- return [file_path for file_path in relevant_file_paths if os.path.isfile(file_path)]
40
+ file_paths = _get_all_existing_files_in_directory(absolute_path)
41
+ return [file_path for file_path in file_paths if os.path.isfile(file_path)]
48
42
 
49
43
 
50
44
  def _get_relevant_files(
@@ -52,9 +46,7 @@ def _get_relevant_files(
52
46
  ) -> List[str]:
53
47
  all_files_to_scan = []
54
48
  for path in paths:
55
- all_files_to_scan.extend(
56
- _get_relevant_files_in_path(path=path, exclude_patterns=['**/.git/**', '**/.cycode/**'])
57
- )
49
+ all_files_to_scan.extend(_get_relevant_files_in_path(path))
58
50
 
59
51
  # we are double the progress bar section length because we are going to process the files twice
60
52
  # first time to get the file list with respect of excluded patterns (excluding takes seconds to execute)
@@ -0,0 +1,42 @@
1
+ import os
2
+ from typing import Generator, Iterable, List, Tuple
3
+
4
+ from cycode.cli.utils.ignore_utils import IgnoreFilterManager
5
+ from cycode.cyclient import logger
6
+
7
+ _SUPPORTED_IGNORE_PATTERN_FILES = { # oneday we will bring .cycodeignore or something like that
8
+ '.gitignore',
9
+ }
10
+ _DEFAULT_GLOBAL_IGNORE_PATTERNS = [
11
+ '.git',
12
+ '.cycode',
13
+ ]
14
+
15
+
16
+ def _walk_to_top(path: str) -> Iterable[str]:
17
+ while os.path.dirname(path) != path:
18
+ yield path
19
+ path = os.path.dirname(path)
20
+
21
+ if path:
22
+ yield path # Include the top-level directory
23
+
24
+
25
+ def _collect_top_level_ignore_files(path: str) -> List[str]:
26
+ ignore_files = []
27
+ for dir_path in _walk_to_top(path):
28
+ for ignore_file in _SUPPORTED_IGNORE_PATTERN_FILES:
29
+ ignore_file_path = os.path.join(dir_path, ignore_file)
30
+ if os.path.exists(ignore_file_path):
31
+ logger.debug('Apply top level ignore file: %s', ignore_file_path)
32
+ ignore_files.append(ignore_file_path)
33
+ return ignore_files
34
+
35
+
36
+ def walk_ignore(path: str) -> Generator[Tuple[str, List[str], List[str]], None, None]:
37
+ ignore_filter_manager = IgnoreFilterManager.build(
38
+ path=path,
39
+ global_ignore_file_paths=_collect_top_level_ignore_files(path),
40
+ global_patterns=_DEFAULT_GLOBAL_IGNORE_PATTERNS,
41
+ )
42
+ yield from ignore_filter_manager.walk()
@@ -79,7 +79,8 @@ class ConfigurationManager:
79
79
  config_file_manager = self.get_config_file_manager(scope)
80
80
  config_file_manager.add_exclusion(scan_type, exclusion_type, value)
81
81
 
82
- def _merge_exclusions(self, local_exclusions: Dict, global_exclusions: Dict) -> Dict:
82
+ @staticmethod
83
+ def _merge_exclusions(local_exclusions: Dict, global_exclusions: Dict) -> Dict:
83
84
  keys = set(list(local_exclusions.keys()) + list(global_exclusions.keys()))
84
85
  return {key: local_exclusions.get(key, []) + global_exclusions.get(key, []) for key in keys}
85
86