@@ -82,7 +82,11 @@ def find_line_in_file(packagename: str, packageversion: str, manifest_file: str)
82
82
needle_key = f'"{ found_key } ":' # e.g. "node_modules/axios":
83
83
needle_version = f'"version": "{ packageversion } "'
84
84
lines = raw_text .splitlines ()
85
+ < << << << HEAD
85
86
best_line = 1
87
+ == == == =
88
+ best_line = - 1
89
+ > >> >> >> 7 ddb4537518fa762da7ebebff2044ce71e720f3c
86
90
snippet = None
87
91
88
92
for i , line in enumerate (lines , start = 1 ):
@@ -97,10 +101,17 @@ def find_line_in_file(packagename: str, packageversion: str, manifest_file: str)
97
101
else :
98
102
return 1 , f'"{ found_key } ": { found_info } '
99
103
else :
104
+ << << << < HEAD
100
105
return 1 , f"{ packagename } { packageversion } (not found in { manifest_file } )"
101
106
102
107
except (FileNotFoundError , json .JSONDecodeError ):
103
108
return 1 , f"Error reading { manifest_file } "
109
+ == == == =
110
+ return - 1 , f"{ packagename } { packageversion } (not found in { manifest_file } )"
111
+
112
+ except (FileNotFoundError , json .JSONDecodeError ):
113
+ return - 1 , f"Error reading { manifest_file } "
114
+ >> >> >> > 7 ddb4537518fa762da7ebebff2044ce71e720f3c
104
115
105
116
# ----------------------------------------------------
106
117
# 2) Text-based / line-based manifests
@@ -142,6 +153,7 @@ def find_line_in_file(packagename: str, packageversion: str, manifest_file: str)
142
153
for line_number , line_content in enumerate (lines , start = 1 ):
143
154
# For Python conditional dependencies, ignore everything after first ';'
144
155
line_main = line_content .split (";" , 1 )[0 ].strip ()
156
+ << << << < HEAD
145
157
146
158
# Use a case-insensitive regex search
147
159
if re .search (searchstring , line_main , re .IGNORECASE ):
@@ -191,6 +203,36 @@ def create_security_comment_sarif(diff) -> dict:
191
203
Create SARIF-compliant output from the diff report, including dynamic URL generation
192
204
based on manifest type and improved <br/> formatting for GitHub SARIF display.
193
205
"""
206
+ == == == =
207
+
208
+ # Use a case-insensitive regex search
209
+ if re .search (searchstring , line_main , re .IGNORECASE ):
210
+ return line_number , line_content .strip ()
211
+
212
+ except FileNotFoundError :
213
+ return - 1 , f"{ manifest_file } not found"
214
+ except Exception as e :
215
+ return - 1 , f"Error reading { manifest_file } : { e } "
216
+
217
+ return - 1 , f"{ packagename } { packageversion } (not found)"
218
+
219
+ @staticmethod
220
+ def create_security_comment_sarif (diff : Diff ) -> dict :
221
+ """
222
+ Create SARIF-compliant output from the diff report, including line references
223
+ and a link to the Socket docs in the fullDescription. Also converts any \r \n
224
+ into <br/> so they render properly in GitHub's SARIF display.
225
+ """
226
+ # Check if there's a blocking error in new alerts
227
+ scan_failed = False
228
+ if len (diff .new_alerts ) == 0 :
229
+ for alert in diff .new_alerts :
230
+ if alert .error :
231
+ scan_failed = True
232
+ break
233
+
234
+ # Basic SARIF skeleton
235
+ > >> >> >> 7 ddb4537518fa762da7ebebff2044ce71e720f3c
194
236
sarif_data = {
195
237
"$schema" : "https://json.schemastore.org/sarif-2.1.0.json" ,
196
238
"version" : "2.1.0" ,
@@ -217,11 +259,27 @@ def create_security_comment_sarif(diff) -> dict:
217
259
rule_id = f"{ pkg_name } =={ pkg_version } "
218
260
severity = alert .severity
219
261
262
+ < << << << HEAD
220
263
# Generate the correct URL for the alert based on manifest type
264
+ == == == =
265
+ # Convert any \r\n in short desc to <br/> so they display properly
266
+ short_desc_raw = f"{ alert .props .get ('note' , '' )} \r \n \r \n Suggested Action:\r \n { alert .suggestion } "
267
+ short_desc = short_desc_raw .replace ("\r \n " , "<br/>" )
268
+
269
+ # Build link to Socket docs, e.g. "https://socket.dev/npm/package/foo/alerts/1.2.3"
270
+ socket_url = f"https://socket.dev/npm/package/{ pkg_name } /alerts/{ pkg_version } "
271
+
272
+ # Also convert \r\n in the main description to <br/>, then append the Socket docs link
273
+ base_desc = alert .description .replace ("\r \n " , "<br/>" )
274
+ full_desc_raw = f"{ alert .title } - { base_desc } <br/>{ socket_url } "
275
+
276
+ # Identify the manifest file and line
277
+ >> >> >> > 7 ddb4537518fa762da7ebebff2044ce71e720f3c
221
278
introduced_list = alert .introduced_by
222
279
manifest_file = introduced_list [0 ][1 ] if introduced_list and isinstance (introduced_list [0 ], list ) else alert .manifests or "requirements.txt"
223
280
socket_url = Messages .get_manifest_type_url (manifest_file , pkg_name , pkg_version )
224
281
282
+ < << << << HEAD
225
283
# Prepare descriptions with <br/> replacements
226
284
short_desc = f"{ alert .props .get ('note' , '' )} <br/><br/>Suggested Action:<br/>{ alert .suggestion } "
227
285
full_desc = f"{ alert .title } - { alert .description .replace ('\r \n ' , '<br/>' )} \r \n <a href=\" { socket_url } \" >{ socket_url } </a>"
@@ -232,19 +290,33 @@ def create_security_comment_sarif(diff) -> dict:
232
290
line_number = 1 # Ensure SARIF compliance
233
291
234
292
# Create the rule if not already defined
293
+ == == == =
294
+ line_number , line_content = Messages .find_line_in_file (pkg_name , pkg_version , manifest_file )
295
+
296
+ # If not already defined, create a rule for this package
297
+ > >> >> >> 7 ddb4537518fa762da7ebebff2044ce71e720f3c
235
298
if rule_id not in rules_map :
236
299
rules_map [rule_id ] = {
237
300
"id" : rule_id ,
238
301
"name" : f"{ pkg_name } =={ pkg_version } " ,
239
302
"shortDescription" : {"text" : f"Alert generated for { rule_id } by Socket Security" },
303
+ << << << < HEAD
240
304
"fullDescription" : {"text" : full_desc },
241
305
"helpUri" : socket_url ,
306
+ == == == =
307
+ "fullDescription" : {"text" : full_desc_raw },
308
+ "helpUri" : alert .url ,
309
+ > >> >> >> 7 ddb4537518fa762da7ebebff2044ce71e720f3c
242
310
"defaultConfiguration" : {
243
311
"level" : Messages .map_severity_to_sarif (severity )
244
312
},
245
313
}
246
314
315
+ << << << < HEAD
247
316
# Add the SARIF result
317
+ == == == =
318
+ # Create a SARIF "result" referencing the line where we found the match
319
+ >> >> >> > 7 ddb4537518fa762da7ebebff2044ce71e720f3c
248
320
result_obj = {
249
321
"ruleId" : rule_id ,
250
322
"message" : {"text" : short_desc },
@@ -262,7 +334,11 @@ def create_security_comment_sarif(diff) -> dict:
262
334
}
263
335
results_list .append (result_obj )
264
336
337
+ < << << << HEAD
265
338
# Attach rules and results
339
+ == == == =
340
+ # Attach our rules and results to the SARIF data
341
+ >> >> >> > 7 ddb4537518fa762da7ebebff2044ce71e720f3c
266
342
sarif_data ["runs" ][0 ]["tool" ]["driver" ]["rules" ] = list (rules_map .values ())
267
343
sarif_data ["runs" ][0 ]["results" ] = results_list
268
344
0 commit comments