github.com/stefanmcshane/helm@v0.0.0-20221213002717-88a4a2c6e77d/pkg/chart/metadata.go (about) 1 /* 2 Copyright The Helm Authors. 3 Licensed under the Apache License, Version 2.0 (the "License"); 4 you may not use this file except in compliance with the License. 5 You may obtain a copy of the License at 6 7 http://www.apache.org/licenses/LICENSE-2.0 8 9 Unless required by applicable law or agreed to in writing, software 10 distributed under the License is distributed on an "AS IS" BASIS, 11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 See the License for the specific language governing permissions and 13 limitations under the License. 14 */ 15 16 package chart 17 18 import ( 19 "strings" 20 "unicode" 21 22 "github.com/Masterminds/semver/v3" 23 ) 24 25 // Maintainer describes a Chart maintainer. 26 type Maintainer struct { 27 // Name is a user name or organization name 28 Name string `json:"name,omitempty"` 29 // Email is an optional email address to contact the named maintainer 30 Email string `json:"email,omitempty"` 31 // URL is an optional URL to an address for the named maintainer 32 URL string `json:"url,omitempty"` 33 } 34 35 // Validate checks valid data and sanitizes string characters. 36 func (m *Maintainer) Validate() error { 37 if m == nil { 38 return ValidationError("maintainer cannot be an empty list") 39 } 40 m.Name = sanitizeString(m.Name) 41 m.Email = sanitizeString(m.Email) 42 m.URL = sanitizeString(m.URL) 43 return nil 44 } 45 46 // Metadata for a Chart file. This models the structure of a Chart.yaml file. 47 type Metadata struct { 48 // The name of the chart. Required. 49 Name string `json:"name,omitempty"` 50 // The URL to a relevant project page, git repo, or contact person 51 Home string `json:"home,omitempty"` 52 // Source is the URL to the source code of this chart 53 Sources []string `json:"sources,omitempty"` 54 // A SemVer 2 conformant version string of the chart. Required. 55 Version string `json:"version,omitempty"` 56 // A one-sentence description of the chart 57 Description string `json:"description,omitempty"` 58 // A list of string keywords 59 Keywords []string `json:"keywords,omitempty"` 60 // A list of name and URL/email address combinations for the maintainer(s) 61 Maintainers []*Maintainer `json:"maintainers,omitempty"` 62 // The URL to an icon file. 63 Icon string `json:"icon,omitempty"` 64 // The API Version of this chart. Required. 65 APIVersion string `json:"apiVersion,omitempty"` 66 // The condition to check to enable chart 67 Condition string `json:"condition,omitempty"` 68 // The tags to check to enable chart 69 Tags string `json:"tags,omitempty"` 70 // The version of the application enclosed inside of this chart. 71 AppVersion string `json:"appVersion,omitempty"` 72 // Whether or not this chart is deprecated 73 Deprecated bool `json:"deprecated,omitempty"` 74 // Annotations are additional mappings uninterpreted by Helm, 75 // made available for inspection by other applications. 76 Annotations map[string]string `json:"annotations,omitempty"` 77 // KubeVersion is a SemVer constraint specifying the version of Kubernetes required. 78 KubeVersion string `json:"kubeVersion,omitempty"` 79 // Dependencies are a list of dependencies for a chart. 80 Dependencies []*Dependency `json:"dependencies,omitempty"` 81 // Specifies the chart type: application or library 82 Type string `json:"type,omitempty"` 83 } 84 85 // Validate checks the metadata for known issues and sanitizes string 86 // characters. 87 func (md *Metadata) Validate() error { 88 if md == nil { 89 return ValidationError("chart.metadata is required") 90 } 91 92 md.Name = sanitizeString(md.Name) 93 md.Description = sanitizeString(md.Description) 94 md.Home = sanitizeString(md.Home) 95 md.Icon = sanitizeString(md.Icon) 96 md.Condition = sanitizeString(md.Condition) 97 md.Tags = sanitizeString(md.Tags) 98 md.AppVersion = sanitizeString(md.AppVersion) 99 md.KubeVersion = sanitizeString(md.KubeVersion) 100 for i := range md.Sources { 101 md.Sources[i] = sanitizeString(md.Sources[i]) 102 } 103 for i := range md.Keywords { 104 md.Keywords[i] = sanitizeString(md.Keywords[i]) 105 } 106 107 if md.APIVersion == "" { 108 return ValidationError("chart.metadata.apiVersion is required") 109 } 110 if md.Name == "" { 111 return ValidationError("chart.metadata.name is required") 112 } 113 if md.Version == "" { 114 return ValidationError("chart.metadata.version is required") 115 } 116 if !isValidSemver(md.Version) { 117 return ValidationErrorf("chart.metadata.version %q is invalid", md.Version) 118 } 119 if !isValidChartType(md.Type) { 120 return ValidationError("chart.metadata.type must be application or library") 121 } 122 123 for _, m := range md.Maintainers { 124 if err := m.Validate(); err != nil { 125 return err 126 } 127 } 128 129 // Aliases need to be validated here to make sure that the alias name does 130 // not contain any illegal characters. 131 for _, dependency := range md.Dependencies { 132 if err := dependency.Validate(); err != nil { 133 return err 134 } 135 } 136 return nil 137 } 138 139 func isValidChartType(in string) bool { 140 switch in { 141 case "", "application", "library": 142 return true 143 } 144 return false 145 } 146 147 func isValidSemver(v string) bool { 148 _, err := semver.NewVersion(v) 149 return err == nil 150 } 151 152 // sanitizeString normalize spaces and removes non-printable characters. 153 func sanitizeString(str string) string { 154 return strings.Map(func(r rune) rune { 155 if unicode.IsSpace(r) { 156 return ' ' 157 } 158 if unicode.IsPrint(r) { 159 return r 160 } 161 return -1 162 }, str) 163 }