@@ -195,10 +195,10 @@ def create_security_comment_sarif(diff) -> dict:
195
195
scan_failed = False
196
196
if len (diff .new_alerts ) == 0 :
197
197
for alert in diff .new_alerts :
198
- alert : Issue
199
198
if alert .error :
200
199
scan_failed = True
201
200
break
201
+
202
202
sarif_data = {
203
203
"$schema" : "https://json.schemastore.org/sarif-2.1.0.json" ,
204
204
"version" : "2.1.0" ,
@@ -225,21 +225,27 @@ def create_security_comment_sarif(diff) -> dict:
225
225
rule_id = f"{ pkg_name } =={ pkg_version } "
226
226
severity = alert .severity
227
227
228
- # Generate the correct URL for the alert based on manifest type
229
- introduced_list = alert .introduced_by
230
- manifest_file = introduced_list [0 ][1 ] if introduced_list and isinstance (introduced_list [0 ], list ) else alert .manifests or "requirements.txt"
231
- socket_url = Messages .get_manifest_type_url (manifest_file , pkg_name , pkg_version )
228
+ # --- NEW LOGIC: Determine the list of manifest files ---
229
+ if alert .introduced_by and isinstance (alert .introduced_by [0 ], list ):
230
+ # Extract file names from each introduced_by entry
231
+ manifest_files = [entry [1 ] for entry in alert .introduced_by ]
232
+ elif alert .manifests :
233
+ # Split semicolon-delimited manifest string if necessary
234
+ manifest_files = [mf .strip () for mf in alert .manifests .split (";" )]
235
+ else :
236
+ manifest_files = ["requirements.txt" ]
232
237
233
- # Prepare descriptions with <br/> replacements
234
- short_desc = f"{ alert .props .get ('note' , '' )} <br/><br/>Suggested Action:<br/>{ alert .suggestion } <br/><a href=\" { socket_url } \" >{ socket_url } </a>"
235
- full_desc = "{} - {}" .format (alert .title , alert .description .replace ('\r \n ' , '<br/>' ))
238
+ # Use the first file for generating the help URL.
239
+ socket_url = Messages .get_manifest_type_url (manifest_files [0 ], pkg_name , pkg_version )
236
240
237
- # Identify the line and snippet in the manifest file
238
- line_number , line_content = Messages .find_line_in_file (pkg_name , pkg_version , manifest_file )
239
- if line_number < 1 :
240
- line_number = 1 # Ensure SARIF compliance
241
+ # Prepare the description messages.
242
+ short_desc = (
243
+ f"{ alert .props .get ('note' , '' )} <br/><br/>Suggested Action:<br/>"
244
+ f"{ alert .suggestion } <br/><a href=\" { socket_url } \" >{ socket_url } </a>"
245
+ )
246
+ full_desc = "{} - {}" .format (alert .title , alert .description .replace ('\r \n ' , '<br/>' ))
241
247
242
- # Create the rule if not already defined
248
+ # Create the rule if not already defined.
243
249
if rule_id not in rules_map :
244
250
rules_map [rule_id ] = {
245
251
"id" : rule_id ,
@@ -252,25 +258,31 @@ def create_security_comment_sarif(diff) -> dict:
252
258
},
253
259
}
254
260
255
- # Add the SARIF result
261
+ # --- NEW LOGIC: Create separate locations for each manifest file ---
262
+ locations = []
263
+ for mf in manifest_files :
264
+ line_number , line_content = Messages .find_line_in_file (pkg_name , pkg_version , mf )
265
+ if line_number < 1 :
266
+ line_number = 1 # Ensure SARIF compliance.
267
+ locations .append ({
268
+ "physicalLocation" : {
269
+ "artifactLocation" : {"uri" : mf },
270
+ "region" : {
271
+ "startLine" : line_number ,
272
+ "snippet" : {"text" : line_content },
273
+ },
274
+ }
275
+ })
276
+
277
+ # Add the SARIF result.
256
278
result_obj = {
257
279
"ruleId" : rule_id ,
258
280
"message" : {"text" : short_desc },
259
- "locations" : [
260
- {
261
- "physicalLocation" : {
262
- "artifactLocation" : {"uri" : manifest_file },
263
- "region" : {
264
- "startLine" : line_number ,
265
- "snippet" : {"text" : line_content },
266
- },
267
- }
268
- }
269
- ],
281
+ "locations" : locations ,
270
282
}
271
283
results_list .append (result_obj )
272
284
273
- # Attach rules and results
285
+ # Attach rules and results.
274
286
sarif_data ["runs" ][0 ]["tool" ]["driver" ]["rules" ] = list (rules_map .values ())
275
287
sarif_data ["runs" ][0 ]["results" ] = results_list
276
288
0 commit comments