...
1
15
16 package chart
17
18 import (
19 "path/filepath"
20 "strings"
21 "unicode"
22
23 "github.com/Masterminds/semver/v3"
24 )
25
26
27 type Maintainer struct {
28
29 Name string `json:"name,omitempty"`
30
31 Email string `json:"email,omitempty"`
32
33 URL string `json:"url,omitempty"`
34 }
35
36
37 func (m *Maintainer) Validate() error {
38 if m == nil {
39 return ValidationError("maintainers must not contain empty or null nodes")
40 }
41 m.Name = sanitizeString(m.Name)
42 m.Email = sanitizeString(m.Email)
43 m.URL = sanitizeString(m.URL)
44 return nil
45 }
46
47
48 type Metadata struct {
49
50 Name string `json:"name,omitempty"`
51
52 Home string `json:"home,omitempty"`
53
54 Sources []string `json:"sources,omitempty"`
55
56 Version string `json:"version,omitempty"`
57
58 Description string `json:"description,omitempty"`
59
60 Keywords []string `json:"keywords,omitempty"`
61
62 Maintainers []*Maintainer `json:"maintainers,omitempty"`
63
64 Icon string `json:"icon,omitempty"`
65
66 APIVersion string `json:"apiVersion,omitempty"`
67
68 Condition string `json:"condition,omitempty"`
69
70 Tags string `json:"tags,omitempty"`
71
72 AppVersion string `json:"appVersion,omitempty"`
73
74 Deprecated bool `json:"deprecated,omitempty"`
75
76
77 Annotations map[string]string `json:"annotations,omitempty"`
78
79 KubeVersion string `json:"kubeVersion,omitempty"`
80
81 Dependencies []*Dependency `json:"dependencies,omitempty"`
82
83 Type string `json:"type,omitempty"`
84 }
85
86
87
88 func (md *Metadata) Validate() error {
89 if md == nil {
90 return ValidationError("chart.metadata is required")
91 }
92
93 md.Name = sanitizeString(md.Name)
94 md.Description = sanitizeString(md.Description)
95 md.Home = sanitizeString(md.Home)
96 md.Icon = sanitizeString(md.Icon)
97 md.Condition = sanitizeString(md.Condition)
98 md.Tags = sanitizeString(md.Tags)
99 md.AppVersion = sanitizeString(md.AppVersion)
100 md.KubeVersion = sanitizeString(md.KubeVersion)
101 for i := range md.Sources {
102 md.Sources[i] = sanitizeString(md.Sources[i])
103 }
104 for i := range md.Keywords {
105 md.Keywords[i] = sanitizeString(md.Keywords[i])
106 }
107
108 if md.APIVersion == "" {
109 return ValidationError("chart.metadata.apiVersion is required")
110 }
111 if md.Name == "" {
112 return ValidationError("chart.metadata.name is required")
113 }
114
115 if md.Name != filepath.Base(md.Name) {
116 return ValidationErrorf("chart.metadata.name %q is invalid", md.Name)
117 }
118
119 if md.Version == "" {
120 return ValidationError("chart.metadata.version is required")
121 }
122 if !isValidSemver(md.Version) {
123 return ValidationErrorf("chart.metadata.version %q is invalid", md.Version)
124 }
125 if !isValidChartType(md.Type) {
126 return ValidationError("chart.metadata.type must be application or library")
127 }
128
129 for _, m := range md.Maintainers {
130 if err := m.Validate(); err != nil {
131 return err
132 }
133 }
134
135
136
137 dependencies := map[string]*Dependency{}
138 for _, dependency := range md.Dependencies {
139 if err := dependency.Validate(); err != nil {
140 return err
141 }
142 key := dependency.Name
143 if dependency.Alias != "" {
144 key = dependency.Alias
145 }
146 if dependencies[key] != nil {
147 return ValidationErrorf("more than one dependency with name or alias %q", key)
148 }
149 dependencies[key] = dependency
150 }
151 return nil
152 }
153
154 func isValidChartType(in string) bool {
155 switch in {
156 case "", "application", "library":
157 return true
158 }
159 return false
160 }
161
162 func isValidSemver(v string) bool {
163 _, err := semver.NewVersion(v)
164 return err == nil
165 }
166
167
168 func sanitizeString(str string) string {
169 return strings.Map(func(r rune) rune {
170 if unicode.IsSpace(r) {
171 return ' '
172 }
173 if unicode.IsPrint(r) {
174 return r
175 }
176 return -1
177 }, str)
178 }
179
View as plain text