Skip to content

Commit

Permalink
Merge pull request #9532 from DefectDojo/release/2.31.1
Browse files Browse the repository at this point in the history
Release: Merge release into master from: release/2.31.1
  • Loading branch information
Maffooch authored Feb 12, 2024
2 parents 738dca4 + 53111c5 commit d698a7a
Show file tree
Hide file tree
Showing 17 changed files with 448 additions and 138 deletions.
13 changes: 8 additions & 5 deletions .github/workflows/fetch-oas.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ on:
This will override any version calculated by the release-drafter.
required: true

env:
release_version: ${{ github.event.inputs.version || github.event.inputs.release_number }}

jobs:
oas_fetch:
name: Fetch OpenAPI Specifications
Expand All @@ -21,19 +24,19 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ github.event.inputs.version }}
ref: release/${{ env.release_version }}

- name: Load docker images
run: |-
docker pull defectdojo/defectdojo-django:${{ github.event.inputs.version }}-alpine
docker pull defectdojo/defectdojo-nginx:${{ github.event.inputs.version }}-alpine
docker pull defectdojo/defectdojo-django:${{ env.release_version }}-alpine
docker pull defectdojo/defectdojo-nginx:${{ env.release_version }}-alpine
docker images
- name: Start Dojo
run: docker-compose --profile postgres-redis --env-file ./docker/environments/postgres-redis.env up --no-deps -d postgres nginx uwsgi
env:
DJANGO_VERSION: ${{ github.event.inputs.version }}-alpine
NGINX_VERSION: ${{ github.event.inputs.version }}-alpine
DJANGO_VERSION: ${{ env.release_version }}-alpine
NGINX_VERSION: ${{ env.release_version }}-alpine

