devsecops-engine-tools 1.101.1__py3-none-any.whl → 1.102.0__py3-none-any.whl

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.

Potentially problematic release.


This version of devsecops-engine-tools might be problematic. Click here for more details.

Files changed (24) hide show
  1. devsecops_engine_tools/engine_core/src/applications/runner_engine_core.py +19 -4
  2. devsecops_engine_tools/engine_core/src/domain/model/finding.py +9 -1
  3. devsecops_engine_tools/engine_core/src/domain/usecases/break_build.py +11 -7
  4. devsecops_engine_tools/engine_core/src/infrastructure/driven_adapters/azure/azure_devops.py +3 -1
  5. devsecops_engine_tools/engine_core/src/infrastructure/driven_adapters/defect_dojo/defect_dojo.py +88 -74
  6. devsecops_engine_tools/engine_core/src/infrastructure/driven_adapters/github/github_actions.py +3 -1
  7. devsecops_engine_tools/engine_core/src/infrastructure/driven_adapters/printer_pretty_table/printer_pretty_table.py +14 -7
  8. devsecops_engine_tools/engine_core/src/infrastructure/driven_adapters/runtime_local/runtime_local.py +1 -0
  9. devsecops_engine_tools/engine_sast/engine_code/src/applications/runner_engine_code.py +17 -1
  10. devsecops_engine_tools/engine_sast/engine_code/src/domain/model/gateways/tool_gateway.py +24 -11
  11. devsecops_engine_tools/engine_sast/engine_code/src/domain/usecases/code_scan.py +100 -37
  12. devsecops_engine_tools/engine_sast/engine_code/src/infrastructure/driven_adapters/bearer/bearer_deserealizator.py +9 -4
  13. devsecops_engine_tools/engine_sast/engine_code/src/infrastructure/driven_adapters/kiuwan/__init__.py +0 -0
  14. devsecops_engine_tools/engine_sast/engine_code/src/infrastructure/driven_adapters/kiuwan/kiuwan_deserealizator.py +59 -0
  15. devsecops_engine_tools/engine_sast/engine_code/src/infrastructure/driven_adapters/kiuwan/kiuwan_tool.py +537 -0
  16. devsecops_engine_tools/engine_sast/engine_secret/src/infrastructure/driven_adapters/gitleaks/gitleaks_tool.py +1 -1
  17. devsecops_engine_tools/engine_utilities/azuredevops/models/AzurePredefinedVariables.py +3 -0
  18. devsecops_engine_tools/engine_utilities/github/models/GithubPredefinedVariables.py +3 -0
  19. devsecops_engine_tools/version.py +1 -1
  20. {devsecops_engine_tools-1.101.1.dist-info → devsecops_engine_tools-1.102.0.dist-info}/METADATA +1 -1
  21. {devsecops_engine_tools-1.101.1.dist-info → devsecops_engine_tools-1.102.0.dist-info}/RECORD +24 -21
  22. {devsecops_engine_tools-1.101.1.dist-info → devsecops_engine_tools-1.102.0.dist-info}/WHEEL +0 -0
  23. {devsecops_engine_tools-1.101.1.dist-info → devsecops_engine_tools-1.102.0.dist-info}/entry_points.txt +0 -0
  24. {devsecops_engine_tools-1.101.1.dist-info → devsecops_engine_tools-1.102.0.dist-info}/top_level.txt +0 -0
@@ -7,13 +7,29 @@ from devsecops_engine_tools.engine_sast.engine_code.src.infrastructure.driven_ad
7
7
  from devsecops_engine_tools.engine_utilities.git_cli.infrastructure.git_run import (
8
8
  GitRun
9
9
  )
10
+ from devsecops_engine_tools.engine_utilities.utils.logger_info import MyLogger
11
+ from devsecops_engine_tools.engine_utilities import settings
12
+ from devsecops_engine_tools.engine_sast.engine_code.src.infrastructure.driven_adapters.kiuwan.kiuwan_tool import get_kiuwan_instance
13
+
14
+
15
+ logger = MyLogger.__call__(**settings.SETTING_LOGGER).get_logger()
10
16
 
11
17
  def runner_engine_code(dict_args, tool, devops_platform_gateway, remote_config_source_gateway):
12
18
  try:
19
+ logger.info("Selecting tool...")
13
20
  tool_gateway = None
14
21
  git_gateway = GitRun()
15
22
  if (tool == "BEARER"):
23
+ logger.info("Bearer tool selected...")
16
24
  tool_gateway = BearerTool()
