Skip to content

Commit a4e5698

Browse files
author
Tejas Saubhage
committed
test(qualys): add unit test for same QID different ports deduplication fix
- Add test XML with same QID on ports 80, 443, 8080 - Add test verifying each port gets its own endpoint - Add 2.57.x release notes mentioning the fix Addresses review feedback from @Maffooch on PR #14528
1 parent 4bfd7e4 commit a4e5698

File tree

3 files changed

+110
-0
lines changed

3 files changed

+110
-0
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
title: "Upgrading to DefectDojo Version 2.57.x"
3+
toc_hide: true
4+
weight: -20570
5+
description: No special instructions.
6+
---
7+
8+
## Upgrading to DefectDojo Version 2.57.x
9+
10+
There are no special upgrade instructions for this release.
11+
12+
## Release Notes
13+
14+
### Bug Fixes
15+
16+
- **Qualys Parser**: Fixed an issue where findings with the same QID but different ports were being collapsed into a single finding. Each QID+port combination now correctly gets its own endpoint, preserving port-level granularity without affecting finding titles or deduplication. ([#13682](https://github.com/DefectDojo/django-DefectDojo/issues/13682))
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<ASSET_DATA_REPORT>
3+
<HEADER>
4+
<COMPANY><![CDATA[Test Company]]></COMPANY>
5+
<REPORT_FILTERS>
6+
<COMBINED_IP_LIST>
7+
<RANGE>
8+
<START>192.168.1.1</START>
9+
<END>192.168.1.1</END>
10+
</RANGE>
11+
</COMBINED_IP_LIST>
12+
</REPORT_FILTERS>
13+
</HEADER>
14+
<GLOSSARY>
15+
<VULN_DETAILS_LIST>
16+
<VULN_DETAILS id="qid_12345">
17+
<QID id="qid_12345">12345</QID>
18+
<TITLE><![CDATA[Test Vulnerability]]></TITLE>
19+
<SEVERITY>3</SEVERITY>
20+
<CATEGORY><![CDATA[Test]]></CATEGORY>
21+
<LAST_UPDATE>2024-01-01T00:00:00Z</LAST_UPDATE>
22+
<DIAGNOSIS><![CDATA[Test diagnosis]]></DIAGNOSIS>
23+
<SOLUTION><![CDATA[Test solution]]></SOLUTION>
24+
</VULN_DETAILS>
25+
</VULN_DETAILS_LIST>
26+
</GLOSSARY>
27+
<HOST_LIST>
28+
<HOST>
29+
<IP>192.168.1.1</IP>
30+
<TRACKING_METHOD>IP</TRACKING_METHOD>
31+
<DNS><![CDATA[testhost.example.com]]></DNS>
32+
<OS><![CDATA[Linux]]></OS>
33+
<LAST_SCAN_DATETIME>2024-01-01T00:00:00Z</LAST_SCAN_DATETIME>
34+
<VULN_INFO_LIST>
35+
<VULN_INFO>
36+
<QID id="qid_12345">12345</QID>
37+
<TYPE>Practice</TYPE>
38+
<PORT>80</PORT>
39+
<SSL>false</SSL>
40+
<RESULT format="table"><![CDATA[Test result on port 80]]></RESULT>
41+
<FIRST_FOUND>2024-01-01T00:00:00Z</FIRST_FOUND>
42+
<LAST_FOUND>2024-01-01T00:00:00Z</LAST_FOUND>
43+
<TIMES_FOUND>1</TIMES_FOUND>
44+
</VULN_INFO>
45+
<VULN_INFO>
46+
<QID id="qid_12345">12345</QID>
47+
<TYPE>Practice</TYPE>
48+
<PORT>443</PORT>
49+
<SSL>true</SSL>
50+
<RESULT format="table"><![CDATA[Test result on port 443]]></RESULT>
51+
<FIRST_FOUND>2024-01-01T00:00:00Z</FIRST_FOUND>
52+
<LAST_FOUND>2024-01-01T00:00:00Z</LAST_FOUND>
53+
<TIMES_FOUND>1</TIMES_FOUND>
54+
</VULN_INFO>
55+
<VULN_INFO>
56+
<QID id="qid_12345">12345</QID>
57+
<TYPE>Practice</TYPE>
58+
<PORT>8080</PORT>
59+
<SSL>false</SSL>
60+
<RESULT format="table"><![CDATA[Test result on port 8080]]></RESULT>
61+
<FIRST_FOUND>2024-01-01T00:00:00Z</FIRST_FOUND>
62+
<LAST_FOUND>2024-01-01T00:00:00Z</LAST_FOUND>
63+
<TIMES_FOUND>1</TIMES_FOUND>
64+
</VULN_INFO>
65+
</VULN_INFO_LIST>
66+
</HOST>
67+
</HOST_LIST>
68+
</ASSET_DATA_REPORT>

unittests/tools/test_qualys_parser.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,3 +239,29 @@ def test_get_severity(self):
239239
}
240240

241241
self.assertEqual(expected_counts, counts)
242+
243+
def test_parse_file_same_qid_different_ports_has_separate_endpoints(self):
244+
"""Test that findings with same QID but different ports get separate endpoints.
245+
Regression test for https://github.com/DefectDojo/django-DefectDojo/issues/13682
246+
"""
247+
with (
248+
get_unit_tests_scans_path("qualys") / "qualys_same_qid_different_ports.xml").open(encoding="utf-8",
249+
) as testfile:
250+
parser = QualysParser()
251+
findings = parser.get_findings(testfile, Test())
252+
self.validate_locations(findings)
253+
# Same QID on 3 different ports should produce 3 separate findings
254+
self.assertEqual(3, len(findings))
255+
# All findings should have the same title (QID unchanged)
256+
for finding in findings:
257+
self.assertEqual(finding.title, "QID-12345 | Test Vulnerability")
258+
# Each finding should have a different port on its endpoint
259+
ports = set()
260+
for finding in findings:
261+
locations = self.get_unsaved_locations(finding)
262+
self.assertEqual(1, len(locations))
263+
self.assertEqual(locations[0].host, "testhost.example.com")
264+
ports.add(locations[0].port)
265+
# All 3 ports should be present
266+
self.assertEqual({80, 443, 8080}, ports)
267+

0 commit comments

Comments
 (0)