Skip to content

Commit d7b286d

Browse files
authored
Merge pull request DefectDojo#6188 from DefectDojo/release/2.9.1
Release: Merge release into master from: release/2.9.1
2 parents d07c007 + 8fc38da commit d7b286d

File tree

8 files changed

+180
-19
lines changed

8 files changed

+180
-19
lines changed

components/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "defectdojo",
3-
"version": "2.9.0",
3+
"version": "2.9.1",
44
"license" : "BSD-3-Clause",
55
"private": true,
66
"dependencies": {

dojo/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@
44
# Django starts so that shared_task will use this app.
55
from .celery import app as celery_app # noqa
66

7-
__version__ = '2.9.0'
7+
__version__ = '2.9.1'
88
__url__ = 'https://github.com/DefectDojo/django-DefectDojo'
99
__docs__ = 'https://defectdojo.github.io/django-DefectDojo'

dojo/db_migrations/0150_dedupe_endpoint_status.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from django.db import migrations
2-
from django.db.models import Count
2+
from django.db.models import Count, Q
33
import logging
44

55
logger = logging.getLogger(__name__)
@@ -16,7 +16,8 @@ def dedupe_endpoint_status(apps, schema_editor):
1616
Endpoint = apps.get_model('dojo', 'endpoint')
1717
Finding = apps.get_model('dojo', 'finding')
1818

19-
to_process = Endpoint_Status.objects.values('finding', 'endpoint').annotate(cnt=Count('id')).filter(cnt__gt=1)
19+
to_process = Endpoint_Status.objects.exclude(Q(endpoint=None) | Q(finding=None))\
20+
.values('finding', 'endpoint').annotate(cnt=Count('id')).filter(cnt__gt=1)
2021
if to_process.count() == 0:
2122
logger.info('There is nothing to process')
2223
else:

dojo/endpoint/utils.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,3 +361,16 @@ def endpoint_meta_import(file, product, create_endpoints, create_tags, create_me
361361
# if tags are not supposed to be added, this value remain unchanged
362362
endpoint.tags = existing_tags
363363
endpoint.save()
364+
365+
366+
def remove_broken_endpoint_statuses(apps):
367+
Finding = apps.get_model('dojo', 'Finding')
368+
Endpoint = apps.get_model('dojo', 'Endpoint')
369+
Endpoint_Status = apps.get_model('dojo', 'endpoint_status')
370+
broken_eps = Endpoint_Status.objects.filter(Q(endpoint=None) | Q(finding=None))
371+
if broken_eps.count() == 0:
372+
logger.info('There is no broken endpoint_status')
373+
else:
374+
logger.warning('We identified %s broken endpoint_statuses', broken_eps.count())
375+
deleted = broken_eps.delete()
376+
logger.warning('We removed: %s', deleted)
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from django.core.management.base import BaseCommand
2+
from django.apps import apps
3+
from dojo.endpoint.utils import remove_broken_endpoint_statuses
4+
5+
import logging
6+
7+
logger = logging.getLogger(__name__)
8+
9+
10+
class Command(BaseCommand):
11+
12+
help = 'Usage: manage.py remove_broken_endpoint_statuses.py'
13+
14+
def handle(self, *args, **options):
15+
remove_broken_endpoint_statuses(apps=apps)

helm/defectdojo/Chart.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
apiVersion: v1
2-
appVersion: "2.9.0"
2+
appVersion: "2.9.1"
33
description: A Helm chart for Kubernetes to install DefectDojo
44
name: defectdojo
5-
version: 1.6.30
5+
version: 1.6.31
66
icon: https://www.defectdojo.org/img/favicon.ico
77
maintainers:
88
- name: madchap

unittests/test_endpoint_model.py

Lines changed: 97 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1+
import datetime
12
from .dojo_test_case import DojoTestCase
23

34
from dojo.endpoint.utils import endpoint_get_or_create
4-
from dojo.models import Endpoint
5+
from dojo.models import Product_Type, Product, Engagement, Test, Finding, Endpoint, Endpoint_Status
56
from django.core.exceptions import ValidationError
7+
from django.apps import apps
8+
from django.utils import timezone
9+
from dojo.endpoint.utils import remove_broken_endpoint_statuses
610

711

812
class TestEndpointModel(DojoTestCase):
@@ -149,3 +153,95 @@ def test_get_or_create(self):
149153
port=8443
150154
)
151155
self.assertTrue(created7)
156+
157+
158+
# TODO: These tests can be skipped in the future (when Endpoint_Status.{finding,endpoint}(null=False,blank=False))
159+
# @skip("Outdated - this class was testing clean-up broken entries in old version of model; new version of model doesn't to store broken entries")
160+
class TestEndpointStatusBrokenModel(DojoTestCase):
161+
162+
def test_endpoint_status_broken(self):
163+
164+
self.prod_type = Product_Type.objects.create()
165+
self.product = Product.objects.create(prod_type=self.prod_type)
166+
self.engagement = Engagement.objects.create(
167+
product=self.product,
168+
target_start=datetime.datetime(2020, 1, 1, tzinfo=timezone.utc),
169+
target_end=datetime.datetime(2022, 1, 1, tzinfo=timezone.utc)
170+
)
171+
self.test = Test.objects.create(
172+
engagement=self.engagement,
173+
target_start=datetime.datetime(2020, 1, 1, tzinfo=timezone.utc),
174+
target_end=datetime.datetime(2022, 1, 1, tzinfo=timezone.utc),
175+
test_type_id=1
176+
)
177+
from django.contrib.auth import get_user_model
178+
user = get_user_model().objects.create().pk
179+
self.finding = Finding.objects.create(test=self.test, reporter_id=user).pk
180+
self.endpoint = Endpoint.objects.create(protocol='http', host='foo.bar.eps').pk
181+
self.another_finding = Finding.objects.create(test=self.test, reporter_id=user).pk
182+
self.another_endpoint = Endpoint.objects.create(protocol='http', host='bar.foo.eps').pk
183+
self.endpoint_status = {
184+
'standard': Endpoint_Status.objects.create(
185+
date=datetime.datetime(2021, 3, 1, tzinfo=timezone.utc),
186+
last_modified=datetime.datetime(2021, 4, 1, tzinfo=timezone.utc),
187+
mitigated=False,
188+
finding_id=self.finding,
189+
endpoint_id=self.endpoint
190+
).pk,
191+
'removed_endpoint': Endpoint_Status.objects.create(
192+
date=datetime.datetime(2021, 2, 1, tzinfo=timezone.utc),
193+
last_modified=datetime.datetime(2021, 5, 1, tzinfo=timezone.utc),
194+
mitigated=True,
195+
finding_id=self.another_finding,
196+
endpoint_id=None
197+
).pk,
198+
'removed_finding': Endpoint_Status.objects.create(
199+
date=datetime.datetime(2021, 2, 1, tzinfo=timezone.utc),
200+
last_modified=datetime.datetime(2021, 5, 1, tzinfo=timezone.utc),
201+
mitigated=True,
202+
finding_id=None,
203+
endpoint_id=self.another_endpoint
204+
).pk,
205+
}
206+
207+
Finding.objects.get(id=self.finding).endpoint_status.add(
208+
Endpoint_Status.objects.get(id=self.endpoint_status['standard'])
209+
)
210+
Finding.objects.get(id=self.another_finding).endpoint_status.add(
211+
Endpoint_Status.objects.get(id=self.endpoint_status['removed_endpoint'])
212+
)
213+
214+
Endpoint.objects.get(id=self.endpoint).endpoint_status.add(
215+
Endpoint_Status.objects.get(id=self.endpoint_status['standard'])
216+
)
217+
Endpoint.objects.get(id=self.another_endpoint).endpoint_status.add(
218+
Endpoint_Status.objects.get(id=self.endpoint_status['removed_finding'])
219+
)
220+
221+
remove_broken_endpoint_statuses(apps)
222+
223+
with self.subTest('Stadnard eps for finding'):
224+
f = Finding.objects.filter(id=self.finding)
225+
self.assertEqual(f.count(), 1)
226+
f = f.first()
227+
self.assertEqual(f.endpoint_status.count(), 1)
228+
self.assertEqual(f.endpoint_status.first().pk, self.endpoint_status['standard'])
229+
230+
with self.subTest('Broken eps for finding'):
231+
f = Finding.objects.filter(id=self.another_finding)
232+
self.assertEqual(f.count(), 1)
233+
f = f.first()
234+
self.assertEqual(f.endpoint_status.count(), 0)
235+
236+
with self.subTest('Stadnard eps for endpoint'):
237+
e = Endpoint.objects.filter(id=self.endpoint)
238+
self.assertEqual(e.count(), 1)
239+
e = e.first()
240+
self.assertEqual(e.endpoint_status.count(), 1)
241+
self.assertEqual(e.endpoint_status.first().pk, self.endpoint_status['standard'])
242+
243+
with self.subTest('Broken eps for endpoint'):
244+
e = Endpoint.objects.filter(id=self.another_endpoint)
245+
self.assertEqual(e.count(), 1)
246+
e = e.first()
247+
self.assertEqual(e.endpoint_status.count(), 0)

unittests/test_migrations.py

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -164,11 +164,11 @@ def test_migration_endpoint(self):
164164
self.assertFalse(eps[0].mitigated)
165165

166166

167-
# TODO: These tests can be skipped in 2.10.x or later
167+
# TODO: These tests can be skipped in 2.11.x or later
168168
# @skip("Outdated - Any future changes of code should not affect these tests")
169169
class TestEndpointStatusMigration(MigratorTestCase):
170170
migrate_from = ('dojo', '0149_harmonize_user_format')
171-
migrate_to = ('dojo', '0150_dedupe_endpoint_status')
171+
migrate_to = ('dojo', '0151_index_endpoint_status')
172172

173173
def prepare(self):
174174
Product_Type = self.old_state.apps.get_model('dojo', 'Product_Type')
@@ -218,6 +218,34 @@ def prepare(self):
218218
finding_id=self.finding,
219219
endpoint_id=self.endpoint
220220
).pk,
221+
'empty_endpoint_1': Endpoint_Status.objects.create(
222+
date=datetime.datetime(2021, 2, 1, tzinfo=timezone.utc),
223+
last_modified=datetime.datetime(2021, 5, 1, tzinfo=timezone.utc),
224+
mitigated=True,
225+
finding_id=self.finding,
226+
endpoint_id=None
227+
).pk,
228+
'empty_endpoint_2': Endpoint_Status.objects.create(
229+
date=datetime.datetime(2021, 2, 1, tzinfo=timezone.utc),
230+
last_modified=datetime.datetime(2021, 5, 1, tzinfo=timezone.utc),
231+
mitigated=True,
232+
finding_id=self.finding,
233+
endpoint_id=None
234+
).pk,
235+
'empty_finding_1': Endpoint_Status.objects.create(
236+
date=datetime.datetime(2021, 2, 1, tzinfo=timezone.utc),
237+
last_modified=datetime.datetime(2021, 5, 1, tzinfo=timezone.utc),
238+
mitigated=True,
239+
finding_id=None,
240+
endpoint_id=self.endpoint
241+
).pk,
242+
'empty_finding_2': Endpoint_Status.objects.create(
243+
date=datetime.datetime(2021, 2, 1, tzinfo=timezone.utc),
244+
last_modified=datetime.datetime(2021, 5, 1, tzinfo=timezone.utc),
245+
mitigated=True,
246+
finding_id=None,
247+
endpoint_id=self.endpoint
248+
).pk,
221249
}
222250

