From 4fa2dca6056bfa441918a9dcbe7e96068392746a Mon Sep 17 00:00:00 2001 From: Michael David Herrera Vargas Date: Wed, 8 Jan 2025 14:48:58 -0500 Subject: [PATCH] add documentation of use cmdb and update unit test --- README.md | 2 +- example_remote_config_local/README.md | 118 ++++++++ .../engine_core/ConfigTool.json | 44 +-- .../domain/model/vulnerability_management.py | 3 + .../src/domain/usecases/handle_scan.py | 3 + .../driven_adapters/azure/azure_devops.py | 4 + .../defect_dojo/defect_dojo.py | 121 ++++++--- .../driven_adapters/github/github_actions.py | 6 +- .../runtime_local/runtime_local.py | 5 +- .../defect_dojo/test_defect_dojo.py | 255 ++++++++++++++++-- .../models/AzurePredefinedVariables.py | 5 + .../domain/serializers/import_scan.py | 10 +- .../infraestructure/driver_adapters/cmdb.py | 8 +- .../models/GithubPredefinedVariables.py | 6 + .../src/domain/usecases/report_sonar.py | 5 +- .../test/domain/usecases/test_report_sonar.py | 4 +- .../models/test_AzurePredefinedVariables.py | 4 + 17 files changed, 510 insertions(+), 93 deletions(-) create mode 100644 example_remote_config_local/README.md diff --git a/README.md b/README.md index 5092d39bc..ae6fe9573 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ devsecops-engine-tools --platform_devops ["local","azure","github"] --remote_con ┃ ┗ 📜ConfigTool.json ┃ ┗ 📜Exclusions.json ``` - +for more information visit [here](https://github.com/bancolombia/devsecops-engine-tools/blob/trunk/example_remote_config_local/README.md) #### Tools available for the modules (Configuration engine_core/ConfigTool.json) diff --git a/example_remote_config_local/README.md b/example_remote_config_local/README.md new file mode 100644 index 000000000..cf8322446 --- /dev/null +++ b/example_remote_config_local/README.md @@ -0,0 +1,118 @@ +# Example use remote config for vulnerability management + +Initially, we need to know that the DevSecOps engine tools include a module for connecting to a vulnerability centralizer (DefectDojo). As a primary requirement for using this module, it must be considered whether a CMDB will be used or not. This is configurable through the remote config located in the [engine_core](https://github.com/bancolombia/devsecops-engine-tools/blob/trunk/example_remote_config_local/engine_core/ConfigTool.json). Below, examples of the two possible cases will be provided: + +### Using CMDB: +Let's suppose the CMDB response is as follows: +```json +{ + "count": 2, + "value": [ + { + "ApplicationCode": "code1-app", + "ApplicationName": "Example Application Name 1", + "ApplicationType": "Example Application type 1", + "ApplicationTag": "Example Application tag 1", + "ApplicationDescription": "Example Application description 1", + "Env": "PDN" + }, + { + "ApplicationCode": "code1-app", + "ApplicationName": "Example Application Name 1", + "ApplicationType": "Example Application type 1", + "ApplicationTag": "Example Application tag 1", + "ApplicationDescription": "Example Application description 1", + "Env": "DEV" + } + ] +} +``` + +Then, the remote config settings should look similar to this: +```json +"DEFECT_DOJO": { + "HOST_DEFECT_DOJO": "http://localhost:8080", + "LIMITS_QUERY": 100, + "MAX_RETRIES_QUERY": 5, + "CMDB": { + "USE_CMDB": true, + "HOST_CMDB": "http://host_cmdb_example", + "REGEX_EXPRESSION_CMDB": "^([^-]+)", + "CMDB_MAPPING_PATH": "/path/mapping_cmdb.json", + "CMDB_MAPPING": { + "PRODUCT_TYPE_NAME": "ApplicationType", + "PRODUCT_NAME": "ApplicationName", + "TAG_PRODUCT": "ApplicationTag", + "PRODUCT_DESCRIPTION": "ApplicationDescription", + "CODIGO_APP": "ApplicationCode" + }, + "CMDB_REQUEST_RESPONSE": { + "HEADERS": { + "Content-Type": "application/json", + "Api-Key": "tokenvalue" + }, + "METHOD": "GET", + "PARAMS": { + "appCode": "codappvalue" + }, + "RESPONSE": ["value", 0] + } + } +} +``` + +**Let’s detail the description for the elements under the CMDB key:** + +*USE_CMDB:* The value is a boolean, indicating whether or not CMDB will be used. + +*USE_CMDB:* The value is a boolean, indicating whether or not CMDB will be used. + +*HOST_CMDB:* The URL of the API for querying the CMDB. + +*REGEX_EXPRESSION_CMDB:* Regular expression. + +*CMDB_MAPPING_PATH:* Location of the mapping for possible product types. + +*CMDB_MAPPING:* Element containing the equivalent mappings between DefectDojo and the CMDB. + +*MDB_REQUEST_RESPONSE:* Contains the necessary elements to make a request to the CMDB. + +*HEADERS:* Headers required to make the request. Note that the authentication type must be via Api-Key. The value "tokenvalue" should remain as is, as it is necessary for replacing the token. + +*METHOD:* Can be either POST or GET. + +*PARAMS:* Used if the selected METHOD is GET. The value "codappvalue" should remain as is, as it is necessary for replacement. + +*BODY:* Used if the selected METHOD is POST. The value "codappvalue" should remain as is, as it is necessary for replacement. + +### Without Using CMDB: +For this case, three environment variables must be created according to the DevOps platform. +```bash +## Platform local +DET_VM_PRODUCT_TYPE_NAME="Example product type name" +DET_VM_PRODUCT_NAME="Example product type name" +DET_VM_PRODUCT_DESCRIPTION="Example product descrition" + +## Platform azure +VM_PRODUCT_TYPE_NAME="Example product type name" +VM_PRODUCT_NAME="Example product type name" +VM_PRODUCT_DESCRIPTION="Example product descrition" + +## Platform github +VM_PRODUCT_TYPE_NAME="Example product type name" +VM_PRODUCT_NAME="Example product type name" +VM_PRODUCT_DESCRIPTION="Example product descrition" +``` + +The remote config settings should look similar to this: +```json + "DEFECT_DOJO": { + "HOST_DEFECT_DOJO": "http://localhost:8080", + "LIMITS_QUERY": 100, + "MAX_RETRIES_QUERY": 5, + "CMDB": { + "USE_CMDB": false, + "REGEX_EXPRESSION_CMDB": "^([^-]+)", + } + } +``` \ No newline at end of file diff --git a/example_remote_config_local/engine_core/ConfigTool.json b/example_remote_config_local/engine_core/ConfigTool.json index c8db7edce..6ecc7e326 100644 --- a/example_remote_config_local/engine_core/ConfigTool.json +++ b/example_remote_config_local/engine_core/ConfigTool.json @@ -14,29 +14,35 @@ "main" ], "DEFECT_DOJO": { - "CMDB_MAPPING_PATH": "", - "HOST_CMDB": "", "HOST_DEFECT_DOJO": "", - "REGEX_EXPRESSION_CMDB": "", "LIMITS_QUERY": 100, "MAX_RETRIES_QUERY": 5, - "CMDB_MAPPING": { - "PRODUCT_TYPE_NAME": "", - "PRODUCT_NAME": "", - "TAG_PRODUCT": "", - "PRODUCT_DESCRIPTION": "", - "CODIGO_APP": "" - }, - "CMDB_REQUEST_RESPONSE": { - "HEADERS": { - "Content-Type": "application/json", - "apiKey": "tokenvalue" + "CMDB": { + "USE_CMDB": false, + "HOST_CMDB": "", + "REGEX_EXPRESSION_CMDB": "", + "CMDB_MAPPING_PATH": "", + "CMDB_MAPPING": { + "PRODUCT_TYPE_NAME": "", + "PRODUCT_NAME": "", + "TAG_PRODUCT": "", + "PRODUCT_DESCRIPTION": "", + "CODIGO_APP": "" }, - "METHOD": "GET|POST", - "PARAMS": { - "appCode": "codappvalue" - }, - "RESPONSE": [0] + "CMDB_REQUEST_RESPONSE": { + "HEADERS": { + "Content-Type": "application/json", + "Api-Key": "tokenvalue" + }, + "METHOD": "GET|POST", + "PARAMS": { + "appCode": "codappvalue" + }, + "BODY": { + "appCode": "codappvalue" + }, + "RESPONSE": [0] + } } } }, diff --git a/tools/devsecops_engine_tools/engine_core/src/domain/model/vulnerability_management.py b/tools/devsecops_engine_tools/engine_core/src/domain/model/vulnerability_management.py index 1d7c147e9..c4630abbe 100644 --- a/tools/devsecops_engine_tools/engine_core/src/domain/model/vulnerability_management.py +++ b/tools/devsecops_engine_tools/engine_core/src/domain/model/vulnerability_management.py @@ -18,3 +18,6 @@ class VulnerabilityManagement: branch_tag: str commit_hash: str environment: str + vm_product_type_name: str + vm_product_name: str + vm_product_description: str diff --git a/tools/devsecops_engine_tools/engine_core/src/domain/usecases/handle_scan.py b/tools/devsecops_engine_tools/engine_core/src/domain/usecases/handle_scan.py index 07aadbb13..d5f754fe9 100644 --- a/tools/devsecops_engine_tools/engine_core/src/domain/usecases/handle_scan.py +++ b/tools/devsecops_engine_tools/engine_core/src/domain/usecases/handle_scan.py @@ -196,6 +196,9 @@ def _use_vulnerability_management( self.devops_platform_gateway.get_variable("branch_tag"), self.devops_platform_gateway.get_variable("commit_hash"), env, + self.devops_platform_gateway.get_variable("vm_product_type_name"), + self.devops_platform_gateway.get_variable("vm_product_name"), + self.devops_platform_gateway.get_variable("vm_product_description"), ) ) diff --git a/tools/devsecops_engine_tools/engine_core/src/infrastructure/driven_adapters/azure/azure_devops.py b/tools/devsecops_engine_tools/engine_core/src/infrastructure/driven_adapters/azure/azure_devops.py index 8d957dc83..d1f592f50 100644 --- a/tools/devsecops_engine_tools/engine_core/src/infrastructure/driven_adapters/azure/azure_devops.py +++ b/tools/devsecops_engine_tools/engine_core/src/infrastructure/driven_adapters/azure/azure_devops.py @@ -7,6 +7,7 @@ SystemVariables, ReleaseVariables, AgentVariables, + VMVariables ) from devsecops_engine_tools.engine_utilities.azuredevops.infrastructure.azure_devops_api import ( AzureDevopsApi, @@ -95,6 +96,9 @@ def get_variable(self, variable): "target_branch": SystemVariables.System_TargetBranchName, "source_branch": SystemVariables.System_SourceBranch, "repository_provider": BuildVariables.Build_Repository_Provider, + "vm_product_type_name": VMVariables.Vm_Product_Type_Name, + "vm_product_name": VMVariables.Vm_Product_Name, + "vm_product_description": VMVariables.Vm_Product_Description, } try: return variable_map.get(variable).value() diff --git a/tools/devsecops_engine_tools/engine_core/src/infrastructure/driven_adapters/defect_dojo/defect_dojo.py b/tools/devsecops_engine_tools/engine_core/src/infrastructure/driven_adapters/defect_dojo/defect_dojo.py index fa386a88d..1641baa76 100644 --- a/tools/devsecops_engine_tools/engine_core/src/infrastructure/driven_adapters/defect_dojo/defect_dojo.py +++ b/tools/devsecops_engine_tools/engine_core/src/infrastructure/driven_adapters/defect_dojo/defect_dojo.py @@ -30,6 +30,7 @@ from devsecops_engine_tools.engine_utilities.utils.logger_info import MyLogger from devsecops_engine_tools.engine_utilities import settings +from devsecops_engine_tools.engine_utilities.defect_dojo.domain.serializers.import_scan import ImportScanSerializer import time import concurrent.futures @@ -87,45 +88,17 @@ def send_vulnerability_management( tags = vulnerability_management.dict_args["tool"] if vulnerability_management.dict_args["tool"] == "engine_iac": tags = f"{vulnerability_management.dict_args['tool']}_{'_'.join(vulnerability_management.dict_args['platform'])}" - request: ImportScanRequest = Connect.cmdb( - cmdb_mapping={ - "product_type_name": vulnerability_management.config_tool["VULNERABILITY_MANAGER"]["DEFECT_DOJO"]["CMDB_MAPPING"]["PRODUCT_TYPE_NAME"], - "product_name": vulnerability_management.config_tool["VULNERABILITY_MANAGER"]["DEFECT_DOJO"]["CMDB_MAPPING"]["PRODUCT_NAME"], - "tag_product": vulnerability_management.config_tool["VULNERABILITY_MANAGER"]["DEFECT_DOJO"]["CMDB_MAPPING"]["TAG_PRODUCT"], - "product_description": vulnerability_management.config_tool["VULNERABILITY_MANAGER"]["DEFECT_DOJO"]["CMDB_MAPPING"]["PRODUCT_DESCRIPTION"], - "codigo_app": vulnerability_management.config_tool["VULNERABILITY_MANAGER"]["DEFECT_DOJO"]["CMDB_MAPPING"]["CODIGO_APP"], - }, - compact_remote_config_url=f'{vulnerability_management.base_compact_remote_config_url}{vulnerability_management.config_tool["VULNERABILITY_MANAGER"]["DEFECT_DOJO"]["CMDB_MAPPING_PATH"]}', - personal_access_token=vulnerability_management.access_token, - token_cmdb=token_cmdb, - host_cmdb=vulnerability_management.config_tool[ - "VULNERABILITY_MANAGER" - ]["DEFECT_DOJO"]["HOST_CMDB"], - cmdb_request_response=vulnerability_management.config_tool["VULNERABILITY_MANAGER"]["DEFECT_DOJO"]["CMDB_REQUEST_RESPONSE"], - expression=vulnerability_management.config_tool[ - "VULNERABILITY_MANAGER" - ]["DEFECT_DOJO"]["REGEX_EXPRESSION_CMDB"], - token_defect_dojo=token_dd, - host_defect_dojo=vulnerability_management.config_tool[ - "VULNERABILITY_MANAGER" - ]["DEFECT_DOJO"]["HOST_DEFECT_DOJO"], - scan_type=scan_type_mapping[vulnerability_management.scan_type], - engagement_name=vulnerability_management.input_core.scope_pipeline, - service=vulnerability_management.input_core.scope_pipeline, - file=vulnerability_management.input_core.path_file_results, - version=vulnerability_management.version, - build_id=vulnerability_management.build_id, - source_code_management_uri=vulnerability_management.source_code_management_uri, - branch_tag=vulnerability_management.branch_tag, - commit_hash=vulnerability_management.commit_hash, - environment=( - enviroment_mapping[vulnerability_management.environment.lower()] - if vulnerability_management.environment is not None - and vulnerability_management.environment.lower() - in enviroment_mapping - else enviroment_mapping["default"] - ), - tags=tags, + + use_cmdb = vulnerability_management.config_tool["VULNERABILITY_MANAGER"]["DEFECT_DOJO"]["CMDB"]["USE_CMDB"] + + request = self.build_request( + vulnerability_management, + token_cmdb, + token_dd, + scan_type_mapping, + enviroment_mapping, + tags, + use_cmdb ) def request_func(): @@ -155,6 +128,74 @@ def request_func(): ) ) + def build_request( + self, + vulnerability_management: VulnerabilityManagement, + token_cmdb, + token_dd, + scan_type_mapping, + enviroment_mapping, + tags, + use_cmdb: bool + ): + common_fields = { + "scan_type": scan_type_mapping[vulnerability_management.scan_type], + "file": vulnerability_management.input_core.path_file_results, + "engagement_name": vulnerability_management.input_core.scope_pipeline, + "source_code_management_uri": vulnerability_management.source_code_management_uri, + "tags": tags, + "version": vulnerability_management.version, + "build_id": vulnerability_management.build_id, + "branch_tag": vulnerability_management.branch_tag, + "commit_hash": vulnerability_management.commit_hash, + "service": vulnerability_management.input_core.scope_pipeline, + "environment": ( + enviroment_mapping[vulnerability_management.environment.lower()] + if vulnerability_management.environment is not None + and vulnerability_management.environment.lower() + in enviroment_mapping + else enviroment_mapping["default"] + ), + "token_defect_dojo": token_dd, + "host_defect_dojo": vulnerability_management.config_tool[ + "VULNERABILITY_MANAGER" + ]["DEFECT_DOJO"]["HOST_DEFECT_DOJO"], + "expression": vulnerability_management.config_tool[ + "VULNERABILITY_MANAGER" + ]["DEFECT_DOJO"]["CMDB"]["REGEX_EXPRESSION_CMDB"], + } + + if use_cmdb: + cmdb_mapping = vulnerability_management.config_tool["VULNERABILITY_MANAGER"]["DEFECT_DOJO"]["CMDB"]["CMDB_MAPPING"] + return Connect.cmdb( + cmdb_mapping={ + "product_type_name": cmdb_mapping["PRODUCT_TYPE_NAME"], + "product_name": cmdb_mapping["PRODUCT_NAME"], + "tag_product": cmdb_mapping["TAG_PRODUCT"], + "product_description": cmdb_mapping["PRODUCT_DESCRIPTION"], + "codigo_app": cmdb_mapping["CODIGO_APP"], + }, + compact_remote_config_url=f'{vulnerability_management.base_compact_remote_config_url}{vulnerability_management.config_tool["VULNERABILITY_MANAGER"]["DEFECT_DOJO"]["CMDB"]["CMDB_MAPPING_PATH"]}', + personal_access_token=vulnerability_management.access_token, + token_cmdb=token_cmdb, + host_cmdb=vulnerability_management.config_tool[ + "VULNERABILITY_MANAGER" + ]["DEFECT_DOJO"]["CMDB"]["HOST_CMDB"], + cmdb_request_response=vulnerability_management.config_tool["VULNERABILITY_MANAGER"]["DEFECT_DOJO"]["CMDB"]["CMDB_REQUEST_RESPONSE"], + **common_fields, + ) + else: + request: ImportScanRequest = ImportScanSerializer().load( + { + "product_type_name":vulnerability_management.vm_product_type_name, + "product_name": vulnerability_management.vm_product_name, + "product_description":vulnerability_management.vm_product_description, + "code_app":vulnerability_management.vm_product_name, + **common_fields, + } + ) + return request + def get_product_type_service(self, service, dict_args, secret_tool, config_tool): try: session_manager = self._get_session_manager( @@ -171,7 +212,7 @@ def request_func(): request={ "name": Connect.get_code_app( service, - config_tool["VULNERABILITY_MANAGER"]["DEFECT_DOJO"][ + config_tool["VULNERABILITY_MANAGER"]["DEFECT_DOJO"]["CMDB"][ "REGEX_EXPRESSION_CMDB" ], ), diff --git a/tools/devsecops_engine_tools/engine_core/src/infrastructure/driven_adapters/github/github_actions.py b/tools/devsecops_engine_tools/engine_core/src/infrastructure/driven_adapters/github/github_actions.py index 797fe18a4..9ccd76791 100755 --- a/tools/devsecops_engine_tools/engine_core/src/infrastructure/driven_adapters/github/github_actions.py +++ b/tools/devsecops_engine_tools/engine_core/src/infrastructure/driven_adapters/github/github_actions.py @@ -6,7 +6,8 @@ BuildVariables, SystemVariables, ReleaseVariables, - AgentVariables + AgentVariables, + VMVariables ) from devsecops_engine_tools.engine_utilities.github.infrastructure.github_api import ( GithubApi, @@ -85,6 +86,9 @@ def get_variable(self, variable): "target_branch": SystemVariables.github_event_base_ref, "source_branch": SystemVariables.github_ref, "repository_provider": BuildVariables.GitHub, + "vm_product_type_name": VMVariables.Vm_Product_Type_Name, + "vm_product_name": VMVariables.Vm_Product_Name, + "vm_product_description": VMVariables.Vm_Product_Description, } try: return variable_map.get(variable).value() diff --git a/tools/devsecops_engine_tools/engine_core/src/infrastructure/driven_adapters/runtime_local/runtime_local.py b/tools/devsecops_engine_tools/engine_core/src/infrastructure/driven_adapters/runtime_local/runtime_local.py index 2e493f382..8ff12292e 100755 --- a/tools/devsecops_engine_tools/engine_core/src/infrastructure/driven_adapters/runtime_local/runtime_local.py +++ b/tools/devsecops_engine_tools/engine_core/src/infrastructure/driven_adapters/runtime_local/runtime_local.py @@ -66,6 +66,9 @@ def get_variable(self, variable): "temp_directory" : "DET_TEMP_DIRECTORY", "target_branch" : "DET_TARGET_BRANCH", "source_branch" : "DET_SOURCE_BRANCH", - "repository_provider" : "DET_REPOSITORY_PROVIDER" + "repository_provider" : "DET_REPOSITORY_PROVIDER", + "vm_product_type_name" : "DET_VM_PRODUCT_TYPE_NAME", + "vm_product_name" : "DET_VM_PRODUCT_NAME", + "vm_product_description" : "DET_VM_PRODUCT_DESCRIPTION", } return os.environ.get(env_variables[variable], None) \ No newline at end of file diff --git a/tools/devsecops_engine_tools/engine_core/test/infrastructure/driven_adapters/defect_dojo/test_defect_dojo.py b/tools/devsecops_engine_tools/engine_core/test/infrastructure/driven_adapters/defect_dojo/test_defect_dojo.py index f8fec6769..041fceccc 100644 --- a/tools/devsecops_engine_tools/engine_core/test/infrastructure/driven_adapters/defect_dojo/test_defect_dojo.py +++ b/tools/devsecops_engine_tools/engine_core/test/infrastructure/driven_adapters/defect_dojo/test_defect_dojo.py @@ -40,30 +40,33 @@ def test_send_vulnerability_management(self, mock_send_import_scan): "VULNERABILITY_MANAGER": { "BRANCH_FILTER": "trunk,master,release,develop", "DEFECT_DOJO": { - "CMDB_MAPPING_PATH": "mapping_path", - "HOST_CMDB": "cmdb_host", - "REGEX_EXPRESSION_CMDB": "regex", "HOST_DEFECT_DOJO": "host_defect_dojo", "MAX_RETRIES_QUERY": 5, - "CMDB_MAPPING": { - "PRODUCT_TYPE_NAME": "nombreevc", - "PRODUCT_NAME": "nombreapp", - "TAG_PRODUCT": "nombreentorno", - "PRODUCT_DESCRIPTION": "arearesponsableti", - "CODIGO_APP": "CodigoApp" - }, - "CMDB_REQUEST_RESPONSE": { - "HEADERS": { - "Content-Type": "application/json", - "tokenkey": "tokenvalue" - }, - "METHOD": "POST", - "BODY": { - "codapp": "codappvalue" + "CMDB": { + "USE_CMDB": True, + "HOST_CMDB": "cmdb_host", + "REGEX_EXPRESSION_CMDB": "regex", + "CMDB_MAPPING_PATH": "mapping_path", + "CMDB_MAPPING": { + "PRODUCT_TYPE_NAME": "nombreevc", + "PRODUCT_NAME": "nombreapp", + "TAG_PRODUCT": "nombreentorno", + "PRODUCT_DESCRIPTION": "arearesponsableti", + "CODIGO_APP": "CodigoApp" }, - "RESPONSE": [0] - } - }, + "CMDB_REQUEST_RESPONSE": { + "HEADERS": { + "Content-Type": "application/json", + "tokenkey": "tokenvalue" + }, + "METHOD": "POST", + "BODY": { + "codapp": "codappvalue" + }, + "RESPONSE": [0] + } + } + } } } self.vulnerability_management.access_token = "access_token" @@ -144,6 +147,212 @@ def test_send_vulnerability_management_exception(self): in str(context.exception) ) + + def test_build_request_with_cmdb(self): + use_cmdb = True + tags = "engine_iac_k8s" + + self.vulnerability_management.scan_type = "CHECKOV" + self.vulnerability_management.input_core = MagicMock() + self.vulnerability_management.input_core.path_file_results = "file_path" + self.vulnerability_management.input_core.scope_pipeline = "engagement_name" + self.vulnerability_management.source_code_management_uri = "source_code_uri" + self.vulnerability_management.version = "1.0" + self.vulnerability_management.build_id = "build_id" + self.vulnerability_management.branch_tag = "trunk" + self.vulnerability_management.commit_hash = "commit_hash" + self.vulnerability_management.environment = "dev" + + self.vulnerability_management.config_tool = { + "VULNERABILITY_MANAGER": { + "BRANCH_FILTER": "trunk,master,release,develop", + "DEFECT_DOJO": { + "HOST_DEFECT_DOJO": "host_defect_dojo", + "MAX_RETRIES_QUERY": 5, + "CMDB": { + "USE_CMDB": True, + "HOST_CMDB": "cmdb_host", + "REGEX_EXPRESSION_CMDB": "regex", + "CMDB_MAPPING_PATH": "mapping_path", + "CMDB_MAPPING": { + "PRODUCT_TYPE_NAME": "nombreevc", + "PRODUCT_NAME": "nombreapp", + "TAG_PRODUCT": "nombreentorno", + "PRODUCT_DESCRIPTION": "arearesponsableti", + "CODIGO_APP": "CodigoApp" + }, + "CMDB_REQUEST_RESPONSE": { + "HEADERS": { + "Content-Type": "application/json", + "tokenkey": "tokenvalue" + }, + "METHOD": "POST", + "BODY": { + "codapp": "codappvalue" + }, + "RESPONSE": [0] + } + } + } + } + } + self.vulnerability_management.base_compact_remote_config_url = "http://example.com/" + self.vulnerability_management.access_token = "access_token" + + self.token_cmdb = "token_cmdb" + self.token_dd = "token_dd" + + self.scan_type_mapping = { + "CHECKOV": "Checkov Scan" + } + self.enviroment_mapping = { + "dev": "Development", + "qa": "Staging", + "pdn": "Production", + "default": "Production", + } + + with patch( + "devsecops_engine_tools.engine_core.src.infrastructure.driven_adapters.defect_dojo.defect_dojo.Connect.cmdb" + ) as mock_cmdb: + mock_cmdb.return_value = "cmdb_request_result" + + result = self.defect_dojo.build_request( + vulnerability_management=self.vulnerability_management, + token_cmdb=self.token_cmdb, + token_dd=self.token_dd, + scan_type_mapping=self.scan_type_mapping, + enviroment_mapping=self.enviroment_mapping, + tags=tags, + use_cmdb=use_cmdb, + ) + + mock_cmdb.assert_called_once_with( + cmdb_mapping={ + "product_type_name": "nombreevc", + "product_name": "nombreapp", + "tag_product": "nombreentorno", + "product_description": "arearesponsableti", + "codigo_app": "CodigoApp", + }, + compact_remote_config_url="http://example.com/mapping_path", + personal_access_token="access_token", + token_cmdb=self.token_cmdb, + host_cmdb="cmdb_host", + cmdb_request_response={ + "HEADERS": { + "Content-Type": "application/json", + "tokenkey": "tokenvalue" + }, + "METHOD": "POST", + "BODY": { + "codapp": "codappvalue" + }, + "RESPONSE": [0] + }, + scan_type="Checkov Scan", + file="file_path", + engagement_name="engagement_name", + source_code_management_uri="source_code_uri", + tags=tags, + version="1.0", + build_id="build_id", + branch_tag="trunk", + commit_hash="commit_hash", + service="engagement_name", + environment="Development", + token_defect_dojo=self.token_dd, + host_defect_dojo="host_defect_dojo", + expression="regex", + ) + self.assertEqual(result, "cmdb_request_result") + + def test_build_request_without_cmdb(self): + use_cmdb = False + tags = "engine_iac_k8s" + + self.vulnerability_management.scan_type = "CHECKOV" + self.vulnerability_management.input_core = MagicMock() + self.vulnerability_management.input_core.path_file_results = "file_path" + self.vulnerability_management.input_core.scope_pipeline = "engagement_name" + self.vulnerability_management.source_code_management_uri = "source_code_uri" + self.vulnerability_management.version = "1.0" + self.vulnerability_management.build_id = "build_id" + self.vulnerability_management.branch_tag = "trunk" + self.vulnerability_management.commit_hash = "commit_hash" + self.vulnerability_management.environment = "dev" + self.vulnerability_management.vm_product_type_name = "ProductType" + self.vulnerability_management.vm_product_name = "ProductName" + self.vulnerability_management.vm_product_description = "ProductDescription" + + self.vulnerability_management.config_tool = { + "VULNERABILITY_MANAGER": { + "BRANCH_FILTER": "trunk,master,release,develop", + "DEFECT_DOJO": { + "HOST_DEFECT_DOJO": "host_defect_dojo", + "MAX_RETRIES_QUERY": 5, + "CMDB": { + "USE_CMDB": True, + "REGEX_EXPRESSION_CMDB": "regex" + } + } + } + } + self.vulnerability_management.base_compact_remote_config_url = "http://example.com/" + self.vulnerability_management.access_token = "access_token" + + self.token_cmdb = "token_cmdb" + self.token_dd = "token_dd" + + self.scan_type_mapping = { + "CHECKOV": "Checkov Scan" + } + self.enviroment_mapping = { + "dev": "Development", + "qa": "Staging", + "pdn": "Production", + "default": "Production", + } + + with patch( + "devsecops_engine_tools.engine_core.src.infrastructure.driven_adapters.defect_dojo.defect_dojo.ImportScanSerializer" + ) as mock_serializer: + mock_serializer().load.return_value = "import_scan_request_result" + + result = self.defect_dojo.build_request( + vulnerability_management=self.vulnerability_management, + token_cmdb=self.token_cmdb, + token_dd=self.token_dd, + scan_type_mapping=self.scan_type_mapping, + enviroment_mapping=self.enviroment_mapping, + tags=tags, + use_cmdb=use_cmdb, + ) + + mock_serializer().load.assert_called_once_with( + { + "product_type_name": "ProductType", + "product_name": "ProductName", + "product_description": "ProductDescription", + "code_app": "ProductName", + "scan_type": "Checkov Scan", + "file": "file_path", + "engagement_name": "engagement_name", + "source_code_management_uri": "source_code_uri", + "tags": tags, + "version": "1.0", + "build_id": "build_id", + "branch_tag": "trunk", + "commit_hash": "commit_hash", + "service": "engagement_name", + "environment": "Development", + "token_defect_dojo": self.token_dd, + "host_defect_dojo": "host_defect_dojo", + "expression": "regex", + } + ) + self.assertEqual(result, "import_scan_request_result") + @patch( "devsecops_engine_tools.engine_core.src.infrastructure.driven_adapters.defect_dojo.defect_dojo.SessionManager" ) @@ -165,7 +374,9 @@ def test_get_product_type_service( "HOST_DEFECT_DOJO": "host_defect_dojo", "LIMITS_QUERY": 80, "MAX_RETRIES_QUERY": 5, - "REGEX_EXPRESSION_CMDB": "regex", + "CMDB": { + "REGEX_EXPRESSION_CMDB": "regex" + } } } } diff --git a/tools/devsecops_engine_tools/engine_utilities/azuredevops/models/AzurePredefinedVariables.py b/tools/devsecops_engine_tools/engine_utilities/azuredevops/models/AzurePredefinedVariables.py index 5248a4cfe..92d3db89c 100644 --- a/tools/devsecops_engine_tools/engine_utilities/azuredevops/models/AzurePredefinedVariables.py +++ b/tools/devsecops_engine_tools/engine_utilities/azuredevops/models/AzurePredefinedVariables.py @@ -63,3 +63,8 @@ class AgentVariables(BaseEnum): Agent_WorkFolder = "Agent.WorkFolder" Agent_TempDirectory = "Agent.TempDirectory" Agent_OS = "Agent.OS" + +class VMVariables(BaseEnum): + Vm_Product_Type_Name = "Vm.Product.Type.Name" + Vm_Product_Name = "Vm.Product.Name" + Vm_Product_Description = "Vm.Product.Description" diff --git a/tools/devsecops_engine_tools/engine_utilities/defect_dojo/domain/serializers/import_scan.py b/tools/devsecops_engine_tools/engine_utilities/defect_dojo/domain/serializers/import_scan.py index c516533f5..8a953e1cf 100644 --- a/tools/devsecops_engine_tools/engine_utilities/defect_dojo/domain/serializers/import_scan.py +++ b/tools/devsecops_engine_tools/engine_utilities/defect_dojo/domain/serializers/import_scan.py @@ -198,17 +198,17 @@ class ImportScanSerializer(Schema): service = fields.Str(required=False) group_by = fields.Str(required=False) test_title = fields.Str(required=False) - description_product = fields.Str(required=False) + product_description = fields.Str(required=False) create_finding_groups_for_all_findings = fields.Str(required=False) tools_configuration = fields.Int(required=False, load_default=1) code_app = fields.Str(required=False) # defect-dojo credential - token_cmdb = fields.Str(required=True) - host_cmdb = fields.Url(required=True) - cmdb_request_response = fields.Dict(required=True) + token_cmdb = fields.Str(required=False) + host_cmdb = fields.Url(required=False) + cmdb_request_response = fields.Dict(required=False) token_defect_dojo = fields.Str(required=True) host_defect_dojo = fields.Str(required=True) - cmdb_mapping = fields.Dict(required=True) + cmdb_mapping = fields.Dict(required=False) product_type_name_mapping = fields.Dict(required=False) # Config remote credential compact_remote_config_url = fields.Str(required=False) diff --git a/tools/devsecops_engine_tools/engine_utilities/defect_dojo/infraestructure/driver_adapters/cmdb.py b/tools/devsecops_engine_tools/engine_utilities/defect_dojo/infraestructure/driver_adapters/cmdb.py index 77f94cac3..1892d6dea 100644 --- a/tools/devsecops_engine_tools/engine_utilities/defect_dojo/infraestructure/driver_adapters/cmdb.py +++ b/tools/devsecops_engine_tools/engine_utilities/defect_dojo/infraestructure/driver_adapters/cmdb.py @@ -84,8 +84,12 @@ def get_nested_data(self, response, keys: list) -> dict: for key in keys: if isinstance(data, dict) and key in data: data = data[key] - elif isinstance(data, list) and isinstance(key, int) and 0 <= key < len(data): - data = data[key] + elif isinstance(data, list) and isinstance(key, int): + key = key if key >=0 else len(data) + key + if 0 <= key < len(data): + data = data[key] + else: + raise KeyError(f"Index '{key}' out of range in the current context.") else: raise KeyError(f"Key '{key}' not found or invalid in the current context.") return data diff --git a/tools/devsecops_engine_tools/engine_utilities/github/models/GithubPredefinedVariables.py b/tools/devsecops_engine_tools/engine_utilities/github/models/GithubPredefinedVariables.py index f74d991b3..720afa642 100644 --- a/tools/devsecops_engine_tools/engine_utilities/github/models/GithubPredefinedVariables.py +++ b/tools/devsecops_engine_tools/engine_utilities/github/models/GithubPredefinedVariables.py @@ -54,3 +54,9 @@ class AgentVariables(BaseEnum): github_workspace = "github.workspace" runner_os = "runner.os" runner_tool_cache = "runner.tool.cache" + + +class VMVariables(BaseEnum): + Vm_Product_Type_Name = "Vm.Product.Type.Name" + Vm_Product_Name = "Vm.Product.Name" + Vm_Product_Description = "Vm.Product.Description" diff --git a/tools/devsecops_engine_tools/engine_utilities/sonarqube/src/domain/usecases/report_sonar.py b/tools/devsecops_engine_tools/engine_utilities/sonarqube/src/domain/usecases/report_sonar.py index 0e36ae4bc..d7e245ea7 100644 --- a/tools/devsecops_engine_tools/engine_utilities/sonarqube/src/domain/usecases/report_sonar.py +++ b/tools/devsecops_engine_tools/engine_utilities/sonarqube/src/domain/usecases/report_sonar.py @@ -99,7 +99,10 @@ def process(self, args): build_id = self.devops_platform_gateway.get_variable("build_id"), branch_tag = branch, commit_hash = self.devops_platform_gateway.get_variable("commit_hash"), - environment = environment + environment = environment, + vm_product_type_name = self.devops_platform_gateway.get_variable("vm_product_type_name"), + vm_product_name = self.devops_platform_gateway.get_variable("vm_product_name"), + vm_product_description = self.devops_platform_gateway.get_variable("vm_product_description"), ) for project_key in project_keys: diff --git a/tools/devsecops_engine_tools/engine_utilities/sonarqube/test/domain/usecases/test_report_sonar.py b/tools/devsecops_engine_tools/engine_utilities/sonarqube/test/domain/usecases/test_report_sonar.py index 3e3a9e4e1..f17e6388a 100644 --- a/tools/devsecops_engine_tools/engine_utilities/sonarqube/test/domain/usecases/test_report_sonar.py +++ b/tools/devsecops_engine_tools/engine_utilities/sonarqube/test/domain/usecases/test_report_sonar.py @@ -28,7 +28,9 @@ def test_process_valid( "build_execution_id", "build_id", "commit_hash", - "repository_provider" + "repository_provider", + "vm_product_type_name", + "vm_product_name" ] mock_set_repository.return_value = "repository_uri" mock_define_env.return_value = "dev" diff --git a/tools/devsecops_engine_tools/engine_utilities/test/azuredevops/models/test_AzurePredefinedVariables.py b/tools/devsecops_engine_tools/engine_utilities/test/azuredevops/models/test_AzurePredefinedVariables.py index 251e401b3..18b466057 100644 --- a/tools/devsecops_engine_tools/engine_utilities/test/azuredevops/models/test_AzurePredefinedVariables.py +++ b/tools/devsecops_engine_tools/engine_utilities/test/azuredevops/models/test_AzurePredefinedVariables.py @@ -5,6 +5,7 @@ BuildVariables, ReleaseVariables, AgentVariables, + VMVariables ) @@ -24,6 +25,9 @@ (ReleaseVariables.Artifact_Path, "ARTIFACT_PATH", "ArtifactPathValue"), (AgentVariables.Agent_WorkFolder, "AGENT_WORKFOLDER", "AgentWorkFolder"), (AgentVariables.Agent_BuildDirectory, "AGENT_BUILDDIRECTORY", "AgentBuildDirectory"), + (VMVariables.Vm_Product_Type_Name, "VM_PRODUCT_TYPE_NAME", "ProductTypeName"), + (VMVariables.Vm_Product_Name, "VM_PRODUCT_NAME", "ProductName"), + (VMVariables.Vm_Product_Description, "VM_PRODUCT_DESCRIPTION", "ProductDescription"), ], ) def test_enum_env_name(monkeypatch, enum_class, expected_env_name, expected_value):