Skip to content

Commit

Permalink
Merge pull request #9594 from DefectDojo/release/2.31.2
Browse files Browse the repository at this point in the history
Release: Merge release into master from: release/2.31.2
  • Loading branch information
Maffooch authored Feb 20, 2024
2 parents d698a7a + d40e23a commit a2f7c97
Show file tree
Hide file tree
Showing 14 changed files with 56 additions and 31 deletions.
1 change: 1 addition & 0 deletions .github/workflows/pr-labeler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ jobs:
- uses: actions/labeler@v5
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"
sync-labels: true
2 changes: 1 addition & 1 deletion components/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "defectdojo",
"version": "2.31.1",
"version": "2.31.2",
"license" : "BSD-3-Clause",
"private": true,
"dependencies": {
Expand Down
3 changes: 2 additions & 1 deletion docs/content/en/integrations/google-sheets-sync.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
changes into DefectDojo.
2 changes: 1 addition & 1 deletion dojo/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.31.2'
__url__ = 'https://github.com/DefectDojo/django-DefectDojo'
__docs__ = 'https://documentation.defectdojo.com'
2 changes: 1 addition & 1 deletion dojo/endpoint/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion dojo/engagement/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down
8 changes: 5 additions & 3 deletions dojo/jira_link/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -863,17 +863,19 @@ 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)

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)
Expand Down
10 changes: 9 additions & 1 deletion dojo/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 _
Expand Down Expand Up @@ -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
Expand All @@ -4364,6 +4367,7 @@ class TextQuestion(Question):
'''
Question with a text answer
'''
objects = PolymorphicManager()

def get_form(self):
'''
Expand Down Expand Up @@ -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):
'''
Expand Down Expand Up @@ -4476,13 +4480,16 @@ class Answer(PolymorphicModel, TimeStampedModel):
null=False,
blank=False,
on_delete=models.CASCADE)
objects = models.Manager()
polymorphic = PolymorphicManager()


class TextAnswer(Answer):
answer = models.TextField(
blank=False,
help_text=_('The answer text'),
default='')
objects = PolymorphicManager()

def __str__(self):
return self.answer
Expand All @@ -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()):
Expand Down
21 changes: 12 additions & 9 deletions dojo/survey/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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 = []

Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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 = []
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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':
Expand All @@ -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 = []
Expand Down
2 changes: 1 addition & 1 deletion dojo/templates/dojo/engagement.html
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ <h3 class="has-filters">
</div>
</td>
<td> {{ e.target_start }} - {{ e.target_end }}
{% if e.is_overdue %}
{% if e.is_overdue and e.status != 'Completed' %}
<span class="tag-label warning-color">
{{ e.target_end|overdue }} overdue
</span>
Expand Down
2 changes: 1 addition & 1 deletion dojo/templates/dojo/engagements_all.html
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ <h3 class="has-filters">
{% endif %}
<td> {{ e.status }} </td>
<td> {{ e.target_start }} - {{ e.target_end }}
{% if e.is_overdue and e.active %}
{% if e.is_overdue and e.active and e.status != 'Completed' %}
<sup><div class="tag-label warning-color">{{ e.target_end|overdue }} overdue</div></sup>
{% endif %}
</td>
Expand Down
2 changes: 1 addition & 1 deletion dojo/templates/dojo/snippets/engagement_list.html
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ <h4> {% if status == "open" %}Active{% elif status == "paused" %}Paused {% else
</td>
<td class="text-left" class="nowrap">{{ eng.target_start|datediff_time:eng.target_end }}
{% if status == "open" %}
{% if eng.is_overdue %}
{% if eng.is_overdue and eng.status != 'Completed' %}
<sup>
<div class="tag-label warning-color">
{{ eng.target_end|overdue }} overdue
Expand Down
26 changes: 18 additions & 8 deletions dojo/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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):
Expand Down
4 changes: 2 additions & 2 deletions helm/defectdojo/Chart.yaml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
apiVersion: v2
appVersion: "2.31.1"
appVersion: "2.31.2"
description: A Helm chart for Kubernetes to install DefectDojo
name: defectdojo
version: 1.6.109
version: 1.6.110
icon: https://www.defectdojo.org/img/favicon.ico
maintainers:
- name: madchap
Expand Down

0 comments on commit a2f7c97

Please sign in to comment.