Skip to content

Commit 7d81306

Browse files
author
Orlando Barrera II
committed
Testing the sarif file parsing
1 parent 3f9ad6f commit 7d81306

File tree

1 file changed

+29
-50
lines changed

1 file changed

+29
-50
lines changed

socketsecurity/core/messages.py

Lines changed: 29 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -37,78 +37,58 @@ def find_line_in_file(packagename: str, packageversion: str, manifest_file: str)
3737
"""
3838
Finds the line number and snippet of code for the given package/version in a manifest file.
3939
Returns a 2-tuple: (line_number, snippet_or_message).
40-
41-
Supports:
42-
1) JSON-based manifest files (package-lock.json, Pipfile.lock, composer.lock)
43-
- Locates a dictionary entry with the matching package & version
44-
- Does a rough line-based search to find the actual line in the raw text
45-
2) Text-based (requirements.txt, package.json, yarn.lock, etc.)
46-
- Uses compiled regex patterns to detect a match line by line
4740
"""
48-
# Extract just the file name to detect manifest type
4941
file_type = Path(manifest_file).name
50-
42+
logging.debug("Processing manifest file: %s", manifest_file)
43+
5144
# ----------------------------------------------------
5245
# 1) JSON-based manifest files
5346
# ----------------------------------------------------
5447
if file_type in ["package-lock.json", "Pipfile.lock", "composer.lock"]:
5548
try:
56-
# Read entire file so we can parse JSON and also do raw line checks
5749
with open(manifest_file, "r", encoding="utf-8") as f:
5850
raw_text = f.read()
51+
logging.debug("Raw text length: %d", len(raw_text))
52+
try:
53+
data = json.loads(raw_text)
54+
except json.JSONDecodeError:
55+
data = {}
56+
logging.debug("JSON decode failed for %s", manifest_file)
5957

60-
# Attempt JSON parse
61-
data = json.loads(raw_text)
62-
63-
# In practice, you may need to check data["dependencies"], data["default"], etc.
64-
# This is an example approach.
6558
packages_dict = (
6659
data.get("packages")
6760
or data.get("default")
6861
or data.get("dependencies")
6962
or {}
7063
)
71-
64+
logging.debug("Packages dict keys: %s", list(packages_dict.keys()))
7265
found_key = None
7366
found_info = None
74-
# Locate a dictionary entry whose 'version' matches
7567
for key, value in packages_dict.items():
76-
# For NPM package-lock, keys might look like "node_modules/axios"
7768
if key.endswith(packagename) and "version" in value:
7869
if value["version"] == packageversion:
7970
found_key = key
8071
found_info = value
8172
break
8273

8374
if found_key and found_info:
84-
# Search lines to approximate the correct line number
85-
needle_key = f'"{found_key}":' # e.g. "node_modules/axios":
75+
needle_key = f'"{found_key}":'
8676
needle_version = f'"version": "{packageversion}"'
8777
lines = raw_text.splitlines()
88-
best_line = 1
89-
snippet = None
90-
78+
logging.debug("Total lines: %d", len(lines))
9179
for i, line in enumerate(lines, start=1):
9280
if (needle_key in line) or (needle_version in line):
93-
best_line = i
94-
snippet = line.strip()
95-
break # On first match, stop
96-
97-
# If we found an approximate line, return it; else fallback to line 1
98-
if best_line > 0 and snippet:
99-
return best_line, snippet
100-
else:
101-
return 1, f'"{found_key}": {found_info}'
81+
logging.debug("Found match at line %d: %s", i, line.strip())
82+
return i, line.strip()
83+
return 1, f'"{found_key}": {found_info}'
10284
else:
10385
return 1, f"{packagename} {packageversion} (not found in {manifest_file})"
104-
10586
except (FileNotFoundError, json.JSONDecodeError):
10687
return 1, f"Error reading {manifest_file}"
107-
88+
10889
# ----------------------------------------------------
10990
# 2) Text-based / line-based manifests
11091
# ----------------------------------------------------
111-
# Define a dictionary of patterns for common manifest types
11292
search_patterns = {
11393
"package.json": rf'"{packagename}":\s*"{packageversion}"',
11494
"yarn.lock": rf'{packagename}@{packageversion}',
@@ -134,18 +114,16 @@ def find_line_in_file(packagename: str, packageversion: str, manifest_file: str)
134114
"conanfile.txt": rf'{re.escape(packagename)}/{re.escape(packageversion)}',
135115
"vcpkg.json": rf'"{re.escape(packagename)}":\s*"{re.escape(packageversion)}"',
136116
}
137-
138-
# If no specific pattern is found for this file name, fallback to a naive approach
139117
searchstring = search_patterns.get(file_type, rf'{re.escape(packagename)}.*{re.escape(packageversion)}')
118+
logging.debug("Using search pattern for %s: %s", file_type, searchstring)
140119
try:
141-
# Read file lines and search for a match
142120
with open(manifest_file, 'r', encoding="utf-8") as file:
143121
lines = [line.rstrip("\n") for line in file]
122+
logging.debug("Total lines in %s: %d", manifest_file, len(lines))
144123
for line_number, line_content in enumerate(lines, start=1):
145-
# For Python conditional dependencies, ignore everything after first ';'
146124
line_main = line_content.split(";", 1)[0].strip()
147-
# Use a case-insensitive regex search
148125
if re.search(searchstring, line_main, re.IGNORECASE):
126+
logging.debug("Match found in %s at line %d: %s", manifest_file, line_number, line_content.strip())
149127
return line_number, line_content.strip()
150128
except FileNotFoundError:
151129
return 1, f"{manifest_file} not found"
@@ -180,15 +158,20 @@ def get_manifest_type_url(manifest_file: str, pkg_name: str, pkg_version: str) -
180158
"composer.json": "composer",
181159
"vcpkg.json": "vcpkg",
182160
}
183-
184161
file_type = Path(manifest_file).name
185162
url_prefix = manifest_to_url_prefix.get(file_type, "unknown")
186163
return f"https://socket.dev/{url_prefix}/package/{pkg_name}/alerts/{pkg_version}"
187164

