Skip to content

Commit

Permalink
Merge branch 'dev' into master-into-dev/2.34.4-2.35.0-dev
Browse files Browse the repository at this point in the history
  • Loading branch information
Maffooch authored May 20, 2024
2 parents beca985 + f6f44b9 commit 1c58c27
Show file tree
Hide file tree
Showing 52 changed files with 985 additions and 260 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/k8s-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ jobs:
uses: actions/checkout@v4

- name: Setup Minikube
uses: manusa/actions-setup-minikube@v2.10.0
uses: manusa/actions-setup-minikube@v2.11.0
with:
minikube version: 'v1.31.2'
kubernetes version: ${{ matrix.k8s }}
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile.integration-tests-debian
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

# code: language=Dockerfile

FROM openapitools/openapi-generator-cli:v7.5.0@sha256:cdf11948948de9c21c6035de47dd5fc73c1651c8ba2ea0a4b86a527608ef52a9 as openapitools
FROM openapitools/openapi-generator-cli:v7.6.0@sha256:f86ca824293602b71b9b66683cc0011f8ff963858bd853621c554ff5cc7dd1d5 as openapitools
FROM python:3.11.4-slim-bullseye@sha256:40319d0a897896e746edf877783ef39685d44e90e1e6de8d964d0382df0d4952 as build
WORKDIR /app
RUN \
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile.nginx-alpine
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ COPY manage.py ./
COPY dojo/ ./dojo/
RUN env DD_SECRET_KEY='.' python3 manage.py collectstatic --noinput && true

FROM nginx:1.26.0-alpine@sha256:ca16009a8c25f52193506d4c90c98efbad4b6cbe73372e2a27972f05c5e02f15
FROM nginx:1.26.0-alpine@sha256:ef587d1eb99e991291c582bfb74f27db27f7ca2c095d4ba06cc3f7c910a0c7b3
ARG uid=1001
ARG appuser=defectdojo
COPY --from=collectstatic /app/static/ /usr/share/nginx/html/static/
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile.nginx-debian
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ COPY dojo/ ./dojo/

RUN env DD_SECRET_KEY='.' python3 manage.py collectstatic --noinput && true

FROM nginx:1.26.0-alpine@sha256:ca16009a8c25f52193506d4c90c98efbad4b6cbe73372e2a27972f05c5e02f15
FROM nginx:1.26.0-alpine@sha256:ef587d1eb99e991291c582bfb74f27db27f7ca2c095d4ba06cc3f7c910a0c7b3
ARG uid=1001
ARG appuser=defectdojo
COPY --from=collectstatic /app/static/ /usr/share/nginx/html/static/
Expand Down
3 changes: 3 additions & 0 deletions docker-compose.override.debug.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,20 @@ services:
- '.:/app:z'
environment:
PYTHONWARNINGS: error # We are strict about Warnings during debugging
DD_DEBUG: 'True'
DD_EMAIL_URL: "smtp://mailhog:1025"
celerybeat:
environment:
PYTHONWARNINGS: error # We are strict about Warnings during debugging
DD_DEBUG: 'True'
volumes:
- '.:/app:z'
initializer:
volumes:
- '.:/app:z'
environment:
PYTHONWARNINGS: error # We are strict about Warnings during debugging
DD_DEBUG: 'True'
DD_ADMIN_USER: "${DD_ADMIN_USER:-admin}"
DD_ADMIN_PASSWORD: "${DD_ADMIN_PASSWORD:-admin}"
nginx:
Expand Down
4 changes: 2 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ services:
volumes:
- defectdojo_data:/var/lib/mysql
postgres:
image: postgres:16.2-alpine@sha256:951bfda460300925caa3949eaa092ba022e9aec191bbea9056a39e2382260b27
image: postgres:16.3-alpine@sha256:7f7832dfb7770c7256fe3f8c4cb57617caee45e2494cc0a736594135237ed9bf
profiles:
- postgres-rabbitmq
- postgres-redis
Expand All @@ -155,7 +155,7 @@ services:
volumes:
- defectdojo_rabbitmq:/var/lib/rabbitmq
redis:
image: redis:7.2.4-alpine@sha256:a40e29800d387e3cf9431902e1e7a362e4d819233d68ae39380532c3310091ac
image: redis:7.2.4-alpine@sha256:c8bb255c3559b3e458766db810aa7b3c7af1235b204cfdb304e79ff388fe1a5a
profiles:
- mysql-redis
- postgres-redis
Expand Down
20 changes: 19 additions & 1 deletion docs/content/en/contributing/how-to-write-a-parser.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ $ docker-compose build --build-arg uid=1000

