Skip to content

Commit 19bf225

Browse files
Maffoochclaude
andauthored
docs: document DD_EDITABLE_MITIGATED_DATA and hide ignored close-finding fields (#15259)
Audit and document the DD_EDITABLE_MITIGATED_DATA setting, which gates editing of a finding's mitigated date / mitigated by. Editing requires both the flag enabled and a superuser (via can_edit_mitigated_data), and is off by default because backdating a mitigation can distort SLA-compliance metrics. - Add an "Editing the Mitigated Date and Mitigated By" section to the Editing Findings docs covering the default-off behavior, the superuser requirement, the SLA-backdating trade-off, the audit trail, the restart requirement, and a Cloud/Pro contact-support note. - Expand the settings.dist.py comment to note the superuser gate, UI+API scope, SLA rationale, and restart requirement. - Hide the mitigated / mitigated_by fields on CloseFindingForm when the setting is disabled, mirroring FindingForm, so users are no longer shown a Mitigated date input whose value is silently ignored on close. - Add a default-off test covering the hidden fields and that a backdated mitigated value is ignored (finding closes with the current date). Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent f5bd12e commit 19bf225

4 files changed

Lines changed: 82 additions & 1 deletion

File tree

docs/content/triage_findings/findings_workflows/editing_findings.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,17 @@ This will open the **Edit Finding** form, where you can edit the metadata, chang
3737
3838
* **SAST / DAST** are labels used to organize your Findings into the context they were discovered in. Generally, this label is populated based on the scanning tool used, but you can adjust this to a more accurate level (for example, if the Finding was found by both a SAST and a DAST tool).
3939

40+
### Editing the Mitigated Date and Mitigated By
41+
42+
By default, a Finding's **Mitigated Date** and **Mitigated By** values are **not editable**. These fields are hidden from both the Edit Finding form and the Close Finding dialog, and the Mitigated Date is always set automatically to the moment the Finding is closed. Attempting to set or backdate these values through the API is rejected for the same reason.
43+
44+
Editing can be turned on with the `DD_EDITABLE_MITIGATED_DATA` server setting. When it is enabled, the **Mitigated Date** and **Mitigated By** fields appear in the Edit Finding form and the Close Finding dialog, and can also be set through the API — but only for users with **superuser** status. In other words, editing requires *both* the setting to be enabled *and* the acting user to be a superuser.
45+
46+
* **Why it's off by default:** allowing a mitigation to be backdated can misrepresent SLA compliance — a Finding that was actually remediated *outside* its SLA window could be recorded as though it had been mitigated *within* SLA. Enabling the setting is forward-looking only; it does **not** change the Mitigated Date or age of any existing Findings.
47+
* **Everything stays auditable:** every change to a Finding, including edits to the Mitigated Date and Mitigated By, is captured in the Finding's history log — who made the change, when, and the previous and new values.
48+
* **Applying the setting:** `DD_EDITABLE_MITIGATED_DATA` is a server-level environment variable (see [Configuration](/get_started/open_source/configuration/)). Changing it requires a service restart to take effect.
49+
* **DefectDojo Cloud / Pro:** this setting cannot be changed from the UI. Contact DefectDojo Support to have it enabled for your instance.
50+
4051
## Bulk Edit Findings
4152

4253
Findings can be edited in bulk from a Finding List, which can be found either on the Findings page itself, or from within a Test.

dojo/finding/ui/forms.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -921,6 +921,11 @@ def __init__(self, *args, **kwargs):
921921
self.fields["mitigated_by"].queryset = get_authorized_users("edit")
922922
self.fields["mitigated"].initial = self.instance.mitigated
923923
self.fields["mitigated_by"].initial = self.instance.mitigated_by
924+
else:
925+
# mitigated data is not editable: hide the fields so users are not
926+
# presented with inputs whose values would be silently ignored
927+
del self.fields["mitigated"]
928+
del self.fields["mitigated_by"]
924929
if disclaimer := get_system_setting("disclaimer_notes"):
925930
self.disclaimer = disclaimer.strip()
926931

dojo/settings/settings.dist.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,10 @@
212212
# we limit the amount of duplicates that can be deleted in a single run of that job
213213
# to prevent overlapping runs of that job from occurrring
214214
DD_DUPE_DELETE_MAX_PER_RUN=(int, 200),
215-
# when enabled 'mitigated date' and 'mitigated by' of a finding become editable
215+
# When enabled, superusers can edit a finding's 'mitigated date' and 'mitigated by'
216+
# fields (e.g. backdate a mitigation) from both the UI and the API. Off by default
217+
# because backdating a mitigation can distort SLA-compliance metrics. Changing this
218+
# value requires a service restart to take effect.
216219
DD_EDITABLE_MITIGATED_DATA=(bool, False),
217220
# new feature that tracks history across multiple reimports for the same test
218221
DD_TRACK_IMPORT_HISTORY=(bool, True),

unittests/test_system_settings.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,68 @@ def test_post_request_initializes_form_with_finding_instance(self):
9393
self.assertIn(response.status_code, [200, 302])
9494

9595

96+
@override_settings(DD_EDITABLE_MITIGATED_DATA=False)
97+
class CloseFindingViewMitigatedDataDisabledTest(TestCase):
98+
99+
"""
100+
When DD_EDITABLE_MITIGATED_DATA is disabled (the default), the Close Finding
101+
form must not expose the mitigated/mitigated_by fields, and any mitigated value
102+
supplied in the payload must be ignored so the finding is closed with the
103+
current date rather than a backdated one.
104+
"""
105+
106+
def setUp(self):
107+
self.user = User.objects.create_user(
108+
username="tester-mitigated-disabled",
109+
password="pass", # noqa: S106
110+
is_staff=True,
111+
is_superuser=True,
112+
)
113+
self.client.force_login(self.user)
114+
self.product_type = Product_Type.objects.create(name="Disabled Product Type")
115+
self.product = Product.objects.create(name="Disabled Product", description="test", prod_type=self.product_type)
116+
self.engagement = Engagement.objects.create(
117+
name="Disabled Engagement",
118+
product=self.product,
119+
target_start=now(),
120+
target_end=now(),
121+
)
122+
self.test_type = Test_Type.objects.create(name="Disabled Unit Test Type")
123+
self.test = Test.objects.create(
124+
engagement=self.engagement,
125+
test_type=self.test_type,
126+
title="Test for Finding",
127+
target_start=now(),
128+
target_end=now(),
129+
)
130+
self.finding = Finding.objects.create(
131+
title="Close Finding Disabled Test",
132+
active=True,
133+
test=self.test,
134+
reporter=self.user,
135+
)
136+
self.url = reverse("close_finding", args=[self.finding.id])
137+
138+
def test_close_form_hides_mitigated_fields(self):
139+
response = self.client.get(self.url)
140+
self.assertEqual(response.status_code, 200)
141+
form = response.context["form"]
142+
self.assertNotIn("mitigated", form.fields)
143+
self.assertNotIn("mitigated_by", form.fields)
144+
145+
def test_backdated_mitigated_is_ignored(self):
146+
response = self.client.post(
147+
self.url,
148+
{"entry": "Closing this finding", "mitigated": "2020-01-01"},
149+
)
150+
self.assertEqual(response.status_code, 302)
151+
self.finding.refresh_from_db()
152+
self.assertTrue(self.finding.is_mitigated)
153+
self.assertIsNotNone(self.finding.mitigated)
154+
# the backdated value must be ignored: mitigation date is "now", not 2020
155+
self.assertEqual(self.finding.mitigated.year, now().year)
156+
157+
96158
class TestSystemSettingsMiddlewareIntegration(DojoTestCase):
97159

98160
"""Integration tests for DojoSytemSettingsMiddleware using RequestFactory."""

0 commit comments

Comments
 (0)