Skip to content

Commit bae53d1

Browse files
Preserve verified flag when promoting duplicate to new original (#14934)
When the original of a duplicate cluster is deleted (e.g. via engagement deletion), reconfigure_duplicate_cluster promotes the first remaining duplicate to the new primary. It already copies active and is_mitigated from the original, but not verified. The promoted finding kept its own verified=False, which blocked Jira's "Push All Issues" (requires active+verified). Add verified to the fields copied to the new original. Fixes #14911
1 parent 74a525e commit bae53d1

2 files changed

Lines changed: 45 additions & 2 deletions

File tree

dojo/finding/helper.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,7 @@ def reconfigure_duplicate_cluster(original, cluster_outside):
603603
duplicate=False,
604604
duplicate_finding=None,
605605
active=original.active,
606+
verified=original.verified,
606607
is_mitigated=original.is_mitigated,
607608
)
608609
new_original.found_by.set(original.found_by.all())

unittests/test_prepare_duplicates_for_delete.py

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -294,22 +294,64 @@ def test_multiple_originals(self):
294294
self.assertFalse(dupe_of_b.duplicate)
295295
self.assertIsNone(dupe_of_b.duplicate_finding)
296296

297-
def test_original_status_copied_to_new_original(self):
298-
"""New original inherits active/is_mitigated status from deleted original."""
297+
def test_original_status_copied_to_new_original_active_verified(self):
298+
"""
299+
New original inherits active/verified/is_mitigated from deleted original.
300+
301+
Positive case: original is an open, verified, not-mitigated finding.
302+
Duplicate starts with the opposite of each field so every copy is observable.
303+
304+
Regression test for issue #14911: promoted duplicates kept verified=False
305+
even when the original was verified, blocking Jira "Push All Issues".
306+
"""
307+
original = self._create_finding(self.test1, "Original")
308+
original.active = True
309+
original.verified = True
310+
original.is_mitigated = False
311+
super(Finding, original).save(skip_validation=True)
312+
313+
outside_dupe = self._create_finding(self.test2, "Outside Dupe")
314+
outside_dupe.is_mitigated = True
315+
super(Finding, outside_dupe).save(skip_validation=True)
316+
self._make_duplicate(outside_dupe, original) # forces active=False, verified default False
317+
318+
with impersonate(self.testuser):
319+
prepare_duplicates_for_delete(self.test1)
320+
321+
outside_dupe.refresh_from_db()
322+
self.assertFalse(outside_dupe.duplicate)
323+
self.assertTrue(outside_dupe.active)
324+
self.assertTrue(outside_dupe.verified)
325+
self.assertFalse(outside_dupe.is_mitigated)
326+
327+
def test_original_status_copied_to_new_original_inactive_mitigated(self):
328+
"""
329+
New original inherits active/verified/is_mitigated from deleted original.
330+
331+
Negative case: original is closed, unverified, mitigated.
332+
Duplicate starts with the opposite of each field so every copy is observable.
333+
"""
299334
original = self._create_finding(self.test1, "Original")
300335
original.active = False
336+
original.verified = False
301337
original.is_mitigated = True
302338
super(Finding, original).save(skip_validation=True)
303339

304340
outside_dupe = self._create_finding(self.test2, "Outside Dupe")
341+
outside_dupe.verified = True
342+
super(Finding, outside_dupe).save(skip_validation=True)
305343
self._make_duplicate(outside_dupe, original)
344+
# _make_duplicate forces active=False; flip to True so the copy is observable
345+
outside_dupe.active = True
346+
super(Finding, outside_dupe).save(skip_validation=True)
306347

307348
with impersonate(self.testuser):
308349
prepare_duplicates_for_delete(self.test1)
309350

310351
outside_dupe.refresh_from_db()
311352
self.assertFalse(outside_dupe.duplicate)
312353
self.assertFalse(outside_dupe.active)
354+
self.assertFalse(outside_dupe.verified)
313355
self.assertTrue(outside_dupe.is_mitigated)
314356

315357
def test_found_by_copied_to_new_original(self):

0 commit comments

Comments
 (0)