Skip to content

Commit ea86b72

Browse files
fix: risk acceptance proof download throws 500 (#14478)
* 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. * 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. * 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 <select> visible for Selenium interaction - Upload a proof file to enable download regression test for #14467 - Add test_download_risk_acceptance_proof to verify no 500 error on download - Tighten assertions so failures are no longer masked --------- Co-authored-by: Matt Tesauro <mtesauro@gmail.com>
1 parent 2e1c162 commit ea86b72

2 files changed

Lines changed: 64 additions & 77 deletions

File tree

dojo/engagement/views.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1580,7 +1580,7 @@ def download_risk_acceptance(request, eid, raid):
15801580
raise PermissionDenied
15811581
response = StreamingHttpResponse(
15821582
FileIterWrapper(
1583-
(Path(settings.MEDIA_ROOT) / "risk_acceptance.path.name").open(mode="rb")))
1583+
(Path(settings.MEDIA_ROOT) / risk_acceptance.path.name).open(mode="rb")))
15841584
response["Content-Disposition"] = f'attachment; filename="{risk_acceptance.filename()}"'
15851585
mimetype, _encoding = mimetypes.guess_type(risk_acceptance.path.name)
15861586
response["Content-Type"] = mimetype or "application/octet-stream"

tests/risk_acceptance_test.py

Lines changed: 63 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
import os
12
import sys
23
import time
34
import unittest
5+
from pathlib import Path
46

57
from base_test_class import BaseTestCase, on_exception_html_source_logger, set_suite_settings
68
from product_test import ProductTest
@@ -9,36 +11,6 @@
911

1012
class RiskAcceptanceTest(BaseTestCase):
1113

12-
def _get_engagement_url(self, driver):
13-
"""Navigate to the Beta Test engagement via the all engagements list."""
14-
self.goto_all_engagements_overview(driver)
15-
time.sleep(1)
16-
# Find the Beta Test engagement link in the table
17-
eng_links = driver.find_elements(By.LINK_TEXT, "Beta Test")
18-
if len(eng_links) > 0:
19-
eng_links[0].click()
20-
time.sleep(1)
21-
return driver.current_url
22-
# Fallback: try partial link text
23-
eng_links = driver.find_elements(By.PARTIAL_LINK_TEXT, "Beta")
24-
if len(eng_links) > 0:
25-
eng_links[0].click()
26-
time.sleep(1)
27-
return driver.current_url
28-
return None
29-
30-
def _get_engagement_id(self, driver):
31-
"""Get the engagement ID from the current engagement page URL."""
32-
eng_url = self._get_engagement_url(driver)
33-
if eng_url is None:
34-
return None
35-
# URL pattern: .../engagement/<id>
36-
parts = eng_url.rstrip("/").split("/")
37-
for i, part in enumerate(parts):
38-
if part == "engagement" and i + 1 < len(parts):
39-
return parts[i + 1]
40-
return parts[-1]
41-
4214
@on_exception_html_source_logger
4315
def test_enable_full_risk_acceptance(self):
4416
"""Enable full risk acceptance on the QA Test product."""
@@ -48,7 +20,6 @@ def test_enable_full_risk_acceptance(self):
4820
driver.find_element(By.ID, "dropdownMenu1").click()
4921
driver.find_element(By.LINK_TEXT, "Edit").click()
5022
time.sleep(1)
51-
# Enable full risk acceptance checkbox
5223
checkbox = driver.find_element(By.ID, "id_enable_full_risk_acceptance")
5324
if not checkbox.is_selected():
5425
checkbox.click()
@@ -61,80 +32,95 @@ def test_enable_full_risk_acceptance(self):
6132

