diff --git a/socketsecurity/__init__.py b/socketsecurity/__init__.py
index 6e9694e..f441f16 100644
--- a/socketsecurity/__init__.py
+++ b/socketsecurity/__init__.py
@@ -1,2 +1,2 @@
__author__ = 'socket.dev'
-__version__ = '1.0.44'
+__version__ = '1.0.46'
\ No newline at end of file
diff --git a/socketsecurity/core/messages.py b/socketsecurity/core/messages.py
index f914bb9..eef755f 100644
--- a/socketsecurity/core/messages.py
+++ b/socketsecurity/core/messages.py
@@ -82,7 +82,7 @@ def find_line_in_file(packagename: str, packageversion: str, manifest_file: str)
needle_key = f'"{found_key}":' # e.g. "node_modules/axios":
needle_version = f'"version": "{packageversion}"'
lines = raw_text.splitlines()
- best_line = -1
+ best_line = 1
snippet = None
for i, line in enumerate(lines, start=1):
@@ -97,10 +97,10 @@ def find_line_in_file(packagename: str, packageversion: str, manifest_file: str)
else:
return 1, f'"{found_key}": {found_info}'
else:
- return -1, f"{packagename} {packageversion} (not found in {manifest_file})"
+ return 1, f"{packagename} {packageversion} (not found in {manifest_file})"
except (FileNotFoundError, json.JSONDecodeError):
- return -1, f"Error reading {manifest_file}"
+ return 1, f"Error reading {manifest_file}"
# ----------------------------------------------------
# 2) Text-based / line-based manifests
@@ -148,28 +148,49 @@ def find_line_in_file(packagename: str, packageversion: str, manifest_file: str)
return line_number, line_content.strip()
except FileNotFoundError:
- return -1, f"{manifest_file} not found"
+ return 1, f"{manifest_file} not found"
except Exception as e:
- return -1, f"Error reading {manifest_file}: {e}"
+ return 1, f"Error reading {manifest_file}: {e}"
- return -1, f"{packagename} {packageversion} (not found)"
+ return 1, f"{packagename} {packageversion} (not found)"
@staticmethod
- def create_security_comment_sarif(diff: Diff) -> dict:
+ def get_manifest_type_url(manifest_file: str, pkg_name: str, pkg_version: str) -> str:
"""
- Create SARIF-compliant output from the diff report, including line references
- and a link to the Socket docs in the fullDescription. Also converts any \r\n
- into
so they render properly in GitHub's SARIF display.
+ Determine the correct URL path based on the manifest file type.
"""
- # Check if there's a blocking error in new alerts
- scan_failed = False
- if len(diff.new_alerts) == 0:
- for alert in diff.new_alerts:
- if alert.error:
- scan_failed = True
- break
+ manifest_to_url_prefix = {
+ "package.json": "npm",
+ "package-lock.json": "npm",
+ "yarn.lock": "npm",
+ "pnpm-lock.yaml": "npm",
+ "requirements.txt": "pypi",
+ "pyproject.toml": "pypi",
+ "Pipfile": "pypi",
+ "go.mod": "go",
+ "go.sum": "go",
+ "pom.xml": "maven",
+ "build.gradle": "maven",
+ ".csproj": "nuget",
+ ".fsproj": "nuget",
+ "paket.dependencies": "nuget",
+ "Cargo.toml": "cargo",
+ "Gemfile": "rubygems",
+ "Gemfile.lock": "rubygems",
+ "composer.json": "composer",
+ "vcpkg.json": "vcpkg",
+ }
+
+ file_type = Path(manifest_file).name
+ url_prefix = manifest_to_url_prefix.get(file_type, "unknown")
+ return f"https://socket.dev/{url_prefix}/package/{pkg_name}/alerts/{pkg_version}"
- # Basic SARIF skeleton
+ @staticmethod
+ def create_security_comment_sarif(diff) -> dict:
+ """
+ Create SARIF-compliant output from the diff report, including dynamic URL generation
+ based on manifest type and improved
formatting for GitHub SARIF display.
+ """
sarif_data = {
"$schema": "https://json.schemastore.org/sarif-2.1.0.json",
"version": "2.1.0",
@@ -196,40 +217,34 @@ def create_security_comment_sarif(diff: Diff) -> dict:
rule_id = f"{pkg_name}=={pkg_version}"
severity = alert.severity
- # Convert any \r\n in short desc to
so they display properly
- short_desc_raw = f"{alert.props.get('note', '')}\r\n\r\nSuggested Action:\r\n{alert.suggestion}"
- short_desc = short_desc_raw.replace("\r\n", "
")
-
- # Build link to Socket docs, e.g. "https://socket.dev/npm/package/foo/alerts/1.2.3"
- socket_url = f"https://socket.dev/npm/package/{pkg_name}/alerts/{pkg_version}"
-
- # Also convert \r\n in the main description to
, then append the Socket docs link
- base_desc = alert.description.replace("\r\n", "
")
- full_desc_raw = f"{alert.title} - {base_desc}
{socket_url}"
-
- # Identify the manifest file and line
+ # Generate the correct URL for the alert based on manifest type
introduced_list = alert.introduced_by
- if introduced_list and isinstance(introduced_list[0], list) and len(introduced_list[0]) > 1:
- manifest_file = introduced_list[0][1]
- else:
- manifest_file = alert.manifests or "requirements.txt"
+ manifest_file = introduced_list[0][1] if introduced_list and isinstance(introduced_list[0], list) else alert.manifests or "requirements.txt"
+ socket_url = Messages.get_manifest_type_url(manifest_file, pkg_name, pkg_version)
+
+ # Prepare descriptions with
replacements
+ short_desc = f"{alert.props.get('note', '')}
Suggested Action:
{alert.suggestion}"
+ full_desc = f"{alert.title} - {alert.description.replace('\r\n', '
')}
{socket_url}"
+ # Identify the line and snippet in the manifest file
line_number, line_content = Messages.find_line_in_file(pkg_name, pkg_version, manifest_file)
+ if line_number < 1:
+ line_number = 1 # Ensure SARIF compliance
- # If not already defined, create a rule for this package
+ # Create the rule if not already defined
if rule_id not in rules_map:
rules_map[rule_id] = {
"id": rule_id,
"name": f"{pkg_name}=={pkg_version}",
"shortDescription": {"text": f"Alert generated for {rule_id} by Socket Security"},
- "fullDescription": {"text": full_desc_raw},
- "helpUri": alert.url,
+ "fullDescription": {"text": full_desc},
+ "helpUri": socket_url,
"defaultConfiguration": {
"level": Messages.map_severity_to_sarif(severity)
},
}
- # Create a SARIF "result" referencing the line where we found the match
+ # Add the SARIF result
result_obj = {
"ruleId": rule_id,
"message": {"text": short_desc},
@@ -247,7 +262,7 @@ def create_security_comment_sarif(diff: Diff) -> dict:
}
results_list.append(result_obj)
- # Attach our rules and results to the SARIF data
+ # Attach rules and results
sarif_data["runs"][0]["tool"]["driver"]["rules"] = list(rules_map.values())
sarif_data["runs"][0]["results"] = results_list