diff --git a/src/pkg/bundle/create.go b/src/pkg/bundle/create.go index 51cf89be..984c5d56 100644 --- a/src/pkg/bundle/create.go +++ b/src/pkg/bundle/create.go @@ -41,6 +41,13 @@ func (b *Bundle) Create() error { return err } + // validate bundle name to avoid bad characters + name, err := utils.FormatBundleName(b.bundle.Metadata.Name) + if err != nil { + return err + } + b.bundle.Metadata.Name = name + // confirm creation if ok := b.confirmBundleCreation(); !ok { return fmt.Errorf("bundle creation cancelled") diff --git a/src/pkg/utils/utils.go b/src/pkg/utils/utils.go index 6b8859f4..e119e813 100644 --- a/src/pkg/utils/utils.go +++ b/src/pkg/utils/utils.go @@ -7,6 +7,7 @@ package utils import ( "context" "encoding/json" + "errors" "fmt" "io" "os" @@ -223,3 +224,15 @@ func JSONValue(value any) (string, error) { } return string(bytes), nil } + +// formatBundleName first validates the bundle name does not have bad characters +// and then returns a lowercased version, with spaces (" ") replaced with "-". +func FormatBundleName(src string) (string, error) { + if regexp.MustCompile(`[^a-zA-Z0-9 -]+`).MatchString(src) { + return "", errors.New("bundle names should only include letters, numbers, and hypens") + } + src = strings.TrimSpace(src) + src = regexp.MustCompile(` +`).ReplaceAllString(src, "-") + src = strings.ToLower(src) + return src, nil +} diff --git a/src/pkg/utils/utils_test.go b/src/pkg/utils/utils_test.go index 73adff15..196071bd 100644 --- a/src/pkg/utils/utils_test.go +++ b/src/pkg/utils/utils_test.go @@ -88,3 +88,55 @@ func Test_IsRegistryURL(t *testing.T) { }) } } + +func Test_formatBundleName(t *testing.T) { + tests := map[string]struct { + src string + expected string + shouldErr bool // not used yet + }{ + "valid": { + src: "wordpress", + expected: "wordpress", + }, + "valid mixed caps": { + src: "woRdprEsS", + expected: "wordpress", + }, + "valid spaces": { + src: "woRdprEsS version 1", + expected: "wordpress-version-1", + }, + "valid leading spaces": { + // leading spaces trimmed but the space after the first "-" is + // converted to "-" + src: " - woRdprEsS version 1 ", + expected: "--wordpress-version-1", + }, + "invalid chars": { + src: "woRdprEsS*version 1", + shouldErr: true, + }, + "more invalid chars": { + src: "&*^woRdprEsS*version 1", + shouldErr: true, + }, + } + + for name, tt := range tests { + t.Run(name, func(t *testing.T) { + result, err := FormatBundleName(tt.src) + if tt.shouldErr && err != nil { + // expected error + return + } + if tt.shouldErr && err == nil { + t.Fatalf("expected error but got none") + } + if !tt.shouldErr && err != nil { + t.Fatalf("got error but expected none: %s", err) + } + require.Equal(t, tt.expected, result) + }) + } +}