6233
@on_exception_html_source_logger
6334
def test_add_risk_acceptance(self):
64-
"""Add a risk acceptance to the engagement."""
35+
"""Add a risk acceptance with proof to the Ad Hoc Engagement."""
6536
driver = self.driver
66-
eid = self._get_engagement_id(driver)
67-
self.assertIsNotNone(eid, "Could not find Beta Test engagement")
68-
driver.get(self.base_url + f"engagement/{eid}/risk_acceptance/add")
37+
# Navigate to the Ad Hoc Engagement (where test_add_product_finding creates its finding)
38+
self.goto_all_engagements_overview(driver)
39+
time.sleep(1)
40+
driver.find_element(By.LINK_TEXT, "Ad Hoc Engagement").click()
41+
time.sleep(1)
42+
# Click "Add Risk Acceptance" from the engagement page
43+
driver.find_element(By.CSS_SELECTOR, "a[href*='risk_acceptance/add']").click()
6944
time.sleep(2)
7045
# Fill the risk acceptance form
7146
name_field = driver.find_element(By.ID, "id_name")
7247
name_field.clear()
7348
name_field.send_keys("Test Risk Acceptance")
74-
# Select an accepted finding if available
75-
findings_select = driver.find_elements(By.ID, "id_accepted_findings")
76-
if len(findings_select) > 0:
77-
options = findings_select[0].find_elements(By.TAG_NAME, "option")
78-
if len(options) > 0:
79-
options[0].click()
80-
# Radio buttons for recommendation and decision - click Accept options
49+
# Select an accepted finding - the native <select> is hidden by bootstrap-select
50+
driver.execute_script("document.getElementById('id_accepted_findings').style.display = 'inline'")
51+
findings_select = driver.find_element(By.ID, "id_accepted_findings")
52+
options = findings_select.find_elements(By.TAG_NAME, "option")
53+
self.assertTrue(len(options) > 0, "No findings available for risk acceptance")
54+
options[0].click()
55+
# Radio buttons for recommendation and decision
8156
rec_radios = driver.find_elements(By.NAME, "recommendation")
8257
if len(rec_radios) > 0:
8358
rec_radios[0].click()
8459
dec_radios = driver.find_elements(By.NAME, "decision")
8560
if len(dec_radios) > 0:
8661
dec_radios[0].click()
62+
# Upload a proof file
63+
proof_path = Path(os.path.realpath(__file__)).parent / "dedupe_scans" / "dedupe_path_1.json"
64+
driver.find_element(By.ID, "id_path").send_keys(str(proof_path))
8765
# Owner is pre-filled (current user), submit
8866
driver.find_element(By.CSS_SELECTOR, "input.btn.btn-primary").click()
8967
time.sleep(1)
9068

9169
self.assertTrue(
92-
self.is_success_message_present(text="Risk acceptance saved")
93-
or self.is_text_present_on_page(text="Risk Acceptance")
94-
or self.is_text_present_on_page(text="Engagement"),
70+
self.is_success_message_present(text="Risk acceptance saved"),
71+
"Risk acceptance was not saved",
9572
)
9673

