Skip to content

Commit

Permalink
Added util func around semver to allow for custom preprocessing. Upgr…
Browse files Browse the repository at this point in the history
…aded semver lib (#25437)

For #22919

- [x] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/Committing-Changes.md#changes-files)
for more information.
- [x] Added/updated automated tests
- [ ] A detailed QA plan exists on the associated ticket (if it isn't
there, work with the product group's QA engineer to add it)
- [ ] Manual QA for all new/changed functionality
ksykulev authored Jan 23, 2025
1 parent a3b06fa commit d893025
Showing 9 changed files with 60 additions and 15 deletions.
1 change: 1 addition & 0 deletions changes/22919-semver-util
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* Added util wrapper func around semver package to allow for custom preprocessing. Upgraded semver library to 3.3.1 and usage everywhere to version 3.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -155,7 +155,7 @@ require (
github.com/AlekSi/pointer v1.2.0 // indirect
github.com/BurntSushi/toml v1.3.2 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.1.1 // indirect
github.com/Masterminds/semver/v3 v3.3.1 // indirect
github.com/Masterminds/sprig v2.22.0+incompatible // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/OneOfOne/xxhash v1.2.8 // indirect
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -55,6 +55,8 @@ github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF0
github.com/Masterminds/semver/v3 v3.1.0/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
github.com/Masterminds/semver/v3 v3.3.1 h1:QtNSWtVZ3nBfk8mAOu/B6v7FMJ+NHTIgUPi7rj+4nv4=
github.com/Masterminds/semver/v3 v3.3.1/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60=
github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
4 changes: 2 additions & 2 deletions server/fleet/hosts.go
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@ import (
"strings"
"time"

"github.com/Masterminds/semver"
"github.com/Masterminds/semver/v3"
)

type HostStatus string
@@ -1277,7 +1277,7 @@ func IsMacOSMajorVersionOK(host *Host) (bool, error) {
return false, nil
}

version, err := semver.NewVersion(parts[1])
version, err := VersionToSemverVersion(parts[1])
if err != nil {
return false, fmt.Errorf("parsing macOS version \"%s\": %w", parts[1], err)
}
6 changes: 2 additions & 4 deletions server/fleet/operating_systems.go
Original file line number Diff line number Diff line change
@@ -2,10 +2,9 @@ package fleet

import (
"fmt"
"regexp"
"strings"

"github.com/Masterminds/semver"
"github.com/Masterminds/semver/v3"
)

// OperatingSystem is an operating system uniquely identified according to its name and version.
@@ -35,7 +34,6 @@ func (os OperatingSystem) IsWindows() bool {
}

var macOSNudgeLastVersion = semver.MustParse("14")
var macOSRapidSecurityResponseVersionSuffix = regexp.MustCompile(` \([a-z]\)`)

// RequiresNudge returns whether the target platform is darwin and
// below version 14. Starting at macOS 14 nudge is no longer required,
@@ -46,7 +44,7 @@ func (os *OperatingSystem) RequiresNudge() (bool, error) {
}

// strip Rapid Security Response suffix (e.g. version 13.3.7 (a)) if any
version, err := semver.NewVersion(macOSRapidSecurityResponseVersionSuffix.ReplaceAllString(os.Version, ``))
version, err := VersionToSemverVersion(os.Version)
if err != nil {
return false, fmt.Errorf("parsing macos version \"%s\": %w", os.Version, err)
}
21 changes: 18 additions & 3 deletions server/fleet/utils.go
Original file line number Diff line number Diff line change
@@ -4,9 +4,10 @@ import (
"encoding/json"
"errors"
"io"
"regexp"
"strings"

"github.com/Masterminds/semver"
"github.com/Masterminds/semver/v3"
"github.com/fatih/color"
"golang.org/x/text/unicode/norm"
)
@@ -72,8 +73,8 @@ func Preprocess(input string) string {
// An invalid semantic version string is considered less than a valid one. All invalid semantic
// version strings compare equal to each other.
func CompareVersions(a string, b string) int {
verA, errA := semver.NewVersion(a)
verB, errB := semver.NewVersion(b)
verA, errA := VersionToSemverVersion(a)
verB, errB := VersionToSemverVersion(b)
switch {
case errA != nil && errB != nil:
return 0
@@ -91,3 +92,17 @@ func CompareVersions(a string, b string) int {
func IsAtLeastVersion(currentVersion string, minimumVersion string) bool {
return CompareVersions(currentVersion, minimumVersion) >= 0
}

var macOSRapidSecurityResponseVersionSuffix = regexp.MustCompile(` \([a-z]\)`)

// VersionToSemvarVersion converts a version string to a semver version. This wrap semver.NewVersion
// and applies some additional formatting to the version string.
// Formatting applied:
// - Strip mac rapid security response suffix - "13.3.1 (a)" -> "13.3.1"
func VersionToSemverVersion(version string) (*semver.Version, error) {
ver, err := semver.NewVersion(macOSRapidSecurityResponseVersionSuffix.ReplaceAllString(version, ``))
if err != nil {
return nil, err
}
return ver, nil
}
29 changes: 29 additions & 0 deletions server/fleet/utils_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package fleet

import (
"testing"

"github.com/stretchr/testify/require"
)

func TestVersionToSemvarVersion(t *testing.T) {
tests := []struct {
version string
want string
}{
{"1", "1.0.0"},
{"1.0", "1.0.0"},
{"0.0.4", "0.0.4"},
{"1.0.0", "1.0.0"},
{"12.0.9", "12.0.9"},
{"1.0.0-alpha", "1.0.0-alpha"},
{"1.1.2+meta", "1.1.2+meta"},
{"13.3.1 (a)", "13.3.1"},
}

for _, tt := range tests {
result, err := VersionToSemverVersion(tt.version)
require.NoError(t, err)
require.Equal(t, tt.want, result.String())
}
}
5 changes: 2 additions & 3 deletions server/mdm/apple/util.go
Original file line number Diff line number Diff line change
@@ -14,7 +14,6 @@ import (
"strings"
"time"

"github.com/Masterminds/semver"
"github.com/fleetdm/fleet/v4/server/fleet"
"github.com/fleetdm/fleet/v4/server/mdm/nanomdm/mdm"
)
@@ -113,11 +112,11 @@ func EnrollURL(token string, appConfig *fleet.AppConfig) (string, error) {
// IsLessThanVersion returns true if the current version is less than the target version.
// If either version is invalid, an error is returned.
func IsLessThanVersion(current string, target string) (bool, error) {
cv, err := semver.NewVersion(current)
cv, err := fleet.VersionToSemverVersion(current)
if err != nil {
return false, fmt.Errorf("invalid current version: %w", err)
}
tv, err := semver.NewVersion(target)
tv, err := fleet.VersionToSemverVersion(target)
if err != nil {
return false, fmt.Errorf("invalid target version: %w", err)
}
5 changes: 3 additions & 2 deletions server/vulnerabilities/nvd/cpe_matching_rule.go
Original file line number Diff line number Diff line change
@@ -5,7 +5,8 @@ import (
"fmt"
"strings"

"github.com/Masterminds/semver"
"github.com/Masterminds/semver/v3"
"github.com/fleetdm/fleet/v4/server/fleet"
"github.com/fleetdm/fleet/v4/server/vulnerabilities/nvd/tools/wfn"
)

@@ -60,7 +61,7 @@ func (rule CPEMatchingRule) CPEMatches(cpeMeta *wfn.Attributes) bool {
return !rule.IgnoreIf(cpeMeta)
}

ver, err := semver.NewVersion(wfn.StripSlashes(cpeMeta.Version))
ver, err := fleet.VersionToSemverVersion(wfn.StripSlashes(cpeMeta.Version))
if err != nil {
return false
}

0 comments on commit d893025

Please sign in to comment.