Skip to content

Commit

Permalink
Extra validation when converting labels to kubernetes (appsody#565)
Browse files Browse the repository at this point in the history
* Extra validation when converting labels to kubernetes

* update comment

* Check for empty name

* Fix comment spelling

* Fix linter
  • Loading branch information
kylegc authored and tnixa committed Nov 1, 2019
1 parent b7cecde commit 3cfbc39
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 13 deletions.
60 changes: 49 additions & 11 deletions cmd/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,23 +193,61 @@ func convertLabelsToKubeFormat(labels map[string]string) map[string]string {
var kubeLabels = make(map[string]string)

for key, value := range labels {
prefixes := strings.Split(key, ".")
nPrefixes := len(prefixes)
newKey := ""
for i := nPrefixes - 2; i >= 0; i-- {
newKey += prefixes[i]
if i > 0 {
newKey += "."
}
newKey, err := ConvertLabelToKubeFormat(key)
if err != nil {
Debug.logf("Skipping image label \"%s\" - %v", key, err)
} else {
kubeLabels[newKey] = value
}

newKey += "/" + prefixes[nPrefixes-1]
kubeLabels[newKey] = value
}

return kubeLabels
}

func ConvertLabelToKubeFormat(key string) (string, error) {
// regular expression to strip off the domain prefix
// this matches anything starting with an alphanumeric, followed by
// alphanumerics or dots, and ending with a dot
regex, err := regexp.Compile(`^[a-z0-9A-Z][a-z0-9A-Z.]*\.`)
if err != nil {
return "", err
}
loc := regex.FindStringIndex(key)
var prefix string
var name string
if loc == nil {
// did not start with a domain so there will be no prefix
prefix = ""
name = key
} else {
prefix = key[0:loc[1]]
name = key[loc[1]:]
// reverse the prefix domain
domainSections := strings.Split(prefix, ".")
newPrefix := ""
for i := len(domainSections) - 1; i >= 0; i-- {
if domainSections[i] != "" {
newPrefix += domainSections[i]
if i > 0 {
newPrefix += "."
}
}
}
prefix = newPrefix + "/"
}
if name == "" {
return "", errors.New("Invalid kubernetes metadata name. Must not be empty")
}
if len(prefix) > 253 {
return "", errors.New("Invalid kubernetes metadata prefix. Must be less than 253 characters")
}
match, err := IsValidKubernetesLabelValue(name)
if !match {
return "", errors.Errorf("Invalid kubernetes metadata name. %v", err)
}
return prefix + name, nil
}

func createLabelPairs(labels map[string]string) []string {
var labelsArr []string

Expand Down
4 changes: 2 additions & 2 deletions cmd/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -312,8 +312,8 @@ func IsValidKubernetesLabelValue(value string) (bool, error) {
if value == "" {
return true, nil
}
if len(value) > 68 {
return false, errors.New("The label must be 68 characters or less")
if len(value) > 63 {
return false, errors.New("The label must be 63 characters or less")
}

match, err := regexp.MatchString("^[a-z0-9A-Z]([a-z0-9A-Z-_.]*[a-z0-9A-Z])?$", value)
Expand Down
50 changes: 50 additions & 0 deletions cmd/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,3 +226,53 @@ func TestInvalidCmdOutput(t *testing.T) {
}

}

var convertLabelTests = []struct {
input string
expectedOutput string
}{
{"org.opencontainers.image.created", "image.opencontainers.org/created"},
{"dev.appsody.stack.id", "stack.appsody.dev/id"},
{"dev.appsody.app.name", "app.appsody.dev/name"},
{"dev.appsody.app-name", "appsody.dev/app-name"},
{"dev.app-sody.app.name", "dev/app-sody.app.name"},
{"d.name", "d/name"},
{"app.name", "app/name"},
{"app-name", "app-name"},
{"Description", "Description"},
{"maintainer", "maintainer"},
{"dev.appsody.app.a23456789012345678901234567890123456789012345678901234567890123",
"app.appsody.dev/a23456789012345678901234567890123456789012345678901234567890123"}, // exact length limit on name
}

func TestConvertLabelToKubeFormat(t *testing.T) {
for _, test := range convertLabelTests {
t.Run(test.input, func(t *testing.T) {
output, err := cmd.ConvertLabelToKubeFormat(test.input)
if err != nil {
t.Error(err)
} else if output != test.expectedOutput {
t.Errorf("Expected %s to convert to %s but got %s", test.input, test.expectedOutput, output)
}
})

}
}

var invalidConvertLabelTests = []string{
"inva$lid",
".name",
"dev.appsody.",
"dev.appsody.app.a234567890123456789012345678901234567890123456789012345678901234", // one over length limit
}

func TestInvalidConvertLabelToKubeFormat(t *testing.T) {
for _, test := range invalidConvertLabelTests {
t.Run(test, func(t *testing.T) {
_, err := cmd.ConvertLabelToKubeFormat(test)
if err == nil {
t.Errorf("Expected error but got none converting %s", test)
}
})
}
}

0 comments on commit 3cfbc39

Please sign in to comment.