Skip to content

Commit 42d07bc

Browse files
committed
change fortify parser to prefer true line
1 parent 6cbc85e commit 42d07bc

2 files changed

Lines changed: 46 additions & 15 deletions

File tree

dojo/tools/fortify/fpr_parser.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,10 @@ def compute_status(self, related_data, vulnerability) -> tuple[bool, bool]:
334334
return True, False
335335

336336
def compute_line(self, vulnerability, snippet) -> str:
337+
# Prefer the line Fortify reports for the vulnerability itself; the snippet
338+
# StartLine includes leading context lines and does not point at the finding.
339+
if vulnerability.source_location_line:
340+
return vulnerability.source_location_line
337341
if snippet and snippet.start_line:
338342
return snippet.start_line
339-
return vulnerability.source_location_line
343+
return None

unittests/tools/test_fortify_parser.py

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -93,18 +93,18 @@ def test_fortify_many_fdr_findings(self):
9393

9494
with self.subTest(i=0):
9595
finding = findings[0]
96-
self.assertEqual("Cross-Site Request Forgery - category.html: 219 (114E5A67-3446-4DD5-B578-D0E6FDBB304E)", finding.title)
96+
self.assertEqual("Cross-Site Request Forgery - category.html: 222 (114E5A67-3446-4DD5-B578-D0E6FDBB304E)", finding.title)
9797
self.assertEqual("Low", finding.severity)
9898
self.assertEqual("1B87289954501EF8FD3861819DD98C27", finding.unique_id_from_tool)
9999
self.assertEqual("public/category.html", finding.file_path)
100-
self.assertEqual(219, finding.line)
100+
self.assertEqual(222, finding.line)
101101
with self.subTest(i=1):
102102
finding = findings[50]
103-
self.assertEqual("Insecure Transport - footer.html: 104 (C72A3E77-8324-4FF9-B958-74FCDDF39D17)", finding.title)
103+
self.assertEqual("Insecure Transport - footer.html: 107 (C72A3E77-8324-4FF9-B958-74FCDDF39D17)", finding.title)
104104
self.assertEqual("Medium", finding.severity)
105105
self.assertEqual("D739B2E51B127BDFA4FE07B5A7662A45", finding.unique_id_from_tool)
106106
self.assertEqual("public/footer.html", finding.file_path)
107-
self.assertEqual(104, finding.line)
107+
self.assertEqual(107, finding.line)
108108

109109
def test_fortify_hello_world_fpr_findings(self):
110110
with (get_unit_tests_scans_path("fortify") / "hello_world.fpr").open(encoding="utf-8") as testfile:
@@ -117,18 +117,45 @@ def test_fortify_hello_world_fpr_findings(self):
117117

118118
with self.subTest(i=0):
119119
finding = findings[0]
120-
self.assertEqual("Password Management - HelloWorld.java: 5 (720E3A66-55AC-4D2D-8DB9-DC30E120A52F)", finding.title)
120+
self.assertEqual("Password Management - HelloWorld.java: 8 (720E3A66-55AC-4D2D-8DB9-DC30E120A52F)", finding.title)
121121
self.assertEqual("Low", finding.severity)
122122
self.assertEqual("A5338E223E737FF81F8A806C50A05969", finding.unique_id_from_tool)
123123
self.assertEqual("src/main/java/hello/HelloWorld.java", finding.file_path)
124-
self.assertEqual(5, finding.line)
124+
self.assertEqual(8, finding.line)
125125
with self.subTest(i=1):
126126
finding = findings[1]
127-
self.assertEqual("Password Management - HelloWorld.java: 13 (9C5BD1B5-C296-48d4-B5F5-5D2958661BC4)", finding.title)
127+
self.assertEqual("Password Management - HelloWorld.java: 16 (9C5BD1B5-C296-48d4-B5F5-5D2958661BC4)", finding.title)
128128
self.assertEqual("High", finding.severity)
129129
self.assertEqual("D3166922519EDD92D132761602EB71B4", finding.unique_id_from_tool)
130130
self.assertEqual("src/main/java/hello/HelloWorld.java", finding.file_path)
131-
self.assertEqual(13, finding.line)
131+
self.assertEqual(16, finding.line)
132+
133+
# Regression: FPR parser stored the snippet context StartLine (reported line - 3)
134+
# instead of Fortify's reported SourceLocation line, breaking file_path+line dedup.
135+
def test_fortify_fpr_uses_true_source_location_line(self):
136+
with (get_unit_tests_scans_path("fortify") / "many_findings.fpr").open(encoding="utf-8") as testfile:
137+
parser = FortifyParser()
138+
findings = parser.get_findings(testfile, Test())
139+
finding = findings[0]
140+
# control: the description records Fortify's reported line verbatim
141+
self.assertIn("**SourceLocationLine:** 222", finding.description)
142+
# the stored line must match the reported line, not the snippet start (219)
143+
self.assertEqual(
144+
222, finding.line,
145+
msg=f"expected line=222 (SourceLocationLine), stored line={finding.line}",
146+
)
147+
self.assertEqual("Cross-Site Request Forgery - category.html: 222 (114E5A67-3446-4DD5-B578-D0E6FDBB304E)", finding.title)
148+
with (get_unit_tests_scans_path("fortify") / "hello_world.fpr").open(encoding="utf-8") as testfile:
149+
parser = FortifyParser()
150+
findings = parser.get_findings(testfile, Test())
151+
# near the top of a file the snippet start clamps to 1, so the offset
152+
# is not even constant: reported line 3, snippet start 1
153+
finding = findings[2]
154+
self.assertIn("**SourceLocationLine:** 3", finding.description)
155+
self.assertEqual(
156+
3, finding.line,
157+
msg=f"expected line=3 (SourceLocationLine), stored line={finding.line}",
158+
)
132159

