From 64d2b64ef89e16f5376f9e8c35c3e42eed2f8b5e Mon Sep 17 00:00:00 2001 From: lelia <2418071+lelia@users.noreply.github.com> Date: Fri, 24 Apr 2026 13:11:06 -0400 Subject: [PATCH 1/3] fix: handle missing diff scores in dependency overview Signed-off-by: lelia <2418071+lelia@users.noreply.github.com> --- socketsecurity/core/classes.py | 6 ++- socketsecurity/core/messages.py | 25 ++++++++-- tests/unit/test_dependency_overview.py | 67 ++++++++++++++++++++++++++ 3 files changed, 91 insertions(+), 7 deletions(-) create mode 100644 tests/unit/test_dependency_overview.py diff --git a/socketsecurity/core/classes.py b/socketsecurity/core/classes.py index d211079..db14522 100644 --- a/socketsecurity/core/classes.py +++ b/socketsecurity/core/classes.py @@ -207,7 +207,7 @@ def from_diff_artifact(cls, data: dict) -> "Package": name=data["name"], version=data["version"], type=data["type"], - score=data.get("score", data.get("scores", {})), + score=data.get("score") or data.get("scores") or {}, alerts=data.get("alerts", []), author=data.get("author", []), size=data.get("size"), @@ -236,7 +236,7 @@ def from_diff_artifact(cls, data: dict) -> "Package": name=data["name"], version=data["version"], type=data["type"], - score=data.get("score", data.get("scores", {})), + score=data.get("score") or data.get("scores") or {}, alerts=data.get("alerts", []), author=data.get("author", []), size=data.get("size"), @@ -448,6 +448,8 @@ def __init__(self, **kwargs): self.capabilities = [] if not hasattr(self, "is_new"): self.is_new = False + if not hasattr(self, "scores") or self.scores is None: + self.scores = {} self.author_url = Purl.generate_author_data(self.author, self.ecosystem) @staticmethod diff --git a/socketsecurity/core/messages.py b/socketsecurity/core/messages.py index 2f1cf91..319e454 100644 --- a/socketsecurity/core/messages.py +++ b/socketsecurity/core/messages.py @@ -1179,12 +1179,27 @@ 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})" + def get_score_for_badge(score_name: str) -> float: + scores = getattr(added, "scores", None) + if isinstance(scores, dict): + raw_score = scores.get(score_name) + else: + raw_score = getattr(scores, score_name, None) if scores is not None else None + + if raw_score is None: + return 1.0 + + score = float(raw_score) + if score > 1: + score = score / 100 + return max(0.0, min(score, 1.0)) + # 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)) + supply_chain_risk_badge = score_to_badge(get_score_for_badge("supplyChain")) + vulnerability_badge = score_to_badge(get_score_for_badge("vulnerability")) + quality_badge = score_to_badge(get_score_for_badge("quality")) + maintenance_badge = score_to_badge(get_score_for_badge("maintenance")) + license_badge = score_to_badge(get_score_for_badge("license")) # Add the row for this package row = [ diff --git a/tests/unit/test_dependency_overview.py b/tests/unit/test_dependency_overview.py new file mode 100644 index 0000000..3afb805 --- /dev/null +++ b/tests/unit/test_dependency_overview.py @@ -0,0 +1,67 @@ +from socketsecurity.core.classes import Diff, Package, Purl +from socketsecurity.core.messages import Messages + + +def _make_purl(name: str, scores) -> Purl: + return Purl( + id=f"pkg:npm/{name}@1.0.0", + name=name, + version="1.0.0", + ecosystem="npm", + direct=True, + introduced_by=[("direct", "package.json")], + author=["test-author"], + size=1000, + transitives=0, + url=f"https://socket.dev/npm/package/{name}/overview/1.0.0", + purl=f"pkg:npm/{name}@1.0.0", + scores=scores, + ) + + +def test_package_from_diff_artifact_normalizes_null_score(): + package = Package.from_diff_artifact( + { + "id": "pkg:npm/example@1.0.0", + "name": "example", + "version": "1.0.0", + "type": "npm", + "diffType": "added", + "score": None, + "alerts": [], + "author": [], + "topLevelAncestors": [], + "direct": True, + "manifestFiles": [], + } + ) + + assert package.score == {} + + +def test_dependency_overview_template_defaults_missing_or_null_scores(tmp_path, monkeypatch): + monkeypatch.chdir(tmp_path) + + diff = Diff( + id="test-diff", + diff_url="https://socket.dev/test-diff", + new_packages=[ + _make_purl("missing-scores", None), + _make_purl( + "partial-scores", + { + "supplyChain": 0.42, + "vulnerability": None, + }, + ), + ], + removed_packages=[], + new_alerts=[], + ) + + comment = Messages.dependency_overview_template(diff) + + assert "Socket Security: Dependency Overview" in comment + assert "score-42.svg" in comment + assert "score-100.svg" in comment + assert "score-10000.svg" not in comment From 305a6bd7e139022371516dbbbd122e3ad7d4a68f Mon Sep 17 00:00:00 2001 From: lelia <2418071+lelia@users.noreply.github.com> Date: Fri, 24 Apr 2026 13:12:32 -0400 Subject: [PATCH 2/3] chore: bump release version for CLI Signed-off-by: lelia <2418071+lelia@users.noreply.github.com> --- pyproject.toml | 2 +- socketsecurity/__init__.py | 2 +- uv.lock | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index c0e07c7..095ed3b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "hatchling.build" [project] name = "socketsecurity" -version = "2.2.85" +version = "2.2.86" requires-python = ">= 3.11" license = {"file" = "LICENSE"} dependencies = [ diff --git a/socketsecurity/__init__.py b/socketsecurity/__init__.py index ec5936b..c816fab 100644 --- a/socketsecurity/__init__.py +++ b/socketsecurity/__init__.py @@ -1,3 +1,3 @@ __author__ = 'socket.dev' -__version__ = '2.2.85' +__version__ = '2.2.86' USER_AGENT = f'SocketPythonCLI/{__version__}' diff --git a/uv.lock b/uv.lock index cb5ff37..1744a7d 100644 --- a/uv.lock +++ b/uv.lock @@ -1168,7 +1168,7 @@ wheels = [ [[package]] name = "socketsecurity" -version = "2.2.84" +version = "2.2.86" source = { editable = "." } dependencies = [ { name = "bs4" }, From 2e311786f6d86d830a1f00363edf0ba8488dbee3 Mon Sep 17 00:00:00 2001 From: lelia <2418071+lelia@users.noreply.github.com> Date: Fri, 24 Apr 2026 13:12:49 -0400 Subject: [PATCH 3/3] chore: bump SDK version for release Signed-off-by: lelia <2418071+lelia@users.noreply.github.com> --- pyproject.toml | 2 +- uv.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 095ed3b..49bb294 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ dependencies = [ 'GitPython', 'packaging', 'python-dotenv', - "socketdev>=3.0.32,<4.0.0", + "socketdev>=3.0.33,<4.0.0", "bs4>=0.0.2", "markdown>=3.10", ] diff --git a/uv.lock b/uv.lock index 1744a7d..a90e6b2 100644 --- a/uv.lock +++ b/uv.lock @@ -1155,15 +1155,15 @@ wheels = [ [[package]] name = "socketdev" -version = "3.0.32" +version = "3.0.33" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "requests" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/06/03/95800661041781428cc753aea65d8e1bc44d108f4be29c6a0815d18fcdd3/socketdev-3.0.32.tar.gz", hash = "sha256:89167632834dcf222877d599e68ed87a3a08e7abe171759f54490712ea8aa89a", size = 170997, upload-time = "2026-02-27T17:59:58.554Z" } +sdist = { url = "https://files.pythonhosted.org/packages/19/8c/b4608637bda66dd32cf9a421cee66e93d429f7445c8bd709032772e0f4ca/socketdev-3.0.33.tar.gz", hash = "sha256:704d672649f27390733cef4cbdad9ce8dc994794a4af56f77d2f2dc815bfe762", size = 172013, upload-time = "2026-04-24T17:02:48.616Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/81/5c/58fa24c442d2bb8b8cab926c89cd4fb2613f73a35556e385d9bdb00abb72/socketdev-3.0.32-py3-none-any.whl", hash = "sha256:6a22356dadf4741eb731593b1d5ed4d708769f945998723bbfd1b613b8c968cc", size = 66868, upload-time = "2026-02-27T17:59:56.896Z" }, + { url = "https://files.pythonhosted.org/packages/07/78/4408ba21724ce0648e39bd17854b19186ab77f6baedbb8b98721d6dd287a/socketdev-3.0.33-py3-none-any.whl", hash = "sha256:642eebd0b01b884c6aba8b5264e749ff71310147104e8e8de02ab24e4eab5837", size = 66975, upload-time = "2026-04-24T17:02:46.439Z" }, ] [[package]] @@ -1221,7 +1221,7 @@ requires-dist = [ { name = "python-dotenv" }, { name = "requests" }, { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.3.0" }, - { name = "socketdev", specifier = ">=3.0.32,<4.0.0" }, + { name = "socketdev", specifier = ">=3.0.33,<4.0.0" }, { name = "twine", marker = "extra == 'dev'" }, { name = "uv", marker = "extra == 'dev'", specifier = ">=0.1.0" }, ]