9774
@on_exception_html_source_logger
9875
def test_view_risk_acceptance(self):
99-
"""View a risk acceptance from the engagement."""
76+
"""View a risk acceptance from the Ad Hoc Engagement."""
10077
driver = self.driver
101-
eng_url = self._get_engagement_url(driver)
102-
self.assertIsNotNone(eng_url, "Could not find Beta Test engagement")
78+
self.goto_all_engagements_overview(driver)
10379
time.sleep(1)
104-
# Look for risk acceptance links on the engagement page
80+
driver.find_element(By.LINK_TEXT, "Ad Hoc Engagement").click()
81+
time.sleep(1)
82+
# Click on the risk acceptance name link
10583
risk_links = driver.find_elements(By.PARTIAL_LINK_TEXT, "Test Risk Acceptance")
106-
if len(risk_links) > 0:
107-
risk_links[0].click()
108-
time.sleep(1)
109-
self.assertTrue(
110-
self.is_text_present_on_page(text="Risk Acceptance")
111-
or self.is_text_present_on_page(text="Test Risk Acceptance"),
112-
)
113-
else:
114-
# Risk acceptance may be listed differently
115-
self.assertFalse(self.is_error_message_present())
84+
self.assertTrue(len(risk_links) > 0, "Could not find Test Risk Acceptance link")
85+
risk_links[0].click()
86+
time.sleep(1)
87+
self.assertTrue(
88+
self.is_text_present_on_page(text="Risk Acceptance")
89+
or self.is_text_present_on_page(text="Test Risk Acceptance"),
90+
)
91+
92+
@on_exception_html_source_logger
93+
def test_download_risk_acceptance_proof(self):
94+
"""Download the proof file from a risk acceptance (regression test for #14467)."""
95+
driver = self.driver
96+
# Navigate to the Ad Hoc Engagement where the RA was created
97+
self.goto_all_engagements_overview(driver)
98+
time.sleep(1)
99+
driver.find_element(By.LINK_TEXT, "Ad Hoc Engagement").click()
100+
time.sleep(1)
101+
# Click the proof download link ("Yes") in the Risk Acceptance table
102+
download_links = driver.find_elements(By.CSS_SELECTOR, "a[href*='risk_acceptance'][href*='download']")
103+
self.assertTrue(len(download_links) > 0, "Could not find proof download link on engagement page")
104+
download_links[0].click()
105+
time.sleep(2)
106+
# Verify no 500 error occurred
107+
self.assertFalse(self.is_error_message_present())
108+
body_text = driver.find_element(By.TAG_NAME, "body").text
109+
self.assertNotIn("Internal Server Error", body_text)
116110

117111
@on_exception_html_source_logger
118112
def test_delete_risk_acceptance(self):
119-
"""Delete a risk acceptance."""
113+
"""Delete a risk acceptance from the Ad Hoc Engagement."""
120114
driver = self.driver
121-
eng_url = self._get_engagement_url(driver)
122-
self.assertIsNotNone(eng_url, "Could not find Beta Test engagement")
115+
self.goto_all_engagements_overview(driver)
123116
time.sleep(1)
124-
# Find delete links for risk acceptances
125-
delete_links = driver.find_elements(By.CSS_SELECTOR, "a[href*='risk_acceptance'][href*='delete']")
126-
if len(delete_links) > 0:
127-
delete_links[0].click()
128-
time.sleep(1)
129-
# Confirm delete - the URL pattern is a GET request that performs delete
130-
# Check if we're on a confirmation page
131-
confirm_btns = driver.find_elements(By.CSS_SELECTOR, "input.btn.btn-danger")
132-
if len(confirm_btns) > 0:
133-
confirm_btns[0].click()
134-
else:
135-
button_btns = driver.find_elements(By.CSS_SELECTOR, "button.btn.btn-danger")
136-
if len(button_btns) > 0:
137-
button_btns[0].click()
117+
driver.find_element(By.LINK_TEXT, "Ad Hoc Engagement").click()
118+
time.sleep(1)
119+
# Find delete form for risk acceptance (uses POST via hidden form)
120+
delete_forms = driver.find_elements(By.CSS_SELECTOR, "form[id^='delete-risk_acceptance-form']")
121+
if len(delete_forms) > 0:
122+
# The delete link triggers the form via JS; submit the form directly
123+
driver.execute_script("arguments[0].submit()", delete_forms[0])
138124
time.sleep(1)
139125
self.assertTrue(
140126
self.is_success_message_present(text="Risk acceptance deleted successfully")
@@ -154,6 +140,7 @@ def suite():
154140
suite.addTest(RiskAcceptanceTest("test_enable_full_risk_acceptance"))
155141
suite.addTest(RiskAcceptanceTest("test_add_risk_acceptance"))
156142
suite.addTest(RiskAcceptanceTest("test_view_risk_acceptance"))
143+
suite.addTest(RiskAcceptanceTest("test_download_risk_acceptance_proof"))
157144
suite.addTest(RiskAcceptanceTest("test_delete_risk_acceptance"))
158145
suite.addTest(ProductTest("test_delete_product"))
159146
return suite

0 commit comments

Comments
 (0)