133160
def test_fortify_webinspect_4_2_many_findings(self):
134161
with (get_unit_tests_scans_path("fortify") / "webinspect_4_2_many_findings.xml").open(encoding="utf-8") as testfile:
@@ -152,14 +179,14 @@ def test_fortify_fpr_suppressed_finding(self):
152179

153180
with self.subTest(i=0):
154181
finding = findings[0]
155-
self.assertEqual("Password Management - HelloWorld.java: 5 (720E3A66-55AC-4D2D-8DB9-DC30E120A52F)", finding.title)
182+
self.assertEqual("Password Management - HelloWorld.java: 8 (720E3A66-55AC-4D2D-8DB9-DC30E120A52F)", finding.title)
156183
self.assertEqual("A5338E223E737FF81F8A806C50A05969", finding.unique_id_from_tool)
157184
self.assertTrue(finding.active)
158185
self.assertFalse(finding.false_p)
159186
self.assertEqual("", finding.impact)
160187
with self.subTest(i=1):
161188
finding = findings[2]
162-
self.assertEqual("Build Misconfiguration - pom.xml: 1 (FF57412F-DD28-44DE-8F4F-0AD39620768C)", finding.title)
189+
self.assertEqual("Build Misconfiguration - pom.xml: 3 (FF57412F-DD28-44DE-8F4F-0AD39620768C)", finding.title)
163190
self.assertEqual("87E3EC5CC8154C006783CC461A6DDEEB", finding.unique_id_from_tool)
164191
self.assertFalse(finding.active)
165192
self.assertTrue(finding.false_p)
@@ -176,16 +203,16 @@ def test_fortify_hello_world_fpr_rule_without_metainfo(self):
176203

177204
with self.subTest(i=0):
178205
finding = findings[0]
179-
self.assertEqual("Password Management - HelloWorld.java: 5 (720E3A66-55AC-4D2D-8DB9-DC30E120A52F)", finding.title)
206+
self.assertEqual("Password Management - HelloWorld.java: 8 (720E3A66-55AC-4D2D-8DB9-DC30E120A52F)", finding.title)
180207
# Info as rule has no metainfo/impact
181208
self.assertEqual("Info", finding.severity)
182209
self.assertEqual("A5338E223E737FF81F8A806C50A05969", finding.unique_id_from_tool)
183210
self.assertEqual("src/main/java/hello/HelloWorld.java", finding.file_path)
184-
self.assertEqual(5, finding.line)
211+
self.assertEqual(8, finding.line)
185212
with self.subTest(i=1):
186213
finding = findings[1]
187-
self.assertEqual("Password Management - HelloWorld.java: 13 (9C5BD1B5-C296-48d4-B5F5-5D2958661BC4)", finding.title)
214+
self.assertEqual("Password Management - HelloWorld.java: 16 (9C5BD1B5-C296-48d4-B5F5-5D2958661BC4)", finding.title)
188215
self.assertEqual("High", finding.severity)
189216
self.assertEqual("D3166922519EDD92D132761602EB71B4", finding.unique_id_from_tool)
190217
self.assertEqual("src/main/java/hello/HelloWorld.java", finding.file_path)
191-
self.assertEqual(13, finding.line)
218+
self.assertEqual(16, finding.line)

0 commit comments

Comments
 (0)