From a4630c244b27371613597e8e68c5d0df07ca5383 Mon Sep 17 00:00:00 2001 From: Rebecca Mahany-Horton Date: Tue, 27 Feb 2024 15:16:19 -0500 Subject: [PATCH] Set minimum launcher version for pinning --- ee/agent/flags/flag_controller.go | 18 ++-------- ee/tuf/autoupdate.go | 24 +++++++++++++ ee/tuf/autoupdate_test.go | 60 +++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+), 15 deletions(-) diff --git a/ee/agent/flags/flag_controller.go b/ee/agent/flags/flag_controller.go index ce348eb32..3d1be45bd 100644 --- a/ee/agent/flags/flag_controller.go +++ b/ee/agent/flags/flag_controller.go @@ -8,9 +8,9 @@ import ( "sync" "time" - "github.com/Masterminds/semver" "github.com/kolide/launcher/ee/agent/flags/keys" "github.com/kolide/launcher/ee/agent/types" + "github.com/kolide/launcher/ee/tuf" "github.com/kolide/launcher/pkg/autoupdate" "github.com/kolide/launcher/pkg/launcher" "golang.org/x/exp/maps" @@ -501,13 +501,7 @@ func (fc *FlagController) PinnedLauncherVersion() string { WithOverrideString(fc.overrides[keys.PinnedLauncherVersion]), WithDefaultString(""), WithSanitizer(func(version string) string { - // We accept any valid semver -- the autoupdater will handle checking - // if the version actually exists at update time. - _, err := semver.NewVersion(version) - if err != nil { - return "" - } - return version + return tuf.SanitizePinnedVersion("launcher", version) }), ).get(fc.getControlServerValue(keys.PinnedLauncherVersion)) } @@ -526,13 +520,7 @@ func (fc *FlagController) PinnedOsquerydVersion() string { WithOverrideString(fc.overrides[keys.PinnedOsquerydVersion]), WithDefaultString(""), WithSanitizer(func(version string) string { - // We accept any valid semver -- the autoupdater will handle checking - // if the version actually exists at update time. - _, err := semver.NewVersion(version) - if err != nil { - return "" - } - return version + return tuf.SanitizePinnedVersion("osqueryd", version) }), ).get(fc.getControlServerValue(keys.PinnedOsquerydVersion)) } diff --git a/ee/tuf/autoupdate.go b/ee/tuf/autoupdate.go index 0e480a7b6..ed2d25cb9 100644 --- a/ee/tuf/autoupdate.go +++ b/ee/tuf/autoupdate.go @@ -21,6 +21,7 @@ import ( "sync" "time" + "github.com/Masterminds/semver" "github.com/kolide/kit/version" "github.com/kolide/launcher/ee/agent/flags/keys" "github.com/kolide/launcher/ee/agent/types" @@ -711,3 +712,26 @@ func (ta *TufAutoupdater) cleanUpOldErrors() { ) } } + +var pinnedLauncherVersionMinimum = semver.MustParse("1.6.1") + +func SanitizePinnedVersion(binary autoupdatableBinary, version string) string { + parsedVersion, err := semver.NewVersion(version) + if err != nil { + // Invalid semver + return "" + } + + // For osqueryd, we will accept any valid semver -- the autoupdater will validate + // that the version exists at update time. + if binary != binaryLauncher { + return version + } + + // For launcher, we require that the version is at least greater than v1.6.1, the + // first version to support pinning versions. + if parsedVersion.LessThan(pinnedLauncherVersionMinimum) { + return "" + } + return version +} diff --git a/ee/tuf/autoupdate_test.go b/ee/tuf/autoupdate_test.go index 34385a317..8b294e515 100644 --- a/ee/tuf/autoupdate_test.go +++ b/ee/tuf/autoupdate_test.go @@ -943,6 +943,66 @@ func Test_cleanUpOldErrors(t *testing.T) { require.Equal(t, 1, keyCount, "cleanup routine did not clean up correct number of old errors") } +func TestSanitizePinnedVersion(t *testing.T) { + t.Parallel() + + for _, tt := range []struct { + name string + pinnedVersion string + binary autoupdatableBinary + expectedSanitizedVersion string + }{ + { + name: "osqueryd, valid version", + pinnedVersion: "5.10.0", + binary: binaryOsqueryd, + expectedSanitizedVersion: "5.10.0", + }, + { + name: "osqueryd, invalid version", + pinnedVersion: "version five point ten point zero, please", + binary: binaryOsqueryd, + expectedSanitizedVersion: "", + }, + { + name: "osqueryd, valid early version", + pinnedVersion: "1.0.0", + binary: binaryOsqueryd, + expectedSanitizedVersion: "1.0.0", + }, + { + name: "launcher, valid version", + pinnedVersion: "1.6.3", + binary: binaryLauncher, + expectedSanitizedVersion: "1.6.3", + }, + { + name: "launcher, invalid version", + pinnedVersion: "alpha", + binary: binaryLauncher, + expectedSanitizedVersion: "", + }, + { + name: "launcher, version too early", + pinnedVersion: "1.5.3", + binary: binaryLauncher, + expectedSanitizedVersion: "", + }, + { + name: "launcher, valid version at minimum", + pinnedVersion: pinnedLauncherVersionMinimum.Original(), + binary: binaryLauncher, + expectedSanitizedVersion: pinnedLauncherVersionMinimum.Original(), + }, + } { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + require.Equal(t, tt.expectedSanitizedVersion, SanitizePinnedVersion(tt.binary, tt.pinnedVersion)) + }) + } +} + func setupStorage(t *testing.T) types.KVStore { s, err := storageci.NewStore(t, multislogger.NewNopLogger(), storage.AutoupdateErrorsStore.String()) require.NoError(t, err)