@@ -82,7 +82,7 @@ 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
- best_line = - 1
85
+ best_line = 1
86
86
snippet = None
87
87
88
88
for i , line in enumerate (lines , start = 1 ):
@@ -97,10 +97,10 @@ def find_line_in_file(packagename: str, packageversion: str, manifest_file: str)
97
97
else :
98
98
return 1 , f'"{ found_key } ": { found_info } '
99
99
else :
100
- return - 1 , f"{ packagename } { packageversion } (not found in { manifest_file } )"
100
+ return 1 , f"{ packagename } { packageversion } (not found in { manifest_file } )"
101
101
102
102
except (FileNotFoundError , json .JSONDecodeError ):
103
- return - 1 , f"Error reading { manifest_file } "
103
+ return 1 , f"Error reading { manifest_file } "
104
104
105
105
# ----------------------------------------------------
106
106
# 2) Text-based / line-based manifests
@@ -148,28 +148,49 @@ def find_line_in_file(packagename: str, packageversion: str, manifest_file: str)
148
148
return line_number , line_content .strip ()
149
149
150
150
except FileNotFoundError :
151
- return - 1 , f"{ manifest_file } not found"
151
+ return 1 , f"{ manifest_file } not found"
152
152
except Exception as e :
153
- return - 1 , f"Error reading { manifest_file } : { e } "
153
+ return 1 , f"Error reading { manifest_file } : { e } "
154
154
155
- return - 1 , f"{ packagename } { packageversion } (not found)"
155
+ return 1 , f"{ packagename } { packageversion } (not found)"
156
156
157
157
@staticmethod
158
- def create_security_comment_sarif ( diff : Diff ) -> dict :
158
+ def get_manifest_type_url ( manifest_file : str , pkg_name : str , pkg_version : str ) -> str :
159
159
"""
160
- Create SARIF-compliant output from the diff report, including line references
161
- and a link to the Socket docs in the fullDescription. Also converts any \r \n
162
- into <br/> so they render properly in GitHub's SARIF display.
160
+ Determine the correct URL path based on the manifest file type.
163
161
"""
164
- # Check if there's a blocking error in new alerts
165
- scan_failed = False
166
- if len (diff .new_alerts ) == 0 :
167
- for alert in diff .new_alerts :
168
- if alert .error :
169
- scan_failed = True
170
- break
162
+ manifest_to_url_prefix = {
163
+ "package.json" : "npm" ,
164
+ "package-lock.json" : "npm" ,
165
+ "yarn.lock" : "npm" ,
166
+ "pnpm-lock.yaml" : "npm" ,
167
+ "requirements.txt" : "pypi" ,
168
+ "pyproject.toml" : "pypi" ,
169
+ "Pipfile" : "pypi" ,
170
+ "go.mod" : "go" ,
171
+ "go.sum" : "go" ,
172
+ "pom.xml" : "maven" ,
173
+ "build.gradle" : "maven" ,
174
+ ".csproj" : "nuget" ,
175
+ ".fsproj" : "nuget" ,
176
+ "paket.dependencies" : "nuget" ,
177
+ "Cargo.toml" : "cargo" ,
178
+ "Gemfile" : "rubygems" ,
179
+ "Gemfile.lock" : "rubygems" ,
180
+ "composer.json" : "composer" ,
181
+ "vcpkg.json" : "vcpkg" ,
182
+ }
183
+
184
+ file_type = Path (manifest_file ).name
185
+ url_prefix = manifest_to_url_prefix .get (file_type , "unknown" )
186
+ return f"https://socket.dev/{ url_prefix } /package/{ pkg_name } /alerts/{ pkg_version } "
171
187
172
- # Basic SARIF skeleton
188
+ @staticmethod
189
+ def create_security_comment_sarif (diff ) -> dict :
190
+ """
191
+ Create SARIF-compliant output from the diff report, including dynamic URL generation
192
+ based on manifest type and improved <br/> formatting for GitHub SARIF display.
193
+ """
173
194
sarif_data = {
174
195
"$schema" : "https://json.schemastore.org/sarif-2.1.0.json" ,
175
196
"version" : "2.1.0" ,
@@ -196,40 +217,34 @@ def create_security_comment_sarif(diff: Diff) -> dict:
196
217
rule_id = f"{ pkg_name } =={ pkg_version } "
197
218
severity = alert .severity
198
219
199
- # Convert any \r\n in short desc to <br/> so they display properly
200
- short_desc_raw = f"{ alert .props .get ('note' , '' )} \r \n \r \n Suggested Action:\r \n { alert .suggestion } "
201
- short_desc = short_desc_raw .replace ("\r \n " , "<br/>" )
202
-
203
- # Build link to Socket docs, e.g. "https://socket.dev/npm/package/foo/alerts/1.2.3"
204
- socket_url = f"https://socket.dev/npm/package/{ pkg_name } /alerts/{ pkg_version } "
205
-
206
- # Also convert \r\n in the main description to <br/>, then append the Socket docs link
207
- base_desc = alert .description .replace ("\r \n " , "<br/>" )
208
- full_desc_raw = f"{ alert .title } - { base_desc } <br/>{ socket_url } "
209
-
210
- # Identify the manifest file and line
220
+ # Generate the correct URL for the alert based on manifest type
211
221
introduced_list = alert .introduced_by
212
- if introduced_list and isinstance (introduced_list [0 ], list ) and len (introduced_list [0 ]) > 1 :
213
- manifest_file = introduced_list [0 ][1 ]
214
- else :
215
- manifest_file = alert .manifests or "requirements.txt"
222
+ manifest_file = introduced_list [0 ][1 ] if introduced_list and isinstance (introduced_list [0 ], list ) else alert .manifests or "requirements.txt"
223
+ socket_url = Messages .get_manifest_type_url (manifest_file , pkg_name , pkg_version )
224
+
225
+ # Prepare descriptions with <br/> replacements
226
+ short_desc = f"{ alert .props .get ('note' , '' )} <br/><br/>Suggested Action:<br/>{ alert .suggestion } <br/><a href=\" { socket_url } \" >{ socket_url } </a>"
227
+ full_desc = f"{ alert .title } - { alert .description .replace ('\r \n ' , '<br/>' )} "
216
228
229
+ # Identify the line and snippet in the manifest file
217
230
line_number , line_content = Messages .find_line_in_file (pkg_name , pkg_version , manifest_file )
231
+ if line_number < 1 :
232
+ line_number = 1 # Ensure SARIF compliance
218
233
219
- # If not already defined, create a rule for this package
234
+ # Create the rule if not already defined
220
235
if rule_id not in rules_map :
221
236
rules_map [rule_id ] = {
222
237
"id" : rule_id ,
223
238
"name" : f"{ pkg_name } =={ pkg_version } " ,
224
239
"shortDescription" : {"text" : f"Alert generated for { rule_id } by Socket Security" },
225
- "fullDescription" : {"text" : full_desc_raw },
226
- "helpUri" : alert . url ,
240
+ "fullDescription" : {"text" : full_desc },
241
+ "helpUri" : socket_url ,
227
242
"defaultConfiguration" : {
228
243
"level" : Messages .map_severity_to_sarif (severity )
229
244
},
230
245
}
231
246
232
- # Create a SARIF " result" referencing the line where we found the match
247
+ # Add the SARIF result
233
248
result_obj = {
234
249
"ruleId" : rule_id ,
235
250
"message" : {"text" : short_desc },
@@ -247,7 +262,7 @@ def create_security_comment_sarif(diff: Diff) -> dict:
247
262
}
248
263
results_list .append (result_obj )
249
264
250
- # Attach our rules and results to the SARIF data
265
+ # Attach rules and results
251
266
sarif_data ["runs" ][0 ]["tool" ]["driver" ]["rules" ] = list (rules_map .values ())
252
267
sarif_data ["runs" ][0 ]["results" ] = results_list
253
268
0 commit comments