Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release: Merge release into master from: release/2.31.1 #9532

Merged
merged 12 commits into from
Feb 12, 2024
Merged
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

Check warning on line 1 in dojo/db_migrations/0201_populate_finding_sla_expiration_date.py

View check run for this annotation

DryRunSecurity / Configured Sensitive Files Check

Sensitive File Edit

This file edit was detected to be sensitive according to the DryRun Security Configuration for this repository. Any edit to this file by an Author not in the allowedAuthors list will be considered sensitive.
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
@@ -1,4 +1,4 @@
import collections

Check warning on line 1 in dojo/filters.py

View check run for this annotation

DryRunSecurity / Configured Sensitive Files Check

Sensitive File Edit

This file edit was detected to be sensitive according to the DryRun Security Configuration for this repository. Any edit to this file by an Author not in the allowedAuthors list will be considered sensitive.
from drf_spectacular.types import OpenApiTypes

from drf_spectacular.utils import extend_schema_field
Expand All @@ -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 @@
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 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
Loading