From cfd59ee425e93085ebca30e906bac6122dcbecef Mon Sep 17 00:00:00 2001 From: Austin Abro Date: Thu, 30 May 2024 18:22:08 +0000 Subject: [PATCH 01/27] reasonable time to commit --- src/types/component.go | 3 +- src/types/package.go | 2 +- src/types/validate_test.go | 262 +++++++++++++++++++++++++++++++++++++ 3 files changed, 265 insertions(+), 2 deletions(-) create mode 100644 src/types/validate_test.go diff --git a/src/types/component.go b/src/types/component.go index 3c4ffa21c4..21c720ffa7 100644 --- a/src/types/component.go +++ b/src/types/component.go @@ -13,7 +13,8 @@ import ( // ZarfComponent is the primary functional grouping of assets to deploy by Zarf. type ZarfComponent struct { // Name is the unique identifier for this component - Name string `json:"name" jsonschema:"description=The name of the component,pattern=^[a-z0-9\\-]*[a-z0-9]$"` + // https://regex101.com/r/FLdG9G/2 + Name string `json:"name" jsonschema:"description=The name of the component,pattern=^[a-z0-9][a-z0-9\\-]*$"` // Description is a message given to a user when deciding to enable this component or not Description string `json:"description,omitempty" jsonschema:"description=Message to include during package deploy describing the purpose of this component"` diff --git a/src/types/package.go b/src/types/package.go index 4f3f222fb0..99ac9ef008 100644 --- a/src/types/package.go +++ b/src/types/package.go @@ -43,7 +43,7 @@ func (pkg ZarfPackage) IsSBOMAble() bool { // ZarfMetadata lists information about the current ZarfPackage. type ZarfMetadata struct { - Name string `json:"name" jsonschema:"description=Name to identify this Zarf package,pattern=^[a-z0-9\\-]*[a-z0-9]$"` + Name string `json:"name" jsonschema:"description=Name to identify this Zarf package,pattern=^[a-z0-9][a-z0-9\\-]*$"` Description string `json:"description,omitempty" jsonschema:"description=Additional information about this package"` Version string `json:"version,omitempty" jsonschema:"description=Generic string set by a package author to track the package version (Note: ZarfInitConfigs will always be versioned to the CLIVersion they were created with)"` URL string `json:"url,omitempty" jsonschema:"description=Link to package information when online"` diff --git a/src/types/validate_test.go b/src/types/validate_test.go new file mode 100644 index 0000000000..f5b21bd182 --- /dev/null +++ b/src/types/validate_test.go @@ -0,0 +1,262 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2021-Present The Zarf Authors + +// Package types contains all the types used by Zarf. +package types + +import ( + "fmt" + "testing" + + "github.com/defenseunicorns/pkg/helpers" + "github.com/defenseunicorns/zarf/src/config/lang" + "github.com/defenseunicorns/zarf/src/pkg/variables" + "github.com/stretchr/testify/assert" +) + +func TestZarfPackageValidate(t *testing.T) { + tests := []struct { + name string + pkg ZarfPackage + wantErr string + }{ + { + pkg: ZarfPackage{ + Kind: ZarfPackageConfig, + Metadata: ZarfMetadata{ + Name: "valid-package", + }, + Components: []ZarfComponent{ + { + Name: "component1", + }, + }, + }, + wantErr: "", + }, + { + pkg: ZarfPackage{ + Kind: ZarfInitConfig, + Metadata: ZarfMetadata{ + Name: "no-init-yolo", + YOLO: true, + }, + Components: []ZarfComponent{ + { + Name: "component1", + }, + }, + }, + wantErr: lang.PkgValidateErrInitNoYOLO, + }, + { + pkg: ZarfPackage{ + Kind: ZarfPackageConfig, + Metadata: ZarfMetadata{ + Name: "-invalid-package", + }, + Components: []ZarfComponent{ + {Name: "component1"}, + }, + }, + wantErr: fmt.Sprintf(lang.PkgValidateErrPkgName, "-invalid-package"), + }, + { + pkg: ZarfPackage{ + Kind: ZarfPackageConfig, + Metadata: ZarfMetadata{ + Name: "empty-components", + }, + Components: []ZarfComponent{}, + }, + wantErr: "package must have at least 1 component", + }, + { + pkg: ZarfPackage{ + Kind: ZarfPackageConfig, + Metadata: ZarfMetadata{ + Name: "bad-var", + }, + Components: []ZarfComponent{ + {Name: "component1"}, + }, + Variables: []variables.InteractiveVariable{ + { + Variable: variables.Variable{Name: "not_uppercase"}, + }, + }, + }, + wantErr: fmt.Errorf(lang.PkgValidateErrVariable, fmt.Errorf(lang.PkgValidateMustBeUppercase, "not_uppercase")).Error(), + }, + { + pkg: ZarfPackage{ + Kind: ZarfPackageConfig, + Metadata: ZarfMetadata{ + Name: "bad-constant", + }, + Components: []ZarfComponent{ + {Name: "component1"}, + }, + Constants: []variables.Constant{ + { + Name: "not_uppercase", + }, + }, + }, + wantErr: fmt.Errorf(lang.PkgValidateErrConstant, fmt.Errorf(lang.PkgValidateErrPkgConstantName, "not_uppercase")).Error(), + }, + { + pkg: ZarfPackage{ + Kind: ZarfPackageConfig, + Metadata: ZarfMetadata{ + Name: "bad-constant-pattern", + }, + Components: []ZarfComponent{ + {Name: "component1"}, + }, + Constants: []variables.Constant{ + { + Name: "BAD", + Pattern: "^good_val$", + Value: "bad_val", + }, + }, + }, + wantErr: fmt.Errorf(lang.PkgValidateErrConstant, fmt.Errorf(lang.PkgValidateErrPkgConstantPattern, "BAD", "^good_val$")).Error(), + }, + { + name: "duplicate component names", + pkg: ZarfPackage{ + Kind: ZarfPackageConfig, + Metadata: ZarfMetadata{ + Name: "valid-package", + }, + Components: []ZarfComponent{ + { + Name: "component1", + }, + { + Name: "component1", + }, + }, + }, + wantErr: fmt.Sprintf(lang.PkgValidateErrComponentNameNotUnique, "component1"), + }, + { + name: "invalid component name", + pkg: ZarfPackage{ + Kind: ZarfPackageConfig, + Metadata: ZarfMetadata{ + Name: "valid-package", + }, + Components: []ZarfComponent{ + { + Name: "Component1", + }, + }, + }, + wantErr: fmt.Sprintf(lang.PkgValidateErrComponentName, "Component1"), + }, + { + name: "unsupported OS", + pkg: ZarfPackage{ + Kind: ZarfPackageConfig, + Metadata: ZarfMetadata{ + Name: "valid-package", + }, + Components: []ZarfComponent{ + { + Name: "component1", + Only: ZarfComponentOnlyTarget{ + LocalOS: "unsupportedOS", + }, + }, + }, + }, + wantErr: fmt.Sprintf(lang.PkgValidateErrComponentLocalOS, "component1", "unsupportedOS", supportedOS), + }, + { + name: "required component with default", + pkg: ZarfPackage{ + Kind: ZarfPackageConfig, + Metadata: ZarfMetadata{ + Name: "valid-package", + }, + Components: []ZarfComponent{ + { + Name: "component1", + Default: true, + Required: helpers.BoolPtr(true), + }, + }, + }, + wantErr: fmt.Sprintf(lang.PkgValidateErrComponentReqDefault, "component1"), + }, + { + name: "required component in group", + pkg: ZarfPackage{ + Kind: ZarfPackageConfig, + Metadata: ZarfMetadata{ + Name: "valid-package", + }, + Components: []ZarfComponent{ + { + Name: "component1", + Required: helpers.BoolPtr(true), + DeprecatedGroup: "group1", + }, + }, + }, + wantErr: fmt.Sprintf(lang.PkgValidateErrComponentReqGrouped, "component1"), + }, + { + name: "duplicate chart names", + pkg: ZarfPackage{ + Kind: ZarfPackageConfig, + Metadata: ZarfMetadata{ + Name: "valid-package", + }, + Components: []ZarfComponent{ + { + Name: "component1", + Charts: []ZarfChart{ + {Name: "chart1", Namespace: "whatever", URL: "http://whatever", Version: "v1.0.0"}, + {Name: "chart1", Namespace: "whatever", URL: "http://whatever", Version: "v1.0.0"}, + }, + }, + }, + }, + wantErr: fmt.Sprintf(lang.PkgValidateErrChartNameNotUnique, "chart1"), + }, + { + name: "duplicate manifest names", + pkg: ZarfPackage{ + Kind: ZarfPackageConfig, + Metadata: ZarfMetadata{ + Name: "valid-package", + }, + Components: []ZarfComponent{ + { + Name: "component1", + Manifests: []ZarfManifest{ + {Name: "manifest1", Files: []string{"file1"}}, + {Name: "manifest1", Files: []string{"file2"}}, + }, + }, + }, + }, + wantErr: fmt.Sprintf(lang.PkgValidateErrManifestNameNotUnique, "manifest1"), + }, + } + + for _, tt := range tests { + t.Run(tt.pkg.Metadata.Name, func(t *testing.T) { + err := tt.pkg.Validate() + if tt.wantErr != "" { + assert.EqualError(t, err, tt.wantErr) + } else { + assert.NoError(t, err) + } + }) + } +} From d510ae809c9490e08f5dd8461b37a169857c8e4a Mon Sep 17 00:00:00 2001 From: Austin Abro Date: Thu, 30 May 2024 20:49:54 +0000 Subject: [PATCH 02/27] manifests validate --- go.mod | 2 +- src/config/lang/english.go | 2 +- src/types/validate.go | 2 +- src/types/validate_test.go | 116 +++++++++++++++++++++++++++++++++++-- 4 files changed, 113 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 1275140145..e28fc09b97 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/defenseunicorns/zarf -go 1.21.8 +go 1.22.3 // TODO (@AABRO): Pending merge into github.com/gojsonschema/gojsonschema (https://github.com/gojsonschema/gojsonschema/pull/5) replace github.com/xeipuuv/gojsonschema => github.com/defenseunicorns/gojsonschema v0.0.0-20231116163348-e00f069122d6 diff --git a/src/config/lang/english.go b/src/config/lang/english.go index adae1f1a41..b8c631ed6c 100644 --- a/src/config/lang/english.go +++ b/src/config/lang/english.go @@ -715,7 +715,7 @@ const ( PkgValidateErrManifest = "invalid manifest definition: %w" PkgValidateErrManifestFileOrKustomize = "manifest %q must have at least one file or kustomization" PkgValidateErrManifestNameLength = "manifest %q exceed the maximum length of %d characters" - PkgValidateErrManifestNameMissing = "manifest %q must include a name" + PkgValidateErrManifestNameMissing = "manifest must include a name" PkgValidateErrManifestNameNotUnique = "manifest name %q is not unique" PkgValidateErrName = "invalid package name: %w" PkgValidateErrPkgConstantName = "constant name %q must be all uppercase and contain no special characters except _" diff --git a/src/types/validate.go b/src/types/validate.go index fbef1dab65..bdae79c53f 100644 --- a/src/types/validate.go +++ b/src/types/validate.go @@ -323,7 +323,7 @@ func (chart ZarfChart) Validate() error { func (manifest ZarfManifest) Validate() error { // Don't allow empty names if manifest.Name == "" { - return fmt.Errorf(lang.PkgValidateErrManifestNameMissing, manifest.Name) + return fmt.Errorf(lang.PkgValidateErrManifestNameMissing) } // Helm max release name diff --git a/src/types/validate_test.go b/src/types/validate_test.go index f5b21bd182..b1f4200d4a 100644 --- a/src/types/validate_test.go +++ b/src/types/validate_test.go @@ -125,11 +125,78 @@ func TestZarfPackageValidate(t *testing.T) { wantErr: fmt.Errorf(lang.PkgValidateErrConstant, fmt.Errorf(lang.PkgValidateErrPkgConstantPattern, "BAD", "^good_val$")).Error(), }, { - name: "duplicate component names", pkg: ZarfPackage{ Kind: ZarfPackageConfig, Metadata: ZarfMetadata{ - Name: "valid-package", + Name: "yolo-images", + YOLO: true, + }, + Components: []ZarfComponent{ + { + Name: "component1", + Images: []string{"an-image"}}, + }, + }, + wantErr: lang.PkgValidateErrYOLONoOCI, + }, + { + pkg: ZarfPackage{ + Kind: ZarfPackageConfig, + Metadata: ZarfMetadata{ + Name: "yolo-repos", + YOLO: true, + }, + Components: []ZarfComponent{ + { + Name: "component1", + Repos: []string{"a-repo"}}, + }, + }, + wantErr: lang.PkgValidateErrYOLONoGit, + }, + { + pkg: ZarfPackage{ + Kind: ZarfPackageConfig, + Metadata: ZarfMetadata{ + Name: "yolo-arch", + YOLO: true, + }, + Components: []ZarfComponent{ + { + Name: "component1", + Only: ZarfComponentOnlyTarget{ + Cluster: ZarfComponentOnlyCluster{ + Architecture: "not-empty", + }, + }}, + }, + }, + wantErr: lang.PkgValidateErrYOLONoArch, + }, + { + pkg: ZarfPackage{ + Kind: ZarfPackageConfig, + Metadata: ZarfMetadata{ + Name: "yolo-distro", + YOLO: true, + }, + Components: []ZarfComponent{ + { + Name: "component1", + Only: ZarfComponentOnlyTarget{ + Cluster: ZarfComponentOnlyCluster{ + Distros: []string{"not-empty"}, + }, + }}, + }, + }, + wantErr: lang.PkgValidateErrYOLONoDistro, + }, + { + pkg: ZarfPackage{ + Kind: ZarfPackageConfig, + Metadata: ZarfMetadata{ + Name: "duplicate-component-names", }, Components: []ZarfComponent{ { @@ -143,19 +210,18 @@ func TestZarfPackageValidate(t *testing.T) { wantErr: fmt.Sprintf(lang.PkgValidateErrComponentNameNotUnique, "component1"), }, { - name: "invalid component name", pkg: ZarfPackage{ Kind: ZarfPackageConfig, Metadata: ZarfMetadata{ - Name: "valid-package", + Name: "invalid-component-name", }, Components: []ZarfComponent{ { - Name: "Component1", + Name: "-component1", }, }, }, - wantErr: fmt.Sprintf(lang.PkgValidateErrComponentName, "Component1"), + wantErr: fmt.Sprintf(lang.PkgValidateErrComponentName, "-component1"), }, { name: "unsupported OS", @@ -260,3 +326,41 @@ func TestZarfPackageValidate(t *testing.T) { }) } } + +func TestValidateManifest(t *testing.T) { + longName := "" + for range ZarfMaxChartNameLength + 1 { + longName += "a" + } + tests := []struct { + manifest ZarfManifest + wantErr string + }{ + { + manifest: ZarfManifest{Name: "valid", Files: []string{"a-file"}}, + wantErr: "", + }, + { + manifest: ZarfManifest{Name: "", Files: []string{"a-file"}}, + wantErr: lang.PkgValidateErrManifestNameMissing, + }, + { + manifest: ZarfManifest{Name: longName, Files: []string{"a-file"}}, + wantErr: fmt.Sprintf(lang.PkgValidateErrManifestNameLength, longName, ZarfMaxChartNameLength), + }, + { + manifest: ZarfManifest{Name: "nothing-there"}, + wantErr: fmt.Sprintf(lang.PkgValidateErrManifestFileOrKustomize, "nothing-there"), + }, + } + for _, tt := range tests { + t.Run(tt.manifest.Name, func(t *testing.T) { + err := tt.manifest.Validate() + if tt.wantErr != "" { + assert.EqualError(t, err, tt.wantErr) + } else { + assert.NoError(t, err) + } + }) + } +} From 96009729de7ad5c8fdaa6d0765a232d8a65b848b Mon Sep 17 00:00:00 2001 From: Austin Abro Date: Fri, 31 May 2024 12:44:12 +0000 Subject: [PATCH 03/27] refactoring validate and messaging --- src/pkg/message/message.go | 12 +- src/types/validate.go | 45 ++-- src/types/validate_test.go | 425 +++++++++++++++++-------------------- 3 files changed, 225 insertions(+), 257 deletions(-) diff --git a/src/pkg/message/message.go b/src/pkg/message/message.go index 713bb90cbe..4d71c7c5af 100644 --- a/src/pkg/message/message.go +++ b/src/pkg/message/message.go @@ -267,7 +267,17 @@ func Paragraph(format string, a ...any) string { // Paragraphn formats text into an n column paragraph func Paragraphn(n int, format string, a ...any) string { - return pterm.DefaultParagraph.WithMaxWidth(n).Sprintf(format, a...) + // Split the formatted string into lines based on newlines + lines := strings.Split(fmt.Sprintf(format, a...), "\n") + + // Format each line individually + formattedLines := make([]string, len(lines)) + for i, line := range lines { + formattedLines[i] = pterm.DefaultParagraph.WithMaxWidth(n).Sprintf(line) + } + + // Join the formatted lines with newlines + return strings.Join(formattedLines, "\n") } // PrintDiff prints the differences between a and b with a as original and b as new diff --git a/src/types/validate.go b/src/types/validate.go index bdae79c53f..c18eaf65ac 100644 --- a/src/types/validate.go +++ b/src/types/validate.go @@ -40,27 +40,28 @@ func SupportedOS() []string { // Validate runs all validation checks on the package. func (pkg ZarfPackage) Validate() error { + errs := []error{} if pkg.Kind == ZarfInitConfig && pkg.Metadata.YOLO { - return fmt.Errorf(lang.PkgValidateErrInitNoYOLO) + errs = append(errs, fmt.Errorf(lang.PkgValidateErrInitNoYOLO)) } if !IsLowercaseNumberHyphenNoStartHyphen(pkg.Metadata.Name) { - return fmt.Errorf(lang.PkgValidateErrPkgName, pkg.Metadata.Name) + errs = append(errs, fmt.Errorf(lang.PkgValidateErrPkgName, pkg.Metadata.Name)) } if len(pkg.Components) == 0 { - return errors.New("package must have at least 1 component") + errs = append(errs, fmt.Errorf("package must have at least 1 component")) } for _, variable := range pkg.Variables { if err := variable.Validate(); err != nil { - return fmt.Errorf(lang.PkgValidateErrVariable, err) + errs = append(errs, fmt.Errorf(lang.PkgValidateErrVariable, err)) } } for _, constant := range pkg.Constants { if err := constant.Validate(); err != nil { - return fmt.Errorf(lang.PkgValidateErrConstant, err) + errs = append(errs, fmt.Errorf(lang.PkgValidateErrConstant, err)) } } @@ -71,19 +72,19 @@ func (pkg ZarfPackage) Validate() error { if pkg.Metadata.YOLO { for _, component := range pkg.Components { if len(component.Images) > 0 { - return fmt.Errorf(lang.PkgValidateErrYOLONoOCI) + errs = append(errs, fmt.Errorf(lang.PkgValidateErrYOLONoOCI)) } if len(component.Repos) > 0 { - return fmt.Errorf(lang.PkgValidateErrYOLONoGit) + errs = append(errs, fmt.Errorf(lang.PkgValidateErrYOLONoGit)) } if component.Only.Cluster.Architecture != "" { - return fmt.Errorf(lang.PkgValidateErrYOLONoArch) + errs = append(errs, fmt.Errorf(lang.PkgValidateErrYOLONoArch)) } if len(component.Only.Cluster.Distros) > 0 { - return fmt.Errorf(lang.PkgValidateErrYOLONoDistro) + errs = append(errs, fmt.Errorf(lang.PkgValidateErrYOLONoDistro)) } } } @@ -91,24 +92,24 @@ func (pkg ZarfPackage) Validate() error { for _, component := range pkg.Components { // ensure component name is unique if _, ok := uniqueComponentNames[component.Name]; ok { - return fmt.Errorf(lang.PkgValidateErrComponentNameNotUnique, component.Name) + errs = append(errs, fmt.Errorf(lang.PkgValidateErrComponentNameNotUnique, component.Name)) } uniqueComponentNames[component.Name] = true if !IsLowercaseNumberHyphenNoStartHyphen(component.Name) { - return fmt.Errorf(lang.PkgValidateErrComponentName, component.Name) + errs = append(errs, fmt.Errorf(lang.PkgValidateErrComponentName, component.Name)) } if !slices.Contains(supportedOS, component.Only.LocalOS) { - return fmt.Errorf(lang.PkgValidateErrComponentLocalOS, component.Name, component.Only.LocalOS, supportedOS) + errs = append(errs, fmt.Errorf(lang.PkgValidateErrComponentLocalOS, component.Name, component.Only.LocalOS, supportedOS)) } if component.IsRequired() { if component.Default { - return fmt.Errorf(lang.PkgValidateErrComponentReqDefault, component.Name) + errs = append(errs, fmt.Errorf(lang.PkgValidateErrComponentReqDefault, component.Name)) } if component.DeprecatedGroup != "" { - return fmt.Errorf(lang.PkgValidateErrComponentReqGrouped, component.Name) + errs = append(errs, fmt.Errorf(lang.PkgValidateErrComponentReqGrouped, component.Name)) } } @@ -116,12 +117,12 @@ func (pkg ZarfPackage) Validate() error { for _, chart := range component.Charts { // ensure chart name is unique if _, ok := uniqueChartNames[chart.Name]; ok { - return fmt.Errorf(lang.PkgValidateErrChartNameNotUnique, chart.Name) + errs = append(errs, fmt.Errorf(lang.PkgValidateErrChartNameNotUnique, chart.Name)) } uniqueChartNames[chart.Name] = true if err := chart.Validate(); err != nil { - return fmt.Errorf(lang.PkgValidateErrChart, err) + errs = append(errs, fmt.Errorf(lang.PkgValidateErrChart, err)) } } @@ -129,24 +130,24 @@ func (pkg ZarfPackage) Validate() error { for _, manifest := range component.Manifests { // ensure manifest name is unique if _, ok := uniqueManifestNames[manifest.Name]; ok { - return fmt.Errorf(lang.PkgValidateErrManifestNameNotUnique, manifest.Name) + errs = append(errs, fmt.Errorf(lang.PkgValidateErrManifestNameNotUnique, manifest.Name)) } uniqueManifestNames[manifest.Name] = true if err := manifest.Validate(); err != nil { - return fmt.Errorf(lang.PkgValidateErrManifest, err) + errs = append(errs, fmt.Errorf(lang.PkgValidateErrManifest, err)) } } if err := component.Actions.Validate(); err != nil { - return fmt.Errorf("%q: %w", component.Name, err) + errs = append(errs, fmt.Errorf("%q: %w", component.Name, err)) } // ensure groups don't have multiple defaults or only one component if component.DeprecatedGroup != "" { if component.Default { if _, ok := groupDefault[component.DeprecatedGroup]; ok { - return fmt.Errorf(lang.PkgValidateErrGroupMultipleDefaults, component.DeprecatedGroup, groupDefault[component.DeprecatedGroup], component.Name) + errs = append(errs, fmt.Errorf(lang.PkgValidateErrGroupMultipleDefaults, component.DeprecatedGroup, groupDefault[component.DeprecatedGroup], component.Name)) } groupDefault[component.DeprecatedGroup] = component.Name } @@ -156,11 +157,11 @@ func (pkg ZarfPackage) Validate() error { for groupKey, componentNames := range groupedComponents { if len(componentNames) == 1 { - return fmt.Errorf(lang.PkgValidateErrGroupOneComponent, groupKey, componentNames[0]) + errs = append(errs, fmt.Errorf(lang.PkgValidateErrGroupOneComponent, groupKey, componentNames[0])) } } - return nil + return errors.Join(errs...) } // Validate runs all validation checks on component actions. diff --git a/src/types/validate_test.go b/src/types/validate_test.go index b1f4200d4a..30c9369768 100644 --- a/src/types/validate_test.go +++ b/src/types/validate_test.go @@ -6,9 +6,9 @@ package types import ( "fmt" + "strings" "testing" - "github.com/defenseunicorns/pkg/helpers" "github.com/defenseunicorns/zarf/src/config/lang" "github.com/defenseunicorns/zarf/src/pkg/variables" "github.com/stretchr/testify/assert" @@ -34,33 +34,6 @@ func TestZarfPackageValidate(t *testing.T) { }, wantErr: "", }, - { - pkg: ZarfPackage{ - Kind: ZarfInitConfig, - Metadata: ZarfMetadata{ - Name: "no-init-yolo", - YOLO: true, - }, - Components: []ZarfComponent{ - { - Name: "component1", - }, - }, - }, - wantErr: lang.PkgValidateErrInitNoYOLO, - }, - { - pkg: ZarfPackage{ - Kind: ZarfPackageConfig, - Metadata: ZarfMetadata{ - Name: "-invalid-package", - }, - Components: []ZarfComponent{ - {Name: "component1"}, - }, - }, - wantErr: fmt.Sprintf(lang.PkgValidateErrPkgName, "-invalid-package"), - }, { pkg: ZarfPackage{ Kind: ZarfPackageConfig, @@ -75,46 +48,22 @@ func TestZarfPackageValidate(t *testing.T) { pkg: ZarfPackage{ Kind: ZarfPackageConfig, Metadata: ZarfMetadata{ - Name: "bad-var", + Name: "-invalid-package", }, Components: []ZarfComponent{ - {Name: "component1"}, + { + Name: "component1", + }, }, Variables: []variables.InteractiveVariable{ { Variable: variables.Variable{Name: "not_uppercase"}, }, }, - }, - wantErr: fmt.Errorf(lang.PkgValidateErrVariable, fmt.Errorf(lang.PkgValidateMustBeUppercase, "not_uppercase")).Error(), - }, - { - pkg: ZarfPackage{ - Kind: ZarfPackageConfig, - Metadata: ZarfMetadata{ - Name: "bad-constant", - }, - Components: []ZarfComponent{ - {Name: "component1"}, - }, Constants: []variables.Constant{ { Name: "not_uppercase", }, - }, - }, - wantErr: fmt.Errorf(lang.PkgValidateErrConstant, fmt.Errorf(lang.PkgValidateErrPkgConstantName, "not_uppercase")).Error(), - }, - { - pkg: ZarfPackage{ - Kind: ZarfPackageConfig, - Metadata: ZarfMetadata{ - Name: "bad-constant-pattern", - }, - Components: []ZarfComponent{ - {Name: "component1"}, - }, - Constants: []variables.Constant{ { Name: "BAD", Pattern: "^good_val$", @@ -122,13 +71,18 @@ func TestZarfPackageValidate(t *testing.T) { }, }, }, - wantErr: fmt.Errorf(lang.PkgValidateErrConstant, fmt.Errorf(lang.PkgValidateErrPkgConstantPattern, "BAD", "^good_val$")).Error(), + wantErr: strings.Join([]string{ + fmt.Sprintf(lang.PkgValidateErrPkgName, "-invalid-package"), + fmt.Errorf(lang.PkgValidateErrVariable, fmt.Errorf(lang.PkgValidateMustBeUppercase, "not_uppercase")).Error(), + fmt.Errorf(lang.PkgValidateErrConstant, fmt.Errorf(lang.PkgValidateErrPkgConstantName, "not_uppercase")).Error(), + fmt.Errorf(lang.PkgValidateErrConstant, fmt.Errorf(lang.PkgValidateErrPkgConstantPattern, "BAD", "^good_val$")).Error(), + }, "\n"), }, { pkg: ZarfPackage{ - Kind: ZarfPackageConfig, + Kind: ZarfInitConfig, Metadata: ZarfMetadata{ - Name: "yolo-images", + Name: "invalid-yolo", YOLO: true, }, Components: []ZarfComponent{ @@ -137,182 +91,185 @@ func TestZarfPackageValidate(t *testing.T) { Images: []string{"an-image"}}, }, }, - wantErr: lang.PkgValidateErrYOLONoOCI, - }, - { - pkg: ZarfPackage{ - Kind: ZarfPackageConfig, - Metadata: ZarfMetadata{ - Name: "yolo-repos", - YOLO: true, - }, - Components: []ZarfComponent{ - { - Name: "component1", - Repos: []string{"a-repo"}}, - }, - }, - wantErr: lang.PkgValidateErrYOLONoGit, - }, - { - pkg: ZarfPackage{ - Kind: ZarfPackageConfig, - Metadata: ZarfMetadata{ - Name: "yolo-arch", - YOLO: true, - }, - Components: []ZarfComponent{ - { - Name: "component1", - Only: ZarfComponentOnlyTarget{ - Cluster: ZarfComponentOnlyCluster{ - Architecture: "not-empty", - }, - }}, - }, - }, - wantErr: lang.PkgValidateErrYOLONoArch, - }, - { - pkg: ZarfPackage{ - Kind: ZarfPackageConfig, - Metadata: ZarfMetadata{ - Name: "yolo-distro", - YOLO: true, - }, - Components: []ZarfComponent{ - { - Name: "component1", - Only: ZarfComponentOnlyTarget{ - Cluster: ZarfComponentOnlyCluster{ - Distros: []string{"not-empty"}, - }, - }}, - }, - }, - wantErr: lang.PkgValidateErrYOLONoDistro, - }, - { - pkg: ZarfPackage{ - Kind: ZarfPackageConfig, - Metadata: ZarfMetadata{ - Name: "duplicate-component-names", - }, - Components: []ZarfComponent{ - { - Name: "component1", - }, - { - Name: "component1", - }, - }, - }, - wantErr: fmt.Sprintf(lang.PkgValidateErrComponentNameNotUnique, "component1"), - }, - { - pkg: ZarfPackage{ - Kind: ZarfPackageConfig, - Metadata: ZarfMetadata{ - Name: "invalid-component-name", - }, - Components: []ZarfComponent{ - { - Name: "-component1", - }, - }, - }, - wantErr: fmt.Sprintf(lang.PkgValidateErrComponentName, "-component1"), - }, - { - name: "unsupported OS", - pkg: ZarfPackage{ - Kind: ZarfPackageConfig, - Metadata: ZarfMetadata{ - Name: "valid-package", - }, - Components: []ZarfComponent{ - { - Name: "component1", - Only: ZarfComponentOnlyTarget{ - LocalOS: "unsupportedOS", - }, - }, - }, - }, - wantErr: fmt.Sprintf(lang.PkgValidateErrComponentLocalOS, "component1", "unsupportedOS", supportedOS), - }, - { - name: "required component with default", - pkg: ZarfPackage{ - Kind: ZarfPackageConfig, - Metadata: ZarfMetadata{ - Name: "valid-package", - }, - Components: []ZarfComponent{ - { - Name: "component1", - Default: true, - Required: helpers.BoolPtr(true), - }, - }, - }, - wantErr: fmt.Sprintf(lang.PkgValidateErrComponentReqDefault, "component1"), - }, - { - name: "required component in group", - pkg: ZarfPackage{ - Kind: ZarfPackageConfig, - Metadata: ZarfMetadata{ - Name: "valid-package", - }, - Components: []ZarfComponent{ - { - Name: "component1", - Required: helpers.BoolPtr(true), - DeprecatedGroup: "group1", - }, - }, - }, - wantErr: fmt.Sprintf(lang.PkgValidateErrComponentReqGrouped, "component1"), - }, - { - name: "duplicate chart names", - pkg: ZarfPackage{ - Kind: ZarfPackageConfig, - Metadata: ZarfMetadata{ - Name: "valid-package", - }, - Components: []ZarfComponent{ - { - Name: "component1", - Charts: []ZarfChart{ - {Name: "chart1", Namespace: "whatever", URL: "http://whatever", Version: "v1.0.0"}, - {Name: "chart1", Namespace: "whatever", URL: "http://whatever", Version: "v1.0.0"}, - }, - }, - }, - }, - wantErr: fmt.Sprintf(lang.PkgValidateErrChartNameNotUnique, "chart1"), - }, - { - name: "duplicate manifest names", - pkg: ZarfPackage{ - Kind: ZarfPackageConfig, - Metadata: ZarfMetadata{ - Name: "valid-package", - }, - Components: []ZarfComponent{ - { - Name: "component1", - Manifests: []ZarfManifest{ - {Name: "manifest1", Files: []string{"file1"}}, - {Name: "manifest1", Files: []string{"file2"}}, - }, - }, - }, - }, - wantErr: fmt.Sprintf(lang.PkgValidateErrManifestNameNotUnique, "manifest1"), + wantErr: strings.Join([]string{ + lang.PkgValidateErrInitNoYOLO, + lang.PkgValidateErrYOLONoOCI, + }, "\n"), }, + // { + // pkg: ZarfPackage{ + // Kind: ZarfPackageConfig, + // Metadata: ZarfMetadata{ + // Name: "yolo-repos", + // YOLO: true, + // }, + // Components: []ZarfComponent{ + // { + // Name: "component1", + // Repos: []string{"a-repo"}}, + // }, + // }, + // wantErr: lang.PkgValidateErrYOLONoGit, + // }, + // { + // pkg: ZarfPackage{ + // Kind: ZarfPackageConfig, + // Metadata: ZarfMetadata{ + // Name: "yolo-arch", + // YOLO: true, + // }, + // Components: []ZarfComponent{ + // { + // Name: "component1", + // Only: ZarfComponentOnlyTarget{ + // Cluster: ZarfComponentOnlyCluster{ + // Architecture: "not-empty", + // }, + // }}, + // }, + // }, + // wantErr: lang.PkgValidateErrYOLONoArch, + // }, + // { + // pkg: ZarfPackage{ + // Kind: ZarfPackageConfig, + // Metadata: ZarfMetadata{ + // Name: "yolo-distro", + // YOLO: true, + // }, + // Components: []ZarfComponent{ + // { + // Name: "component1", + // Only: ZarfComponentOnlyTarget{ + // Cluster: ZarfComponentOnlyCluster{ + // Distros: []string{"not-empty"}, + // }, + // }}, + // }, + // }, + // wantErr: lang.PkgValidateErrYOLONoDistro, + // }, + // { + // pkg: ZarfPackage{ + // Kind: ZarfPackageConfig, + // Metadata: ZarfMetadata{ + // Name: "duplicate-component-names", + // }, + // Components: []ZarfComponent{ + // { + // Name: "component1", + // }, + // { + // Name: "component1", + // }, + // }, + // }, + // wantErr: fmt.Sprintf(lang.PkgValidateErrComponentNameNotUnique, "component1"), + // }, + // { + // pkg: ZarfPackage{ + // Kind: ZarfPackageConfig, + // Metadata: ZarfMetadata{ + // Name: "invalid-component-name", + // }, + // Components: []ZarfComponent{ + // { + // Name: "-component1", + // }, + // }, + // }, + // wantErr: fmt.Sprintf(lang.PkgValidateErrComponentName, "-component1"), + // }, + // { + // name: "unsupported OS", + // pkg: ZarfPackage{ + // Kind: ZarfPackageConfig, + // Metadata: ZarfMetadata{ + // Name: "valid-package", + // }, + // Components: []ZarfComponent{ + // { + // Name: "component1", + // Only: ZarfComponentOnlyTarget{ + // LocalOS: "unsupportedOS", + // }, + // }, + // }, + // }, + // wantErr: fmt.Sprintf(lang.PkgValidateErrComponentLocalOS, "component1", "unsupportedOS", supportedOS), + // }, + // { + // name: "required component with default", + // pkg: ZarfPackage{ + // Kind: ZarfPackageConfig, + // Metadata: ZarfMetadata{ + // Name: "valid-package", + // }, + // Components: []ZarfComponent{ + // { + // Name: "component1", + // Default: true, + // Required: helpers.BoolPtr(true), + // }, + // }, + // }, + // wantErr: fmt.Sprintf(lang.PkgValidateErrComponentReqDefault, "component1"), + // }, + // { + // name: "required component in group", + // pkg: ZarfPackage{ + // Kind: ZarfPackageConfig, + // Metadata: ZarfMetadata{ + // Name: "valid-package", + // }, + // Components: []ZarfComponent{ + // { + // Name: "component1", + // Required: helpers.BoolPtr(true), + // DeprecatedGroup: "group1", + // }, + // }, + // }, + // wantErr: fmt.Sprintf(lang.PkgValidateErrComponentReqGrouped, "component1"), + // }, + // { + // name: "duplicate chart names", + // pkg: ZarfPackage{ + // Kind: ZarfPackageConfig, + // Metadata: ZarfMetadata{ + // Name: "valid-package", + // }, + // Components: []ZarfComponent{ + // { + // Name: "component1", + // Charts: []ZarfChart{ + // {Name: "chart1", Namespace: "whatever", URL: "http://whatever", Version: "v1.0.0"}, + // {Name: "chart1", Namespace: "whatever", URL: "http://whatever", Version: "v1.0.0"}, + // }, + // }, + // }, + // }, + // wantErr: fmt.Sprintf(lang.PkgValidateErrChartNameNotUnique, "chart1"), + // }, + // { + // name: "duplicate manifest names", + // pkg: ZarfPackage{ + // Kind: ZarfPackageConfig, + // Metadata: ZarfMetadata{ + // Name: "valid-package", + // }, + // Components: []ZarfComponent{ + // { + // Name: "component1", + // Manifests: []ZarfManifest{ + // {Name: "manifest1", Files: []string{"file1"}}, + // {Name: "manifest1", Files: []string{"file2"}}, + // }, + // }, + // }, + // }, + // wantErr: fmt.Sprintf(lang.PkgValidateErrManifestNameNotUnique, "manifest1"), + // }, } for _, tt := range tests { From f0f82fee81a8e432e5ae063d36786f186b10c76c Mon Sep 17 00:00:00 2001 From: Austin Abro Date: Fri, 31 May 2024 14:28:58 +0000 Subject: [PATCH 04/27] docs and schema --- zarf.schema.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/zarf.schema.json b/zarf.schema.json index 27a8a89a4c..0f43c9dbe5 100644 --- a/zarf.schema.json +++ b/zarf.schema.json @@ -420,7 +420,7 @@ "properties": { "name": { "type": "string", - "pattern": "^[a-z0-9\\-]*[a-z0-9]$", + "pattern": "^[a-z0-9][a-z0-9\\-]*$", "description": "The name of the component" }, "description": { @@ -1003,7 +1003,7 @@ "properties": { "name": { "type": "string", - "pattern": "^[a-z0-9\\-]*[a-z0-9]$", + "pattern": "^[a-z0-9][a-z0-9\\-]*$", "description": "Name to identify this Zarf package" }, "description": { From 25b1e202256a5345429ed853ffe2c4238ca6d42f Mon Sep 17 00:00:00 2001 From: Austin Abro Date: Fri, 31 May 2024 14:35:30 +0000 Subject: [PATCH 05/27] testing --- src/types/validate_test.go | 80 +++++++++++--------------------------- 1 file changed, 23 insertions(+), 57 deletions(-) diff --git a/src/types/validate_test.go b/src/types/validate_test.go index 30c9369768..cc1ade6e31 100644 --- a/src/types/validate_test.go +++ b/src/types/validate_test.go @@ -52,7 +52,13 @@ func TestZarfPackageValidate(t *testing.T) { }, Components: []ZarfComponent{ { - Name: "component1", + Name: "-invalid", + }, + { + Name: "duplicate", + }, + { + Name: "duplicate", }, }, Variables: []variables.InteractiveVariable{ @@ -76,6 +82,8 @@ func TestZarfPackageValidate(t *testing.T) { fmt.Errorf(lang.PkgValidateErrVariable, fmt.Errorf(lang.PkgValidateMustBeUppercase, "not_uppercase")).Error(), fmt.Errorf(lang.PkgValidateErrConstant, fmt.Errorf(lang.PkgValidateErrPkgConstantName, "not_uppercase")).Error(), fmt.Errorf(lang.PkgValidateErrConstant, fmt.Errorf(lang.PkgValidateErrPkgConstantPattern, "BAD", "^good_val$")).Error(), + fmt.Sprintf(lang.PkgValidateErrComponentName, "-invalid"), + fmt.Sprintf(lang.PkgValidateErrComponentNameNotUnique, "duplicate"), }, "\n"), }, { @@ -87,72 +95,30 @@ func TestZarfPackageValidate(t *testing.T) { }, Components: []ZarfComponent{ { - Name: "component1", - Images: []string{"an-image"}}, + Name: "yolo", + Images: []string{"an-image"}, + Repos: []string{"a-repo"}, + Only: ZarfComponentOnlyTarget{ + Cluster: ZarfComponentOnlyCluster{ + Architecture: "not-empty", + Distros: []string{"not-empty"}, + }, + }, + }, }, }, wantErr: strings.Join([]string{ lang.PkgValidateErrInitNoYOLO, lang.PkgValidateErrYOLONoOCI, + lang.PkgValidateErrYOLONoGit, + lang.PkgValidateErrYOLONoArch, + lang.PkgValidateErrYOLONoDistro, }, "\n"), }, // { // pkg: ZarfPackage{ // Kind: ZarfPackageConfig, // Metadata: ZarfMetadata{ - // Name: "yolo-repos", - // YOLO: true, - // }, - // Components: []ZarfComponent{ - // { - // Name: "component1", - // Repos: []string{"a-repo"}}, - // }, - // }, - // wantErr: lang.PkgValidateErrYOLONoGit, - // }, - // { - // pkg: ZarfPackage{ - // Kind: ZarfPackageConfig, - // Metadata: ZarfMetadata{ - // Name: "yolo-arch", - // YOLO: true, - // }, - // Components: []ZarfComponent{ - // { - // Name: "component1", - // Only: ZarfComponentOnlyTarget{ - // Cluster: ZarfComponentOnlyCluster{ - // Architecture: "not-empty", - // }, - // }}, - // }, - // }, - // wantErr: lang.PkgValidateErrYOLONoArch, - // }, - // { - // pkg: ZarfPackage{ - // Kind: ZarfPackageConfig, - // Metadata: ZarfMetadata{ - // Name: "yolo-distro", - // YOLO: true, - // }, - // Components: []ZarfComponent{ - // { - // Name: "component1", - // Only: ZarfComponentOnlyTarget{ - // Cluster: ZarfComponentOnlyCluster{ - // Distros: []string{"not-empty"}, - // }, - // }}, - // }, - // }, - // wantErr: lang.PkgValidateErrYOLONoDistro, - // }, - // { - // pkg: ZarfPackage{ - // Kind: ZarfPackageConfig, - // Metadata: ZarfMetadata{ // Name: "duplicate-component-names", // }, // Components: []ZarfComponent{ @@ -164,7 +130,7 @@ func TestZarfPackageValidate(t *testing.T) { // }, // }, // }, - // wantErr: fmt.Sprintf(lang.PkgValidateErrComponentNameNotUnique, "component1"), + // wantErr: , // }, // { // pkg: ZarfPackage{ From e18d12c4b38fa8c466d20e09f2bf3999597de717 Mon Sep 17 00:00:00 2001 From: Austin Abro Date: Fri, 31 May 2024 15:22:23 +0000 Subject: [PATCH 06/27] testing --- src/types/validate_test.go | 147 +++++++------------------------------ 1 file changed, 26 insertions(+), 121 deletions(-) diff --git a/src/types/validate_test.go b/src/types/validate_test.go index cc1ade6e31..3a7be337d6 100644 --- a/src/types/validate_test.go +++ b/src/types/validate_test.go @@ -9,6 +9,7 @@ import ( "strings" "testing" + "github.com/defenseunicorns/pkg/helpers" "github.com/defenseunicorns/zarf/src/config/lang" "github.com/defenseunicorns/zarf/src/pkg/variables" "github.com/stretchr/testify/assert" @@ -53,6 +54,24 @@ func TestZarfPackageValidate(t *testing.T) { Components: []ZarfComponent{ { Name: "-invalid", + Only: ZarfComponentOnlyTarget{ + LocalOS: "unsupportedOS", + }, + Required: helpers.BoolPtr(true), + Default: true, + Charts: []ZarfChart{ + {Name: "chart1", Namespace: "whatever", URL: "http://whatever", Version: "v1.0.0"}, + {Name: "chart1", Namespace: "whatever", URL: "http://whatever", Version: "v1.0.0"}, + }, + Manifests: []ZarfManifest{ + {Name: "manifest1", Files: []string{"file1"}}, + {Name: "manifest1", Files: []string{"file2"}}, + }, + }, + { + Name: "required-in-group", + Required: helpers.BoolPtr(true), + DeprecatedGroup: "a-group", }, { Name: "duplicate", @@ -77,13 +96,20 @@ func TestZarfPackageValidate(t *testing.T) { }, }, }, + //TODO refactor this to only have to contain each error so order doesn't matter wantErr: strings.Join([]string{ fmt.Sprintf(lang.PkgValidateErrPkgName, "-invalid-package"), fmt.Errorf(lang.PkgValidateErrVariable, fmt.Errorf(lang.PkgValidateMustBeUppercase, "not_uppercase")).Error(), fmt.Errorf(lang.PkgValidateErrConstant, fmt.Errorf(lang.PkgValidateErrPkgConstantName, "not_uppercase")).Error(), fmt.Errorf(lang.PkgValidateErrConstant, fmt.Errorf(lang.PkgValidateErrPkgConstantPattern, "BAD", "^good_val$")).Error(), fmt.Sprintf(lang.PkgValidateErrComponentName, "-invalid"), + fmt.Sprintf(lang.PkgValidateErrComponentLocalOS, "-invalid", "unsupportedOS", supportedOS), + fmt.Sprintf(lang.PkgValidateErrComponentReqDefault, "-invalid"), + fmt.Sprintf(lang.PkgValidateErrChartNameNotUnique, "chart1"), + fmt.Sprintf(lang.PkgValidateErrManifestNameNotUnique, "manifest1"), + fmt.Sprintf(lang.PkgValidateErrComponentReqGrouped, "required-in-group"), fmt.Sprintf(lang.PkgValidateErrComponentNameNotUnique, "duplicate"), + fmt.Sprintf(lang.PkgValidateErrGroupOneComponent, "a-group", "required-in-group"), }, "\n"), }, { @@ -115,127 +141,6 @@ func TestZarfPackageValidate(t *testing.T) { lang.PkgValidateErrYOLONoDistro, }, "\n"), }, - // { - // pkg: ZarfPackage{ - // Kind: ZarfPackageConfig, - // Metadata: ZarfMetadata{ - // Name: "duplicate-component-names", - // }, - // Components: []ZarfComponent{ - // { - // Name: "component1", - // }, - // { - // Name: "component1", - // }, - // }, - // }, - // wantErr: , - // }, - // { - // pkg: ZarfPackage{ - // Kind: ZarfPackageConfig, - // Metadata: ZarfMetadata{ - // Name: "invalid-component-name", - // }, - // Components: []ZarfComponent{ - // { - // Name: "-component1", - // }, - // }, - // }, - // wantErr: fmt.Sprintf(lang.PkgValidateErrComponentName, "-component1"), - // }, - // { - // name: "unsupported OS", - // pkg: ZarfPackage{ - // Kind: ZarfPackageConfig, - // Metadata: ZarfMetadata{ - // Name: "valid-package", - // }, - // Components: []ZarfComponent{ - // { - // Name: "component1", - // Only: ZarfComponentOnlyTarget{ - // LocalOS: "unsupportedOS", - // }, - // }, - // }, - // }, - // wantErr: fmt.Sprintf(lang.PkgValidateErrComponentLocalOS, "component1", "unsupportedOS", supportedOS), - // }, - // { - // name: "required component with default", - // pkg: ZarfPackage{ - // Kind: ZarfPackageConfig, - // Metadata: ZarfMetadata{ - // Name: "valid-package", - // }, - // Components: []ZarfComponent{ - // { - // Name: "component1", - // Default: true, - // Required: helpers.BoolPtr(true), - // }, - // }, - // }, - // wantErr: fmt.Sprintf(lang.PkgValidateErrComponentReqDefault, "component1"), - // }, - // { - // name: "required component in group", - // pkg: ZarfPackage{ - // Kind: ZarfPackageConfig, - // Metadata: ZarfMetadata{ - // Name: "valid-package", - // }, - // Components: []ZarfComponent{ - // { - // Name: "component1", - // Required: helpers.BoolPtr(true), - // DeprecatedGroup: "group1", - // }, - // }, - // }, - // wantErr: fmt.Sprintf(lang.PkgValidateErrComponentReqGrouped, "component1"), - // }, - // { - // name: "duplicate chart names", - // pkg: ZarfPackage{ - // Kind: ZarfPackageConfig, - // Metadata: ZarfMetadata{ - // Name: "valid-package", - // }, - // Components: []ZarfComponent{ - // { - // Name: "component1", - // Charts: []ZarfChart{ - // {Name: "chart1", Namespace: "whatever", URL: "http://whatever", Version: "v1.0.0"}, - // {Name: "chart1", Namespace: "whatever", URL: "http://whatever", Version: "v1.0.0"}, - // }, - // }, - // }, - // }, - // wantErr: fmt.Sprintf(lang.PkgValidateErrChartNameNotUnique, "chart1"), - // }, - // { - // name: "duplicate manifest names", - // pkg: ZarfPackage{ - // Kind: ZarfPackageConfig, - // Metadata: ZarfMetadata{ - // Name: "valid-package", - // }, - // Components: []ZarfComponent{ - // { - // Name: "component1", - // Manifests: []ZarfManifest{ - // {Name: "manifest1", Files: []string{"file1"}}, - // {Name: "manifest1", Files: []string{"file2"}}, - // }, - // }, - // }, - // }, - // wantErr: fmt.Sprintf(lang.PkgValidateErrManifestNameNotUnique, "manifest1"), - // }, } for _, tt := range tests { From 4bd856a537b51c61acd0f665d552e27ea9b21412 Mon Sep 17 00:00:00 2001 From: Austin Abro Date: Fri, 31 May 2024 15:31:51 +0000 Subject: [PATCH 07/27] testing? --- src/types/validate_test.go | 62 ++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/src/types/validate_test.go b/src/types/validate_test.go index 3a7be337d6..d1a2e4ddf8 100644 --- a/src/types/validate_test.go +++ b/src/types/validate_test.go @@ -6,20 +6,20 @@ package types import ( "fmt" - "strings" "testing" "github.com/defenseunicorns/pkg/helpers" "github.com/defenseunicorns/zarf/src/config/lang" "github.com/defenseunicorns/zarf/src/pkg/variables" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestZarfPackageValidate(t *testing.T) { tests := []struct { - name string - pkg ZarfPackage - wantErr string + name string + pkg ZarfPackage + wantErrs []error }{ { pkg: ZarfPackage{ @@ -33,7 +33,7 @@ func TestZarfPackageValidate(t *testing.T) { }, }, }, - wantErr: "", + wantErrs: nil, }, { pkg: ZarfPackage{ @@ -43,7 +43,7 @@ func TestZarfPackageValidate(t *testing.T) { }, Components: []ZarfComponent{}, }, - wantErr: "package must have at least 1 component", + wantErrs: []error{fmt.Errorf("package must have at least 1 component")}, }, { pkg: ZarfPackage{ @@ -97,20 +97,20 @@ func TestZarfPackageValidate(t *testing.T) { }, }, //TODO refactor this to only have to contain each error so order doesn't matter - wantErr: strings.Join([]string{ - fmt.Sprintf(lang.PkgValidateErrPkgName, "-invalid-package"), - fmt.Errorf(lang.PkgValidateErrVariable, fmt.Errorf(lang.PkgValidateMustBeUppercase, "not_uppercase")).Error(), - fmt.Errorf(lang.PkgValidateErrConstant, fmt.Errorf(lang.PkgValidateErrPkgConstantName, "not_uppercase")).Error(), - fmt.Errorf(lang.PkgValidateErrConstant, fmt.Errorf(lang.PkgValidateErrPkgConstantPattern, "BAD", "^good_val$")).Error(), - fmt.Sprintf(lang.PkgValidateErrComponentName, "-invalid"), - fmt.Sprintf(lang.PkgValidateErrComponentLocalOS, "-invalid", "unsupportedOS", supportedOS), - fmt.Sprintf(lang.PkgValidateErrComponentReqDefault, "-invalid"), - fmt.Sprintf(lang.PkgValidateErrChartNameNotUnique, "chart1"), - fmt.Sprintf(lang.PkgValidateErrManifestNameNotUnique, "manifest1"), - fmt.Sprintf(lang.PkgValidateErrComponentReqGrouped, "required-in-group"), - fmt.Sprintf(lang.PkgValidateErrComponentNameNotUnique, "duplicate"), - fmt.Sprintf(lang.PkgValidateErrGroupOneComponent, "a-group", "required-in-group"), - }, "\n"), + wantErrs: []error{ + fmt.Errorf(lang.PkgValidateErrPkgName, "-invalid-package"), + fmt.Errorf(lang.PkgValidateErrVariable, fmt.Errorf(lang.PkgValidateMustBeUppercase, "not_uppercase")), + fmt.Errorf(lang.PkgValidateErrConstant, fmt.Errorf(lang.PkgValidateErrPkgConstantName, "not_uppercase")), + fmt.Errorf(lang.PkgValidateErrConstant, fmt.Errorf(lang.PkgValidateErrPkgConstantPattern, "BAD", "^good_val$")), + fmt.Errorf(lang.PkgValidateErrComponentName, "-invalid"), + fmt.Errorf(lang.PkgValidateErrComponentLocalOS, "-invalid", "unsupportedOS", supportedOS), + fmt.Errorf(lang.PkgValidateErrComponentReqDefault, "-invalid"), + fmt.Errorf(lang.PkgValidateErrChartNameNotUnique, "chart1"), + fmt.Errorf(lang.PkgValidateErrManifestNameNotUnique, "manifest1"), + fmt.Errorf(lang.PkgValidateErrComponentReqGrouped, "required-in-group"), + fmt.Errorf(lang.PkgValidateErrComponentNameNotUnique, "duplicate"), + fmt.Errorf(lang.PkgValidateErrGroupOneComponent, "a-group", "required-in-group"), + }, }, { pkg: ZarfPackage{ @@ -133,23 +133,25 @@ func TestZarfPackageValidate(t *testing.T) { }, }, }, - wantErr: strings.Join([]string{ - lang.PkgValidateErrInitNoYOLO, - lang.PkgValidateErrYOLONoOCI, - lang.PkgValidateErrYOLONoGit, - lang.PkgValidateErrYOLONoArch, - lang.PkgValidateErrYOLONoDistro, - }, "\n"), + wantErrs: []error{ + fmt.Errorf(lang.PkgValidateErrInitNoYOLO), + fmt.Errorf(lang.PkgValidateErrYOLONoOCI), + fmt.Errorf(lang.PkgValidateErrYOLONoGit), + fmt.Errorf(lang.PkgValidateErrYOLONoArch), + fmt.Errorf(lang.PkgValidateErrYOLONoDistro), + }, }, } for _, tt := range tests { t.Run(tt.pkg.Metadata.Name, func(t *testing.T) { err := tt.pkg.Validate() - if tt.wantErr != "" { - assert.EqualError(t, err, tt.wantErr) - } else { + if tt.wantErrs == nil { assert.NoError(t, err) + return + } + for _, wantErr := range tt.wantErrs { + require.ErrorContains(t, err, wantErr.Error()) } }) } From f304a8eef4dfaaf3a5bf37732d4382c5a03f813a Mon Sep 17 00:00:00 2001 From: Austin Abro Date: Fri, 31 May 2024 15:36:06 +0000 Subject: [PATCH 08/27] refactor tests --- src/types/validate_test.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/types/validate_test.go b/src/types/validate_test.go index d1a2e4ddf8..f58e23f331 100644 --- a/src/types/validate_test.go +++ b/src/types/validate_test.go @@ -22,6 +22,7 @@ func TestZarfPackageValidate(t *testing.T) { wantErrs []error }{ { + name: "valid package", pkg: ZarfPackage{ Kind: ZarfPackageConfig, Metadata: ZarfMetadata{ @@ -36,6 +37,7 @@ func TestZarfPackageValidate(t *testing.T) { wantErrs: nil, }, { + name: "no components", pkg: ZarfPackage{ Kind: ZarfPackageConfig, Metadata: ZarfMetadata{ @@ -46,6 +48,7 @@ func TestZarfPackageValidate(t *testing.T) { wantErrs: []error{fmt.Errorf("package must have at least 1 component")}, }, { + name: "invalid package", pkg: ZarfPackage{ Kind: ZarfPackageConfig, Metadata: ZarfMetadata{ @@ -96,7 +99,6 @@ func TestZarfPackageValidate(t *testing.T) { }, }, }, - //TODO refactor this to only have to contain each error so order doesn't matter wantErrs: []error{ fmt.Errorf(lang.PkgValidateErrPkgName, "-invalid-package"), fmt.Errorf(lang.PkgValidateErrVariable, fmt.Errorf(lang.PkgValidateMustBeUppercase, "not_uppercase")), @@ -113,6 +115,7 @@ func TestZarfPackageValidate(t *testing.T) { }, }, { + name: "invalid yolo", pkg: ZarfPackage{ Kind: ZarfInitConfig, Metadata: ZarfMetadata{ @@ -144,7 +147,7 @@ func TestZarfPackageValidate(t *testing.T) { } for _, tt := range tests { - t.Run(tt.pkg.Metadata.Name, func(t *testing.T) { + t.Run(tt.name, func(t *testing.T) { err := tt.pkg.Validate() if tt.wantErrs == nil { assert.NoError(t, err) From 49a710b077504f4e38a086534ef34be0d50fa755 Mon Sep 17 00:00:00 2001 From: Austin Abro Date: Fri, 31 May 2024 15:40:31 +0000 Subject: [PATCH 09/27] refactor --- src/types/validate_test.go | 62 ++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/src/types/validate_test.go b/src/types/validate_test.go index f58e23f331..afd4ce23a7 100644 --- a/src/types/validate_test.go +++ b/src/types/validate_test.go @@ -19,7 +19,7 @@ func TestZarfPackageValidate(t *testing.T) { tests := []struct { name string pkg ZarfPackage - wantErrs []error + wantErrs []string }{ { name: "valid package", @@ -45,7 +45,7 @@ func TestZarfPackageValidate(t *testing.T) { }, Components: []ZarfComponent{}, }, - wantErrs: []error{fmt.Errorf("package must have at least 1 component")}, + wantErrs: []string{"package must have at least 1 component"}, }, { name: "invalid package", @@ -99,19 +99,19 @@ func TestZarfPackageValidate(t *testing.T) { }, }, }, - wantErrs: []error{ - fmt.Errorf(lang.PkgValidateErrPkgName, "-invalid-package"), - fmt.Errorf(lang.PkgValidateErrVariable, fmt.Errorf(lang.PkgValidateMustBeUppercase, "not_uppercase")), - fmt.Errorf(lang.PkgValidateErrConstant, fmt.Errorf(lang.PkgValidateErrPkgConstantName, "not_uppercase")), - fmt.Errorf(lang.PkgValidateErrConstant, fmt.Errorf(lang.PkgValidateErrPkgConstantPattern, "BAD", "^good_val$")), - fmt.Errorf(lang.PkgValidateErrComponentName, "-invalid"), - fmt.Errorf(lang.PkgValidateErrComponentLocalOS, "-invalid", "unsupportedOS", supportedOS), - fmt.Errorf(lang.PkgValidateErrComponentReqDefault, "-invalid"), - fmt.Errorf(lang.PkgValidateErrChartNameNotUnique, "chart1"), - fmt.Errorf(lang.PkgValidateErrManifestNameNotUnique, "manifest1"), - fmt.Errorf(lang.PkgValidateErrComponentReqGrouped, "required-in-group"), - fmt.Errorf(lang.PkgValidateErrComponentNameNotUnique, "duplicate"), - fmt.Errorf(lang.PkgValidateErrGroupOneComponent, "a-group", "required-in-group"), + wantErrs: []string{ + fmt.Sprintf(lang.PkgValidateErrPkgName, "-invalid-package"), + fmt.Errorf(lang.PkgValidateErrVariable, fmt.Errorf(lang.PkgValidateMustBeUppercase, "not_uppercase")).Error(), + fmt.Errorf(lang.PkgValidateErrConstant, fmt.Errorf(lang.PkgValidateErrPkgConstantName, "not_uppercase")).Error(), + fmt.Errorf(lang.PkgValidateErrConstant, fmt.Errorf(lang.PkgValidateErrPkgConstantPattern, "BAD", "^good_val$")).Error(), + fmt.Sprintf(lang.PkgValidateErrComponentName, "-invalid"), + fmt.Sprintf(lang.PkgValidateErrComponentLocalOS, "-invalid", "unsupportedOS", supportedOS), + fmt.Sprintf(lang.PkgValidateErrComponentReqDefault, "-invalid"), + fmt.Sprintf(lang.PkgValidateErrChartNameNotUnique, "chart1"), + fmt.Sprintf(lang.PkgValidateErrManifestNameNotUnique, "manifest1"), + fmt.Sprintf(lang.PkgValidateErrComponentReqGrouped, "required-in-group"), + fmt.Sprintf(lang.PkgValidateErrComponentNameNotUnique, "duplicate"), + fmt.Sprintf(lang.PkgValidateErrGroupOneComponent, "a-group", "required-in-group"), }, }, { @@ -136,12 +136,12 @@ func TestZarfPackageValidate(t *testing.T) { }, }, }, - wantErrs: []error{ - fmt.Errorf(lang.PkgValidateErrInitNoYOLO), - fmt.Errorf(lang.PkgValidateErrYOLONoOCI), - fmt.Errorf(lang.PkgValidateErrYOLONoGit), - fmt.Errorf(lang.PkgValidateErrYOLONoArch), - fmt.Errorf(lang.PkgValidateErrYOLONoDistro), + wantErrs: []string{ + lang.PkgValidateErrInitNoYOLO, + lang.PkgValidateErrYOLONoOCI, + lang.PkgValidateErrYOLONoGit, + lang.PkgValidateErrYOLONoArch, + lang.PkgValidateErrYOLONoDistro, }, }, } @@ -154,7 +154,7 @@ func TestZarfPackageValidate(t *testing.T) { return } for _, wantErr := range tt.wantErrs { - require.ErrorContains(t, err, wantErr.Error()) + require.ErrorContains(t, err, wantErr) } }) } @@ -167,32 +167,34 @@ func TestValidateManifest(t *testing.T) { } tests := []struct { manifest ZarfManifest - wantErr string + wantErrs []string }{ { manifest: ZarfManifest{Name: "valid", Files: []string{"a-file"}}, - wantErr: "", + wantErrs: nil, }, { manifest: ZarfManifest{Name: "", Files: []string{"a-file"}}, - wantErr: lang.PkgValidateErrManifestNameMissing, + wantErrs: []string{lang.PkgValidateErrManifestNameMissing}, }, { manifest: ZarfManifest{Name: longName, Files: []string{"a-file"}}, - wantErr: fmt.Sprintf(lang.PkgValidateErrManifestNameLength, longName, ZarfMaxChartNameLength), + wantErrs: []string{fmt.Sprintf(lang.PkgValidateErrManifestNameLength, longName, ZarfMaxChartNameLength)}, }, { manifest: ZarfManifest{Name: "nothing-there"}, - wantErr: fmt.Sprintf(lang.PkgValidateErrManifestFileOrKustomize, "nothing-there"), + wantErrs: []string{fmt.Sprintf(lang.PkgValidateErrManifestFileOrKustomize, "nothing-there")}, }, } for _, tt := range tests { t.Run(tt.manifest.Name, func(t *testing.T) { err := tt.manifest.Validate() - if tt.wantErr != "" { - assert.EqualError(t, err, tt.wantErr) - } else { + if tt.wantErrs == nil { assert.NoError(t, err) + return + } + for _, wantErr := range tt.wantErrs { + assert.EqualError(t, err, wantErr) } }) } From d74cc6ec4c1f71d94bcf3c074b5efde7cd7403b4 Mon Sep 17 00:00:00 2001 From: Austin Abro Date: Fri, 31 May 2024 15:47:58 +0000 Subject: [PATCH 10/27] refactor --- src/types/validate.go | 9 +++++---- src/types/validate_test.go | 16 ++++++++++------ 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/types/validate.go b/src/types/validate.go index c18eaf65ac..0794f0eac6 100644 --- a/src/types/validate.go +++ b/src/types/validate.go @@ -322,20 +322,21 @@ func (chart ZarfChart) Validate() error { // Validate runs all validation checks on a manifest. func (manifest ZarfManifest) Validate() error { + errs := []error{} // Don't allow empty names if manifest.Name == "" { - return fmt.Errorf(lang.PkgValidateErrManifestNameMissing) + errs = append(errs, fmt.Errorf(lang.PkgValidateErrManifestNameMissing)) } // Helm max release name if len(manifest.Name) > ZarfMaxChartNameLength { - return fmt.Errorf(lang.PkgValidateErrManifestNameLength, manifest.Name, ZarfMaxChartNameLength) + errs = append(errs, fmt.Errorf(lang.PkgValidateErrManifestNameLength, manifest.Name, ZarfMaxChartNameLength)) } // Require files in manifest if len(manifest.Files) < 1 && len(manifest.Kustomizations) < 1 { - return fmt.Errorf(lang.PkgValidateErrManifestFileOrKustomize, manifest.Name) + errs = append(errs, fmt.Errorf(lang.PkgValidateErrManifestFileOrKustomize, manifest.Name)) } - return nil + return errors.Join(errs...) } diff --git a/src/types/validate_test.go b/src/types/validate_test.go index afd4ce23a7..88b514c6ad 100644 --- a/src/types/validate_test.go +++ b/src/types/validate_test.go @@ -11,7 +11,6 @@ import ( "github.com/defenseunicorns/pkg/helpers" "github.com/defenseunicorns/zarf/src/config/lang" "github.com/defenseunicorns/zarf/src/pkg/variables" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -150,7 +149,7 @@ func TestZarfPackageValidate(t *testing.T) { t.Run(tt.name, func(t *testing.T) { err := tt.pkg.Validate() if tt.wantErrs == nil { - assert.NoError(t, err) + require.NoError(t, err) return } for _, wantErr := range tt.wantErrs { @@ -168,33 +167,38 @@ func TestValidateManifest(t *testing.T) { tests := []struct { manifest ZarfManifest wantErrs []string + name string }{ { + name: "valid", manifest: ZarfManifest{Name: "valid", Files: []string{"a-file"}}, wantErrs: nil, }, { - manifest: ZarfManifest{Name: "", Files: []string{"a-file"}}, + name: "empty name", + manifest: ZarfManifest{Name: ""}, wantErrs: []string{lang.PkgValidateErrManifestNameMissing}, }, { + name: "long name", manifest: ZarfManifest{Name: longName, Files: []string{"a-file"}}, wantErrs: []string{fmt.Sprintf(lang.PkgValidateErrManifestNameLength, longName, ZarfMaxChartNameLength)}, }, { + name: "no files or kustomize", manifest: ZarfManifest{Name: "nothing-there"}, wantErrs: []string{fmt.Sprintf(lang.PkgValidateErrManifestFileOrKustomize, "nothing-there")}, }, } for _, tt := range tests { - t.Run(tt.manifest.Name, func(t *testing.T) { + t.Run(tt.name, func(t *testing.T) { err := tt.manifest.Validate() if tt.wantErrs == nil { - assert.NoError(t, err) + require.NoError(t, err) return } for _, wantErr := range tt.wantErrs { - assert.EqualError(t, err, wantErr) + require.ErrorContains(t, err, wantErr) } }) } From 08f49652cbb2bc11ba549de8c7cc8e2762fb4a4f Mon Sep 17 00:00:00 2001 From: Austin Abro Date: Fri, 31 May 2024 16:22:54 +0000 Subject: [PATCH 11/27] test chart --- src/config/lang/english.go | 2 +- src/types/validate.go | 21 ++++++-------- src/types/validate_test.go | 58 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 13 deletions(-) diff --git a/src/config/lang/english.go b/src/config/lang/english.go index b8c631ed6c..dabf4f3a1e 100644 --- a/src/config/lang/english.go +++ b/src/config/lang/english.go @@ -695,7 +695,7 @@ const ( PkgValidateErrActionClusterNetwork = "a single wait action must contain only one of cluster or network" PkgValidateErrChart = "invalid chart definition: %w" PkgValidateErrChartName = "chart %q exceed the maximum length of %d characters" - PkgValidateErrChartNameMissing = "chart %q must include a name" + PkgValidateErrChartNameMissing = "chart must include a name" PkgValidateErrChartNameNotUnique = "chart name %q is not unique" PkgValidateErrChartNamespaceMissing = "chart %q must include a namespace" PkgValidateErrChartURLOrPath = "chart %q must have either a url or localPath" diff --git a/src/types/validate.go b/src/types/validate.go index 0794f0eac6..0267a1f3ba 100644 --- a/src/types/validate.go +++ b/src/types/validate.go @@ -287,37 +287,34 @@ func (action ZarfComponentAction) Validate() error { // Validate runs all validation checks on a chart. func (chart ZarfChart) Validate() error { - // Don't allow empty names + errs := []error{} + if chart.Name == "" { - return fmt.Errorf(lang.PkgValidateErrChartNameMissing, chart.Name) + errs = append(errs, fmt.Errorf(lang.PkgValidateErrChartNameMissing)) } - // Helm max release name if len(chart.Name) > ZarfMaxChartNameLength { - return fmt.Errorf(lang.PkgValidateErrChartName, chart.Name, ZarfMaxChartNameLength) + errs = append(errs, fmt.Errorf(lang.PkgValidateErrChartName, chart.Name, ZarfMaxChartNameLength)) } - // Must have a namespace if chart.Namespace == "" { - return fmt.Errorf(lang.PkgValidateErrChartNamespaceMissing, chart.Name) + errs = append(errs, fmt.Errorf(lang.PkgValidateErrChartNamespaceMissing, chart.Name)) } // Must have a url or localPath (and not both) if chart.URL != "" && chart.LocalPath != "" { - return fmt.Errorf(lang.PkgValidateErrChartURLOrPath, chart.Name) + errs = append(errs, fmt.Errorf(lang.PkgValidateErrChartURLOrPath, chart.Name)) } - // Must have a url or localPath (and not both) if chart.URL == "" && chart.LocalPath == "" { - return fmt.Errorf(lang.PkgValidateErrChartURLOrPath, chart.Name) + errs = append(errs, fmt.Errorf(lang.PkgValidateErrChartURLOrPath, chart.Name)) } - // Must have a version if chart.Version == "" { - return fmt.Errorf(lang.PkgValidateErrChartVersion, chart.Name) + errs = append(errs, fmt.Errorf(lang.PkgValidateErrChartVersion, chart.Name)) } - return nil + return errors.Join(errs...) } // Validate runs all validation checks on a manifest. diff --git a/src/types/validate_test.go b/src/types/validate_test.go index 88b514c6ad..416b24bbd5 100644 --- a/src/types/validate_test.go +++ b/src/types/validate_test.go @@ -203,3 +203,61 @@ func TestValidateManifest(t *testing.T) { }) } } + +func TestValidateChart(t *testing.T) { + longName := "" + for range ZarfMaxChartNameLength + 1 { + longName += "a" + } + tests := []struct { + chart ZarfChart + wantErrs []string + name string + }{ + { + name: "valid", + chart: ZarfChart{Name: "chart1", Namespace: "whatever", URL: "http://whatever", Version: "v1.0.0"}, + wantErrs: nil, + }, + { + name: "empty name", + chart: ZarfChart{Name: ""}, + wantErrs: []string{lang.PkgValidateErrChartNameMissing}, + }, + { + name: "long name", + chart: ZarfChart{Name: longName}, + wantErrs: []string{ + fmt.Sprintf(lang.PkgValidateErrChartName, longName, ZarfMaxChartNameLength), + }, + }, + { + name: "no url or local path", + chart: ZarfChart{Name: "invalid"}, + wantErrs: []string{ + fmt.Sprintf(lang.PkgValidateErrChartNamespaceMissing, "invalid"), + fmt.Sprintf(lang.PkgValidateErrChartURLOrPath, "invalid"), + fmt.Sprintf(lang.PkgValidateErrChartVersion, "invalid"), + }, + }, + { + name: "both url and local path", + chart: ZarfChart{Name: "invalid", Namespace: "whatever", URL: "http://whatever", LocalPath: "wherever"}, + wantErrs: []string{ + fmt.Sprintf(lang.PkgValidateErrChartURLOrPath, "invalid"), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := tt.chart.Validate() + if tt.wantErrs == nil { + require.NoError(t, err) + return + } + for _, wantErr := range tt.wantErrs { + require.ErrorContains(t, err, wantErr) + } + }) + } +} From 6f4950ef8bb3ee127a279411c275e4665ebe242c Mon Sep 17 00:00:00 2001 From: Austin Abro Date: Fri, 31 May 2024 18:05:45 +0000 Subject: [PATCH 12/27] action set actions --- src/types/validate.go | 36 +++++++++------- src/types/validate_test.go | 87 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+), 16 deletions(-) diff --git a/src/types/validate.go b/src/types/validate.go index 0267a1f3ba..e83ee517da 100644 --- a/src/types/validate.go +++ b/src/types/validate.go @@ -139,7 +139,7 @@ func (pkg ZarfPackage) Validate() error { } } - if err := component.Actions.Validate(); err != nil { + if err := component.Actions.validate(); err != nil { errs = append(errs, fmt.Errorf("%q: %w", component.Name, err)) } @@ -164,25 +164,30 @@ func (pkg ZarfPackage) Validate() error { return errors.Join(errs...) } -// Validate runs all validation checks on component actions. -func (a ZarfComponentActions) Validate() error { +func (a ZarfComponentActions) validate() error { + var errs []error + if err := a.OnCreate.Validate(); err != nil { - return fmt.Errorf(lang.PkgValidateErrAction, err) + errs = append(errs, fmt.Errorf(lang.PkgValidateErrAction, err)) } if a.OnCreate.HasSetVariables() { - return fmt.Errorf("cannot contain setVariables outside of onDeploy in actions") + errs = append(errs, fmt.Errorf("cannot contain setVariables outside of onDeploy in actions")) } if err := a.OnDeploy.Validate(); err != nil { - return fmt.Errorf(lang.PkgValidateErrAction, err) + errs = append(errs, fmt.Errorf(lang.PkgValidateErrAction, err)) } if a.OnRemove.HasSetVariables() { - return fmt.Errorf("cannot contain setVariables outside of onDeploy in actions") + errs = append(errs, fmt.Errorf("cannot contain setVariables outside of onDeploy in actions")) } - return nil + if err := a.OnRemove.Validate(); err != nil { + errs = append(errs, fmt.Errorf(lang.PkgValidateErrAction, err)) + } + + return errors.Join(errs...) } // ValidateImportDefinition validates the component trying to be imported. @@ -258,31 +263,32 @@ func (as ZarfComponentActionSet) Validate() error { // Validate runs all validation checks on an action. func (action ZarfComponentAction) Validate() error { + errs := []error{} // Validate SetVariable for _, variable := range action.SetVariables { if err := variable.Validate(); err != nil { - return err + errs = append(errs, err) } } if action.Wait != nil { // Validate only cmd or wait, not both if action.Cmd != "" { - return fmt.Errorf(lang.PkgValidateErrActionCmdWait, action.Cmd) + errs = append(errs, fmt.Errorf(lang.PkgValidateErrActionCmdWait, action.Cmd)) } // Validate only cluster or network, not both if action.Wait.Cluster != nil && action.Wait.Network != nil { - return fmt.Errorf(lang.PkgValidateErrActionClusterNetwork) + errs = append(errs, fmt.Errorf(lang.PkgValidateErrActionClusterNetwork)) } // Validate at least one of cluster or network if action.Wait.Cluster == nil && action.Wait.Network == nil { - return fmt.Errorf(lang.PkgValidateErrActionClusterNetwork) + errs = append(errs, fmt.Errorf(lang.PkgValidateErrActionClusterNetwork)) } } - return nil + return errors.Join(errs...) } // Validate runs all validation checks on a chart. @@ -320,17 +326,15 @@ func (chart ZarfChart) Validate() error { // Validate runs all validation checks on a manifest. func (manifest ZarfManifest) Validate() error { errs := []error{} - // Don't allow empty names + if manifest.Name == "" { errs = append(errs, fmt.Errorf(lang.PkgValidateErrManifestNameMissing)) } - // Helm max release name if len(manifest.Name) > ZarfMaxChartNameLength { errs = append(errs, fmt.Errorf(lang.PkgValidateErrManifestNameLength, manifest.Name, ZarfMaxChartNameLength)) } - // Require files in manifest if len(manifest.Files) < 1 && len(manifest.Kustomizations) < 1 { errs = append(errs, fmt.Errorf(lang.PkgValidateErrManifestFileOrKustomize, manifest.Name)) } diff --git a/src/types/validate_test.go b/src/types/validate_test.go index 416b24bbd5..0692129fa4 100644 --- a/src/types/validate_test.go +++ b/src/types/validate_test.go @@ -261,3 +261,90 @@ func TestValidateChart(t *testing.T) { }) } } + +func TestZarfComponentActions_Validate(t *testing.T) { + tests := []struct { + name string + actions ZarfComponentActions + wantErrs []string + }{ + { + name: "valid actions", + actions: ZarfComponentActions{ + OnCreate: ZarfComponentActionSet{ + Before: []ZarfComponentAction{ + { + Cmd: "echo 'onCreate before valid'", + }, + }, + }, + OnDeploy: ZarfComponentActionSet{ + Before: []ZarfComponentAction{ + { + Cmd: "echo 'onDeploy before valid'", + }, + }, + }, + }, + wantErrs: nil, + }, + { + name: "setVariables in onCreate", + actions: ZarfComponentActions{ + OnCreate: ZarfComponentActionSet{ + Before: []ZarfComponentAction{ + { + Cmd: "echo 'invalid setVariable'", + SetVariables: []variables.Variable{{Name: "VAR"}}, + }, + }, + }, + }, + wantErrs: []string{"cannot contain setVariables outside of onDeploy in actions"}, + }, + { + name: "invalid onCreate action", + actions: ZarfComponentActions{ + OnCreate: ZarfComponentActionSet{ + Before: []ZarfComponentAction{ + { + Cmd: "cmd", + Wait: &ZarfComponentActionWait{}, + }, + }, + }, + }, + wantErrs: []string{fmt.Errorf(lang.PkgValidateErrAction, fmt.Errorf(lang.PkgValidateErrActionCmdWait, "cmd")).Error()}, + }, + { + name: "invalid onRemove action", + actions: ZarfComponentActions{ + OnRemove: ZarfComponentActionSet{ + Before: []ZarfComponentAction{ + { + Cmd: "cmd", + Wait: &ZarfComponentActionWait{}, + }, + }, + }, + }, + wantErrs: []string{ + fmt.Errorf(lang.PkgValidateErrAction, fmt.Errorf(lang.PkgValidateErrActionCmdWait, "cmd")).Error(), + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := tt.actions.validate() + if tt.wantErrs == nil { + require.NoError(t, err) + return + } + require.Error(t, err) + for _, wantErr := range tt.wantErrs { + require.Contains(t, err.Error(), wantErr) + } + }) + } +} From 45b796fe8eed06e5bc180c25225d89de2497d3c8 Mon Sep 17 00:00:00 2001 From: Austin Abro Date: Fri, 31 May 2024 19:27:06 +0000 Subject: [PATCH 13/27] component validate test --- src/pkg/packager/composer/list.go | 2 +- src/types/validate.go | 15 +-- src/types/validate_test.go | 164 ++++++++++++++++++++++++++++-- 3 files changed, 162 insertions(+), 19 deletions(-) diff --git a/src/pkg/packager/composer/list.go b/src/pkg/packager/composer/list.go index 4f1a484ca3..c88a0bb019 100644 --- a/src/pkg/packager/composer/list.go +++ b/src/pkg/packager/composer/list.go @@ -142,7 +142,7 @@ func NewImportChain(head types.ZarfComponent, index int, originalPackageName, ar } // TODO: stuff like this should also happen in linting - if err := node.ZarfComponent.ValidateImportDefinition(); err != nil { + if err := node.ZarfComponent.Validate(); err != nil { return ic, err } diff --git a/src/types/validate.go b/src/types/validate.go index e83ee517da..4dcb113ed2 100644 --- a/src/types/validate.go +++ b/src/types/validate.go @@ -190,26 +190,27 @@ func (a ZarfComponentActions) validate() error { return errors.Join(errs...) } -// ValidateImportDefinition validates the component trying to be imported. -func (c ZarfComponent) ValidateImportDefinition() error { +// Validate validates the component trying to be imported. +func (c ZarfComponent) Validate() error { + errs := []error{} path := c.Import.Path url := c.Import.URL // ensure path or url is provided if path == "" && url == "" { - return fmt.Errorf(lang.PkgValidateErrImportDefinition, c.Name, "neither a path nor a URL was provided") + errs = append(errs, fmt.Errorf(lang.PkgValidateErrImportDefinition, c.Name, "neither a path nor a URL was provided")) } // ensure path and url are not both provided if path != "" && url != "" { - return fmt.Errorf(lang.PkgValidateErrImportDefinition, c.Name, "both a path and a URL were provided") + errs = append(errs, fmt.Errorf(lang.PkgValidateErrImportDefinition, c.Name, "both a path and a URL were provided")) } // validation for path if url == "" && path != "" { // ensure path is not an absolute path if filepath.IsAbs(path) { - return fmt.Errorf(lang.PkgValidateErrImportDefinition, c.Name, "path cannot be an absolute path") + errs = append(errs, fmt.Errorf(lang.PkgValidateErrImportDefinition, c.Name, "path cannot be an absolute path")) } } @@ -217,11 +218,11 @@ func (c ZarfComponent) ValidateImportDefinition() error { if url != "" && path == "" { ok := helpers.IsOCIURL(url) if !ok { - return fmt.Errorf(lang.PkgValidateErrImportDefinition, c.Name, "URL is not a valid OCI URL") + errs = append(errs, fmt.Errorf(lang.PkgValidateErrImportDefinition, c.Name, "URL is not a valid OCI URL")) } } - return nil + return errors.Join(errs...) } // HasSetVariables returns true if any of the actions contain setVariables. diff --git a/src/types/validate_test.go b/src/types/validate_test.go index 0692129fa4..5c6decaccf 100644 --- a/src/types/validate_test.go +++ b/src/types/validate_test.go @@ -262,7 +262,7 @@ func TestValidateChart(t *testing.T) { } } -func TestZarfComponentActions_Validate(t *testing.T) { +func TestValidateComponentActions(t *testing.T) { tests := []struct { name string actions ZarfComponentActions @@ -308,28 +308,32 @@ func TestZarfComponentActions_Validate(t *testing.T) { OnCreate: ZarfComponentActionSet{ Before: []ZarfComponentAction{ { - Cmd: "cmd", + Cmd: "create", + Wait: &ZarfComponentActionWait{}, + }, + }, + }, + OnDeploy: ZarfComponentActionSet{ + After: []ZarfComponentAction{ + { + Cmd: "deploy", Wait: &ZarfComponentActionWait{}, }, }, }, - }, - wantErrs: []string{fmt.Errorf(lang.PkgValidateErrAction, fmt.Errorf(lang.PkgValidateErrActionCmdWait, "cmd")).Error()}, - }, - { - name: "invalid onRemove action", - actions: ZarfComponentActions{ OnRemove: ZarfComponentActionSet{ - Before: []ZarfComponentAction{ + OnSuccess: []ZarfComponentAction{ { - Cmd: "cmd", + Cmd: "remove", Wait: &ZarfComponentActionWait{}, }, }, }, }, wantErrs: []string{ - fmt.Errorf(lang.PkgValidateErrAction, fmt.Errorf(lang.PkgValidateErrActionCmdWait, "cmd")).Error(), + fmt.Errorf(lang.PkgValidateErrAction, fmt.Errorf(lang.PkgValidateErrActionCmdWait, "create")).Error(), + fmt.Errorf(lang.PkgValidateErrAction, fmt.Errorf(lang.PkgValidateErrActionCmdWait, "deploy")).Error(), + fmt.Errorf(lang.PkgValidateErrAction, fmt.Errorf(lang.PkgValidateErrActionCmdWait, "remove")).Error(), }, }, } @@ -348,3 +352,141 @@ func TestZarfComponentActions_Validate(t *testing.T) { }) } } + +func TestZarfComponentAction_Validate(t *testing.T) { + tests := []struct { + name string + action ZarfComponentAction + expectError bool + wantErr string + }{ + { + name: "valid action no conditions", + action: ZarfComponentAction{}, + expectError: false, + }, + { + name: "cmd and wait both set", + action: ZarfComponentAction{ + Cmd: "ls", + Wait: &ZarfComponentActionWait{Cluster: &ZarfComponentActionWaitCluster{}}, + }, + wantErr: fmt.Sprintf(lang.PkgValidateErrActionCmdWait, "ls"), + }, + { + name: "cluster and network both set", + action: ZarfComponentAction{ + Wait: &ZarfComponentActionWait{Cluster: &ZarfComponentActionWaitCluster{}, Network: &ZarfComponentActionWaitNetwork{}}, + }, + expectError: true, + wantErr: fmt.Sprintf(lang.PkgValidateErrActionClusterNetwork), + }, + { + name: "neither cluster nor network set", + action: ZarfComponentAction{ + Wait: &ZarfComponentActionWait{}, + }, + expectError: true, + wantErr: lang.PkgValidateErrActionClusterNetwork, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := tt.action.Validate() + if tt.wantErr != "" { + require.ErrorContains(t, err, tt.wantErr) + } else { + require.NoError(t, err) + } + }) + } +} + +func TestValidateZarfComponent(t *testing.T) { + tests := []struct { + component ZarfComponent + wantErrs []string + name string + }{ + { + name: "valid path", + component: ZarfComponent{ + Name: "component1", + Import: ZarfComponentImport{ + Path: "relative/path", + }, + }, + wantErrs: nil, + }, + { + name: "valid URL", + component: ZarfComponent{ + Name: "component2", + Import: ZarfComponentImport{ + URL: "oci://example.com/package:v0.0.1", + }, + }, + wantErrs: nil, + }, + { + name: "neither path nor URL provided", + component: ZarfComponent{ + Name: "invalid1", + }, + wantErrs: []string{ + fmt.Sprintf(lang.PkgValidateErrImportDefinition, "invalid1", "neither a path nor a URL was provided"), + }, + }, + { + name: "both path and URL provided", + component: ZarfComponent{ + Name: "invalid2", + Import: ZarfComponentImport{ + Path: "relative/path", + URL: "https://example.com", + }, + }, + wantErrs: []string{ + fmt.Sprintf(lang.PkgValidateErrImportDefinition, "invalid2", "both a path and a URL were provided"), + }, + }, + { + name: "absolute path provided", + component: ZarfComponent{ + Name: "invalid3", + Import: ZarfComponentImport{ + Path: "/absolute/path", + }, + }, + wantErrs: []string{ + fmt.Sprintf(lang.PkgValidateErrImportDefinition, "invalid3", "path cannot be an absolute path"), + }, + }, + { + name: "invalid URL provided", + component: ZarfComponent{ + Name: "invalid4", + Import: ZarfComponentImport{ + URL: "ftp://example.com", + }, + }, + wantErrs: []string{ + fmt.Sprintf(lang.PkgValidateErrImportDefinition, "invalid4", "URL is not a valid OCI URL"), + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := tt.component.Validate() + if tt.wantErrs == nil { + require.NoError(t, err) + return + } + for _, wantErr := range tt.wantErrs { + require.ErrorContains(t, err, wantErr) + } + }) + } +} From e073960a21a630ff03377af2684c9453911bae98 Mon Sep 17 00:00:00 2001 From: Austin Abro Date: Fri, 31 May 2024 19:31:24 +0000 Subject: [PATCH 14/27] group default check --- src/types/validate_test.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/types/validate_test.go b/src/types/validate_test.go index 5c6decaccf..38793a81e3 100644 --- a/src/types/validate_test.go +++ b/src/types/validate_test.go @@ -75,6 +75,16 @@ func TestZarfPackageValidate(t *testing.T) { Required: helpers.BoolPtr(true), DeprecatedGroup: "a-group", }, + { + Name: "multi-default", + Default: true, + DeprecatedGroup: "multi-default", + }, + { + Name: "multi-default-2", + Default: true, + DeprecatedGroup: "multi-default", + }, { Name: "duplicate", }, @@ -111,6 +121,7 @@ func TestZarfPackageValidate(t *testing.T) { fmt.Sprintf(lang.PkgValidateErrComponentReqGrouped, "required-in-group"), fmt.Sprintf(lang.PkgValidateErrComponentNameNotUnique, "duplicate"), fmt.Sprintf(lang.PkgValidateErrGroupOneComponent, "a-group", "required-in-group"), + fmt.Sprintf(lang.PkgValidateErrGroupMultipleDefaults, "multi-default", "multi-default", "multi-default-2"), }, }, { From 6003939cbd4dc004cfb73110d8f39a983d74dc2c Mon Sep 17 00:00:00 2001 From: Austin Abro Date: Fri, 31 May 2024 19:52:27 +0000 Subject: [PATCH 15/27] refactor to elements match --- src/types/validate_test.go | 84 ++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 48 deletions(-) diff --git a/src/types/validate_test.go b/src/types/validate_test.go index 38793a81e3..177e3309af 100644 --- a/src/types/validate_test.go +++ b/src/types/validate_test.go @@ -6,6 +6,7 @@ package types import ( "fmt" + "strings" "testing" "github.com/defenseunicorns/pkg/helpers" @@ -163,9 +164,8 @@ func TestZarfPackageValidate(t *testing.T) { require.NoError(t, err) return } - for _, wantErr := range tt.wantErrs { - require.ErrorContains(t, err, wantErr) - } + errs := strings.Split(err.Error(), "\n") + require.ElementsMatch(t, errs, tt.wantErrs) }) } } @@ -187,7 +187,7 @@ func TestValidateManifest(t *testing.T) { }, { name: "empty name", - manifest: ZarfManifest{Name: ""}, + manifest: ZarfManifest{Name: "", Files: []string{"a-file"}}, wantErrs: []string{lang.PkgValidateErrManifestNameMissing}, }, { @@ -208,9 +208,8 @@ func TestValidateManifest(t *testing.T) { require.NoError(t, err) return } - for _, wantErr := range tt.wantErrs { - require.ErrorContains(t, err, wantErr) - } + errs := strings.Split(err.Error(), "\n") + require.ElementsMatch(t, errs, tt.wantErrs) }) } } @@ -232,12 +231,12 @@ func TestValidateChart(t *testing.T) { }, { name: "empty name", - chart: ZarfChart{Name: ""}, + chart: ZarfChart{Name: "", Namespace: "whatever", URL: "http://whatever", Version: "v1.0.0"}, wantErrs: []string{lang.PkgValidateErrChartNameMissing}, }, { name: "long name", - chart: ZarfChart{Name: longName}, + chart: ZarfChart{Name: longName, Namespace: "whatever", URL: "http://whatever", Version: "v1.0.0"}, wantErrs: []string{ fmt.Sprintf(lang.PkgValidateErrChartName, longName, ZarfMaxChartNameLength), }, @@ -253,7 +252,7 @@ func TestValidateChart(t *testing.T) { }, { name: "both url and local path", - chart: ZarfChart{Name: "invalid", Namespace: "whatever", URL: "http://whatever", LocalPath: "wherever"}, + chart: ZarfChart{Name: "invalid", Namespace: "whatever", URL: "http://whatever", LocalPath: "wherever", Version: "v1.0.0"}, wantErrs: []string{ fmt.Sprintf(lang.PkgValidateErrChartURLOrPath, "invalid"), }, @@ -266,9 +265,8 @@ func TestValidateChart(t *testing.T) { require.NoError(t, err) return } - for _, wantErr := range tt.wantErrs { - require.ErrorContains(t, err, wantErr) - } + errs := strings.Split(err.Error(), "\n") + require.ElementsMatch(t, tt.wantErrs, errs) }) } } @@ -320,7 +318,7 @@ func TestValidateComponentActions(t *testing.T) { Before: []ZarfComponentAction{ { Cmd: "create", - Wait: &ZarfComponentActionWait{}, + Wait: &ZarfComponentActionWait{Cluster: &ZarfComponentActionWaitCluster{}}, }, }, }, @@ -328,7 +326,7 @@ func TestValidateComponentActions(t *testing.T) { After: []ZarfComponentAction{ { Cmd: "deploy", - Wait: &ZarfComponentActionWait{}, + Wait: &ZarfComponentActionWait{Cluster: &ZarfComponentActionWaitCluster{}}, }, }, }, @@ -336,7 +334,7 @@ func TestValidateComponentActions(t *testing.T) { OnSuccess: []ZarfComponentAction{ { Cmd: "remove", - Wait: &ZarfComponentActionWait{}, + Wait: &ZarfComponentActionWait{Cluster: &ZarfComponentActionWaitCluster{}}, }, }, }, @@ -356,60 +354,51 @@ func TestValidateComponentActions(t *testing.T) { require.NoError(t, err) return } - require.Error(t, err) - for _, wantErr := range tt.wantErrs { - require.Contains(t, err.Error(), wantErr) - } + errs := strings.Split(err.Error(), "\n") + require.ElementsMatch(t, tt.wantErrs, errs) }) } } -func TestZarfComponentAction_Validate(t *testing.T) { +func TestValidateComponentAction(t *testing.T) { tests := []struct { - name string - action ZarfComponentAction - expectError bool - wantErr string + name string + action ZarfComponentAction + wantErrs []string }{ { - name: "valid action no conditions", - action: ZarfComponentAction{}, - expectError: false, + name: "valid action no conditions", + action: ZarfComponentAction{}, }, { - name: "cmd and wait both set", + name: "cmd and wait both set, nothing in wait", action: ZarfComponentAction{ Cmd: "ls", - Wait: &ZarfComponentActionWait{Cluster: &ZarfComponentActionWaitCluster{}}, + Wait: &ZarfComponentActionWait{}, + }, + wantErrs: []string{ + fmt.Sprintf(lang.PkgValidateErrActionCmdWait, "ls"), + lang.PkgValidateErrActionClusterNetwork, }, - wantErr: fmt.Sprintf(lang.PkgValidateErrActionCmdWait, "ls"), }, { name: "cluster and network both set", action: ZarfComponentAction{ Wait: &ZarfComponentActionWait{Cluster: &ZarfComponentActionWaitCluster{}, Network: &ZarfComponentActionWaitNetwork{}}, }, - expectError: true, - wantErr: fmt.Sprintf(lang.PkgValidateErrActionClusterNetwork), - }, - { - name: "neither cluster nor network set", - action: ZarfComponentAction{ - Wait: &ZarfComponentActionWait{}, - }, - expectError: true, - wantErr: lang.PkgValidateErrActionClusterNetwork, + wantErrs: []string{fmt.Sprintf(lang.PkgValidateErrActionClusterNetwork)}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := tt.action.Validate() - if tt.wantErr != "" { - require.ErrorContains(t, err, tt.wantErr) - } else { + if tt.wantErrs == nil { require.NoError(t, err) + return } + errs := strings.Split(err.Error(), "\n") + require.ElementsMatch(t, tt.wantErrs, errs) }) } } @@ -479,7 +468,7 @@ func TestValidateZarfComponent(t *testing.T) { component: ZarfComponent{ Name: "invalid4", Import: ZarfComponentImport{ - URL: "ftp://example.com", + URL: "https://example.com", }, }, wantErrs: []string{ @@ -495,9 +484,8 @@ func TestValidateZarfComponent(t *testing.T) { require.NoError(t, err) return } - for _, wantErr := range tt.wantErrs { - require.ErrorContains(t, err, wantErr) - } + errs := strings.Split(err.Error(), "\n") + require.ElementsMatch(t, tt.wantErrs, errs) }) } } From 58a66d2e29c660608bc8182daaaea3b0cfac039c Mon Sep 17 00:00:00 2001 From: Austin Abro Date: Fri, 31 May 2024 19:58:12 +0000 Subject: [PATCH 16/27] comment --- src/pkg/message/message.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/pkg/message/message.go b/src/pkg/message/message.go index 4d71c7c5af..4af0fb5dce 100644 --- a/src/pkg/message/message.go +++ b/src/pkg/message/message.go @@ -267,16 +267,14 @@ func Paragraph(format string, a ...any) string { // Paragraphn formats text into an n column paragraph func Paragraphn(n int, format string, a ...any) string { - // Split the formatted string into lines based on newlines + // Split the text to keep pterm formatting but add newlines lines := strings.Split(fmt.Sprintf(format, a...), "\n") - // Format each line individually formattedLines := make([]string, len(lines)) for i, line := range lines { formattedLines[i] = pterm.DefaultParagraph.WithMaxWidth(n).Sprintf(line) } - // Join the formatted lines with newlines return strings.Join(formattedLines, "\n") } From d9edf5b82707b3e57f4d7978ac4f8803baecd119 Mon Sep 17 00:00:00 2001 From: Austin Abro Date: Fri, 31 May 2024 19:58:55 +0000 Subject: [PATCH 17/27] comment --- src/types/component.go | 1 - 1 file changed, 1 deletion(-) diff --git a/src/types/component.go b/src/types/component.go index 21c720ffa7..a9997ac504 100644 --- a/src/types/component.go +++ b/src/types/component.go @@ -13,7 +13,6 @@ import ( // ZarfComponent is the primary functional grouping of assets to deploy by Zarf. type ZarfComponent struct { // Name is the unique identifier for this component - // https://regex101.com/r/FLdG9G/2 Name string `json:"name" jsonschema:"description=The name of the component,pattern=^[a-z0-9][a-z0-9\\-]*$"` // Description is a message given to a user when deciding to enable this component or not From d450545b1e2dbae859091f8e3f5a1046d2bc2198 Mon Sep 17 00:00:00 2001 From: Austin Abro Date: Fri, 31 May 2024 20:23:41 +0000 Subject: [PATCH 18/27] specify --- src/config/lang/english.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/config/lang/english.go b/src/config/lang/english.go index dabf4f3a1e..36112f99a9 100644 --- a/src/config/lang/english.go +++ b/src/config/lang/english.go @@ -722,10 +722,10 @@ const ( PkgValidateErrPkgConstantPattern = "provided value for constant %q does not match pattern %q" PkgValidateErrPkgName = "package name %q must be all lowercase and contain no special characters except '-' and cannot start with a '-'" PkgValidateErrVariable = "invalid package variable: %w" - PkgValidateErrYOLONoArch = "cluster architecture not allowed" - PkgValidateErrYOLONoDistro = "cluster distros not allowed" - PkgValidateErrYOLONoGit = "git repos not allowed" - PkgValidateErrYOLONoOCI = "OCI images not allowed" + PkgValidateErrYOLONoArch = "cluster architecture not allowed in YOLO" + PkgValidateErrYOLONoDistro = "cluster distros not allowed in YOLO" + PkgValidateErrYOLONoGit = "git repos not allowed in YOLO" + PkgValidateErrYOLONoOCI = "OCI images not allowed in YOLO" ) // Collection of reusable error messages. From 1c52d09635523a6d5a2a6793bd9b55a6a3d194f5 Mon Sep 17 00:00:00 2001 From: Austin Abro Date: Fri, 31 May 2024 20:30:12 +0000 Subject: [PATCH 19/27] test names --- src/types/validate_test.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/types/validate_test.go b/src/types/validate_test.go index 177e3309af..ff76595540 100644 --- a/src/types/validate_test.go +++ b/src/types/validate_test.go @@ -432,47 +432,47 @@ func TestValidateZarfComponent(t *testing.T) { { name: "neither path nor URL provided", component: ZarfComponent{ - Name: "invalid1", + Name: "neither", }, wantErrs: []string{ - fmt.Sprintf(lang.PkgValidateErrImportDefinition, "invalid1", "neither a path nor a URL was provided"), + fmt.Sprintf(lang.PkgValidateErrImportDefinition, "neither", "neither a path nor a URL was provided"), }, }, { name: "both path and URL provided", component: ZarfComponent{ - Name: "invalid2", + Name: "both", Import: ZarfComponentImport{ Path: "relative/path", URL: "https://example.com", }, }, wantErrs: []string{ - fmt.Sprintf(lang.PkgValidateErrImportDefinition, "invalid2", "both a path and a URL were provided"), + fmt.Sprintf(lang.PkgValidateErrImportDefinition, "both", "both a path and a URL were provided"), }, }, { name: "absolute path provided", component: ZarfComponent{ - Name: "invalid3", + Name: "abs-path", Import: ZarfComponentImport{ Path: "/absolute/path", }, }, wantErrs: []string{ - fmt.Sprintf(lang.PkgValidateErrImportDefinition, "invalid3", "path cannot be an absolute path"), + fmt.Sprintf(lang.PkgValidateErrImportDefinition, "abs-path", "path cannot be an absolute path"), }, }, { name: "invalid URL provided", component: ZarfComponent{ - Name: "invalid4", + Name: "bad-url", Import: ZarfComponentImport{ URL: "https://example.com", }, }, wantErrs: []string{ - fmt.Sprintf(lang.PkgValidateErrImportDefinition, "invalid4", "URL is not a valid OCI URL"), + fmt.Sprintf(lang.PkgValidateErrImportDefinition, "bad-url", "URL is not a valid OCI URL"), }, }, } From 691403ec415a73bb500f1a70615a4c06342cb85a Mon Sep 17 00:00:00 2001 From: Austin Abro Date: Fri, 31 May 2024 20:49:03 +0000 Subject: [PATCH 20/27] test names --- src/types/validate_test.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/types/validate_test.go b/src/types/validate_test.go index ff76595540..8f627c1fea 100644 --- a/src/types/validate_test.go +++ b/src/types/validate_test.go @@ -6,6 +6,7 @@ package types import ( "fmt" + "path/filepath" "strings" "testing" @@ -404,6 +405,8 @@ func TestValidateComponentAction(t *testing.T) { } func TestValidateZarfComponent(t *testing.T) { + absPath, err := filepath.Abs("abs") + require.NoError(t, err) tests := []struct { component ZarfComponent wantErrs []string @@ -456,7 +459,7 @@ func TestValidateZarfComponent(t *testing.T) { component: ZarfComponent{ Name: "abs-path", Import: ZarfComponentImport{ - Path: "/absolute/path", + Path: absPath, }, }, wantErrs: []string{ From e9dda964d16f09b3941d0d03141eb69e70b1be3b Mon Sep 17 00:00:00 2001 From: Austin Abro Date: Mon, 3 Jun 2024 11:56:28 +0000 Subject: [PATCH 21/27] fix flake --- src/pkg/packager/sources/new_test.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/pkg/packager/sources/new_test.go b/src/pkg/packager/sources/new_test.go index 91ea3e2c2f..ee770f51aa 100644 --- a/src/pkg/packager/sources/new_test.go +++ b/src/pkg/packager/sources/new_test.go @@ -150,8 +150,7 @@ func TestPackageSource(t *testing.T) { for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { - t.Parallel() - + // TODO once our messaging is thread safe, re-parallelize this test opts := &types.ZarfPackageOptions{ PackageSource: tt.src, Shasum: tt.shasum, From 20fa460fafe3293ce8f6a60804eff0e061551f27 Mon Sep 17 00:00:00 2001 From: Austin Abro Date: Mon, 3 Jun 2024 16:40:51 +0000 Subject: [PATCH 22/27] parallel --- src/types/validate_test.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/types/validate_test.go b/src/types/validate_test.go index 8f627c1fea..14cc51663c 100644 --- a/src/types/validate_test.go +++ b/src/types/validate_test.go @@ -159,7 +159,9 @@ func TestZarfPackageValidate(t *testing.T) { } for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { + t.Parallel() err := tt.pkg.Validate() if tt.wantErrs == nil { require.NoError(t, err) @@ -203,7 +205,9 @@ func TestValidateManifest(t *testing.T) { }, } for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { + t.Parallel() err := tt.manifest.Validate() if tt.wantErrs == nil { require.NoError(t, err) @@ -260,7 +264,9 @@ func TestValidateChart(t *testing.T) { }, } for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { + t.Parallel() err := tt.chart.Validate() if tt.wantErrs == nil { require.NoError(t, err) @@ -349,7 +355,9 @@ func TestValidateComponentActions(t *testing.T) { } for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { + t.Parallel() err := tt.actions.validate() if tt.wantErrs == nil { require.NoError(t, err) @@ -392,7 +400,9 @@ func TestValidateComponentAction(t *testing.T) { } for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { + t.Parallel() err := tt.action.Validate() if tt.wantErrs == nil { require.NoError(t, err) @@ -481,7 +491,9 @@ func TestValidateZarfComponent(t *testing.T) { } for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { + t.Parallel() err := tt.component.Validate() if tt.wantErrs == nil { require.NoError(t, err) From 95d879fdf5af8966c7ef8ba9f46e8660ffdf7b5d Mon Sep 17 00:00:00 2001 From: Austin Abro Date: Mon, 3 Jun 2024 16:44:36 +0000 Subject: [PATCH 23/27] downgrade version + rename --- go.mod | 2 +- src/types/validate_test.go | 142 ++++++++++++++++++------------------- 2 files changed, 69 insertions(+), 75 deletions(-) diff --git a/go.mod b/go.mod index e28fc09b97..1275140145 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/defenseunicorns/zarf -go 1.22.3 +go 1.21.8 // TODO (@AABRO): Pending merge into github.com/gojsonschema/gojsonschema (https://github.com/gojsonschema/gojsonschema/pull/5) replace github.com/xeipuuv/gojsonschema => github.com/defenseunicorns/gojsonschema v0.0.0-20231116163348-e00f069122d6 diff --git a/src/types/validate_test.go b/src/types/validate_test.go index 14cc51663c..0a3b50d16d 100644 --- a/src/types/validate_test.go +++ b/src/types/validate_test.go @@ -18,9 +18,9 @@ import ( func TestZarfPackageValidate(t *testing.T) { tests := []struct { - name string - pkg ZarfPackage - wantErrs []string + name string + pkg ZarfPackage + expectedErrs []string }{ { name: "valid package", @@ -35,7 +35,7 @@ func TestZarfPackageValidate(t *testing.T) { }, }, }, - wantErrs: nil, + expectedErrs: nil, }, { name: "no components", @@ -46,7 +46,7 @@ func TestZarfPackageValidate(t *testing.T) { }, Components: []ZarfComponent{}, }, - wantErrs: []string{"package must have at least 1 component"}, + expectedErrs: []string{"package must have at least 1 component"}, }, { name: "invalid package", @@ -110,7 +110,7 @@ func TestZarfPackageValidate(t *testing.T) { }, }, }, - wantErrs: []string{ + expectedErrs: []string{ fmt.Sprintf(lang.PkgValidateErrPkgName, "-invalid-package"), fmt.Errorf(lang.PkgValidateErrVariable, fmt.Errorf(lang.PkgValidateMustBeUppercase, "not_uppercase")).Error(), fmt.Errorf(lang.PkgValidateErrConstant, fmt.Errorf(lang.PkgValidateErrPkgConstantName, "not_uppercase")).Error(), @@ -148,7 +148,7 @@ func TestZarfPackageValidate(t *testing.T) { }, }, }, - wantErrs: []string{ + expectedErrs: []string{ lang.PkgValidateErrInitNoYOLO, lang.PkgValidateErrYOLONoOCI, lang.PkgValidateErrYOLONoGit, @@ -163,45 +163,42 @@ func TestZarfPackageValidate(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() err := tt.pkg.Validate() - if tt.wantErrs == nil { + if tt.expectedErrs == nil { require.NoError(t, err) return } errs := strings.Split(err.Error(), "\n") - require.ElementsMatch(t, errs, tt.wantErrs) + require.ElementsMatch(t, errs, tt.expectedErrs) }) } } func TestValidateManifest(t *testing.T) { - longName := "" - for range ZarfMaxChartNameLength + 1 { - longName += "a" - } + longName := strings.Repeat("a", ZarfMaxChartNameLength+1) tests := []struct { - manifest ZarfManifest - wantErrs []string - name string + manifest ZarfManifest + expectedErrs []string + name string }{ { - name: "valid", - manifest: ZarfManifest{Name: "valid", Files: []string{"a-file"}}, - wantErrs: nil, + name: "valid", + manifest: ZarfManifest{Name: "valid", Files: []string{"a-file"}}, + expectedErrs: nil, }, { - name: "empty name", - manifest: ZarfManifest{Name: "", Files: []string{"a-file"}}, - wantErrs: []string{lang.PkgValidateErrManifestNameMissing}, + name: "empty name", + manifest: ZarfManifest{Name: "", Files: []string{"a-file"}}, + expectedErrs: []string{lang.PkgValidateErrManifestNameMissing}, }, { - name: "long name", - manifest: ZarfManifest{Name: longName, Files: []string{"a-file"}}, - wantErrs: []string{fmt.Sprintf(lang.PkgValidateErrManifestNameLength, longName, ZarfMaxChartNameLength)}, + name: "long name", + manifest: ZarfManifest{Name: longName, Files: []string{"a-file"}}, + expectedErrs: []string{fmt.Sprintf(lang.PkgValidateErrManifestNameLength, longName, ZarfMaxChartNameLength)}, }, { - name: "no files or kustomize", - manifest: ZarfManifest{Name: "nothing-there"}, - wantErrs: []string{fmt.Sprintf(lang.PkgValidateErrManifestFileOrKustomize, "nothing-there")}, + name: "no files or kustomize", + manifest: ZarfManifest{Name: "nothing-there"}, + expectedErrs: []string{fmt.Sprintf(lang.PkgValidateErrManifestFileOrKustomize, "nothing-there")}, }, } for _, tt := range tests { @@ -209,47 +206,44 @@ func TestValidateManifest(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() err := tt.manifest.Validate() - if tt.wantErrs == nil { + if tt.expectedErrs == nil { require.NoError(t, err) return } errs := strings.Split(err.Error(), "\n") - require.ElementsMatch(t, errs, tt.wantErrs) + require.ElementsMatch(t, errs, tt.expectedErrs) }) } } func TestValidateChart(t *testing.T) { - longName := "" - for range ZarfMaxChartNameLength + 1 { - longName += "a" - } + longName := strings.Repeat("a", ZarfMaxChartNameLength+1) tests := []struct { - chart ZarfChart - wantErrs []string - name string + chart ZarfChart + expectedErrs []string + name string }{ { - name: "valid", - chart: ZarfChart{Name: "chart1", Namespace: "whatever", URL: "http://whatever", Version: "v1.0.0"}, - wantErrs: nil, + name: "valid", + chart: ZarfChart{Name: "chart1", Namespace: "whatever", URL: "http://whatever", Version: "v1.0.0"}, + expectedErrs: nil, }, { - name: "empty name", - chart: ZarfChart{Name: "", Namespace: "whatever", URL: "http://whatever", Version: "v1.0.0"}, - wantErrs: []string{lang.PkgValidateErrChartNameMissing}, + name: "empty name", + chart: ZarfChart{Name: "", Namespace: "whatever", URL: "http://whatever", Version: "v1.0.0"}, + expectedErrs: []string{lang.PkgValidateErrChartNameMissing}, }, { name: "long name", chart: ZarfChart{Name: longName, Namespace: "whatever", URL: "http://whatever", Version: "v1.0.0"}, - wantErrs: []string{ + expectedErrs: []string{ fmt.Sprintf(lang.PkgValidateErrChartName, longName, ZarfMaxChartNameLength), }, }, { name: "no url or local path", chart: ZarfChart{Name: "invalid"}, - wantErrs: []string{ + expectedErrs: []string{ fmt.Sprintf(lang.PkgValidateErrChartNamespaceMissing, "invalid"), fmt.Sprintf(lang.PkgValidateErrChartURLOrPath, "invalid"), fmt.Sprintf(lang.PkgValidateErrChartVersion, "invalid"), @@ -258,7 +252,7 @@ func TestValidateChart(t *testing.T) { { name: "both url and local path", chart: ZarfChart{Name: "invalid", Namespace: "whatever", URL: "http://whatever", LocalPath: "wherever", Version: "v1.0.0"}, - wantErrs: []string{ + expectedErrs: []string{ fmt.Sprintf(lang.PkgValidateErrChartURLOrPath, "invalid"), }, }, @@ -268,21 +262,21 @@ func TestValidateChart(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() err := tt.chart.Validate() - if tt.wantErrs == nil { + if tt.expectedErrs == nil { require.NoError(t, err) return } errs := strings.Split(err.Error(), "\n") - require.ElementsMatch(t, tt.wantErrs, errs) + require.ElementsMatch(t, tt.expectedErrs, errs) }) } } func TestValidateComponentActions(t *testing.T) { tests := []struct { - name string - actions ZarfComponentActions - wantErrs []string + name string + actions ZarfComponentActions + expectedErrs []string }{ { name: "valid actions", @@ -302,7 +296,7 @@ func TestValidateComponentActions(t *testing.T) { }, }, }, - wantErrs: nil, + expectedErrs: nil, }, { name: "setVariables in onCreate", @@ -316,7 +310,7 @@ func TestValidateComponentActions(t *testing.T) { }, }, }, - wantErrs: []string{"cannot contain setVariables outside of onDeploy in actions"}, + expectedErrs: []string{"cannot contain setVariables outside of onDeploy in actions"}, }, { name: "invalid onCreate action", @@ -346,7 +340,7 @@ func TestValidateComponentActions(t *testing.T) { }, }, }, - wantErrs: []string{ + expectedErrs: []string{ fmt.Errorf(lang.PkgValidateErrAction, fmt.Errorf(lang.PkgValidateErrActionCmdWait, "create")).Error(), fmt.Errorf(lang.PkgValidateErrAction, fmt.Errorf(lang.PkgValidateErrActionCmdWait, "deploy")).Error(), fmt.Errorf(lang.PkgValidateErrAction, fmt.Errorf(lang.PkgValidateErrActionCmdWait, "remove")).Error(), @@ -359,21 +353,21 @@ func TestValidateComponentActions(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() err := tt.actions.validate() - if tt.wantErrs == nil { + if tt.expectedErrs == nil { require.NoError(t, err) return } errs := strings.Split(err.Error(), "\n") - require.ElementsMatch(t, tt.wantErrs, errs) + require.ElementsMatch(t, tt.expectedErrs, errs) }) } } func TestValidateComponentAction(t *testing.T) { tests := []struct { - name string - action ZarfComponentAction - wantErrs []string + name string + action ZarfComponentAction + expectedErrs []string }{ { name: "valid action no conditions", @@ -385,7 +379,7 @@ func TestValidateComponentAction(t *testing.T) { Cmd: "ls", Wait: &ZarfComponentActionWait{}, }, - wantErrs: []string{ + expectedErrs: []string{ fmt.Sprintf(lang.PkgValidateErrActionCmdWait, "ls"), lang.PkgValidateErrActionClusterNetwork, }, @@ -395,7 +389,7 @@ func TestValidateComponentAction(t *testing.T) { action: ZarfComponentAction{ Wait: &ZarfComponentActionWait{Cluster: &ZarfComponentActionWaitCluster{}, Network: &ZarfComponentActionWaitNetwork{}}, }, - wantErrs: []string{fmt.Sprintf(lang.PkgValidateErrActionClusterNetwork)}, + expectedErrs: []string{fmt.Sprintf(lang.PkgValidateErrActionClusterNetwork)}, }, } @@ -404,12 +398,12 @@ func TestValidateComponentAction(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() err := tt.action.Validate() - if tt.wantErrs == nil { + if tt.expectedErrs == nil { require.NoError(t, err) return } errs := strings.Split(err.Error(), "\n") - require.ElementsMatch(t, tt.wantErrs, errs) + require.ElementsMatch(t, tt.expectedErrs, errs) }) } } @@ -418,9 +412,9 @@ func TestValidateZarfComponent(t *testing.T) { absPath, err := filepath.Abs("abs") require.NoError(t, err) tests := []struct { - component ZarfComponent - wantErrs []string - name string + component ZarfComponent + expectedErrs []string + name string }{ { name: "valid path", @@ -430,7 +424,7 @@ func TestValidateZarfComponent(t *testing.T) { Path: "relative/path", }, }, - wantErrs: nil, + expectedErrs: nil, }, { name: "valid URL", @@ -440,14 +434,14 @@ func TestValidateZarfComponent(t *testing.T) { URL: "oci://example.com/package:v0.0.1", }, }, - wantErrs: nil, + expectedErrs: nil, }, { name: "neither path nor URL provided", component: ZarfComponent{ Name: "neither", }, - wantErrs: []string{ + expectedErrs: []string{ fmt.Sprintf(lang.PkgValidateErrImportDefinition, "neither", "neither a path nor a URL was provided"), }, }, @@ -460,7 +454,7 @@ func TestValidateZarfComponent(t *testing.T) { URL: "https://example.com", }, }, - wantErrs: []string{ + expectedErrs: []string{ fmt.Sprintf(lang.PkgValidateErrImportDefinition, "both", "both a path and a URL were provided"), }, }, @@ -472,7 +466,7 @@ func TestValidateZarfComponent(t *testing.T) { Path: absPath, }, }, - wantErrs: []string{ + expectedErrs: []string{ fmt.Sprintf(lang.PkgValidateErrImportDefinition, "abs-path", "path cannot be an absolute path"), }, }, @@ -484,7 +478,7 @@ func TestValidateZarfComponent(t *testing.T) { URL: "https://example.com", }, }, - wantErrs: []string{ + expectedErrs: []string{ fmt.Sprintf(lang.PkgValidateErrImportDefinition, "bad-url", "URL is not a valid OCI URL"), }, }, @@ -495,12 +489,12 @@ func TestValidateZarfComponent(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() err := tt.component.Validate() - if tt.wantErrs == nil { + if tt.expectedErrs == nil { require.NoError(t, err) return } errs := strings.Split(err.Error(), "\n") - require.ElementsMatch(t, tt.wantErrs, errs) + require.ElementsMatch(t, tt.expectedErrs, errs) }) } } From 8bd80821dd5acbd53d34eef0beabf8dc31c0d4ec Mon Sep 17 00:00:00 2001 From: Austin Abro Date: Mon, 3 Jun 2024 17:19:07 +0000 Subject: [PATCH 24/27] parrallel --- src/types/validate_test.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/types/validate_test.go b/src/types/validate_test.go index 0a3b50d16d..be8cbc065d 100644 --- a/src/types/validate_test.go +++ b/src/types/validate_test.go @@ -17,6 +17,7 @@ import ( ) func TestZarfPackageValidate(t *testing.T) { + t.Parallel() tests := []struct { name string pkg ZarfPackage @@ -174,6 +175,7 @@ func TestZarfPackageValidate(t *testing.T) { } func TestValidateManifest(t *testing.T) { + t.Parallel() longName := strings.Repeat("a", ZarfMaxChartNameLength+1) tests := []struct { manifest ZarfManifest @@ -217,6 +219,7 @@ func TestValidateManifest(t *testing.T) { } func TestValidateChart(t *testing.T) { + t.Parallel() longName := strings.Repeat("a", ZarfMaxChartNameLength+1) tests := []struct { chart ZarfChart @@ -273,6 +276,7 @@ func TestValidateChart(t *testing.T) { } func TestValidateComponentActions(t *testing.T) { + t.Parallel() tests := []struct { name string actions ZarfComponentActions @@ -364,6 +368,7 @@ func TestValidateComponentActions(t *testing.T) { } func TestValidateComponentAction(t *testing.T) { + t.Parallel() tests := []struct { name string action ZarfComponentAction @@ -409,6 +414,7 @@ func TestValidateComponentAction(t *testing.T) { } func TestValidateZarfComponent(t *testing.T) { + t.Parallel() absPath, err := filepath.Abs("abs") require.NoError(t, err) tests := []struct { From 04825237e7de53b9ee7cc966eb08a7f7af18c834 Mon Sep 17 00:00:00 2001 From: Austin Abro Date: Tue, 4 Jun 2024 11:44:50 +0000 Subject: [PATCH 25/27] change err joining --- src/types/validate.go | 128 +++++++++++++++++++++--------------------- 1 file changed, 64 insertions(+), 64 deletions(-) diff --git a/src/types/validate.go b/src/types/validate.go index 4dcb113ed2..8b00b090e0 100644 --- a/src/types/validate.go +++ b/src/types/validate.go @@ -40,28 +40,28 @@ func SupportedOS() []string { // Validate runs all validation checks on the package. func (pkg ZarfPackage) Validate() error { - errs := []error{} + var err error if pkg.Kind == ZarfInitConfig && pkg.Metadata.YOLO { - errs = append(errs, fmt.Errorf(lang.PkgValidateErrInitNoYOLO)) + err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrInitNoYOLO)) } if !IsLowercaseNumberHyphenNoStartHyphen(pkg.Metadata.Name) { - errs = append(errs, fmt.Errorf(lang.PkgValidateErrPkgName, pkg.Metadata.Name)) + err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrPkgName, pkg.Metadata.Name)) } if len(pkg.Components) == 0 { - errs = append(errs, fmt.Errorf("package must have at least 1 component")) + err = errors.Join(err, fmt.Errorf("package must have at least 1 component")) } for _, variable := range pkg.Variables { - if err := variable.Validate(); err != nil { - errs = append(errs, fmt.Errorf(lang.PkgValidateErrVariable, err)) + if varErr := variable.Validate(); varErr != nil { + err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrVariable, varErr)) } } for _, constant := range pkg.Constants { - if err := constant.Validate(); err != nil { - errs = append(errs, fmt.Errorf(lang.PkgValidateErrConstant, err)) + if varErr := constant.Validate(); varErr != nil { + err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrConstant, varErr)) } } @@ -72,19 +72,19 @@ func (pkg ZarfPackage) Validate() error { if pkg.Metadata.YOLO { for _, component := range pkg.Components { if len(component.Images) > 0 { - errs = append(errs, fmt.Errorf(lang.PkgValidateErrYOLONoOCI)) + err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrYOLONoOCI)) } if len(component.Repos) > 0 { - errs = append(errs, fmt.Errorf(lang.PkgValidateErrYOLONoGit)) + err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrYOLONoGit)) } if component.Only.Cluster.Architecture != "" { - errs = append(errs, fmt.Errorf(lang.PkgValidateErrYOLONoArch)) + err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrYOLONoArch)) } if len(component.Only.Cluster.Distros) > 0 { - errs = append(errs, fmt.Errorf(lang.PkgValidateErrYOLONoDistro)) + err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrYOLONoDistro)) } } } @@ -92,24 +92,24 @@ func (pkg ZarfPackage) Validate() error { for _, component := range pkg.Components { // ensure component name is unique if _, ok := uniqueComponentNames[component.Name]; ok { - errs = append(errs, fmt.Errorf(lang.PkgValidateErrComponentNameNotUnique, component.Name)) + err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrComponentNameNotUnique, component.Name)) } uniqueComponentNames[component.Name] = true if !IsLowercaseNumberHyphenNoStartHyphen(component.Name) { - errs = append(errs, fmt.Errorf(lang.PkgValidateErrComponentName, component.Name)) + err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrComponentName, component.Name)) } if !slices.Contains(supportedOS, component.Only.LocalOS) { - errs = append(errs, fmt.Errorf(lang.PkgValidateErrComponentLocalOS, component.Name, component.Only.LocalOS, supportedOS)) + err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrComponentLocalOS, component.Name, component.Only.LocalOS, supportedOS)) } if component.IsRequired() { if component.Default { - errs = append(errs, fmt.Errorf(lang.PkgValidateErrComponentReqDefault, component.Name)) + err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrComponentReqDefault, component.Name)) } if component.DeprecatedGroup != "" { - errs = append(errs, fmt.Errorf(lang.PkgValidateErrComponentReqGrouped, component.Name)) + err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrComponentReqGrouped, component.Name)) } } @@ -117,12 +117,12 @@ func (pkg ZarfPackage) Validate() error { for _, chart := range component.Charts { // ensure chart name is unique if _, ok := uniqueChartNames[chart.Name]; ok { - errs = append(errs, fmt.Errorf(lang.PkgValidateErrChartNameNotUnique, chart.Name)) + err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrChartNameNotUnique, chart.Name)) } uniqueChartNames[chart.Name] = true - if err := chart.Validate(); err != nil { - errs = append(errs, fmt.Errorf(lang.PkgValidateErrChart, err)) + if chartErr := chart.Validate(); chartErr != nil { + err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrChart, chartErr)) } } @@ -130,24 +130,24 @@ func (pkg ZarfPackage) Validate() error { for _, manifest := range component.Manifests { // ensure manifest name is unique if _, ok := uniqueManifestNames[manifest.Name]; ok { - errs = append(errs, fmt.Errorf(lang.PkgValidateErrManifestNameNotUnique, manifest.Name)) + err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrManifestNameNotUnique, manifest.Name)) } uniqueManifestNames[manifest.Name] = true - if err := manifest.Validate(); err != nil { - errs = append(errs, fmt.Errorf(lang.PkgValidateErrManifest, err)) + if manifestErr := manifest.Validate(); manifestErr != nil { + err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrManifest, manifestErr)) } } - if err := component.Actions.validate(); err != nil { - errs = append(errs, fmt.Errorf("%q: %w", component.Name, err)) + if actionsErr := component.Actions.validate(); actionsErr != nil { + err = errors.Join(err, fmt.Errorf("%q: %w", component.Name, actionsErr)) } // ensure groups don't have multiple defaults or only one component if component.DeprecatedGroup != "" { if component.Default { if _, ok := groupDefault[component.DeprecatedGroup]; ok { - errs = append(errs, fmt.Errorf(lang.PkgValidateErrGroupMultipleDefaults, component.DeprecatedGroup, groupDefault[component.DeprecatedGroup], component.Name)) + err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrGroupMultipleDefaults, component.DeprecatedGroup, groupDefault[component.DeprecatedGroup], component.Name)) } groupDefault[component.DeprecatedGroup] = component.Name } @@ -157,60 +157,60 @@ func (pkg ZarfPackage) Validate() error { for groupKey, componentNames := range groupedComponents { if len(componentNames) == 1 { - errs = append(errs, fmt.Errorf(lang.PkgValidateErrGroupOneComponent, groupKey, componentNames[0])) + err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrGroupOneComponent, groupKey, componentNames[0])) } } - return errors.Join(errs...) + return err } func (a ZarfComponentActions) validate() error { - var errs []error + var err error - if err := a.OnCreate.Validate(); err != nil { - errs = append(errs, fmt.Errorf(lang.PkgValidateErrAction, err)) + if setErr := a.OnCreate.Validate(); setErr != nil { + err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrAction, setErr)) } if a.OnCreate.HasSetVariables() { - errs = append(errs, fmt.Errorf("cannot contain setVariables outside of onDeploy in actions")) + err = errors.Join(err, fmt.Errorf("cannot contain setVariables outside of onDeploy in actions")) } - if err := a.OnDeploy.Validate(); err != nil { - errs = append(errs, fmt.Errorf(lang.PkgValidateErrAction, err)) + if setErr := a.OnDeploy.Validate(); setErr != nil { + err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrAction, setErr)) } if a.OnRemove.HasSetVariables() { - errs = append(errs, fmt.Errorf("cannot contain setVariables outside of onDeploy in actions")) + err = errors.Join(err, fmt.Errorf("cannot contain setVariables outside of onDeploy in actions")) } - if err := a.OnRemove.Validate(); err != nil { - errs = append(errs, fmt.Errorf(lang.PkgValidateErrAction, err)) + if setErr := a.OnRemove.Validate(); setErr != nil { + err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrAction, setErr)) } - return errors.Join(errs...) + return err } // Validate validates the component trying to be imported. func (c ZarfComponent) Validate() error { - errs := []error{} + var err error path := c.Import.Path url := c.Import.URL // ensure path or url is provided if path == "" && url == "" { - errs = append(errs, fmt.Errorf(lang.PkgValidateErrImportDefinition, c.Name, "neither a path nor a URL was provided")) + err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrImportDefinition, c.Name, "neither a path nor a URL was provided")) } // ensure path and url are not both provided if path != "" && url != "" { - errs = append(errs, fmt.Errorf(lang.PkgValidateErrImportDefinition, c.Name, "both a path and a URL were provided")) + err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrImportDefinition, c.Name, "both a path and a URL were provided")) } // validation for path if url == "" && path != "" { // ensure path is not an absolute path if filepath.IsAbs(path) { - errs = append(errs, fmt.Errorf(lang.PkgValidateErrImportDefinition, c.Name, "path cannot be an absolute path")) + err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrImportDefinition, c.Name, "path cannot be an absolute path")) } } @@ -218,11 +218,11 @@ func (c ZarfComponent) Validate() error { if url != "" && path == "" { ok := helpers.IsOCIURL(url) if !ok { - errs = append(errs, fmt.Errorf(lang.PkgValidateErrImportDefinition, c.Name, "URL is not a valid OCI URL")) + err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrImportDefinition, c.Name, "URL is not a valid OCI URL")) } } - return errors.Join(errs...) + return err } // HasSetVariables returns true if any of the actions contain setVariables. @@ -264,81 +264,81 @@ func (as ZarfComponentActionSet) Validate() error { // Validate runs all validation checks on an action. func (action ZarfComponentAction) Validate() error { - errs := []error{} + var err error // Validate SetVariable for _, variable := range action.SetVariables { - if err := variable.Validate(); err != nil { - errs = append(errs, err) + if varErr := variable.Validate(); varErr != nil { + err = errors.Join(err, varErr) } } if action.Wait != nil { // Validate only cmd or wait, not both if action.Cmd != "" { - errs = append(errs, fmt.Errorf(lang.PkgValidateErrActionCmdWait, action.Cmd)) + err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrActionCmdWait, action.Cmd)) } // Validate only cluster or network, not both if action.Wait.Cluster != nil && action.Wait.Network != nil { - errs = append(errs, fmt.Errorf(lang.PkgValidateErrActionClusterNetwork)) + err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrActionClusterNetwork)) } // Validate at least one of cluster or network if action.Wait.Cluster == nil && action.Wait.Network == nil { - errs = append(errs, fmt.Errorf(lang.PkgValidateErrActionClusterNetwork)) + err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrActionClusterNetwork)) } } - return errors.Join(errs...) + return err } // Validate runs all validation checks on a chart. func (chart ZarfChart) Validate() error { - errs := []error{} + var err error if chart.Name == "" { - errs = append(errs, fmt.Errorf(lang.PkgValidateErrChartNameMissing)) + err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrChartNameMissing)) } if len(chart.Name) > ZarfMaxChartNameLength { - errs = append(errs, fmt.Errorf(lang.PkgValidateErrChartName, chart.Name, ZarfMaxChartNameLength)) + err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrChartName, chart.Name, ZarfMaxChartNameLength)) } if chart.Namespace == "" { - errs = append(errs, fmt.Errorf(lang.PkgValidateErrChartNamespaceMissing, chart.Name)) + err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrChartNamespaceMissing, chart.Name)) } // Must have a url or localPath (and not both) if chart.URL != "" && chart.LocalPath != "" { - errs = append(errs, fmt.Errorf(lang.PkgValidateErrChartURLOrPath, chart.Name)) + err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrChartURLOrPath, chart.Name)) } if chart.URL == "" && chart.LocalPath == "" { - errs = append(errs, fmt.Errorf(lang.PkgValidateErrChartURLOrPath, chart.Name)) + err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrChartURLOrPath, chart.Name)) } if chart.Version == "" { - errs = append(errs, fmt.Errorf(lang.PkgValidateErrChartVersion, chart.Name)) + err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrChartVersion, chart.Name)) } - return errors.Join(errs...) + return err } // Validate runs all validation checks on a manifest. func (manifest ZarfManifest) Validate() error { - errs := []error{} + var err error if manifest.Name == "" { - errs = append(errs, fmt.Errorf(lang.PkgValidateErrManifestNameMissing)) + err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrManifestNameMissing)) } if len(manifest.Name) > ZarfMaxChartNameLength { - errs = append(errs, fmt.Errorf(lang.PkgValidateErrManifestNameLength, manifest.Name, ZarfMaxChartNameLength)) + err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrManifestNameLength, manifest.Name, ZarfMaxChartNameLength)) } if len(manifest.Files) < 1 && len(manifest.Kustomizations) < 1 { - errs = append(errs, fmt.Errorf(lang.PkgValidateErrManifestFileOrKustomize, manifest.Name)) + err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrManifestFileOrKustomize, manifest.Name)) } - return errors.Join(errs...) + return err } From 7b4a42bf72d5030ba29983c75ac3677be8388826 Mon Sep 17 00:00:00 2001 From: Austin Abro Date: Tue, 4 Jun 2024 12:29:56 +0000 Subject: [PATCH 26/27] fix component action validation --- src/types/validate.go | 30 +++++++++++++----------------- src/types/validate_test.go | 7 +++++++ 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/src/types/validate.go b/src/types/validate.go index 8b00b090e0..94f30a6c27 100644 --- a/src/types/validate.go +++ b/src/types/validate.go @@ -168,7 +168,7 @@ func (a ZarfComponentActions) validate() error { var err error if setErr := a.OnCreate.Validate(); setErr != nil { - err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrAction, setErr)) + err = errors.Join(err, setErr) } if a.OnCreate.HasSetVariables() { @@ -176,7 +176,7 @@ func (a ZarfComponentActions) validate() error { } if setErr := a.OnDeploy.Validate(); setErr != nil { - err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrAction, setErr)) + err = errors.Join(err, setErr) } if a.OnRemove.HasSetVariables() { @@ -184,7 +184,7 @@ func (a ZarfComponentActions) validate() error { } if setErr := a.OnRemove.Validate(); setErr != nil { - err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrAction, setErr)) + err = errors.Join(err, setErr) } return err @@ -241,25 +241,21 @@ func (as ZarfComponentActionSet) HasSetVariables() bool { // Validate runs all validation checks on component action sets. func (as ZarfComponentActionSet) Validate() error { - validate := func(actions []ZarfComponentAction) error { + var err error + validate := func(actions []ZarfComponentAction) { for _, action := range actions { - if err := action.Validate(); err != nil { - return err + if actionErr := action.Validate(); actionErr != nil { + err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrAction, actionErr)) } + } - return nil } - if err := validate(as.Before); err != nil { - return err - } - if err := validate(as.After); err != nil { - return err - } - if err := validate(as.OnSuccess); err != nil { - return err - } - return validate(as.OnFailure) + validate(as.Before) + validate(as.After) + validate(as.OnFailure) + validate(as.OnSuccess) + return err } // Validate runs all validation checks on an action. diff --git a/src/types/validate_test.go b/src/types/validate_test.go index be8cbc065d..5fcce6821b 100644 --- a/src/types/validate_test.go +++ b/src/types/validate_test.go @@ -342,12 +342,19 @@ func TestValidateComponentActions(t *testing.T) { Wait: &ZarfComponentActionWait{Cluster: &ZarfComponentActionWaitCluster{}}, }, }, + OnFailure: []ZarfComponentAction{ + { + Cmd: "remove2", + Wait: &ZarfComponentActionWait{Cluster: &ZarfComponentActionWaitCluster{}}, + }, + }, }, }, expectedErrs: []string{ fmt.Errorf(lang.PkgValidateErrAction, fmt.Errorf(lang.PkgValidateErrActionCmdWait, "create")).Error(), fmt.Errorf(lang.PkgValidateErrAction, fmt.Errorf(lang.PkgValidateErrActionCmdWait, "deploy")).Error(), fmt.Errorf(lang.PkgValidateErrAction, fmt.Errorf(lang.PkgValidateErrActionCmdWait, "remove")).Error(), + fmt.Errorf(lang.PkgValidateErrAction, fmt.Errorf(lang.PkgValidateErrActionCmdWait, "remove2")).Error(), }, }, } From 40f4f28c3b1f63c807627cd3489141ddffb5a9b5 Mon Sep 17 00:00:00 2001 From: Austin Abro Date: Tue, 4 Jun 2024 12:34:44 +0000 Subject: [PATCH 27/27] more errors.join things --- src/types/validate.go | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/src/types/validate.go b/src/types/validate.go index 94f30a6c27..fa5cfcbd87 100644 --- a/src/types/validate.go +++ b/src/types/validate.go @@ -167,25 +167,19 @@ func (pkg ZarfPackage) Validate() error { func (a ZarfComponentActions) validate() error { var err error - if setErr := a.OnCreate.Validate(); setErr != nil { - err = errors.Join(err, setErr) - } + err = errors.Join(err, a.OnCreate.Validate()) if a.OnCreate.HasSetVariables() { err = errors.Join(err, fmt.Errorf("cannot contain setVariables outside of onDeploy in actions")) } - if setErr := a.OnDeploy.Validate(); setErr != nil { - err = errors.Join(err, setErr) - } + err = errors.Join(err, a.OnDeploy.Validate()) if a.OnRemove.HasSetVariables() { err = errors.Join(err, fmt.Errorf("cannot contain setVariables outside of onDeploy in actions")) } - if setErr := a.OnRemove.Validate(); setErr != nil { - err = errors.Join(err, setErr) - } + err = errors.Join(err, a.OnRemove.Validate()) return err } @@ -261,11 +255,8 @@ func (as ZarfComponentActionSet) Validate() error { // Validate runs all validation checks on an action. func (action ZarfComponentAction) Validate() error { var err error - // Validate SetVariable for _, variable := range action.SetVariables { - if varErr := variable.Validate(); varErr != nil { - err = errors.Join(err, varErr) - } + err = errors.Join(err, variable.Validate()) } if action.Wait != nil {