Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 31 additions & 1 deletion grype/version/maven_version.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,49 @@ package version

import (
"fmt"
"regexp"

mvnv "github.com/masahiro331/go-mvn-version"
)

var _ Comparator = (*mavenVersion)(nil)

// javaRuntimeQualifierPattern matches .jreNN or .jdkNN suffixes (case-insensitive) at the end of version strings
var javaRuntimeQualifierPattern = regexp.MustCompile(`(?i)\.(jre|jdk)\d+$`)

type mavenVersion struct {
raw string
obj mvnv.Version
}

// stripJavaRuntimeQualifier removes .jreNN or .jdkNN suffixes from version strings.
// These are runtime-specific qualifiers that don't affect version comparison.
//
// The pattern matches 'jre' or 'jdk' (case-insensitive) followed by one or more digits
// at the END of the version string only. This means:
// - Case-insensitive: Both .jre11 and .JRE11 will be stripped
// - Requires digits: .jre or .jdk without numbers will NOT be stripped
// - End-anchored: .jre11-SNAPSHOT or .jdk17.beta will NOT be stripped
//
// Examples:
// - "12.10.2.jre11" -> "12.10.2" (stripped)
// - "12.10.2.JRE11" -> "12.10.2" (stripped)
// - "12.10.2.jdk17" -> "12.10.2" (stripped)
// - "12.10.2.JDK17" -> "12.10.2" (stripped)
// - "12.10.2" -> "12.10.2" (no change)
// - "12.10.2.jre" -> "12.10.2.jre" (no digits, not stripped)
// - "12.10.2.jre11-SNAPSHOT" -> "12.10.2.jre11-SNAPSHOT" (not at end, not stripped)
func stripJavaRuntimeQualifier(version string) string {
return javaRuntimeQualifierPattern.ReplaceAllString(version, "")
}

func newMavenVersion(raw string) (mavenVersion, error) {
ver, err := mvnv.NewVersion(raw)
// strip Java runtime qualifiers (e.g., .jre11, .jdk17) before parsing to ensure
// versions like "12.10.2" and "12.10.2.jre11" are treated as equivalent for comparison.
// The original raw version is preserved for display purposes.
normalized := stripJavaRuntimeQualifier(raw)

ver, err := mvnv.NewVersion(normalized)
if err != nil {
return mavenVersion{}, fmt.Errorf("could not generate new java version from: %s; %w", raw, err)
}
Expand Down
117 changes: 117 additions & 0 deletions grype/version/maven_version_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,87 @@ import (
"github.com/stretchr/testify/require"
)

func TestStripJavaRuntimeQualifier(t *testing.T) {
tests := []struct {
name string
input string
want string
}{
{
name: "version with jre11",
input: "12.10.2.jre11",
want: "12.10.2",
},
{
name: "version with jdk17",
input: "12.10.2.jdk17",
want: "12.10.2",
},
{
name: "version with uppercase JRE11",
input: "12.10.2.JRE11",
want: "12.10.2",
},
{
name: "version with uppercase JDK17",
input: "12.10.2.JDK17",
want: "12.10.2",
},
{
name: "version with mixed case Jre11",
input: "12.10.2.Jre11",
want: "12.10.2",
},
{
name: "version without qualifier",
input: "12.10.2",
want: "12.10.2",
},
{
name: "version with jre but no digits",
input: "12.10.2.jre",
want: "12.10.2.jre",
},
{
name: "version with jdk but no digits",
input: "12.10.2.jdk",
want: "12.10.2.jdk",
},
{
name: "version with jre0 (zero)",
input: "12.10.2.jre0",
want: "12.10.2",
},
{
name: "version with jdk999 (large number)",
input: "12.10.2.jdk999",
want: "12.10.2",
},
{
name: "version with jre11 followed by SNAPSHOT",
input: "12.10.2.jre11-SNAPSHOT",
want: "12.10.2.jre11-SNAPSHOT",
},
{
name: "version with jdk17 followed by beta",
input: "12.10.2.jdk17.beta",
want: "12.10.2.jdk17.beta",
},
{
name: "version with JRE uppercase followed by SNAPSHOT",
input: "12.10.2.JRE11-SNAPSHOT",
want: "12.10.2.JRE11-SNAPSHOT",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := stripJavaRuntimeQualifier(tt.input)
require.Equal(t, tt.want, got)
})
}
}

func TestMavenVersion_Constraint(t *testing.T) {
tests := []testCase{
// range expressions
Expand Down Expand Up @@ -152,6 +233,42 @@ func TestMavenVersion_Compare(t *testing.T) {
v2: "5.2.25",
want: 0,
},
// JRE/JDK qualifier tests (GitHub issue: JRE version matching)
{
v1: "12.10.2",
v2: "12.10.2.jre11",
want: 0,
},
{
v1: "12.10.2.jre11",
v2: "12.10.2",
want: 0,
},
{
v1: "12.10.2.jdk17",
v2: "12.10.2",
want: 0,
},
{
v1: "12.10.2.jre11",
v2: "12.10.2.jdk17",
want: 0,
},
{
v1: "12.10.1",
v2: "12.10.2.jre11",
want: -1,
},
{
v1: "12.10.2.jre11",
v2: "12.10.1",
want: 1,
},
{
v1: "1.2.3.jre8",
v2: "1.2.4.jre8",
want: -1,
},
}
for _, tt := range tests {
t.Run(tt.v1+" vs "+tt.v2, func(t *testing.T) {
Expand Down
Loading