1
1
// SPDX-License-Identifier: Apache-2.0
2
2
// SPDX-FileCopyrightText: 2021-Present The Zarf Authors
3
3
4
- // Package v1alpha1 holds the definition of the v1alpha1 Zarf Package
5
- package v1alpha1
4
+ // Package lint contains functions for verifying zarf yaml files are valid
5
+ package lint
6
6
7
7
import (
8
8
"errors"
9
9
"fmt"
10
- "path/filepath"
11
10
"regexp"
12
11
"strings"
13
12
14
- "github.com/defenseunicorns/pkg/helpers/v2 "
13
+ "github.com/zarf-dev/zarf/src/api/v1alpha1 "
15
14
"k8s.io/apimachinery/pkg/util/validation"
16
15
)
17
16
18
- // Zarf looks for these strings in zarf.yaml to make dynamic changes
19
- const (
20
- ZarfPackageTemplatePrefix = "###ZARF_PKG_TMPL_"
21
- ZarfPackageVariablePrefix = "###ZARF_PKG_VAR_"
22
- ZarfPackageArch = "###ZARF_PKG_ARCH###"
23
- ZarfComponentName = "###ZARF_COMPONENT_NAME###"
24
- )
25
-
26
17
var (
27
18
// IsLowercaseNumberHyphenNoStartHyphen is a regex for lowercase, numbers and hyphens that cannot start with a hyphen.
28
19
// https://regex101.com/r/FLdG9G/2
@@ -47,105 +38,71 @@ const (
47
38
errChartReleaseNameEmpty = "release name empty, unable to fallback to chart name"
48
39
)
49
40
41
+ // Package errors found during validation.
50
42
const (
51
- //nolint:revive //ignore
52
- PkgValidateErrInitNoYOLO = "sorry, you can't YOLO an init package"
53
- //nolint:revive //ignore
54
- PkgValidateErrConstant = "invalid package constant: %w"
55
- //nolint:revive //ignore
56
- PkgValidateErrYOLONoOCI = "OCI images not allowed in YOLO"
57
- //nolint:revive //ignore
58
- PkgValidateErrYOLONoGit = "git repos not allowed in YOLO"
59
- //nolint:revive //ignore
60
- PkgValidateErrYOLONoArch = "cluster architecture not allowed in YOLO"
61
- //nolint:revive //ignore
62
- PkgValidateErrYOLONoDistro = "cluster distros not allowed in YOLO"
63
- //nolint:revive //ignore
64
- PkgValidateErrComponentNameNotUnique = "component name %q is not unique"
65
- //nolint:revive //ignore
66
- PkgValidateErrComponentReqDefault = "component %q cannot be both required and default"
67
- //nolint:revive //ignore
68
- PkgValidateErrComponentReqGrouped = "component %q cannot be both required and grouped"
69
- //nolint:revive //ignore
70
- PkgValidateErrChartNameNotUnique = "chart name %q is not unique"
71
- //nolint:revive //ignore
72
- PkgValidateErrChart = "invalid chart definition: %w"
73
- //nolint:revive //ignore
74
- PkgValidateErrManifestNameNotUnique = "manifest name %q is not unique"
75
- //nolint:revive //ignore
76
- PkgValidateErrManifest = "invalid manifest definition: %w"
77
- //nolint:revive //ignore
78
- PkgValidateErrGroupMultipleDefaults = "group %q has multiple defaults (%q, %q)"
79
- //nolint:revive //ignore
80
- PkgValidateErrGroupOneComponent = "group %q only has one component (%q)"
81
- //nolint:revive //ignore
82
- PkgValidateErrAction = "invalid action: %w"
83
- //nolint:revive //ignore
84
- PkgValidateErrActionCmdWait = "action %q cannot be both a command and wait action"
85
- //nolint:revive //ignore
86
- PkgValidateErrActionClusterNetwork = "a single wait action must contain only one of cluster or network"
87
- //nolint:revive //ignore
88
- PkgValidateErrChartName = "chart %q exceed the maximum length of %d characters"
89
- //nolint:revive //ignore
90
- PkgValidateErrChartNamespaceMissing = "chart %q must include a namespace"
91
- //nolint:revive //ignore
92
- PkgValidateErrChartURLOrPath = "chart %q must have either a url or localPath"
93
- //nolint:revive //ignore
94
- PkgValidateErrChartVersion = "chart %q must include a chart version"
95
- //nolint:revive //ignore
96
- PkgValidateErrImportDefinition = "invalid imported definition for %s: %s"
97
- //nolint:revive //ignore
43
+ PkgValidateErrInitNoYOLO = "sorry, you can't YOLO an init package"
44
+ PkgValidateErrConstant = "invalid package constant: %w"
45
+ PkgValidateErrYOLONoOCI = "OCI images not allowed in YOLO"
46
+ PkgValidateErrYOLONoGit = "git repos not allowed in YOLO"
47
+ PkgValidateErrYOLONoArch = "cluster architecture not allowed in YOLO"
48
+ PkgValidateErrYOLONoDistro = "cluster distros not allowed in YOLO"
49
+ PkgValidateErrComponentNameNotUnique = "component name %q is not unique"
50
+ PkgValidateErrComponentReqDefault = "component %q cannot be both required and default"
51
+ PkgValidateErrComponentReqGrouped = "component %q cannot be both required and grouped"
52
+ PkgValidateErrChartNameNotUnique = "chart name %q is not unique"
53
+ PkgValidateErrChart = "invalid chart definition: %w"
54
+ PkgValidateErrManifestNameNotUnique = "manifest name %q is not unique"
55
+ PkgValidateErrManifest = "invalid manifest definition: %w"
56
+ PkgValidateErrGroupMultipleDefaults = "group %q has multiple defaults (%q, %q)"
57
+ PkgValidateErrGroupOneComponent = "group %q only has one component (%q)"
58
+ PkgValidateErrAction = "invalid action: %w"
59
+ PkgValidateErrActionCmdWait = "action %q cannot be both a command and wait action"
60
+ PkgValidateErrActionClusterNetwork = "a single wait action must contain only one of cluster or network"
61
+ PkgValidateErrChartName = "chart %q exceed the maximum length of %d characters"
62
+ PkgValidateErrChartNamespaceMissing = "chart %q must include a namespace"
63
+ PkgValidateErrChartURLOrPath = "chart %q must have either a url or localPath"
64
+ PkgValidateErrChartVersion = "chart %q must include a chart version"
98
65
PkgValidateErrManifestFileOrKustomize = "manifest %q must have at least one file or kustomization"
99
- //nolint:revive //ignore
100
- PkgValidateErrManifestNameLength = "manifest %q exceed the maximum length of %d characters"
101
- //nolint:revive //ignore
102
- PkgValidateErrVariable = "invalid package variable: %w"
66
+ PkgValidateErrManifestNameLength = "manifest %q exceed the maximum length of %d characters"
67
+ PkgValidateErrVariable = "invalid package variable: %w"
103
68
)
104
69
105
- // Validate runs all validation checks on the package.
106
- func (pkg ZarfPackage ) Validate ( ) error {
70
+ // ValidatePackage runs all validation checks on the package.
71
+ func ValidatePackage (pkg v1alpha1. ZarfPackage ) error {
107
72
var err error
108
- if pkg .Kind == ZarfInitConfig && pkg .Metadata .YOLO {
73
+ if pkg .Kind == v1alpha1 . ZarfInitConfig && pkg .Metadata .YOLO {
109
74
err = errors .Join (err , fmt .Errorf (PkgValidateErrInitNoYOLO ))
110
75
}
111
-
112
76
for _ , constant := range pkg .Constants {
113
77
if varErr := constant .Validate (); varErr != nil {
114
78
err = errors .Join (err , fmt .Errorf (PkgValidateErrConstant , varErr ))
115
79
}
116
80
}
117
-
118
81
uniqueComponentNames := make (map [string ]bool )
119
82
groupDefault := make (map [string ]string )
120
83
groupedComponents := make (map [string ][]string )
121
-
122
84
if pkg .Metadata .YOLO {
123
85
for _ , component := range pkg .Components {
124
86
if len (component .Images ) > 0 {
125
87
err = errors .Join (err , fmt .Errorf (PkgValidateErrYOLONoOCI ))
126
88
}
127
-
128
89
if len (component .Repos ) > 0 {
129
90
err = errors .Join (err , fmt .Errorf (PkgValidateErrYOLONoGit ))
130
91
}
131
-
132
92
if component .Only .Cluster .Architecture != "" {
133
93
err = errors .Join (err , fmt .Errorf (PkgValidateErrYOLONoArch ))
134
94
}
135
-
136
95
if len (component .Only .Cluster .Distros ) > 0 {
137
96
err = errors .Join (err , fmt .Errorf (PkgValidateErrYOLONoDistro ))
138
97
}
139
98
}
140
99
}
141
-
142
100
for _ , component := range pkg .Components {
143
101
// ensure component name is unique
144
102
if _ , ok := uniqueComponentNames [component .Name ]; ok {
145
103
err = errors .Join (err , fmt .Errorf (PkgValidateErrComponentNameNotUnique , component .Name ))
146
104
}
147
105
uniqueComponentNames [component .Name ] = true
148
-
149
106
if component .IsRequired () {
150
107
if component .Default {
151
108
err = errors .Join (err , fmt .Errorf (PkgValidateErrComponentReqDefault , component .Name ))
@@ -154,37 +111,31 @@ func (pkg ZarfPackage) Validate() error {
154
111
err = errors .Join (err , fmt .Errorf (PkgValidateErrComponentReqGrouped , component .Name ))
155
112
}
156
113
}
157
-
158
114
uniqueChartNames := make (map [string ]bool )
159
115
for _ , chart := range component .Charts {
160
116
// ensure chart name is unique
161
117
if _ , ok := uniqueChartNames [chart .Name ]; ok {
162
118
err = errors .Join (err , fmt .Errorf (PkgValidateErrChartNameNotUnique , chart .Name ))
163
119
}
164
120
uniqueChartNames [chart .Name ] = true
165
-
166
- if chartErr := chart .Validate (); chartErr != nil {
121
+ if chartErr := validateChart (chart ); chartErr != nil {
167
122
err = errors .Join (err , fmt .Errorf (PkgValidateErrChart , chartErr ))
168
123
}
169
124
}
170
-
171
125
uniqueManifestNames := make (map [string ]bool )
172
126
for _ , manifest := range component .Manifests {
173
127
// ensure manifest name is unique
174
128
if _ , ok := uniqueManifestNames [manifest .Name ]; ok {
175
129
err = errors .Join (err , fmt .Errorf (PkgValidateErrManifestNameNotUnique , manifest .Name ))
176
130
}
177
131
uniqueManifestNames [manifest .Name ] = true
178
-
179
- if manifestErr := manifest .Validate (); manifestErr != nil {
132
+ if manifestErr := validateManifest (manifest ); manifestErr != nil {
180
133
err = errors .Join (err , fmt .Errorf (PkgValidateErrManifest , manifestErr ))
181
134
}
182
135
}
183
-
184
- if actionsErr := component .Actions .validate (); actionsErr != nil {
136
+ if actionsErr := validateActions (component .Actions ); actionsErr != nil {
185
137
err = errors .Join (err , fmt .Errorf ("%q: %w" , component .Name , actionsErr ))
186
138
}
187
-
188
139
// ensure groups don't have multiple defaults or only one component
189
140
if component .DeprecatedGroup != "" {
190
141
if component .Default {
@@ -196,74 +147,38 @@ func (pkg ZarfPackage) Validate() error {
196
147
groupedComponents [component .DeprecatedGroup ] = append (groupedComponents [component .DeprecatedGroup ], component .Name )
197
148
}
198
149
}
199
-
200
150
for groupKey , componentNames := range groupedComponents {
201
151
if len (componentNames ) == 1 {
202
152
err = errors .Join (err , fmt .Errorf (PkgValidateErrGroupOneComponent , groupKey , componentNames [0 ]))
203
153
}
204
154
}
205
-
206
155
return err
207
156
}
208
157
209
- func (a ZarfComponentActions ) validate () error {
158
+ // validateActions validates the actions of a component.
159
+ func validateActions (a v1alpha1.ZarfComponentActions ) error {
210
160
var err error
211
161
212
- err = errors .Join (err , a .OnCreate . Validate ( ))
162
+ err = errors .Join (err , validateActionSet ( a .OnCreate ))
213
163
214
- if a .OnCreate . HasSetVariables ( ) {
164
+ if hasSetVariables ( a .OnCreate ) {
215
165
err = errors .Join (err , fmt .Errorf ("cannot contain setVariables outside of onDeploy in actions" ))
216
166
}
217
167
218
- err = errors .Join (err , a .OnDeploy . Validate ( ))
168
+ err = errors .Join (err , validateActionSet ( a .OnDeploy ))
219
169
220
- if a .OnRemove . HasSetVariables ( ) {
170
+ if hasSetVariables ( a .OnRemove ) {
221
171
err = errors .Join (err , fmt .Errorf ("cannot contain setVariables outside of onDeploy in actions" ))
222
172
}
223
173
224
- err = errors .Join (err , a .OnRemove .Validate ())
225
-
226
- return err
227
- }
228
-
229
- // Validate validates the component trying to be imported.
230
- func (c ZarfComponent ) Validate () error {
231
- var err error
232
- path := c .Import .Path
233
- url := c .Import .URL
234
-
235
- // ensure path or url is provided
236
- if path == "" && url == "" {
237
- err = errors .Join (err , fmt .Errorf (PkgValidateErrImportDefinition , c .Name , "neither a path nor a URL was provided" ))
238
- }
239
-
240
- // ensure path and url are not both provided
241
- if path != "" && url != "" {
242
- err = errors .Join (err , fmt .Errorf (PkgValidateErrImportDefinition , c .Name , "both a path and a URL were provided" ))
243
- }
244
-
245
- // validation for path
246
- if url == "" && path != "" {
247
- // ensure path is not an absolute path
248
- if filepath .IsAbs (path ) {
249
- err = errors .Join (err , fmt .Errorf (PkgValidateErrImportDefinition , c .Name , "path cannot be an absolute path" ))
250
- }
251
- }
252
-
253
- // validation for url
254
- if url != "" && path == "" {
255
- ok := helpers .IsOCIURL (url )
256
- if ! ok {
257
- err = errors .Join (err , fmt .Errorf (PkgValidateErrImportDefinition , c .Name , "URL is not a valid OCI URL" ))
258
- }
259
- }
174
+ err = errors .Join (err , validateActionSet (a .OnRemove ))
260
175
261
176
return err
262
177
}
263
178
264
- // HasSetVariables returns true if any of the actions contain setVariables.
265
- func (as ZarfComponentActionSet ) HasSetVariables ( ) bool {
266
- check := func (actions []ZarfComponentAction ) bool {
179
+ // hasSetVariables returns true if any of the actions contain setVariables.
180
+ func hasSetVariables (as v1alpha1. ZarfComponentActionSet ) bool {
181
+ check := func (actions []v1alpha1. ZarfComponentAction ) bool {
267
182
for _ , action := range actions {
268
183
if len (action .SetVariables ) > 0 {
269
184
return true
@@ -275,12 +190,12 @@ func (as ZarfComponentActionSet) HasSetVariables() bool {
275
190
return check (as .Before ) || check (as .After ) || check (as .OnSuccess ) || check (as .OnFailure )
276
191
}
277
192
278
- // Validate runs all validation checks on component action sets.
279
- func (as ZarfComponentActionSet ) Validate ( ) error {
193
+ // validateActionSet runs all validation checks on component action sets.
194
+ func validateActionSet (as v1alpha1. ZarfComponentActionSet ) error {
280
195
var err error
281
- validate := func (actions []ZarfComponentAction ) {
196
+ validate := func (actions []v1alpha1. ZarfComponentAction ) {
282
197
for _ , action := range actions {
283
- if actionErr := action . Validate ( ); actionErr != nil {
198
+ if actionErr := validateAction ( action ); actionErr != nil {
284
199
err = errors .Join (err , fmt .Errorf (PkgValidateErrAction , actionErr ))
285
200
}
286
201
}
@@ -293,8 +208,8 @@ func (as ZarfComponentActionSet) Validate() error {
293
208
return err
294
209
}
295
210
296
- // Validate runs all validation checks on an action.
297
- func (action ZarfComponentAction ) Validate ( ) error {
211
+ // validateAction runs all validation checks on an action.
212
+ func validateAction (action v1alpha1. ZarfComponentAction ) error {
298
213
var err error
299
214
300
215
if action .Wait != nil {
@@ -340,8 +255,8 @@ func validateReleaseName(chartName, releaseName string) (err error) {
340
255
return
341
256
}
342
257
343
- // Validate runs all validation checks on a chart.
344
- func (chart ZarfChart ) Validate ( ) error {
258
+ // validateChart runs all validation checks on a chart.
259
+ func validateChart (chart v1alpha1. ZarfChart ) error {
345
260
var err error
346
261
347
262
if len (chart .Name ) > ZarfMaxChartNameLength {
@@ -372,8 +287,8 @@ func (chart ZarfChart) Validate() error {
372
287
return err
373
288
}
374
289
375
- // Validate runs all validation checks on a manifest.
376
- func (manifest ZarfManifest ) Validate ( ) error {
290
+ // validateManifest runs all validation checks on a manifest.
291
+ func validateManifest (manifest v1alpha1. ZarfManifest ) error {
377
292
var err error
378
293
379
294
if len (manifest .Name ) > ZarfMaxChartNameLength {
0 commit comments