diff --git a/core/src/main/java/org/owasp/dependencycheck/utils/DependencyVersionUtil.java b/core/src/main/java/org/owasp/dependencycheck/utils/DependencyVersionUtil.java index eb943c8eade..18af1ae9244 100644 --- a/core/src/main/java/org/owasp/dependencycheck/utils/DependencyVersionUtil.java +++ b/core/src/main/java/org/owasp/dependencycheck/utils/DependencyVersionUtil.java @@ -45,7 +45,7 @@ public final class DependencyVersionUtil { * version number using the previous regex. */ private static final Pattern RX_SINGLE_VERSION = Pattern.compile( - "\\d+(\\.\\d+){0,6}([._-]?(snapshot|release|final|alpha|beta|rc$|[a-zA-Z]{1,3}[_-]?\\d{1,8}))?"); + "\\d+(\\.\\d+){0,6}([._-]?(snapshot|release|final|alpha|beta|rc$|[a-zA-Z]{1,3}[_-]?\\d{1,8}|[a-zA-Z]\\b))?"); /** * Regular expression to extract the part before the version numbers if diff --git a/core/src/test/java/org/owasp/dependencycheck/utils/DependencyVersionUtilTest.java b/core/src/test/java/org/owasp/dependencycheck/utils/DependencyVersionUtilTest.java index 23f89847e71..c7038a0d284 100644 --- a/core/src/test/java/org/owasp/dependencycheck/utils/DependencyVersionUtilTest.java +++ b/core/src/test/java/org/owasp/dependencycheck/utils/DependencyVersionUtilTest.java @@ -21,6 +21,7 @@ import org.owasp.dependencycheck.BaseTest; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNull; /** @@ -60,6 +61,45 @@ void testParseVersion_String() { } } + /** + * Test of parseVersion method, of class DependencyVersionUtil, for versions + * that consist of a number directly followed by a single letter and no + * period - the scheme used by libjpeg (8a, 9d, 9e). + * + * See https://github.com/dependency-check/DependencyCheck/issues/4139 + */ + @Test + void testParseVersion_singleLetterSuffixWithoutPeriod() { + final String[] names = {"9e", "9d", "8a", "libjpeg-9e", "jpegsr9e"}; + final String[] expected = {"9e", "9d", "8a", "9e", "9e"}; + + for (int i = 0; i < names.length; i++) { + final DependencyVersion version = DependencyVersionUtil.parseVersion(names[i]); + String result = null; + if (version != null) { + result = version.toString(); + } + assertEquals(expected[i], result, "Failed extraction on \"" + names[i] + "\"."); + } + } + + /** + * The user visible consequence of dropping the suffix: 8a and 8b both collapse onto "8", so + * the version CPEAnalyzer derives from the evidence compares equal to the version of a CPE + * for a different release. Its exact match is + * {@code parseVersion(evidence).equals(parseVersion(cpe.getVersion()))}, so a dependency at + * 8a matched the CPE of 8b, and the identified version printed in the report was "8". + */ + @Test + void testParseVersion_singleLetterReleasesAreNotConflated() { + final DependencyVersion evidence = DependencyVersionUtil.parseVersion("libjpeg-turbo-8a.tar.gz", true); + + assertEquals("8a", evidence.toString()); + assertEquals(DependencyVersionUtil.parseVersion("8a"), evidence); + assertNotEquals(DependencyVersionUtil.parseVersion("8b"), evidence); + assertNotEquals(DependencyVersionUtil.parseVersion("9e"), DependencyVersionUtil.parseVersion("9d")); + } + /** * Test of parseVersion method, of class DependencyVersionUtil. */