From 78e6a9409289cc32623e792f0ff0d9eff48a9ba8 Mon Sep 17 00:00:00 2001 From: David Zager Date: Thu, 28 Jun 2018 13:16:01 -0400 Subject: [PATCH] Enforce bundle specs version to be semver (#114) * Enforce bundle specs version to be semver * Allow Bundle Spec's with version 1.0 --- bundle/version.go | 80 +++++++++++++++++++++++++++++++++++++ bundle/version_test.go | 57 ++++++++++++++++++++++++++ registries/registry.go | 48 +--------------------- registries/registry_test.go | 27 +------------ 4 files changed, 141 insertions(+), 71 deletions(-) create mode 100644 bundle/version.go create mode 100644 bundle/version_test.go diff --git a/bundle/version.go b/bundle/version.go new file mode 100644 index 0000000..3d5f303 --- /dev/null +++ b/bundle/version.go @@ -0,0 +1,80 @@ +// +// Copyright (c) 2018 Red Hat, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package bundle + +import ( + "github.com/coreos/go-semver/semver" + log "github.com/sirupsen/logrus" +) + +// These constants describe the minimum and maximum +// accepted APB spec versions. They are used to filter +// acceptable APBs. + +// MinSpecVersion constant to describe minimum supported spec version +const MinSpecVersion = "1.0.0" + +// MaxSpecVersion constant to describe maximum supported spec version +const MaxSpecVersion = "1.0.0" + +// These constants describe the minimum and maximum +// accepted APB runtime versions. They are used to filter +// acceptable APBs. + +// MinRuntimeVersion constant to describe minimum supported runtime version +const MinRuntimeVersion = 1 + +// MaxRuntimeVersion constant to describe maximum supported runtime version +const MaxRuntimeVersion = 2 + +// The minimum/maximum Bundle spec semantic versions +var minSpecSemver = semver.New("1.0.0") +var maxSpecSemver = semver.New("1.0.0") + +// ValidateVersion - Ensure the Bundle Spec Version and Bundle Runtime Version +// are within bounds +func (s *Spec) ValidateVersion() bool { + return s.checkVersion() && s.checkRuntime() +} + +func (s *Spec) checkVersion() bool { + specSemver, err := semver.NewVersion(s.Version) + if err != nil { + if s.Version == "1.0" { + log.Warningf("Spec version is not semver compatable") + return true + } + log.Errorf("Failed to init semver - %v", err) + return false + } + + if specSemver.Compare(*minSpecSemver) < 0 { + log.Errorf("Spec version (%v) is less than the minimum version %v", s.Version, MinSpecVersion) + return false + } + + if specSemver.Compare(*maxSpecSemver) > 0 { + log.Errorf("Spec version (%v) is greater than the maximum version %v", s.Version, MaxSpecVersion) + return false + } + + return true +} + +func (s *Spec) checkRuntime() bool { + return s.Runtime >= MinRuntimeVersion && s.Runtime <= MaxRuntimeVersion +} diff --git a/bundle/version_test.go b/bundle/version_test.go new file mode 100644 index 0000000..434010a --- /dev/null +++ b/bundle/version_test.go @@ -0,0 +1,57 @@ +// +// Copyright (c) 2018 Red Hat, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package bundle + +import ( + //"fmt" + "testing" + + ft "github.com/stretchr/testify/assert" +) + +func TestValidateVersion(t *testing.T) { + + // Test Valid Spec Version + Runtime Version + var testSpec = Spec{ + Version: "1.0.0", + Runtime: 1, + } + ft.True(t, testSpec.ValidateVersion()) + + testSpec.Runtime = 2 + ft.True(t, testSpec.ValidateVersion()) + + testSpec.Version = "1.0" // Deprecated Spec Version + ft.True(t, testSpec.ValidateVersion()) + + // Test Invalid Spec Versions + testSpec.Version = "0.9.0" // less than min + ft.False(t, testSpec.ValidateVersion()) + + testSpec.Version = "1.0.1" // greater than max + ft.False(t, testSpec.ValidateVersion()) + + testSpec.Version = "1.0.0" // back to valid version + ft.True(t, testSpec.ValidateVersion()) + + // Test Invalid Runtime Versions + testSpec.Runtime = 0 + ft.False(t, testSpec.ValidateVersion()) // less than min + + testSpec.Runtime = 3 + ft.False(t, testSpec.ValidateVersion()) // greater than max +} diff --git a/registries/registry.go b/registries/registry.go index 471b478..2c9a6dd 100644 --- a/registries/registry.go +++ b/registries/registry.go @@ -23,7 +23,6 @@ import ( "io/ioutil" "net/url" "regexp" - "strconv" "strings" "sync" @@ -313,24 +312,8 @@ func validateSpecs(inSpecs []*bundle.Spec) []*bundle.Spec { } func validateSpecFormat(spec *bundle.Spec) (bool, string) { - // Specs must have compatible version - if !isCompatibleVersion(spec.Version, "1.0", "1.0") { - return false, fmt.Sprintf( - "APB Spec version [%v] out of bounds %v <= %v", - spec.Version, - "1.0", - "1.0", - ) - } - - // Specs must have compatible runtime version - if !isCompatibleRuntime(spec.Runtime, 1, 2) { - return false, fmt.Sprintf( - "APB Runtime version [%v] out of bounds %v <= %v", - spec.Runtime, - 1, - 2, - ) + if !spec.ValidateVersion() { + return false, fmt.Sprintf("Spec [%v] failed version validation", spec.FQName) } // Specs must have at least one plan @@ -352,33 +335,6 @@ func validateSpecFormat(spec *bundle.Spec) (bool, string) { return true, "" } -func isCompatibleVersion(specVersion string, minVersion string, maxVersion string) bool { - if len(strings.Split(specVersion, ".")) != 2 || len(strings.Split(minVersion, ".")) != 2 || len(strings.Split(maxVersion, ".")) != 2 { - return false - } - specMajorVersion, err := strconv.Atoi(strings.Split(specVersion, ".")[0]) - if err != nil { - return false - } - minMajorVersion, err := strconv.Atoi(strings.Split(minVersion, ".")[0]) - if err != nil { - return false - } - maxMajorVersion, err := strconv.Atoi(strings.Split(maxVersion, ".")[0]) - if err != nil { - return false - } - - if specMajorVersion >= minMajorVersion && specMajorVersion <= maxMajorVersion { - return true - } - return false -} - -func isCompatibleRuntime(specRuntime int, minVersion int, maxVersion int) bool { - return specRuntime >= minVersion && specRuntime <= maxVersion -} - func retrieveRegistryAuth(reg Config, asbNamespace string) (Config, error) { var username, password string var err error diff --git a/registries/registry_test.go b/registries/registry_test.go index 94e6b82..ee94fbd 100644 --- a/registries/registry_test.go +++ b/registries/registry_test.go @@ -28,8 +28,8 @@ import ( var SpecTags = []string{"latest", "old-release"} const SpecID = "ab094014-b740-495e-b178-946d5aa97ebf" -const SpecBadVersion = "2.0" -const SpecVersion = "1.0" +const SpecBadVersion = "2.0.0" +const SpecVersion = "1.0.0" const SpecRuntime = 1 const SpecBadRuntime = 0 const SpecName = "etherpad-bundle" @@ -397,29 +397,6 @@ func TestValidateName(t *testing.T) { } } -func TestVersionCheck(t *testing.T) { - // Test equal versions - ft.True(t, isCompatibleVersion("1.0", "1.0", "1.0")) - // Test out of range by major version - ft.False(t, isCompatibleVersion("2.0", "1.0", "1.0")) - // Test out of range by minor version - ft.True(t, isCompatibleVersion("1.10", "1.0", "1.0")) - // Test out of range by major and minor version - ft.True(t, isCompatibleVersion("2.4", "1.0", "2.0")) - // Test in range with differing major and minor version - ft.True(t, isCompatibleVersion("1.10", "1.0", "2.0")) - // Test out of range by major and minor version - ft.False(t, isCompatibleVersion("0.6", "1.0", "2.0")) - // Test out of range by major and minor version and invalid version - ft.False(t, isCompatibleVersion("0.1.0", "1.0", "1.0")) - // Test in range of long possible window - ft.True(t, isCompatibleVersion("2.5", "1.0", "3.0")) - // Test invalid version - ft.False(t, isCompatibleVersion("1", "1.0", "3.0")) - // Test invalid version - ft.False(t, isCompatibleVersion("2.5", "3.0", "4.0")) -} - type fakeAdapter struct{} func (f fakeAdapter) GetImageNames() ([]string, error) {