From 6ecaff990e8dd79318fdbcbb0d3a6828ee1306a2 Mon Sep 17 00:00:00 2001 From: DefectDojo release bot Date: Mon, 12 Feb 2024 20:12:55 +0000 Subject: [PATCH 01/10] Update versions in application files --- components/package.json | 2 +- dojo/__init__.py | 2 +- helm/defectdojo/Chart.yaml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/package.json b/components/package.json index 4c9fc573d8..9a57f7b78d 100644 --- a/components/package.json +++ b/components/package.json @@ -1,6 +1,6 @@ { "name": "defectdojo", - "version": "2.31.1", + "version": "2.32.0-dev", "license" : "BSD-3-Clause", "private": true, "dependencies": { diff --git a/dojo/__init__.py b/dojo/__init__.py index 174901e835..f1c39c15ed 100644 --- a/dojo/__init__.py +++ b/dojo/__init__.py @@ -4,6 +4,6 @@ # Django starts so that shared_task will use this app. from .celery import app as celery_app # noqa -__version__ = '2.31.1' +__version__ = '2.32.0-dev' __url__ = 'https://github.com/DefectDojo/django-DefectDojo' __docs__ = 'https://documentation.defectdojo.com' diff --git a/helm/defectdojo/Chart.yaml b/helm/defectdojo/Chart.yaml index 0af7d7c32b..60c20292d0 100644 --- a/helm/defectdojo/Chart.yaml +++ b/helm/defectdojo/Chart.yaml @@ -1,8 +1,8 @@ apiVersion: v2 -appVersion: "2.31.1" +appVersion: "2.32.0-dev" description: A Helm chart for Kubernetes to install DefectDojo name: defectdojo -version: 1.6.109 +version: 1.6.110-dev icon: https://www.defectdojo.org/img/favicon.ico maintainers: - name: madchap From d91eab739b1e600ccaeba183d1a64763a1ef63da Mon Sep 17 00:00:00 2001 From: Felix Hernandez Date: Tue, 13 Feb 2024 14:00:18 -0600 Subject: [PATCH 02/10] Fix "Overdue" tag still visible with closed issues (#9539) --- dojo/templates/dojo/engagement.html | 2 +- dojo/templates/dojo/engagements_all.html | 2 +- dojo/templates/dojo/snippets/engagement_list.html | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/dojo/templates/dojo/engagement.html b/dojo/templates/dojo/engagement.html index dc8d2d4416..051dc80485 100644 --- a/dojo/templates/dojo/engagement.html +++ b/dojo/templates/dojo/engagement.html @@ -151,7 +151,7 @@

{{ e.target_start }} - {{ e.target_end }} - {% if e.is_overdue %} + {% if e.is_overdue and e.status != 'Completed' %} {{ e.target_end|overdue }} overdue diff --git a/dojo/templates/dojo/engagements_all.html b/dojo/templates/dojo/engagements_all.html index 5f44ec6da7..80ae6c3092 100644 --- a/dojo/templates/dojo/engagements_all.html +++ b/dojo/templates/dojo/engagements_all.html @@ -141,7 +141,7 @@

{% endif %} {{ e.status }} {{ e.target_start }} - {{ e.target_end }} - {% if e.is_overdue and e.active %} + {% if e.is_overdue and e.active and e.status != 'Completed' %}
{{ e.target_end|overdue }} overdue
{% endif %} diff --git a/dojo/templates/dojo/snippets/engagement_list.html b/dojo/templates/dojo/snippets/engagement_list.html index 514aa7ee33..c502e142c6 100644 --- a/dojo/templates/dojo/snippets/engagement_list.html +++ b/dojo/templates/dojo/snippets/engagement_list.html @@ -179,7 +179,7 @@

{% if status == "open" %}Active{% elif status == "paused" %}Paused {% else {{ eng.target_start|datediff_time:eng.target_end }} {% if status == "open" %} - {% if eng.is_overdue %} + {% if eng.is_overdue and eng.status != 'Completed' %}
{{ eng.target_end|overdue }} overdue From 32485668bf38c27a5ff7399ea5cf07a9e518e24d Mon Sep 17 00:00:00 2001 From: Paul Osinski <42211303+paulOsinski@users.noreply.github.com> Date: Thu, 15 Feb 2024 17:38:01 -0500 Subject: [PATCH 03/10] Update google-sheets-sync.md with deprecation notice (#9495) --- docs/content/en/integrations/google-sheets-sync.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/content/en/integrations/google-sheets-sync.md b/docs/content/en/integrations/google-sheets-sync.md index d2d94746df..b6e97f72f8 100644 --- a/docs/content/en/integrations/google-sheets-sync.md +++ b/docs/content/en/integrations/google-sheets-sync.md @@ -5,6 +5,7 @@ draft: false weight: 7 --- +**Please note - the Google Sheets feature has been deprecated as of DefectDojo version 2.21.0 - these documents are for reference only.** With the Google Sheets sync feature, DefectDojo allow the users to export all the finding details of each test into a separate Google @@ -112,4 +113,4 @@ If a Google Spreadsheet is already created for the Test: After creating a Google Spreadsheet, users can review and edit Finding details using the Google Sheet. If any change is done in the Google Sheet users can click the **Sync Google Sheet** button to get those -changes into DefectDojo. \ No newline at end of file +changes into DefectDojo. From a87f362e9ee69bdce89b7176872f06eaa27c6efa Mon Sep 17 00:00:00 2001 From: kiblik Date: Tue, 20 Feb 2024 18:37:18 +0000 Subject: [PATCH 04/10] Fix handling of incorrect if test import fail (#9544) --- dojo/engagement/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dojo/engagement/views.py b/dojo/engagement/views.py index 20804e1fb0..5ba45ecc49 100644 --- a/dojo/engagement/views.py +++ b/dojo/engagement/views.py @@ -768,7 +768,7 @@ def post(self, request, eid=None, pid=None): return HttpResponseRedirect( reverse('view_test', args=(test.id, ))) - return HttpResponseRedirect(reverse('view_test', args=(test.id, ))) + return HttpResponseRedirect(reverse('import_scan_results', args=(engagement.id, ))) @user_is_authorized(Engagement, Permissions.Engagement_Edit, 'eid') From 8180eaddf7d261cb2df5209a622c0413b0de41a0 Mon Sep 17 00:00:00 2001 From: kiblik Date: Tue, 20 Feb 2024 18:44:20 +0000 Subject: [PATCH 05/10] Labeler: Add sync-labels (#9565) --- .github/workflows/pr-labeler.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/pr-labeler.yml b/.github/workflows/pr-labeler.yml index 1fbc777bd8..34a31a0cab 100644 --- a/.github/workflows/pr-labeler.yml +++ b/.github/workflows/pr-labeler.yml @@ -18,3 +18,4 @@ jobs: - uses: actions/labeler@v5 with: repo-token: "${{ secrets.GITHUB_TOKEN }}" + sync-labels: true From f857e9ff15ed279372fe01ca9f820ea57ac6c5a0 Mon Sep 17 00:00:00 2001 From: Cody Maffucci <46459665+Maffooch@users.noreply.github.com> Date: Tue, 20 Feb 2024 12:59:23 -0600 Subject: [PATCH 06/10] Questionnaires: Correct nested object deletions (#9574) * Questionnaires: Correct nested object deletions * Fix Flake8 --- dojo/models.py | 10 +++++++++- dojo/survey/views.py | 21 ++++++++++++--------- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/dojo/models.py b/dojo/models.py index 45d522963e..174e189a14 100755 --- a/dojo/models.py +++ b/dojo/models.py @@ -27,6 +27,7 @@ from django.utils.html import escape from pytz import all_timezones from polymorphic.models import PolymorphicModel +from polymorphic.managers import PolymorphicManager from multiselectfield import MultiSelectField from django import forms from django.utils.translation import gettext as _ @@ -4355,6 +4356,8 @@ class Meta: help_text=_("If selected, user doesn't have to answer this question")) text = models.TextField(blank=False, help_text=_('The question text'), default='') + objects = models.Manager() + polymorphic = PolymorphicManager() def __str__(self): return self.text @@ -4364,6 +4367,7 @@ class TextQuestion(Question): ''' Question with a text answer ''' + objects = PolymorphicManager() def get_form(self): ''' @@ -4397,8 +4401,8 @@ class ChoiceQuestion(Question): multichoice = models.BooleanField(default=False, help_text=_("Select one or more")) - choices = models.ManyToManyField(Choice) + objects = PolymorphicManager() def get_form(self): ''' @@ -4476,6 +4480,8 @@ class Answer(PolymorphicModel, TimeStampedModel): null=False, blank=False, on_delete=models.CASCADE) + objects = models.Manager() + polymorphic = PolymorphicManager() class TextAnswer(Answer): @@ -4483,6 +4489,7 @@ class TextAnswer(Answer): blank=False, help_text=_('The answer text'), default='') + objects = PolymorphicManager() def __str__(self): return self.answer @@ -4492,6 +4499,7 @@ class ChoiceAnswer(Answer): answer = models.ManyToManyField( Choice, help_text=_('The selected choices as the answer')) + objects = PolymorphicManager() def __str__(self): if len(self.answer.all()): diff --git a/dojo/survey/views.py b/dojo/survey/views.py index f3043b1b75..02fc9f74d5 100644 --- a/dojo/survey/views.py +++ b/dojo/survey/views.py @@ -36,9 +36,9 @@ def delete_engagement_survey(request, eid, sid): if request.method == 'POST': form = Delete_Questionnaire_Form(request.POST, instance=survey) if form.is_valid(): - answers = Answer.objects.filter( + answers = Answer.polymorphic.filter( question__in=[ - question.id for question in survey.survey.questions.all()], + question.id for question in Question.polymorphic.filter(engagement_survey=survey.survey)], answered_survey=survey) for answer in answers: answer.delete() @@ -95,7 +95,7 @@ def answer_questionnaire(request, eid, sid): prefix=str(q.id), answered_survey=survey, question=q, form_tag=False) - for q in survey.survey.questions.all()] + for q in Question.polymorphic.filter(engagement_survey=survey.survey)] questions_are_valid = [] @@ -184,7 +184,7 @@ def get_answered_questions(survey=None, read_only=False): answered_survey=survey, question=q, form_tag=False) - for q in survey.survey.questions.all()] + for q in Question.polymorphic.filter(engagement_survey=survey.survey)] if read_only: for question in questions: @@ -416,7 +416,7 @@ def questionnaire(request): @user_is_configuration_authorized('dojo.view_question') def questions(request): - questions = Question.objects.all() + questions = Question.polymorphic.all() questions = QuestionFilter(request.GET, queryset=questions) paged_questions = get_page_items(request, questions.qs, 25) add_breadcrumb(title="Questions", top_level=False, request=request) @@ -500,7 +500,10 @@ def create_question(request): @user_is_configuration_authorized('dojo.change_question') def edit_question(request, qid): - question = get_object_or_404(Question, id=qid) + try: + question = Question.polymorphic.get(id=qid) + except Question.DoesNotExist: + return Http404() survey = Engagement_Survey.objects.filter(questions__in=[question]) reverted = False answered = [] @@ -652,7 +655,7 @@ def delete_empty_questionnaire(request, esid): form = Delete_Questionnaire_Form(request.POST, instance=survey) if form.is_valid(): answers = Answer.objects.filter( - question__in=[question.id for question in survey.survey.questions.all()], + question__in=[question.id for question in Question.polymorphic.filter(engagement_survey=survey.survey)], answered_survey=survey) for answer in answers: answer.delete() @@ -740,7 +743,7 @@ def answer_empty_survey(request, esid): engagement_survey=engagement_survey, question=q, form_tag=False) - for q in engagement_survey.questions.all() + for q in Question.polymorphic.filter(engagement_survey=engagement_survey) ] if request.method == 'POST': @@ -753,7 +756,7 @@ def answer_empty_survey(request, esid): answered_survey=survey, question=q, form_tag=False) - for q in survey.survey.questions.all() + for q in Question.polymorphic.filter(engagement_survey=survey.survey) ] questions_are_valid = [] From c817d671ed83694c63ee82707daacacadfa08ae6 Mon Sep 17 00:00:00 2001 From: Cody Maffucci <46459665+Maffooch@users.noreply.github.com> Date: Tue, 20 Feb 2024 12:59:32 -0600 Subject: [PATCH 07/10] Jira: Append labels and respect priority on update (#9571) A couple fields are overwritten by DefectDojo when findings are pushed to an existing jira ticket. This can be destructive for developers in the following ways: - Priority: This field often reflects the timeline a particular issue may be fixed. Developers may have more specific context for why a vulnerability may not be as severe as initially thought. - Labels: Labels could be used to sort issues in a given queue to determine who works on a given ticket. When a finding is pushed to jira again after creation, these new labels should not be overwritten These fields should be respected to avoid stomping on any changes/process set by developers --- dojo/jira_link/helper.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/dojo/jira_link/helper.py b/dojo/jira_link/helper.py index ecd5da084f..5318aa0e3e 100644 --- a/dojo/jira_link/helper.py +++ b/dojo/jira_link/helper.py @@ -863,9 +863,10 @@ def update_jira_issue(obj, *args, **kwargs): summary=jira_summary(obj), description=jira_description(obj), component_name=jira_project.component if not issue.fields.components else None, - labels=labels, + labels=labels + issue.fields.labels, environment=jira_environment(obj), - priority_name=jira_priority(obj), + # Do not update the priority in jira after creation as this could have changed in jira, but should not change in dojo + # priority_name=jira_priority(obj), issuetype_fields=issuetype_fields) logger.debug('sending fields to JIRA: %s', fields) @@ -873,7 +874,8 @@ def update_jira_issue(obj, *args, **kwargs): issue.update( summary=fields['summary'], description=fields['description'], - priority=fields['priority'], + # Do not update the priority in jira after creation as this could have changed in jira, but should not change in dojo + # priority=fields['priority'], fields=fields) push_status_to_jira(obj, jira_instance, jira, issue) From 97b5f18d626ebf9a5dafc0fa7fdf9d20733a0cfe Mon Sep 17 00:00:00 2001 From: Cody Maffucci <46459665+Maffooch@users.noreply.github.com> Date: Tue, 20 Feb 2024 13:00:00 -0600 Subject: [PATCH 08/10] Correct Endpoint "Hosts" views when the host field is `None` (#9560) * Endpoints: Force object validation on save * Prevent str concatenation with None type * Remove forced clean on save --- dojo/endpoint/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dojo/endpoint/views.py b/dojo/endpoint/views.py index ae91d83a42..c2b491eb1a 100644 --- a/dojo/endpoint/views.py +++ b/dojo/endpoint/views.py @@ -92,7 +92,7 @@ def get_endpoint_ids(endpoints): hosts = [] ids = [] for e in endpoints: - key = e.host + '-' + str(e.product.id) + key = f"{e.host}-{e.product.id}" if key in hosts: continue else: From 54aa5652f54c678a6fe328aef933002e7019b75e Mon Sep 17 00:00:00 2001 From: Cody Maffucci <46459665+Maffooch@users.noreply.github.com> Date: Tue, 20 Feb 2024 13:19:13 -0600 Subject: [PATCH 09/10] Deduplication: Do not reopen original finding (#9558) --- dojo/utils.py | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/dojo/utils.py b/dojo/utils.py index 135d341e54..fe17b240d2 100644 --- a/dojo/utils.py +++ b/dojo/utils.py @@ -483,14 +483,19 @@ def deduplicate_uid_or_hash_code(new_finding): def set_duplicate(new_finding, existing_finding): + deduplicationLogger.debug(f"new_finding.status(): {new_finding.id} {new_finding.status()}") + deduplicationLogger.debug(f"existing_finding.status(): {existing_finding.id} {existing_finding.status()}") if existing_finding.duplicate: - logger.debug('existing finding: %s:%s:duplicate=%s;duplicate_finding=%s', existing_finding.id, existing_finding.title, existing_finding.duplicate, existing_finding.duplicate_finding.id if existing_finding.duplicate_finding else 'None') + deduplicationLogger.debug('existing finding: %s:%s:duplicate=%s;duplicate_finding=%s', existing_finding.id, existing_finding.title, existing_finding.duplicate, existing_finding.duplicate_finding.id if existing_finding.duplicate_finding else 'None') raise Exception("Existing finding is a duplicate") if existing_finding.id == new_finding.id: raise Exception("Can not add duplicate to itself") - deduplicationLogger.debug('Setting new finding ' + str(new_finding.id) + ' as a duplicate of existing finding ' + str(existing_finding.id)) if is_duplicate_reopen(new_finding, existing_finding): - set_duplicate_reopen(new_finding, existing_finding) + raise Exception("Found a regression. Ignore this so that a new duplicate chain can be made") + if new_finding.duplicate and finding_mitigated(existing_finding): + raise Exception("Skip this finding as we do not want to attach a new duplicate to a mitigated finding") + + deduplicationLogger.debug('Setting new finding ' + str(new_finding.id) + ' as a duplicate of existing finding ' + str(existing_finding.id)) new_finding.duplicate = True new_finding.active = False new_finding.verified = False @@ -509,11 +514,16 @@ def set_duplicate(new_finding, existing_finding): super(Finding, existing_finding).save() -def is_duplicate_reopen(new_finding, existing_finding): - if (existing_finding.is_mitigated or existing_finding.mitigated) and not existing_finding.out_of_scope and not existing_finding.false_p and new_finding.active and not new_finding.is_mitigated: - return True - else: - return False +def is_duplicate_reopen(new_finding, existing_finding) -> bool: + return finding_mitigated(existing_finding) and finding_not_human_set_status(existing_finding) and not finding_mitigated(new_finding) + + +def finding_mitigated(finding: Finding) -> bool: + return finding.active is False and (finding.is_mitigated is True or finding.mitigated is not None) + + +def finding_not_human_set_status(finding: Finding) -> bool: + return finding.out_of_scope is False and finding.false_p is False def set_duplicate_reopen(new_finding, existing_finding): From d40e23afb2de01313ec3e3ceec043d4048f48131 Mon Sep 17 00:00:00 2001 From: DefectDojo release bot Date: Tue, 20 Feb 2024 19:24:04 +0000 Subject: [PATCH 10/10] Update versions in application files --- components/package.json | 2 +- dojo/__init__.py | 2 +- helm/defectdojo/Chart.yaml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/package.json b/components/package.json index 9a57f7b78d..49267ee4a3 100644 --- a/components/package.json +++ b/components/package.json @@ -1,6 +1,6 @@ { "name": "defectdojo", - "version": "2.32.0-dev", + "version": "2.31.2", "license" : "BSD-3-Clause", "private": true, "dependencies": { diff --git a/dojo/__init__.py b/dojo/__init__.py index f1c39c15ed..d7827618d9 100644 --- a/dojo/__init__.py +++ b/dojo/__init__.py @@ -4,6 +4,6 @@ # Django starts so that shared_task will use this app. from .celery import app as celery_app # noqa -__version__ = '2.32.0-dev' +__version__ = '2.31.2' __url__ = 'https://github.com/DefectDojo/django-DefectDojo' __docs__ = 'https://documentation.defectdojo.com' diff --git a/helm/defectdojo/Chart.yaml b/helm/defectdojo/Chart.yaml index 60c20292d0..3e5de678a8 100644 --- a/helm/defectdojo/Chart.yaml +++ b/helm/defectdojo/Chart.yaml @@ -1,8 +1,8 @@ apiVersion: v2 -appVersion: "2.32.0-dev" +appVersion: "2.31.2" description: A Helm chart for Kubernetes to install DefectDojo name: defectdojo -version: 1.6.110-dev +version: 1.6.110 icon: https://www.defectdojo.org/img/favicon.ico maintainers: - name: madchap