From 763776020d256f4b35aee24654f4412abc5ffb87 Mon Sep 17 00:00:00 2001 From: rayair250-droid Date: Fri, 24 Jul 2026 18:33:06 +0200 Subject: [PATCH] fix(alerts): bound changelog upgrade range by target version In fetch_changelog, the condition if version_check or spec_check and parsed_version <= to_version_parsed: parses as 'version_check or (spec_check and ...)' because 'and' binds tighter than 'or', so the parsed_version <= to_version_parsed upper bound only guarded the spec_check branch. When from_version is set, every release newer than from_version was added to the changelog regardless of the target version, contradicting the function's own comment (1.2 -> 1.3 should include 1.2.1 but not later releases). Parenthesize so the target-version bound applies to both branches. Added a regression test. --- safety/alerts/utils.py | 4 +++- tests/alerts/test_utils.py | 25 +++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/safety/alerts/utils.py b/safety/alerts/utils.py index b875f4c6..77cf33aa 100644 --- a/safety/alerts/utils.py +++ b/safety/alerts/utils.py @@ -322,7 +322,9 @@ def fetch_changelog( and from_spec.contains(parsed_version) ) - if version_check or spec_check and parsed_version <= to_version_parsed: + if ( + version_check or spec_check + ) and parsed_version <= to_version_parsed: changelog[version] = log return changelog diff --git a/tests/alerts/test_utils.py b/tests/alerts/test_utils.py index 2ba860c5..fe65530c 100644 --- a/tests/alerts/test_utils.py +++ b/tests/alerts/test_utils.py @@ -1,4 +1,5 @@ import unittest +from unittest.mock import MagicMock, patch from safety.alerts import utils from tests.test_cli import get_vulnerability @@ -147,3 +148,27 @@ def test_cvss3_score_to_label_invalid_score(self): score = 11.0 expected_label = None self.assertEqual(utils.cvss3_score_to_label(score), expected_label) + + @patch("safety.alerts.utils.httpx.get") + def test_fetch_changelog_bounds_upgrade_range_by_target_version(self, mock_get): + # Changelog spanning below, within, and above the requested range. + response = MagicMock() + response.status_code = 200 + response.json.return_value = { + "0.4": "too old", + "1.2.1": "in range", + "1.3": "in range (target)", + "2.0": "beyond target", + } + mock_get.return_value = response + + changelog = utils.fetch_changelog( + "requests", + from_version="1.2", + to_version="1.3", + api_key=self.api_key, + ) + + # Only releases in (1.2, 1.3] should be included: 2.0 is past the + # target version and 0.4 is before the starting version. + self.assertEqual(set(changelog), {"1.2.1", "1.3"})