Skip to content

Commit 0ed1e81

Browse files
authored
fix: ConfigMap/Secret key validation (#623)
* fix: ConfigMap/Secret key validation Signed-off-by: Zbynek Roubalik <[email protected]> * add more tests Signed-off-by: Zbynek Roubalik <[email protected]>
1 parent ac9de9d commit 0ed1e81

File tree

5 files changed

+174
-10
lines changed

5 files changed

+174
-10
lines changed

Diff for: cmd/config_envs.go

+10-6
Original file line numberDiff line numberDiff line change
@@ -281,9 +281,11 @@ func runAddEnvsPrompt(ctx context.Context, f fn.Function) (err error) {
281281
},
282282
},
283283
{
284-
Name: "key",
285-
Prompt: &survey.Input{Message: "Please specify a key from the selected ConfigMap:"},
286-
Validate: survey.Required,
284+
Name: "key",
285+
Prompt: &survey.Input{Message: "Please specify a key from the selected ConfigMap:"},
286+
Validate: func(val interface{}) error {
287+
return utils.ValidateConfigMapKey(val.(string))
288+
},
287289
},
288290
}
289291
answers := struct {
@@ -339,9 +341,11 @@ func runAddEnvsPrompt(ctx context.Context, f fn.Function) (err error) {
339341
},
340342
},
341343
{
342-
Name: "key",
343-
Prompt: &survey.Input{Message: "Please specify a key from the selected Secret:"},
344-
Validate: survey.Required,
344+
Name: "key",
345+
Prompt: &survey.Input{Message: "Please specify a key from the selected Secret:"},
346+
Validate: func(val interface{}) error {
347+
return utils.ValidateSecretKey(val.(string))
348+
},
345349
},
346350
}
347351
answers := struct {

Diff for: config.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ const ConfigFile = "func.yaml"
1919

2020
var (
2121
regWholeSecret = regexp.MustCompile(`^{{\s*secret:((?:\w|['-]\w)+)\s*}}$`)
22-
regKeyFromSecret = regexp.MustCompile(`^{{\s*secret:((?:\w|['-]\w)+):(\w+)\s*}}$`)
22+
regKeyFromSecret = regexp.MustCompile(`^{{\s*secret:((?:\w|['-]\w)+):([-._a-zA-Z0-9]+)\s*}}$`)
2323
regWholeConfigMap = regexp.MustCompile(`^{{\s*configMap:((?:\w|['-]\w)+)\s*}}$`)
24-
regKeyFromConfigMap = regexp.MustCompile(`^{{\s*configMap:((?:\w|['-]\w)+):(\w+)\s*}}$`)
24+
regKeyFromConfigMap = regexp.MustCompile(`^{{\s*configMap:((?:\w|['-]\w)+):([-._a-zA-Z0-9]+)\s*}}$`)
2525
regLocalEnv = regexp.MustCompile(`^{{\s*env:(\w+)\s*}}$`)
2626
)
2727

Diff for: config_test.go

+71-1
Original file line numberDiff line numberDiff line change
@@ -314,10 +314,22 @@ func Test_validateEnvs(t *testing.T) {
314314
valueSecretKey := "{{ secret:mysecret:key }}"
315315
valueSecretKey2 := "{{secret:my-secret:key }}"
316316
valueSecretKey3 := "{{secret:my-secret:key2}}"
317-
valueSecretKeyIncorrect := "{{ secret:my-secret:key.key }}"
317+
valueSecretKey4 := "{{secret:my-secret:key-2}}"
318+
valueSecretKey5 := "{{secret:my-secret:key.2}}"
319+
valueSecretKey6 := "{{secret:my-secret:key_2}}"
320+
valueSecretKey7 := "{{secret:my-secret:key_2-1}}"
321+
valueSecretKey8 := "{{secret:my-secret:key_2-1.3}}"
322+
valueSecretKeyIncorrect := "{{ secret:my-secret:key,key }}"
318323
valueSecretKeyIncorrect2 := "{{ my-secret:key }}"
319324
valueSecretKeyIncorrect3 := "{{ secret:my-secret:key }}foo"
320325
valueConfigMapKey := "{{ configMap:myconfigmap:key }}"
326+
valueConfigMapKey2 := "{{ configMap:myconfigmap:key }}"
327+
valueConfigMapKey3 := "{{ configMap:myconfigmap:key2 }}"
328+
valueConfigMapKey4 := "{{ configMap:myconfigmap:key-2 }}"
329+
valueConfigMapKey5 := "{{ configMap:myconfigmap:key.2 }}"
330+
valueConfigMapKey6 := "{{ configMap:myconfigmap:key_2 }}"
331+
valueConfigMapKey7 := "{{ configMap:myconfigmap:key_2-1 }}"
332+
valueConfigMapKey8 := "{{ configMap:myconfigmap:key_2.1 }}"
321333

322334
valueSecret := "{{ secret:my-secret }}"
323335
valueSecret2 := "{{ secret:mysecret }}"
@@ -467,6 +479,44 @@ func Test_validateEnvs(t *testing.T) {
467479
},
468480
0,
469481
},
482+
{
483+
"correct entry - multiple configMaps with key",
484+
Envs{
485+
Env{
486+
Name: &name,
487+
Value: &valueConfigMapKey,
488+
},
489+
Env{
490+
Name: &name,
491+
Value: &valueConfigMapKey2,
492+
},
493+
Env{
494+
Name: &name,
495+
Value: &valueConfigMapKey3,
496+
},
497+
Env{
498+
Name: &name,
499+
Value: &valueConfigMapKey4,
500+
},
501+
Env{
502+
Name: &name,
503+
Value: &valueConfigMapKey5,
504+
},
505+
Env{
506+
Name: &name,
507+
Value: &valueConfigMapKey6,
508+
},
509+
Env{
510+
Name: &name,
511+
Value: &valueConfigMapKey7,
512+
},
513+
Env{
514+
Name: &name,
515+
Value: &valueConfigMapKey8,
516+
},
517+
},
518+
0,
519+
},
470520
{
471521
"correct entry - multiple secrets with key",
472522
Envs{
@@ -482,6 +532,26 @@ func Test_validateEnvs(t *testing.T) {
482532
Name: &name,
483533
Value: &valueSecretKey3,
484534
},
535+
Env{
536+
Name: &name,
537+
Value: &valueSecretKey4,
538+
},
539+
Env{
540+
Name: &name,
541+
Value: &valueSecretKey5,
542+
},
543+
Env{
544+
Name: &name,
545+
Value: &valueSecretKey6,
546+
},
547+
Env{
548+
Name: &name,
549+
Value: &valueSecretKey7,
550+
},
551+
Env{
552+
Name: &name,
553+
Value: &valueSecretKey8,
554+
},
485555
},
486556
0,
487557
},

Diff for: utils/names.go

+27-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ type ErrInvalidFunctionName error
1414
// ErrInvalidEnvVarName indicates the name did not pass env var name validation.
1515
type ErrInvalidEnvVarName error
1616

17+
// ErrInvalidConfigMapKey indicates the key specified for ConfigMap did not pass validation.
18+
type ErrInvalidConfigMapKey error
19+
20+
// ErrInvalidSecretKey indicates the key specified for ConfigMap did not pass validation.
21+
type ErrInvalidSecretKey error
22+
1723
// ErrInvalidLabel indicates the name did not pass label key validation, or the value did not pass label value validation.
1824
type ErrInvalidLabel error
1925

@@ -36,7 +42,7 @@ func ValidateFunctionName(name string) error {
3642

3743
// ValidateEnvVarName validatest that the input name is a valid Kubernetes Environmet Variable name.
3844
// It must must consist of alphabetic characters, digits, '_', '-', or '.', and must not start with a digit
39-
// (e.g. 'my.env-name', or 'MY_ENV.NAME', or 'MyEnvName1', regex used for validation is '[-._a-zA-Z][-._a-zA-Z0-9]*'))
45+
// (e.g. 'my.env-name', or 'MY_ENV.NAME', or 'MyEnvName1', regex used for validation is '[-._a-zA-Z][-._a-zA-Z0-9]*'
4046
func ValidateEnvVarName(name string) error {
4147
if errs := validation.IsEnvVarName(name); len(errs) > 0 {
4248
return ErrInvalidEnvVarName(errors.New(strings.Join(errs, "")))
@@ -45,6 +51,26 @@ func ValidateEnvVarName(name string) error {
4551
return nil
4652
}
4753

54+
// ValidateConfigMapKey validatest that the input ConfigMap key is valid.
55+
// It must must consist of alphabetic characters, digits, '_', '-', or '.', regex used for validation is '[-._a-zA-Z0-9]+'
56+
func ValidateConfigMapKey(key string) error {
57+
if errs := validation.IsConfigMapKey(key); len(errs) > 0 {
58+
return ErrInvalidConfigMapKey(errors.New(strings.Join(errs, "")))
59+
}
60+
61+
return nil
62+
}
63+
64+
// ValidateSecretKey validatest that the input Secret key is valid.
65+
// It must must consist of alphabetic characters, digits, '_', '-', or '.', regex used for validation is '[-._a-zA-Z0-9]+'
66+
func ValidateSecretKey(key string) error {
67+
if errs := validation.IsConfigMapKey(key); len(errs) > 0 {
68+
return ErrInvalidSecretKey(errors.New(strings.Join(errs, "")))
69+
}
70+
71+
return nil
72+
}
73+
4874
// ValidateLabelKey validates that the input name is a valid Kubernetes key.
4975
// Valid label names have two segments: an optional prefix and name, separated by a slash (/).
5076
// The name segment is required and must be 63 characters or less, beginning and ending with

Diff for: utils/names_test.go

+64
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,70 @@ func TestValidateEnvVarName(t *testing.T) {
8282
}
8383
}
8484

85+
func TestValidateConfigMapKey(t *testing.T) {
86+
cases := []struct {
87+
In string
88+
Valid bool
89+
}{
90+
{"", false},
91+
{"*", false},
92+
{"example", true},
93+
{"example-com", true},
94+
{"example.com", true},
95+
{"-example-com", true},
96+
{"example-com-", true},
97+
{"Example", true},
98+
{"Example_com", true},
99+
{"Example_com.com", true},
100+
{"EXAMPLE", true},
101+
{";Example", false},
102+
{":Example", false},
103+
{",Example", false},
104+
}
105+
106+
for _, c := range cases {
107+
err := ValidateConfigMapKey(c.In)
108+
if err != nil && c.Valid {
109+
t.Fatalf("Unexpected error: %v, for '%v'", err, c.In)
110+
}
111+
if err == nil && !c.Valid {
112+
t.Fatalf("Expected error for invalid entry: %v", c.In)
113+
}
114+
}
115+
}
116+
117+
func TestValidateSecretKey(t *testing.T) {
118+
cases := []struct {
119+
In string
120+
Valid bool
121+
}{
122+
{"", false},
123+
{"*", false},
124+
{"example", true},
125+
{"example-com", true},
126+
{"example.com", true},
127+
{"-example-com", true},
128+
{"example-com-", true},
129+
{"Example", true},
130+
{"Example_com", true},
131+
{"Example_com.com", true},
132+
{"EXAMPLE", true},
133+
{";Example", false},
134+
{":Example", false},
135+
{",Example", false},
136+
}
137+
138+
for _, c := range cases {
139+
err := ValidateSecretKey(c.In)
140+
if err != nil && c.Valid {
141+
t.Fatalf("Unexpected error: %v, for '%v'", err, c.In)
142+
}
143+
if err == nil && !c.Valid {
144+
t.Fatalf("Expected error for invalid entry: %v", c.In)
145+
}
146+
}
147+
}
148+
85149
func TestValidateLabelName(t *testing.T) {
86150
cases := []struct {
87151
In string

0 commit comments

Comments
 (0)