fix: ConfigMap/Secret key validation (#623)

* fix: ConfigMap/Secret key validation

Signed-off-by: Zbynek Roubalik <zroubali@redhat.com>

* add more tests

Signed-off-by: Zbynek Roubalik <zroubali@redhat.com>
This commit is contained in:
Zbynek Roubalik 2021-11-03 18:20:48 +01:00 committed by GitHub
parent ac9de9dfc6
commit 0ed1e81692
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 174 additions and 10 deletions

View File

@ -281,9 +281,11 @@ func runAddEnvsPrompt(ctx context.Context, f fn.Function) (err error) {
},
},
{
Name: "key",
Prompt: &survey.Input{Message: "Please specify a key from the selected ConfigMap:"},
Validate: survey.Required,
Name: "key",
Prompt: &survey.Input{Message: "Please specify a key from the selected ConfigMap:"},
Validate: func(val interface{}) error {
return utils.ValidateConfigMapKey(val.(string))
},
},
}
answers := struct {
@ -339,9 +341,11 @@ func runAddEnvsPrompt(ctx context.Context, f fn.Function) (err error) {
},
},
{
Name: "key",
Prompt: &survey.Input{Message: "Please specify a key from the selected Secret:"},
Validate: survey.Required,
Name: "key",
Prompt: &survey.Input{Message: "Please specify a key from the selected Secret:"},
Validate: func(val interface{}) error {
return utils.ValidateSecretKey(val.(string))
},
},
}
answers := struct {

View File

@ -19,9 +19,9 @@ const ConfigFile = "func.yaml"
var (
regWholeSecret = regexp.MustCompile(`^{{\s*secret:((?:\w|['-]\w)+)\s*}}$`)
regKeyFromSecret = regexp.MustCompile(`^{{\s*secret:((?:\w|['-]\w)+):(\w+)\s*}}$`)
regKeyFromSecret = regexp.MustCompile(`^{{\s*secret:((?:\w|['-]\w)+):([-._a-zA-Z0-9]+)\s*}}$`)
regWholeConfigMap = regexp.MustCompile(`^{{\s*configMap:((?:\w|['-]\w)+)\s*}}$`)
regKeyFromConfigMap = regexp.MustCompile(`^{{\s*configMap:((?:\w|['-]\w)+):(\w+)\s*}}$`)
regKeyFromConfigMap = regexp.MustCompile(`^{{\s*configMap:((?:\w|['-]\w)+):([-._a-zA-Z0-9]+)\s*}}$`)
regLocalEnv = regexp.MustCompile(`^{{\s*env:(\w+)\s*}}$`)
)

View File

@ -314,10 +314,22 @@ func Test_validateEnvs(t *testing.T) {
valueSecretKey := "{{ secret:mysecret:key }}"
valueSecretKey2 := "{{secret:my-secret:key }}"
valueSecretKey3 := "{{secret:my-secret:key2}}"
valueSecretKeyIncorrect := "{{ secret:my-secret:key.key }}"
valueSecretKey4 := "{{secret:my-secret:key-2}}"
valueSecretKey5 := "{{secret:my-secret:key.2}}"
valueSecretKey6 := "{{secret:my-secret:key_2}}"
valueSecretKey7 := "{{secret:my-secret:key_2-1}}"
valueSecretKey8 := "{{secret:my-secret:key_2-1.3}}"
valueSecretKeyIncorrect := "{{ secret:my-secret:key,key }}"
valueSecretKeyIncorrect2 := "{{ my-secret:key }}"
valueSecretKeyIncorrect3 := "{{ secret:my-secret:key }}foo"
valueConfigMapKey := "{{ configMap:myconfigmap:key }}"
valueConfigMapKey2 := "{{ configMap:myconfigmap:key }}"
valueConfigMapKey3 := "{{ configMap:myconfigmap:key2 }}"
valueConfigMapKey4 := "{{ configMap:myconfigmap:key-2 }}"
valueConfigMapKey5 := "{{ configMap:myconfigmap:key.2 }}"
valueConfigMapKey6 := "{{ configMap:myconfigmap:key_2 }}"
valueConfigMapKey7 := "{{ configMap:myconfigmap:key_2-1 }}"
valueConfigMapKey8 := "{{ configMap:myconfigmap:key_2.1 }}"
valueSecret := "{{ secret:my-secret }}"
valueSecret2 := "{{ secret:mysecret }}"
@ -467,6 +479,44 @@ func Test_validateEnvs(t *testing.T) {
},
0,
},
{
"correct entry - multiple configMaps with key",
Envs{
Env{
Name: &name,
Value: &valueConfigMapKey,
},
Env{
Name: &name,
Value: &valueConfigMapKey2,
},
Env{
Name: &name,
Value: &valueConfigMapKey3,
},
Env{
Name: &name,
Value: &valueConfigMapKey4,
},
Env{
Name: &name,
Value: &valueConfigMapKey5,
},
Env{
Name: &name,
Value: &valueConfigMapKey6,
},
Env{
Name: &name,
Value: &valueConfigMapKey7,
},
Env{
Name: &name,
Value: &valueConfigMapKey8,
},
},
0,
},
{
"correct entry - multiple secrets with key",
Envs{
@ -482,6 +532,26 @@ func Test_validateEnvs(t *testing.T) {
Name: &name,
Value: &valueSecretKey3,
},
Env{
Name: &name,
Value: &valueSecretKey4,
},
Env{
Name: &name,
Value: &valueSecretKey5,
},
Env{
Name: &name,
Value: &valueSecretKey6,
},
Env{
Name: &name,
Value: &valueSecretKey7,
},
Env{
Name: &name,
Value: &valueSecretKey8,
},
},
0,
},

View File

@ -14,6 +14,12 @@ type ErrInvalidFunctionName error
// ErrInvalidEnvVarName indicates the name did not pass env var name validation.
type ErrInvalidEnvVarName error
// ErrInvalidConfigMapKey indicates the key specified for ConfigMap did not pass validation.
type ErrInvalidConfigMapKey error
// ErrInvalidSecretKey indicates the key specified for ConfigMap did not pass validation.
type ErrInvalidSecretKey error
// ErrInvalidLabel indicates the name did not pass label key validation, or the value did not pass label value validation.
type ErrInvalidLabel error
@ -36,7 +42,7 @@ func ValidateFunctionName(name string) error {
// ValidateEnvVarName validatest that the input name is a valid Kubernetes Environmet Variable name.
// It must must consist of alphabetic characters, digits, '_', '-', or '.', and must not start with a digit
// (e.g. 'my.env-name', or 'MY_ENV.NAME', or 'MyEnvName1', regex used for validation is '[-._a-zA-Z][-._a-zA-Z0-9]*'))
// (e.g. 'my.env-name', or 'MY_ENV.NAME', or 'MyEnvName1', regex used for validation is '[-._a-zA-Z][-._a-zA-Z0-9]*'
func ValidateEnvVarName(name string) error {
if errs := validation.IsEnvVarName(name); len(errs) > 0 {
return ErrInvalidEnvVarName(errors.New(strings.Join(errs, "")))
@ -45,6 +51,26 @@ func ValidateEnvVarName(name string) error {
return nil
}
// ValidateConfigMapKey validatest that the input ConfigMap key is valid.
// It must must consist of alphabetic characters, digits, '_', '-', or '.', regex used for validation is '[-._a-zA-Z0-9]+'
func ValidateConfigMapKey(key string) error {
if errs := validation.IsConfigMapKey(key); len(errs) > 0 {
return ErrInvalidConfigMapKey(errors.New(strings.Join(errs, "")))
}
return nil
}
// ValidateSecretKey validatest that the input Secret key is valid.
// It must must consist of alphabetic characters, digits, '_', '-', or '.', regex used for validation is '[-._a-zA-Z0-9]+'
func ValidateSecretKey(key string) error {
if errs := validation.IsConfigMapKey(key); len(errs) > 0 {
return ErrInvalidSecretKey(errors.New(strings.Join(errs, "")))
}
return nil
}
// ValidateLabelKey validates that the input name is a valid Kubernetes key.
// Valid label names have two segments: an optional prefix and name, separated by a slash (/).
// The name segment is required and must be 63 characters or less, beginning and ending with

View File

@ -82,6 +82,70 @@ func TestValidateEnvVarName(t *testing.T) {
}
}
func TestValidateConfigMapKey(t *testing.T) {
cases := []struct {
In string
Valid bool
}{
{"", false},
{"*", false},
{"example", true},
{"example-com", true},
{"example.com", true},
{"-example-com", true},
{"example-com-", true},
{"Example", true},
{"Example_com", true},
{"Example_com.com", true},
{"EXAMPLE", true},
{";Example", false},
{":Example", false},
{",Example", false},
}
for _, c := range cases {
err := ValidateConfigMapKey(c.In)
if err != nil && c.Valid {
t.Fatalf("Unexpected error: %v, for '%v'", err, c.In)
}
if err == nil && !c.Valid {
t.Fatalf("Expected error for invalid entry: %v", c.In)
}
}
}
func TestValidateSecretKey(t *testing.T) {
cases := []struct {
In string
Valid bool
}{
{"", false},
{"*", false},
{"example", true},
{"example-com", true},
{"example.com", true},
{"-example-com", true},
{"example-com-", true},
{"Example", true},
{"Example_com", true},
{"Example_com.com", true},
{"EXAMPLE", true},
{";Example", false},
{":Example", false},
{",Example", false},
}
for _, c := range cases {
err := ValidateSecretKey(c.In)
if err != nil && c.Valid {
t.Fatalf("Unexpected error: %v, for '%v'", err, c.In)
}
if err == nil && !c.Valid {
t.Fatalf("Expected error for invalid entry: %v", c.In)
}
}
}
func TestValidateLabelName(t *testing.T) {
cases := []struct {
In string