223251
self.another_finding = Finding.objects.create(test=self.test, reporter_id=user).pk
@@ -234,17 +262,25 @@ def test_migration_endpoint(self):
234262
Endpoint = self.new_state.apps.get_model('dojo', 'Endpoint')
235263
Endpoint_Status = self.new_state.apps.get_model('dojo', 'Endpoint_Status')
236264

237-
eps = Endpoint_Status.objects.filter(
238-
finding_id=self.finding,
239-
endpoint_id=self.endpoint
240-
)
241-
self.assertEqual(eps.count(), 1)
242-
self.assertTrue(eps[0].mitigated)
243-
self.assertEqual(eps[0].date, datetime.datetime(2021, 1, 1, tzinfo=timezone.utc))
244-
self.assertEqual(eps[0].last_modified, datetime.datetime(2021, 5, 1, tzinfo=timezone.utc))
265+
with self.subTest("Standard usecase"):
266+
eps = Endpoint_Status.objects.filter(
267+
finding_id=self.finding,
268+
endpoint_id=self.endpoint
269+
)
270+
self.assertEqual(eps.count(), 1)
271+
self.assertTrue(eps[0].mitigated)
272+
self.assertEqual(eps[0].date, datetime.datetime(2021, 1, 1, tzinfo=timezone.utc))
273+
self.assertEqual(eps[0].last_modified, datetime.datetime(2021, 5, 1, tzinfo=timezone.utc))
245274

246-
eps = Endpoint_Status.objects.filter(pk=self.another_endpoint_status)
247-
self.assertEqual(eps.count(), 1)
275+
eps = Endpoint_Status.objects.filter(pk=self.another_endpoint_status)
276+
self.assertEqual(eps.count(), 1)
277+
278+
with self.subTest("Broken endpoint_statuses"):
279+
eps = Endpoint_Status.objects.filter(endpoint_id=None, finding_id=self.finding)
280+
self.assertEqual(eps.count(), 2)
281+
282+
eps = Endpoint_Status.objects.filter(endpoint_id=self.endpoint, finding_id=None)
283+
self.assertEqual(eps.count(), 2)
248284

249285

250286
# TODO: These tests can be skipped in 2.10.x or later

0 commit comments

Comments
 (0)