25
+ elif (tool == "KIUWAN"):
26
+ logger.info("Kiuwan tool selected...")
27
+ tool_gateway = get_kiuwan_instance(
28
+ dict_args=dict_args,
29
+ devops_platform_gateway=devops_platform_gateway,
30
+ )
31
+
32
+ logger.info("Tool has been selected successfully")
17
33
 
18
34
  return init_engine_sast_code(
19
35
  devops_platform_gateway=devops_platform_gateway,
@@ -29,4 +45,4 @@ def runner_engine_code(dict_args, tool, devops_platform_gateway, remote_config_s
29
45
 
30
46
 
31
47
  if __name__ == "__main__":
32
- runner_engine_code()
48
+ runner_engine_code()
@@ -1,15 +1,28 @@
1
1
  from abc import ABCMeta, abstractmethod
2
- from devsecops_engine_tools.engine_sast.engine_code.src.domain.model.config_tool import (
3
- ConfigTool,
4
- )
2
+ from typing import List, Optional, Any, Tuple
3
+ from devsecops_engine_tools.engine_sast.engine_code.src.domain.model.config_tool import ConfigTool
5
4
 
6
5
  class ToolGateway(metaclass=ABCMeta):
7
-
8
6
  @abstractmethod
9
- def run_tool(self,
10
- folder_to_scan: str,
11
- pull_request_files: list,
12
- agent_work_folder: str,
13
- repository: str,
14
- config_tool: ConfigTool):
15
- "run code scan tool"
7
+ def run_tool(
8
+ self,
9
+ folder_to_scan: str,
10
+ pull_request_files: List[str],
11
+ agent_work_folder: str,
12
+ repository: str,
13
+ config_tool: ConfigTool
14
+ ) -> Tuple[List[Any], Optional[str]]:
15
+ """
16
+ Run the code scan tool.
17
+ Args:
18
+ folder_to_scan: Path to the folder to scan
19
+ pull_request_files: List of files modified in the pull request
20
+ agent_work_folder: Directory for storing temporary files
21
+ repository: Name of the repository
22
+ config_tool: Configuration object for the tool
23
+ Returns:
24
+ Tuple containing:
25
+ - List of findings (vulnerabilities or defects).
26
+ - Path to the results file, or None if no file is generated.
27
+ """
28
+ pass
@@ -1,4 +1,5 @@
1
1
  import re
2
+ from typing import Any, Dict, List, Tuple
2
3
  from devsecops_engine_tools.engine_sast.engine_code.src.domain.model.gateways.tool_gateway import (
3
4
  ToolGateway,
4
5
  )
@@ -33,9 +34,9 @@ class CodeScan:
33
34
  self.remote_config_source_gateway = remote_config_source_gateway
34
35
  self.git_gateway = git_gateway
35
36
 
36
- def set_config_tool(self, dict_args):
37
+ def set_config_tool(self, dict_args: Dict[str, Any], config_tool_path: str):
37
38
  init_config_tool = self.remote_config_source_gateway.get_remote_config(
38
- dict_args["remote_config_repo"], "engine_sast/engine_code/ConfigTool.json", dict_args["remote_config_branch"]
39
+ dict_args["remote_config_repo"], config_tool_path, dict_args["remote_config_branch"]
39
40
  )
40
41
  scope_pipeline = self.devops_platform_gateway.get_variable("pipeline_name")
41
42
  return ConfigTool(json_data=init_config_tool, scope=scope_pipeline)
@@ -88,35 +89,112 @@ class CodeScan:
88
89
  return True
89
90
  return False
90
91
 
91
- def process(self, dict_args, tool):
92
- config_tool = self.set_config_tool(dict_args)
92
+ def _get_config_tool_and_exclusions_data(self, dict_args, tool) -> Tuple[Dict[str, Any], Dict[str, str]]:
93
+
94
+ """
95
+ Get the information related to configuracion and exclusiones for the selected tool.
96
+
97
+ Parameters:
98
+ dict_args: Dictionary with properties setting up from the extension.
99
+ tool: String name of the tool that will be used to run scan.
100
+
101
+ Returns:
102
+ config_tool: Dictionary with the configuration of the tool.
103
+ excusions_data: Dictionary with the exclusions configured for an specific tool and pipelines.
104
+ """
105
+ logger.info("Getting engine_code config tool and exclusions...")
106
+ config_tool = self.set_config_tool(dict_args, "engine_sast/engine_code/ConfigTool.json")
93
107
  exclusions_data = self.remote_config_source_gateway.get_remote_config(
94
- dict_args["remote_config_repo"], "engine_sast/engine_code/Exclusions.json"
108
+ dict_args["remote_config_repo"], "engine_sast/engine_code/Exclusions.json", dict_args["remote_config_branch"]
109
+ )
110
+ return config_tool, exclusions_data
111
+
112
+ def _get_filtered_pr_files(self, dict_args: Dict[str,str], config_tool: Dict[str, Any]) -> List[str]:
113
+ """
114
+ Retrieve and filter pull request files based on exclusion rules.
115
+
116
+ Parameters:
117
+ config_tool: Configuration dictionary for the SAST tool.
118
+
119
+ Returns:
120
+ List of filtered pull request file paths.
121
+ """
122
+ pull_request_files = []
123
+ if not dict_args["folder_path"]:
124
+ pull_request_files = self.get_pull_request_files(
125
+ config_tool.target_branches
126
+ )
127
+ pull_request_files = [
128
+ pf
129
+ for pf in pull_request_files
130
+ if not self.apply_exclude_path(
131
+ config_tool.exclude_folder,
132
+ config_tool.ignore_search_pattern,
133
+ pf,
134
+ )
135
+ ]
136
+ return pull_request_files
137
+
138
+ def _create_input_core(self, list_exclusions: List[str], config_tool: Dict[str, Any], exclusions_data: Dict[str, str], path_file_results: str) -> 'InputCore':
139
+ """
140
+ Create an InputCore object with pipeline and tool configuration.
141
+
142
+ Parameters:
143
+ list_exclusions: List of excluded files or patterns.
144
+ config_tool: Configuration dictionary for the SAST tool.
145
+ exclusions_data: Exclusion data for the tool.
146
+ path_file_results: Path to the results file.
147
+
148
+ Returns:
149
+ InputCore object with pipeline and tool configuration.
150
+ """
151
+ return InputCore(
152
+ totalized_exclusions=list_exclusions,
153
+ threshold_defined=Utils.update_threshold(
154
+ self,
155
+ config_tool.threshold,
156
+ exclusions_data,
157
+ config_tool.scope_pipeline,
158
+ ),
159
+ path_file_results=path_file_results,
160
+ custom_message_break_build=config_tool.message_info_engine_code,
161
+ scope_pipeline=config_tool.scope_pipeline,
162
+ scope_service=config_tool.scope_pipeline,
163
+ stage_pipeline=self.devops_platform_gateway.get_variable("stage").capitalize(),
95
164
  )
165
+
166
+ def process(self, dict_args, tool):
167
+
168
+ """
169
+ This function process the request to a new scan code.
170
+
171
+ Parameters:
172
+ dict_args: Dictionary with properties setting up from the extension.
173
+ tool: String name of the tool that will be used to run scan.
174
+
175
+ Returns:
176
+ findings_list: List with the defects founded during analysis.
177
+ input_core: InputCore instance with properties related to scan proccess.
178
+ """
179
+
180
+ # Retrieve the config tool and exclusions data for the tool used during scan
181
+ config_tool, exclusions_data = self._get_config_tool_and_exclusions_data(
182
+ dict_args, tool
183
+ )
184
+
96
185
  list_exclusions, skip_tool = self.get_exclusions(tool, exclusions_data)
97
186
  findings_list, path_file_results = [], ""
98
187
 
99
188
  if not skip_tool:
100
- pull_request_files = []
101
- if not dict_args["folder_path"]:
102
- pull_request_files = self.get_pull_request_files(
103
- config_tool.target_branches
104
- )
105
- pull_request_files = [
106
- pf
107
- for pf in pull_request_files
108
- if not self.apply_exclude_path(
109
- config_tool.exclude_folder,
110
- config_tool.ignore_search_pattern,
111
- pf,
112
- )
113
- ]
189
+ # Retrieve the pull requests files
190
+ # If folder path was not added in dict args, the pr files will be downloaded excluding the paths excluded
191
+ pull_request_files = self._get_filtered_pr_files(dict_args, config_tool)
114
192
 
115
193
  findings_list, path_file_results = self.tool_gateway.run_tool(
116
194
  dict_args["folder_path"],
117
195
  pull_request_files,
118
196
  self.devops_platform_gateway.get_variable("path_directory"),
119
- self.devops_platform_gateway.get_variable("repository"),
197
+ dict_args.get("repo_name", False) if dict_args.get("repo_name", False) else self.devops_platform_gateway.get_variable("repository"),
120
198
  config_tool,
121
199
  )
122
200
 
@@ -125,21 +203,6 @@ class CodeScan:
125
203
  dict_args["send_metrics"] = "false"
126
204
  dict_args["use_vulnerability_management"] = "false"
127
205
 
128
- input_core = InputCore(
129
- totalized_exclusions=list_exclusions,
130
- threshold_defined=Utils.update_threshold(
131
- self,
132
- config_tool.threshold,
133
- exclusions_data,
134
- config_tool.scope_pipeline,
135
- ),
136
- path_file_results=path_file_results,
137
- custom_message_break_build=config_tool.message_info_engine_code,
138
- scope_pipeline=config_tool.scope_pipeline,
139
- scope_service=config_tool.scope_pipeline,
140
- stage_pipeline=self.devops_platform_gateway.get_variable(
141
- "stage"
142
- ).capitalize(),
143
- )
206
+ input_core = self._create_input_core(list_exclusions, config_tool, exclusions_data, path_file_results)
144
207
 
145
- return findings_list, input_core
208
+ return findings_list, input_core
@@ -1,6 +1,6 @@
1
1
  from devsecops_engine_tools.engine_core.src.domain.model.finding import (
2
2
  Category,
3
- Finding,
3
+ EngineCodeFinding,
4
4
  )
5
5
  from datetime import datetime
6
6
  from dataclasses import dataclass
@@ -12,7 +12,7 @@ class BearerDeserealizator:
12
12
  @classmethod
13
13
  def get_list_finding(cls,
14
14
  scan_result_path,
15
- agent_work_folder) -> "list[Finding]":
15
+ agent_work_folder) -> "list[EngineCodeFinding]":
16
16
  findings = []
17
17
  with open(scan_result_path, encoding='utf-8') as arc:
18
18
  try:
@@ -30,7 +30,7 @@ class BearerDeserealizator:
30
30
  chunks = [description[i : i + 70] for i in range(0, len(description), 70)]
31
31
  formatted_description = "\n".join(chunks) + "\n"
32
32
 
33
- finding = Finding(
33
+ finding = EngineCodeFinding(
34
34
  id=vul["id"],
35
35
  cvss="",
36
36
  where=vul["full_filename"].replace(agent_work_folder, "").replace("/copy_files_bearer", ""),
@@ -41,7 +41,12 @@ class BearerDeserealizator:
41
41
  module="engine_code",
42
42
  category=Category.VULNERABILITY,
43
43
  requirements="",
44
- tool="Bearer"
44
+ tool="Bearer",
45
+ analysis_url=None,
46
+ analysis_code=None,
47
+ label=None,
48
+ application_business_value=None,
49
+ defect_type=None
45
50
  )
46
51
  findings.append(finding)
47
52
 
@@ -0,0 +1,59 @@
1
+ from datetime import datetime
2
+ from typing import Dict, Any, List
3
+
4
+ from devsecops_engine_tools.engine_core.src.domain.model.finding import Category, EngineCodeFinding
5
+
6
+
7
+ class KiuwanDeserealizator:
8
+
9
+ """
10
+ This class has the functions to deserealize the defects found in kiuwan analysis scan.
11
+ """
12
+
13
+ @staticmethod
14
+ def get_findings(
15
+ last_analysis: Dict[str, Any],
16
+ defects_data: Dict[str, Any],
17
+ analysis_code: str,
18
+ severity_mapper: Dict[str,str],
19
+ ) -> List[EngineCodeFinding]:
20
+ """
21
+ Map Kiuwan defects to KiuwanFinding objects.
22
+
23
+ Args:
24
+ last_analysis: Dictionary containing the last analysis data.
25
+ defects_data: Dictionary containing the defects data.
26
+ analysis_code: The code of the analysis.
27
+
28
+ Returns:
29
+ List of KiuwanFinding objects representing the mapped defects.
30
+ """
31
+ analysis_date = last_analysis.get("date", datetime.now().strftime("%d/%m/%Y"))
32
+ application_business_value = last_analysis.get("applicationBusinessValue", "")
33
+
34
+ findings = []
35
+ for defect in defects_data.get("defects", []):
36
+ # Mapear characteristic a Category
37
+ characteristic = defect.get("characteristic", "").lower()
38
+
39
+ finding = EngineCodeFinding(
40
+ id=str(defect.get("defectId", "")),
41
+ cvss=defect.get("ruleCode", ""),
42
+ where=f"{defect.get('file', '')}:{defect.get('line', '')}",
43
+ description=defect.get("rule", ""),
44
+ severity=severity_mapper.get(defect.get("priority", ""), "Undefined"),
45
+ identification_date=analysis_date,
46
+ published_date_cve="",
47
+ module="engine_code",
48
+ category=Category.VULNERABILITY if characteristic == "security" else Category.COMPLIANCE,
49
+ requirements="",
50
+ tool="kiuwan",
51
+ analysis_url=last_analysis.get("analysisURL", "No available"),
52
+ analysis_code=analysis_code,
53
+ label=defect.get("label", ""),
54
+ application_business_value=application_business_value,
55
+ defect_type=characteristic
56
+ )
57
+ findings.append(finding)
58
+
59
+ return findings