Skip to content

Commit 51fcc03

Browse files
refactor: move validate to lint (#2839)
Signed-off-by: Austin Abro <[email protected]> Co-authored-by: schristoff <[email protected]>
1 parent 98c1ab4 commit 51fcc03

File tree

9 files changed

+268
-307
lines changed

9 files changed

+268
-307
lines changed

src/api/v1alpha1/package.go

+8
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@ var (
2525
IsUppercaseNumberUnderscore = regexp.MustCompile(`^[A-Z0-9_]+$`).MatchString
2626
)
2727

28+
// Zarf looks for these strings in zarf.yaml to make dynamic changes
29+
const (
30+
ZarfPackageTemplatePrefix = "###ZARF_PKG_TMPL_"
31+
ZarfPackageVariablePrefix = "###ZARF_PKG_VAR_"
32+
ZarfPackageArch = "###ZARF_PKG_ARCH###"
33+
ZarfComponentName = "###ZARF_COMPONENT_NAME###"
34+
)
35+
2836
// ZarfPackageKind is an enum of the different kinds of Zarf packages.
2937
type ZarfPackageKind string
3038

src/api/v1alpha1/validate.go src/pkg/lint/validate.go

+54-139
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,19 @@
11
// SPDX-License-Identifier: Apache-2.0
22
// SPDX-FileCopyrightText: 2021-Present The Zarf Authors
33

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
66

77
import (
88
"errors"
99
"fmt"
10-
"path/filepath"
1110
"regexp"
1211
"strings"
1312

14-
"github.com/defenseunicorns/pkg/helpers/v2"
13+
"github.com/zarf-dev/zarf/src/api/v1alpha1"
1514
"k8s.io/apimachinery/pkg/util/validation"
1615
)
1716

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-
2617
var (
2718
// IsLowercaseNumberHyphenNoStartHyphen is a regex for lowercase, numbers and hyphens that cannot start with a hyphen.
2819
// https://regex101.com/r/FLdG9G/2
@@ -47,105 +38,71 @@ const (
4738
errChartReleaseNameEmpty = "release name empty, unable to fallback to chart name"
4839
)
4940

41+
// Package errors found during validation.
5042
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"
9865
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"
10368
)
10469

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 {
10772
var err error
108-
if pkg.Kind == ZarfInitConfig && pkg.Metadata.YOLO {
73+
if pkg.Kind == v1alpha1.ZarfInitConfig && pkg.Metadata.YOLO {
10974
err = errors.Join(err, fmt.Errorf(PkgValidateErrInitNoYOLO))
11075
}
111-
11276
for _, constant := range pkg.Constants {
11377
if varErr := constant.Validate(); varErr != nil {
11478
err = errors.Join(err, fmt.Errorf(PkgValidateErrConstant, varErr))
11579
}
11680
}
117-
11881
uniqueComponentNames := make(map[string]bool)
11982
groupDefault := make(map[string]string)
12083
groupedComponents := make(map[string][]string)
121-
12284
if pkg.Metadata.YOLO {
12385
for _, component := range pkg.Components {
12486
if len(component.Images) > 0 {
12587
err = errors.Join(err, fmt.Errorf(PkgValidateErrYOLONoOCI))
12688
}
127-
12889
if len(component.Repos) > 0 {
12990
err = errors.Join(err, fmt.Errorf(PkgValidateErrYOLONoGit))
13091
}
131-
13292
if component.Only.Cluster.Architecture != "" {
13393
err = errors.Join(err, fmt.Errorf(PkgValidateErrYOLONoArch))
13494
}
135-
13695
if len(component.Only.Cluster.Distros) > 0 {
13796
err = errors.Join(err, fmt.Errorf(PkgValidateErrYOLONoDistro))
13897
}
13998
}
14099
}
141-
142100
for _, component := range pkg.Components {
143101
// ensure component name is unique
144102
if _, ok := uniqueComponentNames[component.Name]; ok {
145103
err = errors.Join(err, fmt.Errorf(PkgValidateErrComponentNameNotUnique, component.Name))
146104
}
147105
uniqueComponentNames[component.Name] = true
148-
149106
if component.IsRequired() {
150107
if component.Default {
151108
err = errors.Join(err, fmt.Errorf(PkgValidateErrComponentReqDefault, component.Name))
@@ -154,37 +111,31 @@ func (pkg ZarfPackage) Validate() error {
154111
err = errors.Join(err, fmt.Errorf(PkgValidateErrComponentReqGrouped, component.Name))
155112
}
156113
}
157-
158114
uniqueChartNames := make(map[string]bool)
159115
for _, chart := range component.Charts {
160116
// ensure chart name is unique
161117
if _, ok := uniqueChartNames[chart.Name]; ok {
162118
err = errors.Join(err, fmt.Errorf(PkgValidateErrChartNameNotUnique, chart.Name))
163119
}
164120
uniqueChartNames[chart.Name] = true
165-
166-
if chartErr := chart.Validate(); chartErr != nil {
121+
if chartErr := validateChart(chart); chartErr != nil {
167122
err = errors.Join(err, fmt.Errorf(PkgValidateErrChart, chartErr))
168123
}
169124
}
170-
171125
uniqueManifestNames := make(map[string]bool)
172126
for _, manifest := range component.Manifests {
173127
// ensure manifest name is unique
174128
if _, ok := uniqueManifestNames[manifest.Name]; ok {
175129
err = errors.Join(err, fmt.Errorf(PkgValidateErrManifestNameNotUnique, manifest.Name))
176130
}
177131
uniqueManifestNames[manifest.Name] = true
178-
179-
if manifestErr := manifest.Validate(); manifestErr != nil {
132+
if manifestErr := validateManifest(manifest); manifestErr != nil {
180133
err = errors.Join(err, fmt.Errorf(PkgValidateErrManifest, manifestErr))
181134
}
182135
}
183-
184-
if actionsErr := component.Actions.validate(); actionsErr != nil {
136+
if actionsErr := validateActions(component.Actions); actionsErr != nil {
185137
err = errors.Join(err, fmt.Errorf("%q: %w", component.Name, actionsErr))
186138
}
187-
188139
// ensure groups don't have multiple defaults or only one component
189140
if component.DeprecatedGroup != "" {
190141
if component.Default {
@@ -196,74 +147,38 @@ func (pkg ZarfPackage) Validate() error {
196147
groupedComponents[component.DeprecatedGroup] = append(groupedComponents[component.DeprecatedGroup], component.Name)
197148
}
198149
}
199-
200150
for groupKey, componentNames := range groupedComponents {
201151
if len(componentNames) == 1 {
202152
err = errors.Join(err, fmt.Errorf(PkgValidateErrGroupOneComponent, groupKey, componentNames[0]))
203153
}
204154
}
205-
206155
return err
207156
}
208157

209-
func (a ZarfComponentActions) validate() error {
158+
// validateActions validates the actions of a component.
159+
func validateActions(a v1alpha1.ZarfComponentActions) error {
210160
var err error
211161

212-
err = errors.Join(err, a.OnCreate.Validate())
162+
err = errors.Join(err, validateActionSet(a.OnCreate))
213163

214-
if a.OnCreate.HasSetVariables() {
164+
if hasSetVariables(a.OnCreate) {
215165
err = errors.Join(err, fmt.Errorf("cannot contain setVariables outside of onDeploy in actions"))
216166
}
217167

218-
err = errors.Join(err, a.OnDeploy.Validate())
168+
err = errors.Join(err, validateActionSet(a.OnDeploy))
219169

220-
if a.OnRemove.HasSetVariables() {
170+
if hasSetVariables(a.OnRemove) {
221171
err = errors.Join(err, fmt.Errorf("cannot contain setVariables outside of onDeploy in actions"))
222172
}
223173

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))
260175

261176
return err
262177
}
263178

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 {
267182
for _, action := range actions {
268183
if len(action.SetVariables) > 0 {
269184
return true
@@ -275,12 +190,12 @@ func (as ZarfComponentActionSet) HasSetVariables() bool {
275190
return check(as.Before) || check(as.After) || check(as.OnSuccess) || check(as.OnFailure)
276191
}
277192

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 {
280195
var err error
281-
validate := func(actions []ZarfComponentAction) {
196+
validate := func(actions []v1alpha1.ZarfComponentAction) {
282197
for _, action := range actions {
283-
if actionErr := action.Validate(); actionErr != nil {
198+
if actionErr := validateAction(action); actionErr != nil {
284199
err = errors.Join(err, fmt.Errorf(PkgValidateErrAction, actionErr))
285200
}
286201
}
@@ -293,8 +208,8 @@ func (as ZarfComponentActionSet) Validate() error {
293208
return err
294209
}
295210

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 {
298213
var err error
299214

300215
if action.Wait != nil {
@@ -340,8 +255,8 @@ func validateReleaseName(chartName, releaseName string) (err error) {
340255
return
341256
}
342257

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 {
345260
var err error
346261

347262
if len(chart.Name) > ZarfMaxChartNameLength {
@@ -372,8 +287,8 @@ func (chart ZarfChart) Validate() error {
372287
return err
373288
}
374289

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 {
377292
var err error
378293

379294
if len(manifest.Name) > ZarfMaxChartNameLength {

0 commit comments

Comments
 (0)