|
5 | 5 | from django.core.exceptions import ValidationError |
6 | 6 | from django.core.files.base import ContentFile |
7 | 7 | from django.core.files.uploadedfile import TemporaryUploadedFile |
| 8 | +from django.db import IntegrityError |
8 | 9 | from django.urls import reverse |
9 | 10 | from django.utils.timezone import make_aware |
10 | 11 |
|
@@ -262,6 +263,13 @@ def determine_process_method( |
262 | 263 | **kwargs, |
263 | 264 | ) |
264 | 265 |
|
| 266 | + def determine_deduplication_algorithm(self) -> str: |
| 267 | + """ |
| 268 | + Determines what dedupe algorithm to use for the Test being processed. |
| 269 | + :return: A string representing the dedupe algorithm to use. |
| 270 | + """ |
| 271 | + return self.test.deduplication_algorithm |
| 272 | + |
265 | 273 | def update_test_meta(self): |
266 | 274 | """ |
267 | 275 | Update the test with some values stored in the kwargs dict. The common |
@@ -357,53 +365,80 @@ def update_import_history( |
357 | 365 | commit_hash=self.commit_hash, |
358 | 366 | type=self.import_type, |
359 | 367 | ) |
360 | | - # Define all of the respective import finding actions for the test import object |
361 | | - test_import_finding_action_list = [] |
| 368 | + |
| 369 | + # Create a history record for each finding |
362 | 370 | for finding in closed_findings: |
363 | | - logger.debug(f"preparing Test_Import_Finding_Action for closed finding: {finding.id}") |
364 | | - test_import_finding_action_list.append(Test_Import_Finding_Action( |
| 371 | + self.create_import_history_record_safe(Test_Import_Finding_Action( |
365 | 372 | test_import=test_import, |
366 | 373 | finding=finding, |
367 | 374 | action=IMPORT_CLOSED_FINDING, |
368 | 375 | )) |
369 | 376 | for finding in new_findings: |
370 | | - logger.debug(f"preparing Test_Import_Finding_Action for created finding: {finding.id}") |
371 | | - test_import_finding_action_list.append(Test_Import_Finding_Action( |
| 377 | + self.create_import_history_record_safe(Test_Import_Finding_Action( |
372 | 378 | test_import=test_import, |
373 | 379 | finding=finding, |
374 | 380 | action=IMPORT_CREATED_FINDING, |
375 | 381 | )) |
376 | 382 | for finding in reactivated_findings: |
377 | | - logger.debug(f"preparing Test_Import_Finding_Action for reactivated finding: {finding.id}") |
378 | | - test_import_finding_action_list.append(Test_Import_Finding_Action( |
| 383 | + self.create_import_history_record_safe(Test_Import_Finding_Action( |
379 | 384 | test_import=test_import, |
380 | 385 | finding=finding, |
381 | 386 | action=IMPORT_REACTIVATED_FINDING, |
382 | 387 | )) |
383 | 388 | for finding in untouched_findings: |
384 | | - logger.debug(f"preparing Test_Import_Finding_Action for untouched finding: {finding.id}") |
385 | | - test_import_finding_action_list.append(Test_Import_Finding_Action( |
| 389 | + self.create_import_history_record_safe(Test_Import_Finding_Action( |
386 | 390 | test_import=test_import, |
387 | 391 | finding=finding, |
388 | 392 | action=IMPORT_UNTOUCHED_FINDING, |
389 | 393 | )) |
390 | | - # Bulk create all the defined objects |
391 | | - Test_Import_Finding_Action.objects.bulk_create(test_import_finding_action_list) |
392 | 394 |
|
393 | 395 | # Add any tags to the findings imported if necessary |
394 | 396 | if self.apply_tags_to_findings and self.tags: |
395 | 397 | for finding in test_import.findings_affected.all(): |
396 | 398 | for tag in self.tags: |
397 | | - finding.tags.add(tag) |
| 399 | + self.add_tags_safe(finding, tag) |
398 | 400 | # Add any tags to any endpoints of the findings imported if necessary |
399 | 401 | if self.apply_tags_to_endpoints and self.tags: |
400 | 402 | for finding in test_import.findings_affected.all(): |
401 | 403 | for endpoint in finding.endpoints.all(): |
402 | 404 | for tag in self.tags: |
403 | | - endpoint.tags.add(tag) |
| 405 | + self.add_tags_safe(endpoint, tag) |
404 | 406 |
|
405 | 407 | return test_import |
406 | 408 |
|
| 409 | + def create_import_history_record_safe( |
| 410 | + self, |
| 411 | + test_import_finding_action, |
| 412 | + ): |
| 413 | + """Creates an import history record, while catching any IntegrityErrors that might happen because of the background job having deleted a finding""" |
| 414 | + logger.debug(f"creating Test_Import_Finding_Action for finding: {test_import_finding_action.finding.id} action: {test_import_finding_action.action}") |
| 415 | + try: |
| 416 | + test_import_finding_action.save() |
| 417 | + except IntegrityError as e: |
| 418 | + # This try catch makes us look we don't know what we're doing, but in https://github.com/DefectDojo/django-DefectDojo/issues/6217 we decided that for now this is the best solution |
| 419 | + logger.warning("Error creating Test_Import_Finding_Action: %s", e) |
| 420 | + logger.debug("Error creating Test_Import_Finding_Action, finding marked as duplicate and deleted ?") |
| 421 | + |
| 422 | + def add_tags_safe( |
| 423 | + self, |
| 424 | + finding_or_endpoint, |
| 425 | + tag, |
| 426 | + ): |
| 427 | + """Adds tags to a finding or endpoint, while catching any IntegrityErrors that might happen because of the background job having deleted a finding""" |
| 428 | + if not isinstance(finding_or_endpoint, Finding) and not isinstance(finding_or_endpoint, Endpoint): |
| 429 | + msg = "finding_or_endpoint must be a Finding or Endpoint object" |
| 430 | + raise TypeError(msg) |
| 431 | + |
| 432 | + msg = "finding" if isinstance(finding_or_endpoint, Finding) else "endpoint" if isinstance(finding_or_endpoint, Endpoint) else "unknown" |
| 433 | + logger.debug(f" adding tag: {tag} to " + msg + f"{finding_or_endpoint.id}") |
| 434 | + |
| 435 | + try: |
| 436 | + finding_or_endpoint.tags.add(tag) |
| 437 | + except IntegrityError as e: |
| 438 | + # This try catch makes us look we don't know what we're doing, but in https://github.com/DefectDojo/django-DefectDojo/issues/6217 we decided that for now this is the best solution |
| 439 | + logger.warning("Error adding tag: %s", e) |
| 440 | + logger.debug("Error adding tag, finding marked as duplicate and deleted ?") |
| 441 | + |
407 | 442 | def construct_imported_message( |
408 | 443 | self, |
409 | 444 | finding_count: int = 0, |
|
0 commit comments