1 package validate
2
3 import (
4 "fmt"
5 "net/url"
6 "regexp"
7 "strings"
8 "time"
9
10 "go.uber.org/multierr"
11
12 wh "edge-infra.dev/pkg/f8n/warehouse"
13 "edge-infra.dev/pkg/f8n/warehouse/pallet"
14 "edge-infra.dev/pkg/lib/build/semver"
15 )
16
17 var revisionHashRegex = "^[a-f0-9]{7,40}$"
18
19
20 var palletAnnotationValidators = map[string]AnnotationValidator{
21 wh.AnnotationKind: validatePalletKind,
22 wh.AnnotationTeam: validateNotEmpty,
23 wh.AnnotationRevision: validateRevision,
24 wh.AnnotationSource: validateSource,
25 wh.AnnotationVersion: validateVersion,
26 wh.AnnotationCreated: validateCreated,
27 wh.AnnotationVendor: validateNotEmpty,
28 }
29
30
31 var palletOptionalAnnotationValidators = map[string]AnnotationValidator{
32 wh.AnnotationTitle: validateNotEmpty,
33 wh.AnnotationDescription: validateNotEmpty,
34 wh.AnnotationDocumentation: validateDocumentation,
35 wh.AnnotationRender: validateRender,
36 wh.AnnotationCapabilities: validateCapabilities,
37 }
38
39
40 var palletManifestAnnotationValidators = map[string]AnnotationValidator{
41 wh.AnnotationKind: validateNotEmpty,
42 wh.AnnotationRefName: validateNotEmpty,
43 wh.AnnotationClusterProviders: validateClusterProviders,
44 }
45
46
47 func BuildInfo(bi pallet.BuildInfo) error {
48 return multierr.Combine(
49 validateSource(bi.Source),
50 validateVersion(bi.Version),
51 validateRevision(bi.Revision),
52 validateCreated(bi.Created),
53 )
54 }
55
56
57 func validatePalletKind(kind string) error {
58 if kind != wh.PalletKind {
59 return errInvalidPalletKindAnnotation
60 }
61 return nil
62 }
63
64
65 func validateRevision(revision string) error {
66 match, _ := regexp.MatchString(revisionHashRegex, revision)
67 if !match {
68 return errInvalidRevisionAnnotation
69 }
70 return nil
71 }
72
73
74 func validateSource(sourceURL string) error {
75 _, err := url.ParseRequestURI(sourceURL)
76 if err != nil {
77 return fmt.Errorf("%v: %v", errInvalidURLAnnotation, err)
78 }
79 return nil
80 }
81
82
83 func validateVersion(version string) error {
84 if err := semver.IsValidSemver(version); err != nil {
85 return fmt.Errorf("%v: %v", errInvalidVersionAnnotation, err)
86 }
87 return nil
88 }
89
90
91 func validateCreated(created string) error {
92 _, err := time.Parse(time.RFC3339, created)
93 if err != nil {
94 return fmt.Errorf("%v: %v", errInvalidTimestampAnnotation, err)
95 }
96 return nil
97 }
98
99
100 func validateDocumentation(documentationURL string) error {
101 _, err := url.ParseRequestURI(documentationURL)
102 if err != nil {
103 return fmt.Errorf("%v: %v", errInvalidURLAnnotation, err)
104 }
105 return nil
106 }
107
108
109 func validateRender(render string) error {
110 if !(render == "true" || render == "false") {
111 return errInvalidBinaryAnnotation
112 }
113 return nil
114 }
115
116
117 func validateCapabilities(capabilities string) error {
118 match, _ := regexp.MatchString(csvListRegex, capabilities)
119 if !match {
120 return errInvalidListAnnotation
121 }
122 return nil
123 }
124
125
126 func validatePalletAgainstRoot(annotations, rootAnnotations map[string]string) error {
127
128 capabilities := strings.Split(annotations[wh.AnnotationCapabilities], ",")
129 rootCapabilities := strings.Split(rootAnnotations[wh.AnnotationCapabilities], ",")
130 for _, capability := range capabilities {
131 if !isValueInRoot(capability, rootCapabilities) {
132 return NewDescriptorError(wh.AnnotationCapabilities, capability, rootCapabilities)
133 }
134 }
135
136
137 providers := strings.Split(annotations[wh.AnnotationClusterProviders], ",")
138 rootProviders := strings.Split(rootAnnotations[wh.AnnotationClusterProviders], ",")
139 for _, provider := range providers {
140 if !isValueInRoot(provider, rootProviders) {
141 return NewDescriptorError(wh.AnnotationClusterProviders, provider, rootProviders)
142 }
143 }
144
145
146 parameters := strings.Split(annotations[wh.AnnotationParameters], ",")
147 rootParameters := strings.Split(rootAnnotations[wh.AnnotationParameters], ",")
148 for _, parameter := range parameters {
149 if !isValueInRoot(parameter, rootParameters) {
150 return NewDescriptorError(wh.AnnotationParameters, parameter, rootParameters)
151 }
152 }
153
154 return nil
155 }
156
157
158 func isValueInRoot(value string, rootValues []string) bool {
159 if value == "" {
160 return true
161 }
162 if len(rootValues) == 0 || rootValues[0] == "" {
163 return false
164 }
165 for _, rootValue := range rootValues {
166 if value == rootValue {
167 return true
168 }
169 }
170 return false
171 }
172
View as plain text