## Factory contract

Parser are loaded dynamicaly with a factory pattern. To have your parser loaded and works correctly, you need to implement the contract.
Parsers are loaded dynamicaly with a factory pattern. To have your parser loaded and works correctly, you need to implement the contract.

1. your parser **MUST** be in a sub-module of module `dojo.tools`
- ex: `dojo.tools.my_tool.parser` module
Expand Down Expand Up @@ -253,6 +253,24 @@ For ex:
self.assertEqual("TEST1", finding.vuln_id_from_tool)
```

### Use with to open example files

In order to make certain that file handles are closed properly, please use the with pattern to open files.
Instead of:
```python
testfile = open("path_to_file.json")
...
testfile.close()
```

use:
```python
with open("path_to_file.json") as testfile:
...
```

This ensures the file is closed at the end of the with statement, even if an exception occurs somewhere in the block.

### Test database

To test your unit tests locally, you first need to grant some rights. Get your MySQL root password from the docker-compose logs, login as root and issue the following commands:
Expand Down
12 changes: 12 additions & 0 deletions docs/content/en/getting_started/upgrading/2.35.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
title: 'Upgrading to DefectDojo Version 2.35.x'
toc_hide: true
weight: -20240506
description: Integrity checker announced
---

From 2.35.0, DefectDojo will perform an integrity check of the `settings.dist.py` file to ensure it has not been modified. If the user changed this file (in the past or even now) the DefectDojo instance will not start until those changes have been reverted.
Any customization of variables needs to be done via environmental variables or in 'local_settings.py'.
For more information check [Configuration documentation page](https://documentation.defectdojo.com/getting_started/configuration/).

There are no other special instructions for upgrading to 2.35.x. Check the [Release Notes](https://github.com/DefectDojo/django-DefectDojo/releases/tag/2.35.0) for the contents of the release.
6 changes: 4 additions & 2 deletions dojo/api_v2/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,7 @@ class Meta:


class UserSerializer(serializers.ModelSerializer):
date_joined = serializers.DateTimeField(read_only=True)
last_login = serializers.DateTimeField(read_only=True)
password = serializers.CharField(
write_only=True,
Expand All @@ -450,6 +451,7 @@ class Meta:
"first_name",
"last_name",
"email",
"date_joined",
"last_login",
"is_active",
"is_superuser",
Expand Down Expand Up @@ -2957,10 +2959,10 @@ class Meta:
def validate(self, data):
async_updating = getattr(self.instance, 'async_updating', None)
if async_updating:
for field in ['critical', 'high', 'medium', 'low']:
for field in ['critical', 'enforce_critical', 'high', 'enforce_high', 'medium', 'enforce_medium', 'low', 'enforce_low']:
old_days = getattr(self.instance, field, None)
new_days = data.get(field, None)
if old_days and new_days and (old_days != new_days):
if old_days is not None and new_days is not None and (old_days != new_days):
msg = 'Finding SLA expiration dates are currently being calculated. The SLA days for this SLA configuration cannot be changed until the calculation is complete.'
raise serializers.ValidationError(msg)
return data
Expand Down
5 changes: 5 additions & 0 deletions dojo/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,13 @@ def ready(self):
# Load any signals here that will be ready for runtime
# Importing the signals file is good enough if using the reciever decorator
import dojo.announcement.signals # noqa: F401
import dojo.endpoint.signals # noqa: F401
import dojo.engagement.signals # noqa: F401
import dojo.finding_group.signals # noqa: F401
import dojo.product.signals # noqa: F401
import dojo.product_type.signals # noqa: F401
import dojo.sla_config.helpers # noqa: F401
import dojo.tags_signals # noqa: F401
import dojo.test.signals # noqa: F401


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Generated by Django 4.1.13 on 2024-05-09 08:03

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('dojo', '0211_system_settings_enable_similar_findings'),
]

operations = [
migrations.AddField(
model_name='sla_configuration',
name='enforce_critical',
field=models.BooleanField(default=True, help_text='When enabled, critical findings will be assigned an SLA expiration date based on the critical finding SLA days within this SLA configuration.', verbose_name='Enforce Critical Finding SLA Days'),
),
migrations.AddField(
model_name='sla_configuration',
name='enforce_high',
field=models.BooleanField(default=True, help_text='When enabled, high findings will be assigned an SLA expiration date based on the high finding SLA days within this SLA configuration.', verbose_name='Enforce High Finding SLA Days'),
),
migrations.AddField(
model_name='sla_configuration',
name='enforce_low',
field=models.BooleanField(default=True, help_text='When enabled, low findings will be assigned an SLA expiration date based on the low finding SLA days within this SLA configuration.', verbose_name='Enforce Low Finding SLA Days'),
),
migrations.AddField(
model_name='sla_configuration',
name='enforce_medium',
field=models.BooleanField(default=True, help_text='When enabled, medium findings will be assigned an SLA expiration date based on the medium finding SLA days within this SLA configuration.', verbose_name='Enforce Medium Finding SLA Days'),
),
migrations.AlterField(
model_name='sla_configuration',
name='critical',
field=models.IntegerField(default=7, help_text='The number of days to remediate a critical finding.', verbose_name='Critical Finding SLA Days'),
),
migrations.AlterField(
model_name='sla_configuration',
name='high',
field=models.IntegerField(default=30, help_text='The number of days to remediate a high finding.', verbose_name='High Finding SLA Days'),
),
migrations.AlterField(
model_name='sla_configuration',
name='low',
field=models.IntegerField(default=120, help_text='The number of days to remediate a low finding.', verbose_name='Low Finding SLA Days'),
),
migrations.AlterField(
model_name='sla_configuration',
name='medium',
field=models.IntegerField(default=90, help_text='The number of days to remediate a medium finding.', verbose_name='Medium Finding SLA Days'),
),
]
30 changes: 30 additions & 0 deletions dojo/endpoint/signals.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from auditlog.models import LogEntry
from django.conf import settings
from django.contrib.contenttypes.models import ContentType
from django.db.models.signals import post_delete
from django.dispatch import receiver
from django.urls import reverse
from django.utils.translation import gettext as _

from dojo.models import Endpoint
from dojo.notifications.helper import create_notification


@receiver(post_delete, sender=Endpoint)
def endpoint_post_delete(sender, instance, using, origin, **kwargs):
if instance == origin:
if settings.ENABLE_AUDITLOG:
le = LogEntry.objects.get(
action=LogEntry.Action.DELETE,
content_type=ContentType.objects.get(app_label='dojo', model='endpoint'),
object_id=instance.id
)
description = _('The endpoint "%(name)s" was deleted by %(user)s') % {
'name': str(instance), 'user': le.actor}
else:
description = _('The endpoint "%(name)s" was deleted') % {'name': str(instance)}
create_notification(event='endpoint_deleted', # template does not exists, it will default to "other" but this event name needs to stay because of unit testing
title=_('Deletion of %(name)s') % {'name': str(instance)},
description=description,
url=reverse('endpoint'),
icon="exclamation-triangle")
7 changes: 0 additions & 7 deletions dojo/endpoint/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
from dojo.filters import EndpointFilter, EndpointFilterWithoutObjectLookups
from dojo.forms import AddEndpointForm, DeleteEndpointForm, DojoMetaDataForm, EditEndpointForm, ImportEndpointMetaForm
from dojo.models import DojoMeta, Endpoint, Endpoint_Status, Finding, Product
from dojo.notifications.helper import create_notification
from dojo.utils import (
Product_Tab,
add_breadcrumb,
Expand Down Expand Up @@ -222,12 +221,6 @@ def delete_endpoint(request, eid):
messages.SUCCESS,
'Endpoint and relationships removed.',
extra_tags='alert-success')
create_notification(event='other',
title=f'Deletion of {endpoint}',
product=product,
description=f'The endpoint "{endpoint}" was deleted by {request.user}',
url=reverse('endpoint'),
icon="exclamation-triangle")
return HttpResponseRedirect(reverse('view_product', args=(product.id,)))

collector = NestedObjects(using=DEFAULT_DB_ALIAS)
Expand Down
57 changes: 57 additions & 0 deletions dojo/engagement/signals.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
from auditlog.models import LogEntry
from django.conf import settings
from django.contrib.contenttypes.models import ContentType
from django.db.models.signals import post_delete, post_save, pre_save
from django.dispatch import receiver
from django.urls import reverse
from django.utils.translation import gettext as _

from dojo.models import Engagement
from dojo.notifications.helper import create_notification


@receiver(post_save, sender=Engagement)
def engagement_post_save(sender, instance, created, **kwargs):
if created:
title = _('Engagement created for "%(product)s": %(name)s') % {'product': instance.product, 'name': instance.name}
create_notification(event='engagement_added', title=title, engagement=instance, product=instance.product,
url=reverse('view_engagement', args=(instance.id,)))


@receiver(pre_save, sender=Engagement)
def engagement_pre_save(sender, instance, **kwargs):
old = sender.objects.filter(pk=instance.pk).first()
if old and instance.status != old.status:
if instance.status in ["Cancelled", "Completed"]:
create_notification(event='engagement_closed',
title=_('Closure of %s') % instance.name,
description=_('The engagement "%s" was closed') % (instance.name),
engagement=instance, url=reverse('engagement_all_findings', args=(instance.id, )))
elif instance.status in ["In Progress"] and old.status not in ["Not Started"]:
create_notification(event='engagement_reopened',
title=_('Reopening of %s') % instance.name,
engagement=instance,
description=_('The engagement "%s" was reopened') % (instance.name),
url=reverse('view_engagement', args=(instance.id, )))


@receiver(post_delete, sender=Engagement)
def engagement_post_delete(sender, instance, using, origin, **kwargs):
if instance == origin:
if settings.ENABLE_AUDITLOG:
le = LogEntry.objects.get(
action=LogEntry.Action.DELETE,
content_type=ContentType.objects.get(app_label='dojo', model='engagement'),
object_id=instance.id
)
description = _('The engagement "%(name)s" was deleted by %(user)s') % {
'name': instance.name, 'user': le.actor}
else:
description = _('The engagement "%(name)s" was deleted') % {'name': instance.name}
create_notification(event='engagement_deleted', # template does not exists, it will default to "other" but this event name needs to stay because of unit testing
title=_('Deletion of %(name)s') % {'name': instance.name},
description=description,
product=instance.product,
url=reverse('view_product', args=(instance.product.id, )),
recipients=[instance.lead],
icon="exclamation-triangle")
25 changes: 2 additions & 23 deletions dojo/engagement/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,10 +279,6 @@ def edit_engagement(request, eid):
engagement = form.save(commit=False)
if (new_status == "Cancelled" or new_status == "Completed"):
engagement.active = False
create_notification(event='close_engagement',
title=f'Closure of {engagement.name}',
description=f'The engagement "{engagement.name}" was closed',
engagement=engagement, url=reverse('engagement_all_findings', args=(engagement.id, ))),
else:
engagement.active = True
engagement.save()
Expand Down Expand Up @@ -361,14 +357,6 @@ def delete_engagement(request, eid):
messages.SUCCESS,
message,
extra_tags='alert-success')
create_notification(event='other',
title=f'Deletion of {engagement.name}',
product=product,
description=f'The engagement "{engagement.name}" was deleted by {request.user}',
url=request.build_absolute_uri(reverse('view_engagements', args=(product.id, ))),
recipients=[engagement.lead],
icon="exclamation-triangle")

return HttpResponseRedirect(reverse("view_engagements", args=(product.id, )))

rels = ['Previewing the relationships has been disabled.', '']
Expand Down Expand Up @@ -404,8 +392,8 @@ def copy_engagement(request, eid):
messages.SUCCESS,
'Engagement Copied successfully.',
extra_tags='alert-success')
create_notification(event='other',
title=f'Copying of {engagement.name}',
create_notification(event='engagement_copied', # TODO - if 'copy' functionality will be supported by API as well, 'create_notification' needs to be migrated to place where it will be able to cover actions from both interfaces
title=_('Copying of %s') % engagement.name,
description=f'The engagement "{engagement.name}" was copied by {request.user}',
product=product,
url=request.build_absolute_uri(reverse('view_engagement', args=(engagement_copy.id, ))),
Expand Down Expand Up @@ -1138,10 +1126,6 @@ def close_eng(request, eid):
messages.SUCCESS,
'Engagement closed successfully.',
extra_tags='alert-success')
create_notification(event='close_engagement',
title=f'Closure of {eng.name}',
description=f'The engagement "{eng.name}" was closed',
engagement=eng, url=reverse('engagement_all_findings', args=(eng.id, ))),
return HttpResponseRedirect(reverse("view_engagements", args=(eng.product.id, )))


Expand All @@ -1154,11 +1138,6 @@ def reopen_eng(request, eid):
messages.SUCCESS,
'Engagement reopened successfully.',
extra_tags='alert-success')
create_notification(event='other',
title=f'Reopening of {eng.name}',
engagement=eng,
description=f'The engagement "{eng.name}" was reopened',
url=reverse('view_engagement', args=(eng.id, ))),
return HttpResponseRedirect(reverse("view_engagements", args=(eng.product.id, )))


Expand Down
Loading

0 comments on commit 1c58c27

Please sign in to comment.