Skip to content

Doug/update comment template #79

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ build-backend = "hatchling.build"

[project]
name = "socketsecurity"
version = "2.0.52"
version = "2.0.54"
requires-python = ">= 3.10"
license = {"file" = "LICENSE"}
dependencies = [
Expand Down
2 changes: 1 addition & 1 deletion socketsecurity/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
__author__ = 'socket.dev'
__version__ = '2.0.52'
__version__ = '2.0.54'
18 changes: 12 additions & 6 deletions socketsecurity/core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
FullScan,
Issue,
Package,
Purl,
Purl
)
from socketsecurity.core.exceptions import APIResourceNotFound
from socketsecurity.core.licenses import Licenses
Expand Down Expand Up @@ -644,7 +644,7 @@ def create_diff_report(
seen_removed_packages = set()

for package_id, package in added_packages.items():
purl = Core.create_purl(package_id, added_packages)
purl = self.create_purl(package_id, added_packages)
base_purl = f"{purl.ecosystem}/{purl.name}@{purl.version}"

if (not direct_only or package.direct) and base_purl not in seen_new_packages:
Expand All @@ -658,7 +658,7 @@ def create_diff_report(
)

for package_id, package in removed_packages.items():
purl = Core.create_purl(package_id, removed_packages)
purl = self.create_purl(package_id, removed_packages)
base_purl = f"{purl.ecosystem}/{purl.name}@{purl.version}"

if (not direct_only or package.direct) and base_purl not in seen_removed_packages:
Expand All @@ -682,8 +682,13 @@ def create_diff_report(

return diff

@staticmethod
def create_purl(package_id: str, packages: dict[str, Package]) -> Purl:
def get_all_scores(self, packages: dict[str, Package]) -> dict[str, Package]:
components = []
for package_id in packages:
package = packages[package_id]
return packages

def create_purl(self, package_id: str, packages: dict[str, Package]) -> Purl:
"""
Creates the extended PURL data for package identification and tracking.

Expand All @@ -707,7 +712,8 @@ def create_purl(package_id: str, packages: dict[str, Package]) -> Purl:
size=package.size,
transitives=package.transitives,
url=package.url,
purl=package.purl
purl=package.purl,
scores=package.score
)
return purl

Expand Down
2 changes: 1 addition & 1 deletion socketsecurity/core/classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,6 @@ def __init__(self, **kwargs):
def __str__(self):
return json.dumps(self.__dict__)


class Purl:
"""
Represents a Package URL (PURL) with extended metadata.
Expand All @@ -392,6 +391,7 @@ class Purl:
author_url: str
url: str
purl: str
scores: dict[str, int]

def __init__(self, **kwargs):
if kwargs:
Expand Down
170 changes: 130 additions & 40 deletions socketsecurity/core/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -302,26 +302,95 @@ def create_security_comment_json(diff: Diff) -> dict:
@staticmethod
def security_comment_template(diff: Diff) -> str:
"""
Creates the security comment template
:param diff: Diff - Diff report with the data needed for the template
:return:
Generates the security comment template in the new required format.
Dynamically determines placement of the alerts table if markers like `<!-- start-socket-alerts-table -->` are used.

:param diff: Diff - Contains the detected vulnerabilities and warnings.
:return: str - The formatted Markdown/HTML string.
"""
md = MdUtils(file_name="markdown_security_temp.md")
md.new_line("<!-- socket-security-comment-actions -->")
md.new_header(level=1, title="Socket Security: Issues Report")
md.new_line("Potential security issues detected. Learn more about [socket.dev](https://socket.dev)")
md.new_line("To accept the risk, merge this PR and you will not be notified again.")
md.new_line()
md.new_line("<!-- start-socket-alerts-table -->")
md, ignore_commands, next_steps = Messages.create_security_alert_table(diff, md)
md.new_line("<!-- end-socket-alerts-table -->")
md.new_line()
md = Messages.create_next_steps(md, next_steps)
md = Messages.create_deeper_look(md)
md = Messages.create_remove_package(md)
md = Messages.create_acceptable_risk(md, ignore_commands)
md.create_md_file()
return md.file_data_text.lstrip()
# Start of the comment
comment = """<!-- socket-security-comment-actions -->

> **❗️ Caution**
> **Review the following alerts detected in dependencies.**
>
> According to your organization’s Security Policy, you **must** resolve all **“Block”** alerts before proceeding. It’s recommended to resolve **“Warn”** alerts too.
> Learn more about [Socket for GitHub](https://socket.dev?utm_medium=gh).

<!-- start-socket-updated-alerts-table -->
<table>
<thead>
<tr>
<th>Action</th>
<th>Severity</th>
<th align="left">Alert (click for details)</th>
</tr>
</thead>
<tbody>
"""

# Loop through alerts, dynamically generating rows
for alert in diff.new_alerts:
severity_icon = Messages.get_severity_icon(alert.severity)
action = "Block" if alert.error else "Warn"
details_open = ""
# Generate a table row for each alert
comment += f"""
<!-- start-socket-alert-{alert.pkg_name}@{alert.pkg_version} -->
<tr>
<td><strong>{action}</strong></td>
<td align="center">
<img src="{severity_icon}" alt="{alert.severity}" width="20" height="20">
</td>
<td>
<details {details_open}>
<summary>{alert.pkg_name}@{alert.pkg_version} - {alert.title}</summary>
<p><strong>Note:</strong> {alert.description}</p>
<p><strong>Source:</strong> <a href="{alert.manifests}">Manifest File</a></p>
<p>ℹ️ Read more on:
<a href="{alert.purl}">This package</a> |
<a href="{alert.url}">This alert</a> |
<a href="https://socket.dev/alerts/malware">What is known malware?</a></p>
<blockquote>
<p><em>Suggestion:</em> {alert.suggestion}</p>
<p><em>Mark as acceptable risk:</em> To ignore this alert only in this pull request, reply with:<br/>
<code>@SocketSecurity ignore {alert.pkg_name}@{alert.pkg_version}</code><br/>
Or ignore all future alerts with:<br/>
<code>@SocketSecurity ignore-all</code></p>
</blockquote>
</details>
</td>
</tr>
<!-- end-socket-alert-{alert.pkg_name}@{alert.pkg_version} -->
"""

# Close table and comment
comment += """
</tbody>
</table>
<!-- end-socket-alerts-table -->

[View full report](https://socket.dev/...&action=error%2Cwarn)
"""

return comment

@staticmethod
def get_severity_icon(severity: str) -> str:
"""
Maps severity levels to their corresponding badge/icon URLs.

:param severity: str - Severity level (e.g., "Critical", "High").
:return: str - Badge/icon URL.
"""
severity_map = {
"critical": "https://github-app-statics.socket.dev/severity-3.svg",
"high": "https://github-app-statics.socket.dev/severity-2.svg",
"medium": "https://github-app-statics.socket.dev/severity-1.svg",
"low": "https://github-app-statics.socket.dev/severity-0.svg",
}
return severity_map.get(severity.lower(), "https://github-app-statics.socket.dev/severity-0.svg")


@staticmethod
def create_next_steps(md: MdUtils, next_steps: dict):
Expand Down Expand Up @@ -456,11 +525,9 @@ def dependency_overview_template(diff: Diff) -> str:
md = MdUtils(file_name="markdown_overview_temp.md")
md.new_line("<!-- socket-overview-comment-actions -->")
md.new_header(level=1, title="Socket Security: Dependency Overview")
md.new_line("New and removed dependencies detected. Learn more about [socket.dev](https://socket.dev)")
md.new_line("Review the following changes in direct dependencies. Learn more about [socket.dev](https://socket.dev)")
md.new_line()
md = Messages.create_added_table(diff, md)
if len(diff.removed_packages) > 0:
md = Messages.create_remove_line(diff, md)
md.create_md_file()
if len(md.file_data_text.lstrip()) >= 65500:
md = Messages.short_dependency_overview_comment(diff)
Expand All @@ -471,7 +538,7 @@ def short_dependency_overview_comment(diff: Diff) -> MdUtils:
md = MdUtils(file_name="markdown_overview_temp.md")
md.new_line("<!-- socket-overview-comment-actions -->")
md.new_header(level=1, title="Socket Security: Dependency Overview")
md.new_line("New and removed dependencies detected. Learn more about [socket.dev](https://socket.dev)")
md.new_line("Review the following changes in direct dependencies. Learn more about [socket.dev](https://socket.dev)")
md.new_line()
md.new_line("The amount of dependency changes were to long for this comment. Please check out the full report")
md.new_line(f"To view more information about this report checkout the [Full Report]({diff.diff_url})")
Expand All @@ -498,40 +565,63 @@ def create_remove_line(diff: Diff, md: MdUtils) -> MdUtils:
def create_added_table(diff: Diff, md: MdUtils) -> MdUtils:
"""
Create the Added packages table for the Dependency Overview template
:param diff: Diff - Diff report with the Added packages information
:param diff: Diff - Diff report with the Added package information
:param md: MdUtils - Main markdown variable
:return:
"""
# Table column headers
overview_table = [
"Diff",
"Package",
"Direct",
"Capabilities",
"Transitives",
"Size",
"Author"
"Supply Chain<br/>Security",
"Vulnerability",
"Quality",
"Maintenance",
"License"
]
num_of_overview_columns = len(overview_table)

count = 0
for added in diff.new_packages:
added: Purl
package_url = Messages.create_purl_link(added)
capabilities = ", ".join(added.capabilities)
added: Purl # Ensure `added` has scores and relevant attributes.

package_url = f"[{added.purl}]({added.url})"
diff_badge = f"[![+](https://github-app-statics.socket.dev/diff-added.svg)]({added.url})"

# Scores dynamically converted to badge URLs and linked
def score_to_badge(score):
score_percent = int(score * 100) # Convert to integer percentage
return f"[![{score_percent}](https://github-app-statics.socket.dev/score-{score_percent}.svg)]({added.url})"

# Generate badges for each score type
supply_chain_risk_badge = score_to_badge(added.scores.get("supplyChain", 100))
vulnerability_badge = score_to_badge(added.scores.get("vulnerability", 100))
quality_badge = score_to_badge(added.scores.get("quality", 100))
maintenance_badge = score_to_badge(added.scores.get("maintenance", 100))
license_badge = score_to_badge(added.scores.get("license", 100))

# Add the row for this package
row = [
diff_badge,
package_url,
added.direct,
capabilities,
added.transitives,
f"{added.size} KB",
added.author_url
supply_chain_risk_badge,
vulnerability_badge,
quality_badge,
maintenance_badge,
license_badge
]
overview_table.extend(row)
count += 1
num_of_overview_rows = count + 1
count += 1 # Count total packages

# Calculate total rows for table
num_of_overview_rows = count + 1 # Include header row

# Generate Markdown table
md.new_table(
columns=num_of_overview_columns,
rows=num_of_overview_rows,
text=overview_table,
text_align="left"
text_align="center"
)
return md

Expand Down
Loading
Loading