From fa0fa8250fa0835ea0315f6cbbcae588c9e4f2e3 Mon Sep 17 00:00:00 2001 From: Valentijn Scholten Date: Mon, 9 Mar 2026 20:14:35 +0100 Subject: [PATCH 1/3] fix: use actual field value instead of string literal for risk acceptance proof download (#14467) The path was wrapped in quotes, causing Django to open a file literally named "risk_acceptance.path.name" instead of the uploaded proof file. Also adds a selenium test for the proof download flow. --- dojo/engagement/views.py | 2 +- tests/risk_acceptance_test.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/dojo/engagement/views.py b/dojo/engagement/views.py index 3ad2f29f8d4..4b48efcbd6e 100644 --- a/dojo/engagement/views.py +++ b/dojo/engagement/views.py @@ -1580,7 +1580,7 @@ def download_risk_acceptance(request, eid, raid): raise PermissionDenied response = StreamingHttpResponse( FileIterWrapper( - (Path(settings.MEDIA_ROOT) / "risk_acceptance.path.name").open(mode="rb"))) + (Path(settings.MEDIA_ROOT) / risk_acceptance.path.name).open(mode="rb"))) response["Content-Disposition"] = f'attachment; filename="{risk_acceptance.filename()}"' mimetype, _encoding = mimetypes.guess_type(risk_acceptance.path.name) response["Content-Type"] = mimetype or "application/octet-stream" diff --git a/tests/risk_acceptance_test.py b/tests/risk_acceptance_test.py index e06467c003a..34436491ef7 100644 --- a/tests/risk_acceptance_test.py +++ b/tests/risk_acceptance_test.py @@ -1,6 +1,8 @@ +import os import sys import time import unittest +from pathlib import Path from base_test_class import BaseTestCase, on_exception_html_source_logger, set_suite_settings from product_test import ProductTest @@ -84,6 +86,9 @@ def test_add_risk_acceptance(self): dec_radios = driver.find_elements(By.NAME, "decision") if len(dec_radios) > 0: dec_radios[0].click() + # Upload a proof file + proof_path = Path(os.path.realpath(__file__)).parent / "dedupe_scans" / "dedupe_path_1.json" + driver.find_element(By.ID, "id_path").send_keys(str(proof_path)) # Owner is pre-filled (current user), submit driver.find_element(By.CSS_SELECTOR, "input.btn.btn-primary").click() time.sleep(1) @@ -114,6 +119,28 @@ def test_view_risk_acceptance(self): # Risk acceptance may be listed differently self.assertFalse(self.is_error_message_present()) + @on_exception_html_source_logger + def test_download_risk_acceptance_proof(self): + """Download the proof file from a risk acceptance (regression test for #14467).""" + driver = self.driver + eng_url = self._get_engagement_url(driver) + self.assertIsNotNone(eng_url, "Could not find Beta Test engagement") + time.sleep(1) + # Navigate to the risk acceptance detail page + risk_links = driver.find_elements(By.PARTIAL_LINK_TEXT, "Test Risk Acceptance") + self.assertTrue(len(risk_links) > 0, "Could not find Test Risk Acceptance link") + risk_links[0].click() + time.sleep(1) + # Click the proof download link + download_links = driver.find_elements(By.CSS_SELECTOR, "a[href*='risk_acceptance'][href*='download']") + self.assertTrue(len(download_links) > 0, "Could not find proof download link") + download_links[0].click() + time.sleep(2) + # Verify no 500 error occurred + self.assertFalse(self.is_error_message_present()) + body_text = driver.find_element(By.TAG_NAME, "body").text + self.assertNotIn("Internal Server Error", body_text) + @on_exception_html_source_logger def test_delete_risk_acceptance(self): """Delete a risk acceptance.""" @@ -154,6 +181,7 @@ def suite(): suite.addTest(RiskAcceptanceTest("test_enable_full_risk_acceptance")) suite.addTest(RiskAcceptanceTest("test_add_risk_acceptance")) suite.addTest(RiskAcceptanceTest("test_view_risk_acceptance")) + suite.addTest(RiskAcceptanceTest("test_download_risk_acceptance_proof")) suite.addTest(RiskAcceptanceTest("test_delete_risk_acceptance")) suite.addTest(ProductTest("test_delete_product")) return suite From 5b2a958fac95d041171e26e7babaa755411db474 Mon Sep 17 00:00:00 2001 From: Valentijn Scholten Date: Tue, 10 Mar 2026 19:14:37 +0100 Subject: [PATCH 2/3] fix: find proof download link directly on engagement page The risk acceptance download link ("Yes") is in the RA table on the engagement detail page. No need to navigate to the RA detail page first. --- tests/risk_acceptance_test.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/tests/risk_acceptance_test.py b/tests/risk_acceptance_test.py index 34436491ef7..63d566f5f87 100644 --- a/tests/risk_acceptance_test.py +++ b/tests/risk_acceptance_test.py @@ -126,14 +126,10 @@ def test_download_risk_acceptance_proof(self): eng_url = self._get_engagement_url(driver) self.assertIsNotNone(eng_url, "Could not find Beta Test engagement") time.sleep(1) - # Navigate to the risk acceptance detail page - risk_links = driver.find_elements(By.PARTIAL_LINK_TEXT, "Test Risk Acceptance") - self.assertTrue(len(risk_links) > 0, "Could not find Test Risk Acceptance link") - risk_links[0].click() - time.sleep(1) - # Click the proof download link + # The engagement detail page has a Risk Acceptance table with a "Yes" + # download link when proof was uploaded. Click it directly. download_links = driver.find_elements(By.CSS_SELECTOR, "a[href*='risk_acceptance'][href*='download']") - self.assertTrue(len(download_links) > 0, "Could not find proof download link") + self.assertTrue(len(download_links) > 0, "Could not find proof download link on engagement page") download_links[0].click() time.sleep(2) # Verify no 500 error occurred From 68e2091d17744d6fc2df1c217825c8e2c1004950 Mon Sep 17 00:00:00 2001 From: Valentijn Scholten Date: Tue, 10 Mar 2026 20:42:49 +0100 Subject: [PATCH 3/3] fix: rewrite risk acceptance selenium tests that were silently broken The existing risk acceptance tests were silently passing despite never actually creating a risk acceptance. Key fixes: - Navigate to Ad Hoc Engagement (where test findings live) instead of Beta Test - Make bootstrap-select hidden native is hidden by bootstrap-select + driver.execute_script("document.getElementById('id_accepted_findings').style.display = 'inline'") + findings_select = driver.find_element(By.ID, "id_accepted_findings") + options = findings_select.find_elements(By.TAG_NAME, "option") + self.assertTrue(len(options) > 0, "No findings available for risk acceptance") + options[0].click() + # Radio buttons for recommendation and decision rec_radios = driver.find_elements(By.NAME, "recommendation") if len(rec_radios) > 0: rec_radios[0].click() @@ -94,40 +67,38 @@ def test_add_risk_acceptance(self): time.sleep(1) self.assertTrue( - self.is_success_message_present(text="Risk acceptance saved") - or self.is_text_present_on_page(text="Risk Acceptance") - or self.is_text_present_on_page(text="Engagement"), + self.is_success_message_present(text="Risk acceptance saved"), + "Risk acceptance was not saved", ) @on_exception_html_source_logger def test_view_risk_acceptance(self): - """View a risk acceptance from the engagement.""" + """View a risk acceptance from the Ad Hoc Engagement.""" driver = self.driver - eng_url = self._get_engagement_url(driver) - self.assertIsNotNone(eng_url, "Could not find Beta Test engagement") + self.goto_all_engagements_overview(driver) + time.sleep(1) + driver.find_element(By.LINK_TEXT, "Ad Hoc Engagement").click() time.sleep(1) - # Look for risk acceptance links on the engagement page + # Click on the risk acceptance name link risk_links = driver.find_elements(By.PARTIAL_LINK_TEXT, "Test Risk Acceptance") - if len(risk_links) > 0: - risk_links[0].click() - time.sleep(1) - self.assertTrue( - self.is_text_present_on_page(text="Risk Acceptance") - or self.is_text_present_on_page(text="Test Risk Acceptance"), - ) - else: - # Risk acceptance may be listed differently - self.assertFalse(self.is_error_message_present()) + self.assertTrue(len(risk_links) > 0, "Could not find Test Risk Acceptance link") + risk_links[0].click() + time.sleep(1) + self.assertTrue( + self.is_text_present_on_page(text="Risk Acceptance") + or self.is_text_present_on_page(text="Test Risk Acceptance"), + ) @on_exception_html_source_logger def test_download_risk_acceptance_proof(self): """Download the proof file from a risk acceptance (regression test for #14467).""" driver = self.driver - eng_url = self._get_engagement_url(driver) - self.assertIsNotNone(eng_url, "Could not find Beta Test engagement") + # Navigate to the Ad Hoc Engagement where the RA was created + self.goto_all_engagements_overview(driver) + time.sleep(1) + driver.find_element(By.LINK_TEXT, "Ad Hoc Engagement").click() time.sleep(1) - # The engagement detail page has a Risk Acceptance table with a "Yes" - # download link when proof was uploaded. Click it directly. + # Click the proof download link ("Yes") in the Risk Acceptance table download_links = driver.find_elements(By.CSS_SELECTOR, "a[href*='risk_acceptance'][href*='download']") self.assertTrue(len(download_links) > 0, "Could not find proof download link on engagement page") download_links[0].click() @@ -139,25 +110,17 @@ def test_download_risk_acceptance_proof(self): @on_exception_html_source_logger def test_delete_risk_acceptance(self): - """Delete a risk acceptance.""" + """Delete a risk acceptance from the Ad Hoc Engagement.""" driver = self.driver - eng_url = self._get_engagement_url(driver) - self.assertIsNotNone(eng_url, "Could not find Beta Test engagement") + self.goto_all_engagements_overview(driver) time.sleep(1) - # Find delete links for risk acceptances - delete_links = driver.find_elements(By.CSS_SELECTOR, "a[href*='risk_acceptance'][href*='delete']") - if len(delete_links) > 0: - delete_links[0].click() - time.sleep(1) - # Confirm delete - the URL pattern is a GET request that performs delete - # Check if we're on a confirmation page - confirm_btns = driver.find_elements(By.CSS_SELECTOR, "input.btn.btn-danger") - if len(confirm_btns) > 0: - confirm_btns[0].click() - else: - button_btns = driver.find_elements(By.CSS_SELECTOR, "button.btn.btn-danger") - if len(button_btns) > 0: - button_btns[0].click() + driver.find_element(By.LINK_TEXT, "Ad Hoc Engagement").click() + time.sleep(1) + # Find delete form for risk acceptance (uses POST via hidden form) + delete_forms = driver.find_elements(By.CSS_SELECTOR, "form[id^='delete-risk_acceptance-form']") + if len(delete_forms) > 0: + # The delete link triggers the form via JS; submit the form directly + driver.execute_script("arguments[0].submit()", delete_forms[0]) time.sleep(1) self.assertTrue( self.is_success_message_present(text="Risk acceptance deleted successfully")