From 95385df7b4e9846abaa00caeca4769afde1f53ce Mon Sep 17 00:00:00 2001 From: David Larsen Date: Thu, 23 Apr 2026 18:25:02 -0400 Subject: [PATCH 1/2] fix: tolerate unknown SocketCategory values in SocketAlert.from_dict The Socket API can emit category values the SDK does not yet know about (e.g. "other"). Strict enum construction in SocketAlert.from_dict turned that into a hard failure that propagated up through stream_diff and crashed any consumer that happened to receive such an alert. Fall back to SocketCategory.MISCELLANEOUS and log a warning when the value is unrecognized, so the SDK stays forward-compatible with new server-side categories without needing a coordinated release. Fixes #78. --- socketdev/fullscans/__init__.py | 11 ++++- tests/unit/test_socket_alert_category.py | 63 ++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 tests/unit/test_socket_alert_category.py diff --git a/socketdev/fullscans/__init__.py b/socketdev/fullscans/__init__.py index a2eb4f2..f295237 100644 --- a/socketdev/fullscans/__init__.py +++ b/socketdev/fullscans/__init__.py @@ -443,11 +443,20 @@ def to_dict(self): @classmethod def from_dict(cls, data: dict) -> "SocketAlert": + try: + category = SocketCategory(data["category"]) + except ValueError: + log.warning( + "Unknown SocketCategory %r; falling back to MISCELLANEOUS. " + "Upgrade socketdev to pick up newer categories.", + data["category"], + ) + category = SocketCategory.MISCELLANEOUS return cls( key=data["key"], type=data["type"], severity=SocketIssueSeverity(data["severity"]), - category=SocketCategory(data["category"]), + category=category, file=data.get("file"), start=data.get("start"), end=data.get("end"), diff --git a/tests/unit/test_socket_alert_category.py b/tests/unit/test_socket_alert_category.py new file mode 100644 index 0000000..02ce1c1 --- /dev/null +++ b/tests/unit/test_socket_alert_category.py @@ -0,0 +1,63 @@ +""" +Unit tests for lenient SocketCategory parsing in SocketAlert.from_dict. + +Regression coverage for +https://github.com/SocketDev/socket-sdk-python/issues/78: the Socket API can +emit category values the SDK does not yet know about (e.g. ``"other"``). Strict +enum parsing turned that into a hard failure that took down every consumer +(notably socketsecurity CI runs) whenever a diff included one of those alerts. + +These tests pin the fallback behavior so the SDK stays forward-compatible with +new server-side categories. +""" + +import logging +import unittest + +from socketdev.fullscans import SocketAlert, SocketCategory, SocketIssueSeverity + + +class TestSocketAlertCategoryParsing(unittest.TestCase): + """SocketAlert.from_dict should tolerate unknown category values.""" + + def _base_payload(self, category: str) -> dict: + return { + "key": "alert-key", + "type": "someAlertType", + "severity": "low", + "category": category, + } + + def test_known_category_is_preserved(self): + alert = SocketAlert.from_dict(self._base_payload("supplyChainRisk")) + self.assertEqual(alert.category, SocketCategory.SUPPLY_CHAIN_RISK) + self.assertEqual(alert.severity, SocketIssueSeverity.LOW) + + def test_unknown_category_falls_back_to_miscellaneous(self): + alert = SocketAlert.from_dict(self._base_payload("other")) + self.assertEqual(alert.category, SocketCategory.MISCELLANEOUS) + + def test_unknown_category_does_not_raise(self): + # Explicit regression assertion: no ValueError for brand-new categories. + try: + SocketAlert.from_dict(self._base_payload("somethingCompletelyNew")) + except ValueError as exc: + self.fail(f"SocketAlert.from_dict raised ValueError for unknown category: {exc}") + + def test_unknown_category_emits_warning(self): + with self.assertLogs("socketdev", level=logging.WARNING) as captured: + SocketAlert.from_dict(self._base_payload("other")) + self.assertTrue( + any("Unknown SocketCategory" in message for message in captured.output), + f"expected a warning about the unknown category, got: {captured.output}", + ) + + def test_every_known_category_round_trips(self): + for category in SocketCategory: + with self.subTest(category=category): + alert = SocketAlert.from_dict(self._base_payload(category.value)) + self.assertEqual(alert.category, category) + + +if __name__ == "__main__": + unittest.main() From 43c089513f542a66b60ab83c8a13a0534ca9e1e4 Mon Sep 17 00:00:00 2001 From: David Larsen Date: Thu, 23 Apr 2026 18:30:34 -0400 Subject: [PATCH 2/2] chore: bump version to 3.0.33 --- pyproject.toml | 2 +- socketdev/version.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 262ca14..bbcccd8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "socketdev" -version = "3.0.32" +version = "3.0.33" requires-python = ">= 3.9" dependencies = [ 'requests', diff --git a/socketdev/version.py b/socketdev/version.py index b70a418..46ae1b5 100644 --- a/socketdev/version.py +++ b/socketdev/version.py @@ -1 +1 @@ -__version__ = "3.0.32" +__version__ = "3.0.33"