- name: Download OpenAPI Specifications
run: |-
Expand Down
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.0",
"version": "2.31.1",
"license" : "BSD-3-Clause",
"private": true,
"dependencies": {
Expand Down
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.0'
__version__ = '2.31.1'
__url__ = 'https://github.com/DefectDojo/django-DefectDojo'
__docs__ = 'https://documentation.defectdojo.com'
8 changes: 8 additions & 0 deletions dojo/api_v2/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -1133,6 +1133,14 @@ class Meta:
model = Tool_Type
fields = "__all__"

def validate(self, data):
if self.context["request"].method == "POST":
name = data.get("name")
# Make sure this will not create a duplicate test type
if Tool_Type.objects.filter(name=name).count() > 0:
raise serializers.ValidationError('A Tool Type with the name already exists')
return data


class RegulationSerializer(serializers.ModelSerializer):
class Meta:
Expand Down
133 changes: 133 additions & 0 deletions dojo/db_migrations/0201_populate_finding_sla_expiration_date.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
from django.db import migrations
from django.utils import timezone
from datetime import datetime
from django.conf import settings
from dateutil.relativedelta import relativedelta
import logging

from dojo.utils import get_work_days

logger = logging.getLogger(__name__)


def calculate_sla_expiration_dates(apps, schema_editor):
System_Settings = apps.get_model('dojo', 'System_Settings')

ss, _ = System_Settings.objects.get_or_create()
if not ss.enable_finding_sla:
return

logger.info('Calculating SLA expiration dates for all findings')

SLA_Configuration = apps.get_model('dojo', 'SLA_Configuration')
Finding = apps.get_model('dojo', 'Finding')

findings = Finding.objects.filter(sla_expiration_date__isnull=True).order_by('id').only('id', 'sla_start_date', 'date', 'severity', 'test', 'mitigated')

page_size = 1000
total_count = Finding.objects.filter(id__gt=0).count()
logger.info('Found %d findings to be updated', total_count)

i = 0
batch = []
last_id = 0
total_pages = (total_count // page_size) + 2
for p in range(1, total_pages):
page = findings.filter(id__gt=last_id)[:page_size]
for find in page:
i += 1
last_id = find.id

start_date = find.sla_start_date if find.sla_start_date else find.date

sla_config = SLA_Configuration.objects.filter(id=find.test.engagement.product.sla_configuration_id).first()
sla_period = getattr(sla_config, find.severity.lower(), None)

days = None
if settings.SLA_BUSINESS_DAYS:
if find.mitigated:
days = get_work_days(find.date, find.mitigated.date())
else:
days = get_work_days(find.date, timezone.now().date())
else:
if isinstance(start_date, datetime):
start_date = start_date.date()

if find.mitigated:
days = (find.mitigated.date() - start_date).days
else:
days = (timezone.now().date() - start_date).days

days = days if days > 0 else 0

days_remaining = None
if sla_period:
days_remaining = sla_period - days

if days_remaining:
if find.mitigated:
find.sla_expiration_date = find.mitigated.date() + relativedelta(days=days_remaining)
else:
find.sla_expiration_date = timezone.now().date() + relativedelta(days=days_remaining)

batch.append(find)

if (i > 0 and i % page_size == 0):
Finding.objects.bulk_update(batch, ['sla_expiration_date'])
batch = []
logger.info('%s out of %s findings processed...', i, total_count)

Finding.objects.bulk_update(batch, ['sla_expiration_date'])
batch = []
logger.info('%s out of %s findings processed...', i, total_count)


def reset_sla_expiration_dates(apps, schema_editor):
System_Settings = apps.get_model('dojo', 'System_Settings')

ss, _ = System_Settings.objects.get_or_create()
if not ss.enable_finding_sla:
return

logger.info('Resetting SLA expiration dates for all findings')

Finding = apps.get_model('dojo', 'Finding')

findings = Finding.objects.filter(sla_expiration_date__isnull=False).order_by('id').only('id')

page_size = 1000
total_count = Finding.objects.filter(id__gt=0).count()
logger.info('Found %d findings to be reset', total_count)

i = 0
batch = []
last_id = 0
total_pages = (total_count // page_size) + 2
for p in range(1, total_pages):
page = findings.filter(id__gt=last_id)[:page_size]
for find in page:
i += 1
last_id = find.id

find.sla_expiration_date = None
batch.append(find)

if (i > 0 and i % page_size == 0):
Finding.objects.bulk_update(batch, ['sla_expiration_date'])
batch = []
logger.info('%s out of %s findings processed...', i, total_count)

Finding.objects.bulk_update(batch, ['sla_expiration_date'])
batch = []
logger.info('%s out of %s findings processed...', i, total_count)


class Migration(migrations.Migration):

dependencies = [
('dojo', '0200_finding_sla_expiration_date_product_async_updating_and_more'),
]

operations = [
migrations.RunPython(calculate_sla_expiration_dates, reset_sla_expiration_dates),
]
17 changes: 7 additions & 10 deletions dojo/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from django.conf import settings
import six
from django.utils.translation import gettext_lazy as _
from django.utils import timezone
from django_filters import FilterSet, CharFilter, OrderingFilter, \
ModelMultipleChoiceFilter, ModelChoiceFilter, MultipleChoiceFilter, \
BooleanFilter, NumberFilter, DateFilter
Expand Down Expand Up @@ -148,16 +149,12 @@ def any(self, qs, name):
return qs

def sla_satisfied(self, qs, name):
for finding in qs:
if finding.violates_sla:
qs = qs.exclude(id=finding.id)
return qs
# return findings that have an sla expiration date after today or no sla expiration date
return qs.filter(Q(sla_expiration_date__isnull=True) | Q(sla_expiration_date__gt=timezone.now().date()))

def sla_violated(self, qs, name):
for finding in qs:
if not finding.violates_sla:
qs = qs.exclude(id=finding.id)
return qs
# return active findings that have an sla expiration date before today
return qs.filter(Q(active=True) & Q(sla_expiration_date__lt=timezone.now().date()))

options = {
None: (_('Any'), any),
Expand All @@ -184,13 +181,13 @@ def any(self, qs, name):

def sla_satisifed(self, qs, name):
for product in qs:
if product.violates_sla:
if product.violates_sla():
qs = qs.exclude(id=product.id)
return qs

def sla_violated(self, qs, name):
for product in qs:
if not product.violates_sla:
if not product.violates_sla():
qs = qs.exclude(id=product.id)
return qs

Expand Down
17 changes: 17 additions & 0 deletions dojo/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -2388,6 +2388,23 @@ class Meta:
model = Tool_Type
exclude = ['product']

def __init__(self, *args, **kwargs):
instance = kwargs.get('instance', None)
self.newly_created = True
if instance is not None:
self.newly_created = instance.pk is None
super().__init__(*args, **kwargs)

def clean(self):
form_data = self.cleaned_data
if self.newly_created:
name = form_data.get("name")
# Make sure this will not create a duplicate test type
if Tool_Type.objects.filter(name=name).count() > 0:
raise forms.ValidationError('A Tool Type with the name already exists')

return form_data


class RegulationForm(forms.ModelForm):
class Meta:
Expand Down
12 changes: 6 additions & 6 deletions dojo/jira_link/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -1036,28 +1036,28 @@ def get_issuetype_fields(

else:
try:
issuetypes = jira.createmeta_issuetypes(project_key)
issuetypes = jira.project_issue_types(project_key)
except JIRAError as e:
e.text = f"Jira API call 'createmeta/issuetypes' failed with status: {e.status_code} and message: {e.text}. Project misconfigured or no permissions in Jira ?"
raise e

issuetype_id = None
for it in issuetypes['values']:
if it['name'] == issuetype_name:
issuetype_id = it['id']
for it in issuetypes:
if it.name == issuetype_name:
issuetype_id = it.id
break

if not issuetype_id:
raise JIRAError("Issue type ID can not be matched. Misconfigured default issue type ?")

try:
issuetype_fields = jira.createmeta_fieldtypes(project_key, issuetype_id)
issuetype_fields = jira.project_issue_fields(project_key, issuetype_id)
except JIRAError as e:
e.text = f"Jira API call 'createmeta/fieldtypes' failed with status: {e.status_code} and message: {e.text}. Misconfigured project or default issue type ?"
raise e

try:
issuetype_fields = [f['fieldId'] for f in issuetype_fields['values']]
issuetype_fields = [f.fieldId for f in issuetype_fields]
except Exception:
raise JIRAError("Misconfigured default issue type ?")

Expand Down
Loading

0 comments on commit d698a7a

Please sign in to comment.