From fdde2e7fdfa78b81ec4780b9bc7d95421f8dc6f0 Mon Sep 17 00:00:00 2001 From: Manoj Gowda Date: Tue, 25 Aug 2026 16:11:50 +0530 Subject: [PATCH] Reject empty strings in Maven, Nuget, Rubygems and Conan versions MavenVersion, NugetVersion, RubygemsVersion and ConanVersion accepted the empty string because their is_valid() overrides only tried to parse the value, and the underlying parsers accept empty input. An accepted empty version then sorted below every real version (Maven, Rubygems), raised TypeError on comparison (Nuget), or both (Conan), silently corrupting downstream range logic instead of failing. Make the overrides honor the base Version.is_valid() contract, which already documents that the empty string is invalid, by checking super().is_valid() first. DebianVersion gets the same guard for consistency although its parser already rejected empty input. Fixes https://github.com/aboutcode-org/univers/issues/204 Signed-off-by: Manoj Gowda --- src/univers/versions.py | 10 +++++++++- tests/test_versions.py | 23 +++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/univers/versions.py b/src/univers/versions.py index 5d6101ac..9d4e4919 100644 --- a/src/univers/versions.py +++ b/src/univers/versions.py @@ -248,6 +248,8 @@ def build_value(cls, string): @classmethod def is_valid(cls, string): + if not super().is_valid(string): + return False try: cls.build_value(string) return True @@ -325,7 +327,7 @@ def build_value(cls, string): @classmethod def is_valid(cls, string): - return gem.GemVersion.is_correct(string) + return super().is_valid(string) and gem.GemVersion.is_correct(string) class ArchLinuxVersion(Version): @@ -375,6 +377,8 @@ def build_value(cls, string): @classmethod def is_valid(cls, string): + if not super().is_valid(string): + return False try: cls.build_value(string) return True @@ -392,6 +396,8 @@ def build_value(cls, string): @classmethod def is_valid(cls, string): + if not super().is_valid(string): + return False try: cls.build_value(string) return True @@ -664,6 +670,8 @@ def build_value(cls, string): @classmethod def is_valid(cls, string): + if not super().is_valid(string): + return False try: cls.build_value(string) return True diff --git a/tests/test_versions.py b/tests/test_versions.py index ab3007d3..b8f9b1d1 100644 --- a/tests/test_versions.py +++ b/tests/test_versions.py @@ -253,3 +253,26 @@ def test_lexicographic_version(): assert LexicographicVersion("Abc") < LexicographicVersion(None) assert LexicographicVersion("123") < LexicographicVersion("bbc") assert LexicographicVersion("2.3.4") > LexicographicVersion("1.2.3") + + +def test_version_with_empty_string_is_invalid(): + # https://github.com/aboutcode-org/univers/issues/204 + # These schemes used to accept the empty string and then sort it as the + # minimum version (Maven, Rubygems), raise on comparison (Nuget), or + # both (Conan), silently corrupting downstream range logic. + import pytest + + from univers.versions import ConanVersion + from univers.versions import InvalidVersion + + for version_class in ( + Version, + MavenVersion, + NugetVersion, + RubygemsVersion, + ConanVersion, + SemverVersion, + PypiVersion, + ): + with pytest.raises(InvalidVersion): + version_class("")