From 4a893b13f8683ff127ffb4a83e64e5a5495c2bbe Mon Sep 17 00:00:00 2001
From: Somtochi Onyekwere <somtochionyekwere@gmail.com>
Date: Wed, 16 Feb 2022 10:47:20 +0100
Subject: [PATCH] validate that object name adheres to RFC 1123 for flux create
 commands

Signed-off-by: Somtochi Onyekwere <somtochionyekwere@gmail.com>
---
 cmd/flux/create.go                  | 18 ++++++++++
 cmd/flux/create_secret_git_test.go  |  2 +-
 cmd/flux/create_secret_helm_test.go |  2 +-
 cmd/flux/create_secret_tls_test.go  |  2 +-
 cmd/flux/create_source_git_test.go  |  2 +-
 cmd/flux/create_test.go             | 55 +++++++++++++++++++++++++++++
 6 files changed, 77 insertions(+), 4 deletions(-)
 create mode 100644 cmd/flux/create_test.go

diff --git a/cmd/flux/create.go b/cmd/flux/create.go
index 758a2f54..1c3d99ef 100644
--- a/cmd/flux/create.go
+++ b/cmd/flux/create.go
@@ -19,6 +19,7 @@ package main
 import (
 	"context"
 	"fmt"
+	"regexp"
 	"strings"
 	"time"
 
@@ -51,6 +52,18 @@ func init() {
 	createCmd.PersistentFlags().BoolVar(&createArgs.export, "export", false, "export in YAML format to stdout")
 	createCmd.PersistentFlags().StringSliceVar(&createArgs.labels, "label", nil,
 		"set labels on the resource (can specify multiple labels with commas: label1=value1,label2=value2)")
+	createCmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) error {
+		if len(args) < 1 {
+			return fmt.Errorf("name is required")
+		}
+
+		name := args[0]
+		if !validateObjectName(name) {
+			return fmt.Errorf("name '%s' is invalid, it should adhere to standard defined in RFC 1123", name)
+		}
+
+		return nil
+	}
 	rootCmd.AddCommand(createCmd)
 }
 
@@ -150,3 +163,8 @@ func parseLabels() (map[string]string, error) {
 
 	return result, nil
 }
+
+func validateObjectName(name string) bool {
+	r := regexp.MustCompile("^[a-z0-9]([a-z0-9\\-]){0,61}[a-z0-9]$")
+	return r.MatchString(name)
+}
diff --git a/cmd/flux/create_secret_git_test.go b/cmd/flux/create_secret_git_test.go
index 01a3e929..16ff400a 100644
--- a/cmd/flux/create_secret_git_test.go
+++ b/cmd/flux/create_secret_git_test.go
@@ -13,7 +13,7 @@ func TestCreateGitSecret(t *testing.T) {
 		{
 			name:   "no args",
 			args:   "create secret git",
-			assert: assertError("secret name is required"),
+			assert: assertError("name is required"),
 		},
 		{
 			name:   "basic secret",
diff --git a/cmd/flux/create_secret_helm_test.go b/cmd/flux/create_secret_helm_test.go
index 04c96dbb..fe0bc0c9 100644
--- a/cmd/flux/create_secret_helm_test.go
+++ b/cmd/flux/create_secret_helm_test.go
@@ -12,7 +12,7 @@ func TestCreateHelmSecret(t *testing.T) {
 	}{
 		{
 			args:   "create secret helm",
-			assert: assertError("secret name is required"),
+			assert: assertError("name is required"),
 		},
 		{
 			args:   "create secret helm helm-secret --username=my-username --password=my-password --namespace=my-namespace --export",
diff --git a/cmd/flux/create_secret_tls_test.go b/cmd/flux/create_secret_tls_test.go
index 8085c584..31d49200 100644
--- a/cmd/flux/create_secret_tls_test.go
+++ b/cmd/flux/create_secret_tls_test.go
@@ -12,7 +12,7 @@ func TestCreateTlsSecretNoArgs(t *testing.T) {
 	}{
 		{
 			args:   "create secret tls",
-			assert: assertError("secret name is required"),
+			assert: assertError("name is required"),
 		},
 		{
 			args:   "create secret tls certs --namespace=my-namespace --cert-file=./testdata/create_secret/tls/test-cert.pem --key-file=./testdata/create_secret/tls/test-key.pem --export",
diff --git a/cmd/flux/create_source_git_test.go b/cmd/flux/create_source_git_test.go
index 1b391bce..73c1724a 100644
--- a/cmd/flux/create_source_git_test.go
+++ b/cmd/flux/create_source_git_test.go
@@ -96,7 +96,7 @@ func TestCreateSourceGit(t *testing.T) {
 		{
 			"NoArgs",
 			"create source git",
-			assertError("GitRepository source name is required"),
+			assertError("name is required"),
 			nil,
 		}, {
 			"Succeeded",
diff --git a/cmd/flux/create_test.go b/cmd/flux/create_test.go
new file mode 100644
index 00000000..ee38fe50
--- /dev/null
+++ b/cmd/flux/create_test.go
@@ -0,0 +1,55 @@
+package main
+
+import (
+	"testing"
+
+	"k8s.io/apimachinery/pkg/util/rand"
+)
+
+func Test_validateObjectName(t *testing.T) {
+	tests := []struct {
+		name  string
+		valid bool
+	}{
+		{
+			name:  "flux-system",
+			valid: true,
+		},
+		{
+			name:  "-flux-system",
+			valid: false,
+		},
+		{
+			name:  "-flux-system-",
+			valid: false,
+		},
+		{
+			name:  "third.first",
+			valid: false,
+		},
+		{
+			name:  "THirdfirst",
+			valid: false,
+		},
+		{
+			name:  "THirdfirst",
+			valid: false,
+		},
+		{
+			name:  rand.String(63),
+			valid: true,
+		},
+		{
+			name:  rand.String(64),
+			valid: false,
+		},
+	}
+
+	for _, tt := range tests {
+		valid := validateObjectName(tt.name)
+		if valid != tt.valid {
+			t.Errorf("expected name %q to return %t for validateObjectName func but got %t",
+				tt.name, tt.valid, valid)
+		}
+	}
+}
-- 
GitLab