From 7a0ed0a42ed757c41e75cab2ebfb86da319e3410 Mon Sep 17 00:00:00 2001 From: Raul Melendez Date: Thu, 23 Apr 2026 21:56:43 -0400 Subject: [PATCH 1/2] =?UTF-8?q?align=20ApiRiskAcceptanceFilter=20date=20pa?= =?UTF-8?q?rams=20with=20API=20conventions=20=E2=80=A2=20use=20DateRangeFi?= =?UTF-8?q?lter=20for=20created=20and=20updated=20=E2=80=A2=20add=20explic?= =?UTF-8?q?it=20DateTimeFilter=20comparisons=20=E2=80=A2=20updated=20risk?= =?UTF-8?q?=20acceptance=20API=20tests=20to=20assert=20new=20query=20param?= =?UTF-8?q?s=20and=20deterministic=20result=20inclusion?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dojo/filters.py | 4 ++ unittests/test_risk_acceptance_api.py | 60 +++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/dojo/filters.py b/dojo/filters.py index 8bc68a39e60..df5d511c7d2 100644 --- a/dojo/filters.py +++ b/dojo/filters.py @@ -3130,6 +3130,10 @@ class Meta: class ApiRiskAcceptanceFilter(DojoFilter): created = DateRangeFilter() updated = DateRangeFilter() + created_before = DateTimeFilter(field_name="created", lookup_expr="lt") + created_after = DateTimeFilter(field_name="created", lookup_expr="gt") + updated_before = DateTimeFilter(field_name="updated", lookup_expr="lt") + updated_after = DateTimeFilter(field_name="updated", lookup_expr="gt") o = OrderingFilter( # tuple-mapping retains order diff --git a/unittests/test_risk_acceptance_api.py b/unittests/test_risk_acceptance_api.py index 45756bb6e54..1232649413d 100644 --- a/unittests/test_risk_acceptance_api.py +++ b/unittests/test_risk_acceptance_api.py @@ -176,6 +176,19 @@ def setUp(self): self.client.credentials(HTTP_AUTHORIZATION="Token " + self.token.key) self.url = reverse("risk_acceptance-list") + # Helper method to create a risk acceptance for testing filters + def create_risk_acceptance(self): + risk_acceptance = Risk_Acceptance.objects.create( + name="Filter Test RA", + recommendation="A", + decision="A", + accepted_by="Test User", + owner=self.user, + ) + risk_acceptance.accepted_findings.add(self.finding_a1) + self.engagement_a.risk_acceptance.add(risk_acceptance) + return risk_acceptance + def test_create_risk_acceptance_links_to_engagement(self): """Test that risk acceptance created via API appears in engagement.risk_acceptance""" payload = { @@ -358,3 +371,50 @@ def test_update_risk_acceptance_add_cross_engagement_fails(self): response = self.client.put(f"{self.url}{ra.id}/", payload, format="json") self.assertEqual(403, response.status_code, response.content) self.assertIn("multiple engagements", str(response.data)) + + def test_risk_acceptance_created_filter(self): + # 1. Create a baseline Risk Acceptance using the existing test setup + risk_acceptance = self.create_risk_acceptance() + + # 2. Manually backdate the created date to test ranges + past_date = datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(days=10) + risk_acceptance.created = past_date + risk_acceptance.save() + + # 3. Test `created_before` (Less than / Before) + # Should return the risk acceptance because it was created 10 days ago + future_date = datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%dT%H:%M:%S.%fZ') + response = self.client.get(reverse('risk_acceptance-list') + f'?created_before={future_date}') + self.assertEqual(response.status_code, 200) + result_ids = {item["id"] for item in response.json()["results"]} + self.assertIn(risk_acceptance.id, result_ids) + + # 4. Test `created_after` (Greater than / After) + # Should NOT return the risk acceptance because it is not newer than today + response = self.client.get(reverse('risk_acceptance-list') + f'?created_after={future_date}') + self.assertEqual(response.status_code, 200) + result_ids = {item["id"] for item in response.json()["results"]} + self.assertNotIn(risk_acceptance.id, result_ids) + + + def test_risk_acceptance_updated_filter(self): + risk_acceptance = self.create_risk_acceptance() + + # Manually backdate the updated date + past_date = datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(days=10) + # We use .update() to bypass the auto_now=True behavior on the updated field + type(risk_acceptance).objects.filter(pk=risk_acceptance.id).update(updated=past_date) + + future_date = datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%dT%H:%M:%S.%fZ') + + # Test updated_before + response = self.client.get(reverse('risk_acceptance-list') + f'?updated_before={future_date}') + self.assertEqual(response.status_code, 200) + result_ids = {item["id"] for item in response.json()["results"]} + self.assertIn(risk_acceptance.id, result_ids) + + # Test updated_after + response = self.client.get(reverse('risk_acceptance-list') + f'?updated_after={future_date}') + self.assertEqual(response.status_code, 200) + result_ids = {item["id"] for item in response.json()["results"]} + self.assertNotIn(risk_acceptance.id, result_ids) From 60c7c69a12aab94b0916ecead68b51ff900105e6 Mon Sep 17 00:00:00 2001 From: Raul Melendez Date: Fri, 1 May 2026 20:45:58 -0400 Subject: [PATCH 2/2] style: fix ruff issues in risk acceptance tests --- unittests/test_risk_acceptance_api.py | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/unittests/test_risk_acceptance_api.py b/unittests/test_risk_acceptance_api.py index 1232649413d..e3a6a96d4d3 100644 --- a/unittests/test_risk_acceptance_api.py +++ b/unittests/test_risk_acceptance_api.py @@ -375,46 +375,45 @@ def test_update_risk_acceptance_add_cross_engagement_fails(self): def test_risk_acceptance_created_filter(self): # 1. Create a baseline Risk Acceptance using the existing test setup risk_acceptance = self.create_risk_acceptance() - + # 2. Manually backdate the created date to test ranges - past_date = datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(days=10) + past_date = datetime.datetime.now(datetime.UTC) - datetime.timedelta(days=10) risk_acceptance.created = past_date risk_acceptance.save() # 3. Test `created_before` (Less than / Before) # Should return the risk acceptance because it was created 10 days ago - future_date = datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%dT%H:%M:%S.%fZ') - response = self.client.get(reverse('risk_acceptance-list') + f'?created_before={future_date}') + future_date = datetime.datetime.now(datetime.UTC).strftime("%Y-%m-%dT%H:%M:%S.%fZ") + response = self.client.get(reverse("risk_acceptance-list") + f"?created_before={future_date}") self.assertEqual(response.status_code, 200) result_ids = {item["id"] for item in response.json()["results"]} self.assertIn(risk_acceptance.id, result_ids) # 4. Test `created_after` (Greater than / After) # Should NOT return the risk acceptance because it is not newer than today - response = self.client.get(reverse('risk_acceptance-list') + f'?created_after={future_date}') + response = self.client.get(reverse("risk_acceptance-list") + f"?created_after={future_date}") self.assertEqual(response.status_code, 200) result_ids = {item["id"] for item in response.json()["results"]} self.assertNotIn(risk_acceptance.id, result_ids) - def test_risk_acceptance_updated_filter(self): risk_acceptance = self.create_risk_acceptance() - + # Manually backdate the updated date - past_date = datetime.datetime.now(datetime.timezone.utc) - datetime.timedelta(days=10) + past_date = datetime.datetime.now(datetime.UTC) - datetime.timedelta(days=10) # We use .update() to bypass the auto_now=True behavior on the updated field type(risk_acceptance).objects.filter(pk=risk_acceptance.id).update(updated=past_date) - future_date = datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%dT%H:%M:%S.%fZ') - + future_date = datetime.datetime.now(datetime.UTC).strftime("%Y-%m-%dT%H:%M:%S.%fZ") + # Test updated_before - response = self.client.get(reverse('risk_acceptance-list') + f'?updated_before={future_date}') + response = self.client.get(reverse("risk_acceptance-list") + f"?updated_before={future_date}") self.assertEqual(response.status_code, 200) result_ids = {item["id"] for item in response.json()["results"]} self.assertIn(risk_acceptance.id, result_ids) # Test updated_after - response = self.client.get(reverse('risk_acceptance-list') + f'?updated_after={future_date}') + response = self.client.get(reverse("risk_acceptance-list") + f"?updated_after={future_date}") self.assertEqual(response.status_code, 200) result_ids = {item["id"] for item in response.json()["results"]} self.assertNotIn(risk_acceptance.id, result_ids)