From d2e51066b25d5fb57129e85c59e8ad0fbe316422 Mon Sep 17 00:00:00 2001 From: Sander van Harmelen Date: Sat, 21 May 2022 11:25:04 +0200 Subject: [PATCH] Validate the module version as version instead of ID Without these changes a module version with prerelease or metadata will fail, while these are actually valid SemVer versions that are allowed by the module registry. --- go.mod | 1 + go.sum | 2 ++ registry_module.go | 4 +-- registry_module_integration_test.go | 55 +++++++++++++++++++++++++++++ validations.go | 17 +++++---- 5 files changed, 71 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index bbf31bdf8..76a7ed002 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( github.com/hashicorp/go-retryablehttp v0.7.0 github.com/hashicorp/go-slug v0.8.0 github.com/hashicorp/go-uuid v1.0.2 + github.com/hashicorp/go-version v1.5.0 github.com/hashicorp/jsonapi v0.0.0-20210826224640-ee7dae0fb22d github.com/stretchr/testify v1.7.0 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 diff --git a/go.sum b/go.sum index 2918378f2..864ec880d 100644 --- a/go.sum +++ b/go.sum @@ -18,6 +18,8 @@ github.com/hashicorp/go-slug v0.8.0 h1:h7AGtXVAI/cJ/Wwa/JQQaftQnWQmZbAzkzgZeZVVm github.com/hashicorp/go-slug v0.8.0/go.mod h1:Ib+IWBYfEfJGI1ZyXMGNbu2BU+aa3Dzu41RKLH301v4= github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.5.0 h1:O293SZ2Eg+AAYijkVK3jR786Am1bhDEh2GHT0tIVE5E= +github.com/hashicorp/go-version v1.5.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/jsonapi v0.0.0-20210826224640-ee7dae0fb22d h1:9ARUJJ1VVynB176G1HCwleORqCaXm/Vx0uUi0dL26I0= github.com/hashicorp/jsonapi v0.0.0-20210826224640-ee7dae0fb22d/go.mod h1:Yog5+CPEM3c99L1CL2CFCYoSzgWm5vTU58idbRUaLik= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= diff --git a/registry_module.go b/registry_module.go index af5d568d5..ee4305f98 100644 --- a/registry_module.go +++ b/registry_module.go @@ -345,7 +345,7 @@ func (r *registryModules) DeleteVersion(ctx context.Context, moduleID RegistryMo if !validString(&version) { return ErrRequiredVersion } - if !validStringID(&version) { + if !validVersion(version) { return ErrInvalidVersion } @@ -408,7 +408,7 @@ func (o RegistryModuleCreateVersionOptions) valid() error { if !validString(o.Version) { return ErrRequiredVersion } - if !validStringID(o.Version) { + if !validVersion(*o.Version) { return ErrInvalidVersion } return nil diff --git a/registry_module_integration_test.go b/registry_module_integration_test.go index 58cbaee25..bc55b71f8 100644 --- a/registry_module_integration_test.go +++ b/registry_module_integration_test.go @@ -141,6 +141,21 @@ func TestRegistryModulesCreateVersion(t *testing.T) { }) }) + t.Run("with prerelease and metadata version", func(t *testing.T) { + options := RegistryModuleCreateVersionOptions{ + Version: String("1.2.3-alpha+feature"), + } + + rmv, err := client.RegistryModules.CreateVersion(ctx, RegistryModuleID{ + Organization: orgTest.Name, + Name: registryModuleTest.Name, + Provider: registryModuleTest.Provider, + }, options) + require.NoError(t, err) + assert.NotEmpty(t, rmv.ID) + assert.Equal(t, *options.Version, rmv.Version) + }) + t.Run("with invalid options", func(t *testing.T) { t.Run("without version", func(t *testing.T) { options := RegistryModuleCreateVersionOptions{} @@ -609,6 +624,46 @@ func TestRegistryModulesDeleteVersion(t *testing.T) { assert.Equal(t, registryModuleTest.VersionStatuses, rm.VersionStatuses) }) + t.Run("with prerelease and metadata version", func(t *testing.T) { + options := RegistryModuleCreateVersionOptions{ + Version: String("1.2.3-alpha+feature"), + } + rmv, err := client.RegistryModules.CreateVersion(ctx, RegistryModuleID{ + Organization: orgTest.Name, + Name: registryModuleTest.Name, + Provider: registryModuleTest.Provider, + }, options) + require.NoError(t, err) + require.NotEmpty(t, rmv.Version) + + rm, err := client.RegistryModules.Read(ctx, RegistryModuleID{ + Organization: orgTest.Name, + Name: registryModuleTest.Name, + Provider: registryModuleTest.Provider, + }) + require.NoError(t, err) + require.NotEmpty(t, rm.VersionStatuses) + require.Equal(t, 2, len(rm.VersionStatuses)) + + err = client.RegistryModules.DeleteVersion(ctx, RegistryModuleID{ + Organization: orgTest.Name, + Name: registryModuleTest.Name, + Provider: registryModuleTest.Provider, + }, rmv.Version) + require.NoError(t, err) + + rm, err = client.RegistryModules.Read(ctx, RegistryModuleID{ + Organization: orgTest.Name, + Name: registryModuleTest.Name, + Provider: registryModuleTest.Provider, + }) + require.NoError(t, err) + assert.NotEmpty(t, rm.VersionStatuses) + assert.Equal(t, 1, len(rm.VersionStatuses)) + assert.NotEqual(t, registryModuleTest.VersionStatuses[0].Version, rmv.Version) + assert.Equal(t, registryModuleTest.VersionStatuses, rm.VersionStatuses) + }) + t.Run("without a name", func(t *testing.T) { err := client.RegistryModules.DeleteVersion(ctx, RegistryModuleID{ Organization: orgTest.Name, diff --git a/validations.go b/validations.go index 2ca32293a..f87442435 100644 --- a/validations.go +++ b/validations.go @@ -3,27 +3,32 @@ package tfe import ( "net/mail" "regexp" + + "github.com/hashicorp/go-version" ) // A regular expression used to validate common string ID patterns. - var reStringID = regexp.MustCompile(`^[a-zA-Z0-9\-._]+$`) -// validString checks if the given input is present and non-empty. +// validEmail checks if the given input is a correct email +func validEmail(v string) bool { + _, err := mail.ParseAddress(v) + return err == nil +} +// validString checks if the given input is present and non-empty. func validString(v *string) bool { return v != nil && *v != "" } // validStringID checks if the given string pointer is non-nil and // contains a typical string identifier. - func validStringID(v *string) bool { return v != nil && reStringID.MatchString(*v) } -// validEmail checks if the given input is a correct email -func validEmail(v string) bool { - _, err := mail.ParseAddress(v) +// validVersion checks if the given input is a valid version. +func validVersion(v string) bool { + _, err := version.NewVersion(v) return err == nil }