Skip to content

Commit 6fad8f7

Browse files
authored
bugfix - Close Old Findings will close all findings even when all findings are present in current import (DefectDojo#8198)
* refactor code that skips mitigated findings * add integration tests * fix formatting * add test for closing old findings without dedupe * add unit test
1 parent bf7727c commit 6fad8f7

8 files changed

+892
-3
lines changed

docker/entrypoint-integration-tests.sh

+16
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,22 @@ else
219219
fail $test
220220
fi
221221

222+
test="Close Old Findings with dedupe integration tests"
223+
echo "Running: $test"
224+
if python3 tests/close_old_findings_dedupe_test.py ; then
225+
success $test
226+
else
227+
fail $test
228+
fi
229+
230+
test="Close Old Findings without dedupe integration tests"
231+
echo "Running: $test"
232+
if python3 tests/close_old_findings_test.py ; then
233+
success $test
234+
else
235+
fail $test
236+
fi
237+
222238
# The below tests are commented out because they are still an unstable work in progress
223239
## Once Ready they can be uncommented.
224240

dojo/importers/importer/importer.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -174,10 +174,12 @@ def process_parsed_findings(self, test, parsed_findings, scan_type, user, active
174174

175175
def close_old_findings(self, test, scan_date_time, user, push_to_jira=None, service=None, close_old_findings_product_scope=False):
176176
# Close old active findings that are not reported by this scan.
177-
new_hash_codes = test.finding_set.values('hash_code')
177+
# Refactoring this to only call test.finding_set.values() once.
178+
findings = test.finding_set.values()
178179
mitigated_hash_codes = []
179-
new_hash_codes = list(new_hash_codes)
180-
for finding in test.finding_set.values():
180+
new_hash_codes = []
181+
for finding in findings:
182+
new_hash_codes.append(finding["hash_code"])
181183
if finding["is_mitigated"]:
182184
mitigated_hash_codes.append(finding["hash_code"])
183185
for hash_code in new_hash_codes:

tests/close_old_findings_dedupe_test.py

+347
Large diffs are not rendered by default.

tests/close_old_findings_test.py

+292
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,292 @@
1+
import logging
2+
import os
3+
import sys
4+
import unittest
5+
6+
from selenium.common.exceptions import TimeoutException
7+
from selenium.webdriver.common.by import By
8+
from selenium.webdriver.support import expected_conditions as EC
9+
from selenium.webdriver.support.ui import Select, WebDriverWait
10+
11+
from base_test_class import (BaseTestCase, on_exception_html_source_logger,
12+
set_suite_settings)
13+
from product_test import ProductTest
14+
15+
logger = logging.getLogger(__name__)
16+
17+
dir_path = os.path.dirname(os.path.realpath(__file__))
18+
19+
20+
class CloseOldTest(BaseTestCase):
21+
# --------------------------------------------------------------------------------------------------------
22+
# This set of tests is similar to close_old_findings_dedupe_test.py, but does not rely on deduplication
23+
# Testing that two different scans of the same type will properly close the old findings on the second import.
24+
# --------------------------------------------------------------------------------------------------------
25+
def setUp(self):
26+
super().setUp()
27+
self.relative_path = dir_path = os.path.dirname(os.path.realpath(__file__))
28+
29+
@on_exception_html_source_logger
30+
def test_delete_findings(self):
31+
logger.debug("removing previous findings...")
32+
driver = self.driver
33+
driver.get(self.base_url + "finding?page=1")
34+
35+
if self.element_exists_by_id("no_findings"):
36+
text = driver.find_element(By.ID, "no_findings").text
37+
if 'No findings found.' in text:
38+
return
39+
40+
driver.find_element(By.ID, "select_all").click()
41+
driver.find_element(By.CSS_SELECTOR, "i.fa-solid.fa-trash").click()
42+
try:
43+
WebDriverWait(driver, 1).until(EC.alert_is_present(),
44+
'Timed out waiting for finding delete ' +
45+
'confirmation popup to appear.')
46+
driver.switch_to.alert.accept()
47+
except TimeoutException:
48+
self.fail('Confirmation dialogue not shown, cannot delete previous findings')
49+
50+
logger.debug("page source when checking for no_findings element")
51+
logger.debug(self.driver.page_source)
52+
text = driver.find_element(By.ID, "no_findings").text
53+
54+
self.assertIsNotNone(text)
55+
self.assertTrue('No findings found.' in text)
56+
# check that user was redirect back to url where it came from based on return_url
57+
self.assertTrue(driver.current_url.endswith('page=1'))
58+
59+
# --------------------------------------------------------------------------------------------------------
60+
# Same scanner import - Close Old Findings on engagement
61+
# --------------------------------------------------------------------------------------------------------
62+
@on_exception_html_source_logger
63+
def test_add_same_engagement_engagement(self):
64+
logger.debug("Same scanner deduplication - Close Old Findings No Dedupe, Same Engagement - dynamic. Creating tests...")
65+
# Create engagement
66+
67+
driver = self.driver
68+
self.goto_product_overview(driver)
69+
driver.find_element(By.CSS_SELECTOR, ".dropdown-toggle.pull-left").click()
70+
driver.find_element(By.LINK_TEXT, "Add New Engagement").click()
71+
driver.find_element(By.ID, "id_name").send_keys("Close Same Engagement No Dedupe")
72+
driver.find_elements(By.CLASS_NAME, "btn-primary")[3].click()
73+
74+
self.assertTrue(self.is_success_message_present(text='Engagement added successfully.'))
75+
76+
# --------------------------------------------------------------------------------------------------------
77+
# Same scanner deduplication - Deduplication on engagement
78+
# Test deduplication for Immuniweb dynamic scanner
79+
# Tests importing findings from the same scanner, first test is the same report twice.
80+
# Second test contains only one of the original findings.
81+
# Uses the import feature
82+
# --------------------------------------------------------------------------------------------------------
83+
@on_exception_html_source_logger
84+
def test_import_same_engagement_tests(self):
85+
logger.debug("Importing reports...")
86+
# Imports into
87+
# First test : Immuniweb Scan (dynamic)
88+
89+
driver = self.driver
90+
self.goto_active_engagements_overview(driver)
91+
driver.find_element(By.PARTIAL_LINK_TEXT, "Close Same Engagement No Dedupe").click()
92+
driver.find_elements(By.CLASS_NAME, "btn-primary")[3].click()
93+
driver.find_element(By.LINK_TEXT, "Import Scan Results").click()
94+
scan_type = Select(driver.find_element(By.ID, "id_scan_type"))
95+
scan_type.select_by_visible_text("Immuniweb Scan")
96+
97+
scan_environment = Select(driver.find_element(By.ID, "id_environment"))
98+
scan_environment.select_by_visible_text("Development")
99+
driver.find_element(By.ID, "id_close_old_findings").click()
100+
driver.find_element(By.ID, "id_file").send_keys(self.relative_path + "/close_old_scans/closeold_nodedupe_1.xml")
101+
driver.find_elements(By.CLASS_NAME, "btn-primary")[1].click()
102+
103+
self.assertTrue(self.is_success_message_present(text='3 findings and closed 0 findings'))
104+
105+
# Second upload. Immuniweb again.
106+
# Same report.
107+
self.goto_active_engagements_overview(driver)
108+
driver.find_element(By.PARTIAL_LINK_TEXT, "Close Same Engagement No Dedupe").click()
109+
driver.find_elements(By.CLASS_NAME, "btn-primary")[3].click()
110+
driver.find_element(By.LINK_TEXT, "Import Scan Results").click()
111+
scan_type = Select(driver.find_element(By.ID, "id_scan_type"))
112+
scan_type.select_by_visible_text("Immuniweb Scan")
113+
114+
scan_environment = Select(driver.find_element(By.ID, "id_environment"))
115+
scan_environment.select_by_visible_text("Development")
116+
driver.find_element(By.ID, "id_close_old_findings").click()
117+
driver.find_element(By.ID, "id_file").send_keys(self.relative_path + "/close_old_scans/closeold_nodedupe_2.xml")
118+
driver.find_elements(By.CLASS_NAME, "btn-primary")[1].click()
119+
120+
self.assertTrue(self.is_success_message_present(text='3 findings and closed 3 findings'))
121+
122+
@on_exception_html_source_logger
123+
def test_close_same_engagement_tests(self):
124+
logger.debug("Importing reports...")
125+
# Second test : Immuniweb Scan (dynamic)
126+
# Should be run after test_import_same_engagement_tests()
127+
128+
driver = self.driver
129+
self.goto_active_engagements_overview(driver)
130+
driver.find_element(By.PARTIAL_LINK_TEXT, "Close Same Engagement No Dedupe").click()
131+
driver.find_elements(By.CLASS_NAME, "btn-primary")[3].click()
132+
driver.find_element(By.LINK_TEXT, "Import Scan Results").click()
133+
scan_type = Select(driver.find_element(By.ID, "id_scan_type"))
134+
scan_type.select_by_visible_text("Immuniweb Scan")
135+
136+
scan_environment = Select(driver.find_element(By.ID, "id_environment"))
137+
scan_environment.select_by_visible_text("Development")
138+
driver.find_element(By.ID, "id_close_old_findings").click()
139+
driver.find_element(By.ID, "id_file").send_keys(self.relative_path + "/dedupe_scans/dedupe_and_close_1.xml")
140+
driver.find_elements(By.CLASS_NAME, "btn-primary")[1].click()
141+
142+
self.assertTrue(self.is_success_message_present(text='1 findings and closed 3 findings'))
143+
144+
# --------------------------------------------------------------------------------------------------------
145+
# Same scanner deduplication - Deduplication on product
146+
# Test deduplication for Immuniweb dynamic scanner
147+
# --------------------------------------------------------------------------------------------------------
148+
149+
@on_exception_html_source_logger
150+
def test_add_same_product_engagement(self):
151+
logger.debug("Same scanner no deduplication - Close Old Findings Same Product - dynamic. Creating tests...")
152+
# Create engagement
153+
154+
driver = self.driver
155+
self.goto_product_overview(driver)
156+
driver.find_element(By.CSS_SELECTOR, ".dropdown-toggle.pull-left").click()
157+
driver.find_element(By.LINK_TEXT, "Add New Engagement").click()
158+
driver.find_element(By.ID, "id_name").send_keys("Close Same Product No Dedupe Test 1")
159+
driver.find_elements(By.CLASS_NAME, "btn-primary")[3].click()
160+
161+
self.assertTrue(self.is_success_message_present(text='Engagement added successfully.'))
162+
163+
self.goto_product_overview(driver)
164+
driver.find_element(By.CSS_SELECTOR, ".dropdown-toggle.pull-left").click()
165+
driver.find_element(By.LINK_TEXT, "Add New Engagement").click()
166+
driver.find_element(By.ID, "id_name").send_keys("Close Same Product No Dedupe Test 2")
167+
driver.find_elements(By.CLASS_NAME, "btn-primary")[3].click()
168+
169+
self.assertTrue(self.is_success_message_present(text='Engagement added successfully.'))
170+
171+
self.goto_product_overview(driver)
172+
driver.find_element(By.CSS_SELECTOR, ".dropdown-toggle.pull-left").click()
173+
driver.find_element(By.LINK_TEXT, "Add New Engagement").click()
174+
driver.find_element(By.ID, "id_name").send_keys("Close Same Product No Dedupe Test 3")
175+
driver.find_elements(By.CLASS_NAME, "btn-primary")[3].click()
176+
177+
self.assertTrue(self.is_success_message_present(text='Engagement added successfully.'))
178+
179+
# --------------------------------------------------------------------------------------------------------
180+
# Same scanner deduplication - Deduplication on product
181+
# Test deduplication for Immuniweb dynamic scanner
182+
# Tests importing findings from the same scanner, first test is the same report twice.
183+
# Second test contains only one of the original findings.
184+
# Uses the import feature
185+
# --------------------------------------------------------------------------------------------------------
186+
187+
@on_exception_html_source_logger
188+
def test_import_same_product_tests(self):
189+
logger.debug("Importing reports...")
190+
# First test : Immuniweb Scan (dynamic)
191+
192+
driver = self.driver
193+
self.goto_active_engagements_overview(driver)
194+
driver.find_element(By.PARTIAL_LINK_TEXT, "Close Same Product No Dedupe Test 1").click()
195+
driver.find_elements(By.CLASS_NAME, "btn-primary")[3].click()
196+
driver.find_element(By.LINK_TEXT, "Import Scan Results").click()
197+
scan_type = Select(driver.find_element(By.ID, "id_scan_type"))
198+
scan_type.select_by_visible_text("Immuniweb Scan")
199+
200+
scan_environment = Select(driver.find_element(By.ID, "id_environment"))
201+
scan_environment.select_by_visible_text("Development")
202+
driver.find_element(By.ID, "id_close_old_findings_product_scope").click()
203+
driver.find_element(By.ID, "id_file").send_keys(self.relative_path + "/close_old_scans/closeold_nodedupe_1.xml")
204+
driver.find_elements(By.CLASS_NAME, "btn-primary")[1].click()
205+
206+
self.assertTrue(self.is_success_message_present(text='3 findings and closed 0 findings'))
207+
208+
# Second upload. Immuniweb again.
209+
# Same report.
210+
self.goto_active_engagements_overview(driver)
211+
driver.find_element(By.PARTIAL_LINK_TEXT, "Close Same Product No Dedupe Test 2").click()
212+
driver.find_elements(By.CLASS_NAME, "btn-primary")[3].click()
213+
driver.find_element(By.LINK_TEXT, "Import Scan Results").click()
214+
scan_type = Select(driver.find_element(By.ID, "id_scan_type"))
215+
scan_type.select_by_visible_text("Immuniweb Scan")
216+
217+
scan_environment = Select(driver.find_element(By.ID, "id_environment"))
218+
scan_environment.select_by_visible_text("Development")
219+
driver.find_element(By.ID, "id_close_old_findings_product_scope").click()
220+
driver.find_element(By.ID, "id_file").send_keys(self.relative_path + "/close_old_scans/closeold_nodedupe_2.xml")
221+
driver.find_elements(By.CLASS_NAME, "btn-primary")[1].click()
222+
223+
self.assertTrue(self.is_success_message_present(text='3 findings and closed 3 findings'))
224+
225+
@on_exception_html_source_logger
226+
def test_close_same_product_tests(self):
227+
logger.debug("Importing reports...")
228+
# Second test : Immuniweb Scan (dynamic)
229+
# Should be run after test_import_same_engagement_tests()
230+
231+
driver = self.driver
232+
self.goto_active_engagements_overview(driver)
233+
driver.find_element(By.PARTIAL_LINK_TEXT, "Close Same Product No Dedupe Test 3").click()
234+
driver.find_elements(By.CLASS_NAME, "btn-primary")[3].click()
235+
driver.find_element(By.LINK_TEXT, "Import Scan Results").click()
236+
scan_type = Select(driver.find_element(By.ID, "id_scan_type"))
237+
scan_type.select_by_visible_text("Immuniweb Scan")
238+
239+
scan_environment = Select(driver.find_element(By.ID, "id_environment"))
240+
scan_environment.select_by_visible_text("Development")
241+
driver.find_element(By.ID, "id_close_old_findings_product_scope").click()
242+
driver.find_element(By.ID, "id_file").send_keys(self.relative_path + "/dedupe_scans/dedupe_and_close_1.xml")
243+
driver.find_elements(By.CLASS_NAME, "btn-primary")[1].click()
244+
245+
self.assertTrue(self.is_success_message_present(text='1 findings and closed 3 findings'))
246+
247+
248+
def add_close_old_tests_to_suite(suite, jira=False, github=False, block_execution=False):
249+
suite.addTest(BaseTestCase('test_login'))
250+
set_suite_settings(suite, jira=jira, github=github, block_execution=block_execution)
251+
252+
if jira:
253+
suite.addTest(BaseTestCase('enable_jira'))
254+
else:
255+
suite.addTest(BaseTestCase('disable_jira'))
256+
if github:
257+
suite.addTest(BaseTestCase('enable_github'))
258+
else:
259+
suite.addTest(BaseTestCase('disable_github'))
260+
if block_execution:
261+
suite.addTest(BaseTestCase('enable_block_execution'))
262+
else:
263+
suite.addTest(BaseTestCase('disable_block_execution'))
264+
265+
suite.addTest(ProductTest('test_create_product'))
266+
# Test same scanners - same engagement - dynamic - dedupe
267+
suite.addTest(CloseOldTest('test_delete_findings'))
268+
suite.addTest(CloseOldTest('test_add_same_engagement_engagement'))
269+
suite.addTest(CloseOldTest('test_import_same_engagement_tests'))
270+
suite.addTest(CloseOldTest('test_close_same_engagement_tests'))
271+
# Test same scanners - same product - dynamic - dedupe
272+
suite.addTest(CloseOldTest('test_delete_findings'))
273+
suite.addTest(CloseOldTest('test_add_same_product_engagement'))
274+
suite.addTest(CloseOldTest('test_import_same_product_tests'))
275+
suite.addTest(CloseOldTest('test_close_same_product_tests'))
276+
# Clean up
277+
suite.addTest(ProductTest('test_delete_product'))
278+
return suite
279+
280+
281+
def suite():
282+
suite = unittest.TestSuite()
283+
add_close_old_tests_to_suite(suite, jira=False, github=False, block_execution=False)
284+
add_close_old_tests_to_suite(suite, jira=True, github=True, block_execution=True)
285+
return suite
286+
287+
288+
if __name__ == "__main__":
289+
runner = unittest.TextTestRunner(descriptions=True, failfast=True, verbosity=2)
290+
ret = not runner.run(suite()).wasSuccessful()
291+
BaseTestCase.tearDownDriver()
292+
sys.exit(ret)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Vulnerabilities>
3+
<Vulnerability>
4+
<ID></ID>
5+
<Name>Finding 1</Name>
6+
<Date></Date>
7+
<Status></Status>
8+
<Type></Type>
9+
<CWE-ID>CWE-23</CWE-ID>
10+
<CVE-ID></CVE-ID>
11+
<CVSSv3></CVSSv3>
12+
<Risk>CRITICAL</Risk>
13+
<URL>https://www.same.com/samesies</URL>
14+
<Description>Test Description</Description>
15+
<PoC></PoC>
16+
</Vulnerability>
17+
18+
<Vulnerability>
19+
<ID></ID>
20+
<Name>Finding 2</Name>
21+
<Date></Date>
22+
<Status></Status>
23+
<Type></Type>
24+
<CWE-ID>CWE-23</CWE-ID>
25+
<CVE-ID></CVE-ID>
26+
<CVSSv3></CVSSv3>
27+
<Risk>CRITICAL</Risk>
28+
<URL>https://www.same.com/samesies</URL>
29+
<Description>Finding 2</Description>
30+
<PoC></PoC>
31+
</Vulnerability>
32+
33+
<Vulnerability>
34+
<ID></ID>
35+
<Name>Finding 3</Name>
36+
<Date></Date>
37+
<Status></Status>
38+
<Type></Type>
39+
<CWE-ID>CWE-23</CWE-ID>
40+
<CVE-ID></CVE-ID>
41+
<CVSSv3></CVSSv3>
42+
<Risk>CRITICAL</Risk>
43+
<URL>https://www.same.com/samesies</URL>
44+
<Description>Finding 3</Description>
45+
<PoC></PoC>
46+
</Vulnerability>
47+
48+
</Vulnerabilities>

0 commit comments

Comments
 (0)