188165
@staticmethod
189166
def create_security_comment_sarif(diff) -> dict:
190167
"""
191-
Create SARIF-compliant output from the diff report.
168+
Create SARIF-compliant output from the diff report, including dynamic URL generation
169+
based on manifest type and improved <br/> formatting for GitHub SARIF display.
170+
171+
This function now:
172+
- Accepts multiple manifest files from alert.introduced_by or alert.manifests.
173+
- Generates one SARIF location per manifest file.
174+
- Falls back to a default ("requirements.txt") if none is found.
192175
"""
193176
if len(diff.new_alerts) == 0:
194177
for alert in diff.new_alerts:
@@ -219,7 +202,7 @@ def create_security_comment_sarif(diff) -> dict:
219202
rule_id = f"{pkg_name}=={pkg_version}"
220203
severity = alert.severity
221204

222-
# --- Extract manifest files ---
205+
# --- Extract manifest files from alert data ---
223206
manifest_files = []
224207
if alert.introduced_by and isinstance(alert.introduced_by, list):
225208
for entry in alert.introduced_by:
@@ -230,16 +213,12 @@ def create_security_comment_sarif(diff) -> dict:
230213
elif hasattr(alert, 'manifests') and alert.manifests:
231214
manifest_files = [mf.strip() for mf in alert.manifests.split(";") if mf.strip()]
232215

233-
# Log the extracted manifest files
234216
logging.debug("Alert %s manifest_files before fallback: %s", rule_id, manifest_files)
235-
236217
if not manifest_files:
237218
manifest_files = ["requirements.txt"]
238219
logging.debug("Alert %s: Falling back to manifest_files: %s", rule_id, manifest_files)
239220

240-
# Log the manifest file used for URL generation
241221
logging.debug("Alert %s: Using manifest_file for URL: %s", rule_id, manifest_files[0])
242-
243222
socket_url = Messages.get_manifest_type_url(manifest_files[0], pkg_name, pkg_version)
244223
short_desc = (f"{alert.props.get('note', '')}<br/><br/>Suggested Action:<br/>{alert.suggestion}"
245224
f"<br/><a href=\"{socket_url}\">{socket_url}</a>")
@@ -257,13 +236,13 @@ def create_security_comment_sarif(diff) -> dict:
257236
},
258237
}
259238

260-
# Create a SARIF location for each manifest file and log each result.
239+
# Create a SARIF location for each manifest file.
261240
locations = []
262241
for mf in manifest_files:
263242
line_number, line_content = Messages.find_line_in_file(pkg_name, pkg_version, mf)
264243
if line_number < 1:
265244
line_number = 1
266-
logging.debug("Alert %s: Manifest %s, line %s: %s", rule_id, mf, line_number, line_content)
245+
logging.debug("Alert %s: Manifest %s, line %d: %s", rule_id, mf, line_number, line_content)
267246
locations.append({
268247
"physicalLocation": {
269248
"artifactLocation": {"uri": mf},
@@ -285,7 +264,7 @@ def create_security_comment_sarif(diff) -> dict:
285264
sarif_data["runs"][0]["results"] = results_list
286265

287266
return sarif_data
288-
267+
289268
@staticmethod
290269
def create_security_comment_json(diff: Diff) -> dict:
291270
scan_failed = False

0 commit comments

Comments
 (0)