From 30b2d49bb51ae9b14f50af2c7b316b1c028c24d4 Mon Sep 17 00:00:00 2001 From: Felix Hernandez Date: Fri, 5 Jan 2024 14:47:32 -0600 Subject: [PATCH] Add a "tag findings" parameter to the import-scan and reimport-scan API endpoints (#8707) * Set Development default environment (new import) * fix flake8 issue * Trivy parser includes causeMetadata in findings description * Fix System Settings Required Fields Jira * remove print * flake code * merge * merge * Add apply tags to findings to importer and reimporter functions * fix changes * Addedd to import scan and reimport scan functions the apply tags parameter * fix validations * remove default true in importscan serializer * fix error in testing tags * added apply tag to findings parameter to UI * removed unnecessary lines --------- Co-authored-by: Felix Hernandez --- dojo/api_v2/serializers.py | 12 ++++++++++++ dojo/engagement/views.py | 3 ++- dojo/forms.py | 12 ++++++++++++ dojo/importers/importer/importer.py | 6 +++++- dojo/importers/reimporter/reimporter.py | 8 ++++++-- 5 files changed, 37 insertions(+), 4 deletions(-) diff --git a/dojo/api_v2/serializers.py b/dojo/api_v2/serializers.py index e1c2a2dafe..a7e317210f 100644 --- a/dojo/api_v2/serializers.py +++ b/dojo/api_v2/serializers.py @@ -2131,6 +2131,10 @@ class ImportScanSerializer(serializers.Serializer): product_type_id = serializers.IntegerField(read_only=True) statistics = ImportStatisticsSerializer(read_only=True, required=False) + apply_tags_to_findings = serializers.BooleanField( + help_text="If set to True, the tags will be applied to the findings", + required=False, + ) def save(self, push_to_jira=False): data = self.validated_data @@ -2149,6 +2153,7 @@ def save(self, push_to_jira=False): commit_hash = data.get("commit_hash", None) api_scan_configuration = data.get("api_scan_configuration", None) service = data.get("service", None) + apply_tags_to_findings = data.get("apply_tags_to_findings", False) source_code_management_uri = data.get( "source_code_management_uri", None ) @@ -2241,6 +2246,7 @@ def save(self, push_to_jira=False): service=service, title=test_title, create_finding_groups_for_all_findings=create_finding_groups_for_all_findings, + apply_tags_to_findings=apply_tags_to_findings, ) if test: @@ -2409,6 +2415,10 @@ class ReImportScanSerializer(TaggitSerializer, serializers.Serializer): product_type_id = serializers.IntegerField(read_only=True) statistics = ImportStatisticsSerializer(read_only=True, required=False) + apply_tags_to_findings = serializers.BooleanField( + help_text="If set to True, the tags will be applied to the findings", + required=False + ) def save(self, push_to_jira=False): logger.debug("push_to_jira: %s", push_to_jira) @@ -2421,6 +2431,7 @@ def save(self, push_to_jira=False): close_old_findings_product_scope = data.get( "close_old_findings_product_scope" ) + apply_tags_to_findings = data.get("apply_tags_to_findings", False) do_not_reactivate = data.get("do_not_reactivate", False) version = data.get("version", None) build_id = data.get("build_id", None) @@ -2521,6 +2532,7 @@ def save(self, push_to_jira=False): service=service, do_not_reactivate=do_not_reactivate, create_finding_groups_for_all_findings=create_finding_groups_for_all_findings, + apply_tags_to_findings=apply_tags_to_findings, ) if test_import: diff --git a/dojo/engagement/views.py b/dojo/engagement/views.py index 635248f0f2..45b45833e0 100644 --- a/dojo/engagement/views.py +++ b/dojo/engagement/views.py @@ -670,6 +670,7 @@ def post(self, request, eid=None, pid=None): api_scan_configuration = form.cleaned_data.get('api_scan_configuration', None) service = form.cleaned_data.get('service', None) close_old_findings = form.cleaned_data.get('close_old_findings', None) + apply_tags_to_findings = form.cleaned_data.get('apply_tags_to_findings', False) # close_old_findings_prodct_scope is a modifier of close_old_findings. # If it is selected, close_old_findings should also be selected. close_old_findings_product_scope = form.cleaned_data.get('close_old_findings_product_scope', None) @@ -736,7 +737,7 @@ def post(self, request, eid=None, pid=None): minimum_severity=minimum_severity, endpoints_to_add=list(form.cleaned_data['endpoints']) + added_endpoints, scan_date=scan_date, version=version, branch_tag=branch_tag, build_id=build_id, commit_hash=commit_hash, push_to_jira=push_to_jira, close_old_findings=close_old_findings, close_old_findings_product_scope=close_old_findings_product_scope, group_by=group_by, api_scan_configuration=api_scan_configuration, service=service, - create_finding_groups_for_all_findings=create_finding_groups_for_all_findings) + create_finding_groups_for_all_findings=create_finding_groups_for_all_findings, apply_tags_to_findings=apply_tags_to_findings) message = f'{scan_type} processed a total of {finding_count} findings' diff --git a/dojo/forms.py b/dojo/forms.py index 94c1e6ee9d..508c24df4a 100755 --- a/dojo/forms.py +++ b/dojo/forms.py @@ -471,6 +471,12 @@ class ImportScanForm(forms.Form): label="Close old findings within this product", required=False, initial=False) + apply_tags_to_findings = forms.BooleanField( + help_text="If set to True, the tags will be applied to the findings", + label="Apply Tags to Findings", + required=False, + initial=False + ) if is_finding_groups_enabled(): group_by = forms.ChoiceField(required=False, choices=Finding_Group.GROUP_BY_OPTIONS, help_text='Choose an option to automatically group new findings by the chosen option.') @@ -557,6 +563,12 @@ class ReImportScanForm(forms.Form): api_scan_configuration = forms.ModelChoiceField(Product_API_Scan_Configuration.objects, required=False, label='API Scan Configuration') service = forms.CharField(max_length=200, required=False, help_text="A service is a self-contained piece of functionality within a Product. This is an optional field which is used in deduplication of findings when set.") source_code_management_uri = forms.URLField(max_length=600, required=False, help_text="Resource link to source code") + apply_tags_to_findings = forms.BooleanField( + help_text="If set to True, the tags will be applied to the findings", + label="Apply Tags to Findings", + required=False, + initial=False + ) if is_finding_groups_enabled(): group_by = forms.ChoiceField(required=False, choices=Finding_Group.GROUP_BY_OPTIONS, help_text='Choose an option to automatically group new findings by the chosen option') diff --git a/dojo/importers/importer/importer.py b/dojo/importers/importer/importer.py index e9508d5ec1..baed2c8d42 100644 --- a/dojo/importers/importer/importer.py +++ b/dojo/importers/importer/importer.py @@ -244,7 +244,7 @@ def close_old_findings(self, test, scan_date_time, user, push_to_jira=None, serv def import_scan(self, scan, scan_type, engagement, lead, environment, active=None, verified=None, tags=None, minimum_severity=None, user=None, endpoints_to_add=None, scan_date=None, version=None, branch_tag=None, build_id=None, commit_hash=None, push_to_jira=None, close_old_findings=False, close_old_findings_product_scope=False, - group_by=None, api_scan_configuration=None, service=None, title=None, create_finding_groups_for_all_findings=True): + group_by=None, api_scan_configuration=None, service=None, title=None, create_finding_groups_for_all_findings=True, apply_tags_to_findings=False): logger.debug(f'IMPORT_SCAN: parameters: {locals()}') @@ -363,6 +363,10 @@ def import_scan(self, scan, scan_type, engagement, lead, environment, active=Non test_import = importer_utils.update_import_history(Test_Import.IMPORT_TYPE, active, verified, tags, minimum_severity, endpoints_to_add, version, branch_tag, build_id, commit_hash, push_to_jira, close_old_findings, test, new_findings, closed_findings) + if apply_tags_to_findings and tags: + for finding in test_import.findings_affected.all(): + for tag in tags: + finding.tags.add(tag) logger.debug('IMPORT_SCAN: Generating notifications') notifications_helper.notify_test_created(test) diff --git a/dojo/importers/reimporter/reimporter.py b/dojo/importers/reimporter/reimporter.py index a31d3673c7..39db0d7e3e 100644 --- a/dojo/importers/reimporter/reimporter.py +++ b/dojo/importers/reimporter/reimporter.py @@ -42,6 +42,7 @@ def process_parsed_findings( scan_date=None, do_not_reactivate=False, create_finding_groups_for_all_findings=True, + apply_tags_to_findings=False, **kwargs, ): @@ -111,7 +112,6 @@ def process_parsed_findings( findings = reimporter_utils.match_new_finding_to_existing_finding( item, test, deduplication_algorithm ) - deduplicationLogger.debug( "found %i findings matching with current new finding", len(findings) ) @@ -571,6 +571,7 @@ def reimport_scan( service=None, do_not_reactivate=False, create_finding_groups_for_all_findings=True, + apply_tags_to_findings=False, ): logger.debug(f"REIMPORT_SCAN: parameters: {locals()}") @@ -741,7 +742,10 @@ def reimport_scan( reactivated_findings, untouched_findings, ) - + if apply_tags_to_findings and tags: + for finding in test_import.findings_affected.all(): + for tag in tags: + finding.tags.add(tag) logger.debug("REIMPORT_SCAN: Generating notifications") updated_count = (