diff --git a/go.mod b/go.mod index 7dabdd850..f8447332b 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.24.1 require ( github.com/BurntSushi/toml v1.5.0 github.com/CycloneDX/cyclonedx-go v0.9.2 - github.com/Masterminds/semver v1.5.0 + github.com/Masterminds/semver/v3 v3.3.0 github.com/Masterminds/sprig/v3 v3.3.0 github.com/OneOfOne/xxhash v1.2.8 github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d @@ -96,7 +96,6 @@ require ( github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20230306123547-8075edf89bb0 // indirect github.com/DataDog/zstd v1.5.5 // indirect github.com/Masterminds/goutils v1.1.1 // indirect - github.com/Masterminds/semver/v3 v3.3.0 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/Microsoft/hcsshim v0.11.7 // indirect github.com/ProtonMail/go-crypto v1.1.6 // indirect diff --git a/go.sum b/go.sum index cfc83879b..3c94844d4 100644 --- a/go.sum +++ b/go.sum @@ -66,8 +66,6 @@ github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ= github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= -github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= -github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0= github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs= diff --git a/syft/format/syftjson/decoder.go b/syft/format/syftjson/decoder.go index 4bcb53ee4..83e5aa7f1 100644 --- a/syft/format/syftjson/decoder.go +++ b/syft/format/syftjson/decoder.go @@ -6,7 +6,7 @@ import ( "io" "strings" - "github.com/Masterminds/semver" + "github.com/Masterminds/semver/v3" "github.com/anchore/syft/internal" "github.com/anchore/syft/internal/log" diff --git a/syft/pkg/cataloger/dart/parse_pubspec_lock.go b/syft/pkg/cataloger/dart/parse_pubspec_lock.go index 0f4135fd6..5a49f70d4 100644 --- a/syft/pkg/cataloger/dart/parse_pubspec_lock.go +++ b/syft/pkg/cataloger/dart/parse_pubspec_lock.go @@ -7,7 +7,6 @@ import ( "regexp" "sort" - "github.com/Masterminds/semver" "gopkg.in/yaml.v3" "github.com/anchore/syft/internal/log" @@ -136,6 +135,13 @@ func (psl *pubspecLock) getSdkVersion(sdk string) (string, error) { return parseMinimumSdkVersion(constraint) } +// semverRegex is a regex pattern that allows for both two-part (major.minor) and three-part (major.minor.patch) versions. +// additionally allows for: +// 1. start with either "^" or ">=" (Dart SDK constraints only use those two) +// 2. followed by a valid semantic version (which may be two or three components) +// 3. followed by a space (if there's a range) or end of string +var semverRegex = regexp.MustCompile(`^(\^|>=)(?P(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:\.(?:0|[1-9]\d*))?(?:-[0-9A-Za-z\-\.]+)?(?:\+[0-9A-Za-z\-\.]+)?)( |$)`) + // Parse a given version range constraint and return its lowest supported version. // // This is intended for packages that are part of an SDK (e.g. Flutter) and don't @@ -153,21 +159,14 @@ func (psl *pubspecLock) getSdkVersion(sdk string) (string, error) { // see https://dart.dev/tools/pub/dependencies#version-constraints for the // constraint format used in Dart SDK defintions. func parseMinimumSdkVersion(constraint string) (string, error) { - // Match strings that - // 1. start with either "^" or ">=" (Dart SDK constraints only use those two) - // 2. followed by a valid semantic version, matched as "version" named subexpression - // 3. followed by a space (if there's a range) or end of string (if there's only a lower boundary) - // |---1--||------------------2------------------||-3-| - re := regexp.MustCompile(`^(\^|>=)(?P` + semver.SemVerRegex + `)( |$)`) - - if !re.MatchString(constraint) { + if !semverRegex.MatchString(constraint) { return "", fmt.Errorf("unsupported or invalid constraint '%s'", constraint) } - // Read "version" subexpression (see 2. above) into version variable + // Read "version" subexpression into version variable var version []byte - matchIndex := re.FindStringSubmatchIndex(constraint) - version = re.ExpandString(version, "$version", constraint, matchIndex) + matchIndex := semverRegex.FindStringSubmatchIndex(constraint) + version = semverRegex.ExpandString(version, "$version", constraint, matchIndex) return string(version), nil } diff --git a/syft/pkg/cataloger/dart/parse_pubspec_lock_test.go b/syft/pkg/cataloger/dart/parse_pubspec_lock_test.go index 9c3f94c8f..ab843f66a 100644 --- a/syft/pkg/cataloger/dart/parse_pubspec_lock_test.go +++ b/syft/pkg/cataloger/dart/parse_pubspec_lock_test.go @@ -235,9 +235,11 @@ func Test_sdkVersionParser_valid(t *testing.T) { } for constraint, expected := range patterns { - version, err = parseMinimumSdkVersion(constraint) - assert.NoError(t, err) - assert.Equalf(t, expected, version, "constraint '%s", constraint) + t.Run(constraint, func(t *testing.T) { + version, err = parseMinimumSdkVersion(constraint) + assert.NoError(t, err) + assert.Equal(t, expected, version) + }) } }