diff --git a/src/pkg/bundle/create.go b/src/pkg/bundle/create.go index e06b56b6..3c691235 100644 --- a/src/pkg/bundle/create.go +++ b/src/pkg/bundle/create.go @@ -11,11 +11,12 @@ import ( "github.com/AlecAivazis/survey/v2" "github.com/defenseunicorns/uds-cli/src/config" "github.com/defenseunicorns/uds-cli/src/pkg/bundler" + "github.com/defenseunicorns/uds-cli/src/pkg/utils" "github.com/defenseunicorns/uds-cli/src/types" zarfConfig "github.com/defenseunicorns/zarf/src/config" "github.com/defenseunicorns/zarf/src/pkg/interactive" "github.com/defenseunicorns/zarf/src/pkg/message" - "github.com/defenseunicorns/zarf/src/pkg/utils" + zarfUtils "github.com/defenseunicorns/zarf/src/pkg/utils" "github.com/pterm/pterm" "helm.sh/helm/v3/pkg/chartutil" ) @@ -24,7 +25,12 @@ import ( func (b *Bundle) Create() error { // read the bundle's metadata into memory - if err := utils.ReadYaml(filepath.Join(b.cfg.CreateOpts.SourceDirectory, b.cfg.CreateOpts.BundleFile), &b.bundle); err != nil { + if err := utils.ReadYAMLStrict(filepath.Join(b.cfg.CreateOpts.SourceDirectory, b.cfg.CreateOpts.BundleFile), &b.bundle); err != nil { + return err + } + + // Populate values from valuesFiles if provided + if err := b.processValuesFiles(); err != nil { return err } @@ -62,7 +68,7 @@ func (b *Bundle) Create() error { if b.cfg.CreateOpts.SigningKeyPath != "" { // write the bundle to disk so we can sign it bundlePath := filepath.Join(b.tmp, config.BundleYAML) - if err := utils.WriteYaml(bundlePath, &b.bundle, 0600); err != nil { + if err := zarfUtils.WriteYaml(bundlePath, &b.bundle, 0600); err != nil { return err } @@ -74,7 +80,7 @@ func (b *Bundle) Create() error { } // sign the bundle signaturePath := filepath.Join(b.tmp, config.BundleYAMLSignature) - _, err := utils.CosignSignBlob(bundlePath, signaturePath, b.cfg.CreateOpts.SigningKeyPath, getSigCreatePassword) + _, err := zarfUtils.CosignSignBlob(bundlePath, signaturePath, b.cfg.CreateOpts.SigningKeyPath, getSigCreatePassword) if err != nil { return err } @@ -94,7 +100,7 @@ func (b *Bundle) Create() error { func (b *Bundle) confirmBundleCreation() (confirm bool) { message.HeaderInfof("🎁 BUNDLE DEFINITION") - utils.ColorPrintYAML(b.bundle, nil, false) + zarfUtils.ColorPrintYAML(b.bundle, nil, false) message.HorizontalRule() pterm.Println() diff --git a/src/pkg/bundle/dev.go b/src/pkg/bundle/dev.go index c36aa4dd..12e0e6a9 100644 --- a/src/pkg/bundle/dev.go +++ b/src/pkg/bundle/dev.go @@ -11,18 +11,18 @@ import ( "regexp" "github.com/defenseunicorns/uds-cli/src/config" + "github.com/defenseunicorns/uds-cli/src/pkg/utils" zarfCLI "github.com/defenseunicorns/zarf/src/cmd" "github.com/defenseunicorns/zarf/src/pkg/message" - zarfUtils "github.com/defenseunicorns/zarf/src/pkg/utils" ) // CreateZarfPkgs creates a zarf package if its missing when in dev mode func (b *Bundle) CreateZarfPkgs() { srcDir := b.cfg.CreateOpts.SourceDirectory bundleYAMLPath := filepath.Join(srcDir, b.cfg.CreateOpts.BundleFile) - if err := zarfUtils.ReadYaml(bundleYAMLPath, &b.bundle); err != nil { - message.Fatalf(err, "Failed to read bundle.yaml: %s", err.Error()) + if err := utils.ReadYAMLStrict(bundleYAMLPath, &b.bundle); err != nil { + message.Fatalf(err, "Failed to read %s, error in YAML: %s", b.cfg.CreateOpts.BundleFile, err.Error()) } zarfPackagePattern := `^zarf-.*\.tar\.zst$` diff --git a/src/pkg/bundle/inspect.go b/src/pkg/bundle/inspect.go index 6ec5c5d4..d60592ce 100644 --- a/src/pkg/bundle/inspect.go +++ b/src/pkg/bundle/inspect.go @@ -6,7 +6,8 @@ package bundle import ( "github.com/defenseunicorns/uds-cli/src/config" - "github.com/defenseunicorns/zarf/src/pkg/utils" + "github.com/defenseunicorns/uds-cli/src/pkg/utils" + zarfUtils "github.com/defenseunicorns/zarf/src/pkg/utils" ) // Inspect pulls/unpacks a bundle's metadata and shows it @@ -44,12 +45,12 @@ func (b *Bundle) Inspect() error { } } // read the bundle's metadata into memory - if err := utils.ReadYaml(loaded[config.BundleYAML], &b.bundle); err != nil { + if err := utils.ReadYAMLStrict(loaded[config.BundleYAML], &b.bundle); err != nil { return err } // show the bundle's metadata - utils.ColorPrintYAML(b.bundle, nil, false) + zarfUtils.ColorPrintYAML(b.bundle, nil, false) // TODO: showing package metadata? // TODO: could be cool to have an interactive mode that lets you select a package and show its metadata diff --git a/src/pkg/bundle/publish.go b/src/pkg/bundle/publish.go index 217ed2a7..c2f0b1c0 100644 --- a/src/pkg/bundle/publish.go +++ b/src/pkg/bundle/publish.go @@ -12,7 +12,6 @@ import ( "github.com/defenseunicorns/pkg/oci" "github.com/defenseunicorns/uds-cli/src/config" "github.com/defenseunicorns/uds-cli/src/pkg/utils" - zarfUtils "github.com/defenseunicorns/zarf/src/pkg/utils" "github.com/defenseunicorns/zarf/src/pkg/zoci" av3 "github.com/mholt/archiver/v3" ocispec "github.com/opencontainers/image-spec/specs-go/v1" @@ -32,7 +31,7 @@ func (b *Bundle) Publish() error { if err != nil { return err } - if err := zarfUtils.ReadYaml(loaded[config.BundleYAML], &b.bundle); err != nil { + if err := utils.ReadYAMLStrict(loaded[config.BundleYAML], &b.bundle); err != nil { return err } err = os.RemoveAll(filepath.Join(b.tmp, "blobs")) // clear tmp dir diff --git a/src/pkg/bundle/remote.go b/src/pkg/bundle/remote.go index d17bb7b0..3c9cfa9b 100644 --- a/src/pkg/bundle/remote.go +++ b/src/pkg/bundle/remote.go @@ -151,7 +151,7 @@ func (op *ociProvider) LoadBundle(opts types.BundlePullOptions, _ int) (*types.U if err != nil { return nil, nil, err } - if err := zarfUtils.ReadYaml(loaded[config.BundleYAML], &bundle); err != nil { + if err := utils.ReadYAMLStrict(loaded[config.BundleYAML], &bundle); err != nil { return nil, nil, err } diff --git a/src/pkg/bundle/remove.go b/src/pkg/bundle/remove.go index 3af1c30d..a8e66f0e 100644 --- a/src/pkg/bundle/remove.go +++ b/src/pkg/bundle/remove.go @@ -8,15 +8,15 @@ import ( "fmt" "strings" + "github.com/defenseunicorns/uds-cli/src/config" + "github.com/defenseunicorns/uds-cli/src/pkg/sources" + "github.com/defenseunicorns/uds-cli/src/pkg/utils" + "github.com/defenseunicorns/uds-cli/src/types" "github.com/defenseunicorns/zarf/src/pkg/message" "github.com/defenseunicorns/zarf/src/pkg/packager" - "github.com/defenseunicorns/zarf/src/pkg/utils" + zarfUtils "github.com/defenseunicorns/zarf/src/pkg/utils" zarfTypes "github.com/defenseunicorns/zarf/src/types" "golang.org/x/exp/slices" - - "github.com/defenseunicorns/uds-cli/src/config" - "github.com/defenseunicorns/uds-cli/src/pkg/sources" - "github.com/defenseunicorns/uds-cli/src/types" ) // Remove removes packages deployed from a bundle @@ -48,7 +48,7 @@ func (b *Bundle) Remove() error { } // read the bundle's metadata into memory - if err := utils.ReadYaml(loaded[config.BundleYAML], &b.bundle); err != nil { + if err := utils.ReadYAMLStrict(loaded[config.BundleYAML], &b.bundle); err != nil { return err } @@ -87,7 +87,7 @@ func removePackages(packagesToRemove []types.Package, b *Bundle) error { pkgCfg := zarfTypes.PackagerConfig{ PkgOpts: opts, } - pkgTmp, err := utils.MakeTempDir(config.CommonOptions.TempDirectory) + pkgTmp, err := zarfUtils.MakeTempDir(config.CommonOptions.TempDirectory) if err != nil { return err } diff --git a/src/pkg/bundler/fetcher/local.go b/src/pkg/bundler/fetcher/local.go index 71f7c946..88d14656 100644 --- a/src/pkg/bundler/fetcher/local.go +++ b/src/pkg/bundler/fetcher/local.go @@ -103,7 +103,7 @@ func (f *localFetcher) GetPkgMetadata() (zarfTypes.ZarfPackage, error) { } zarfYAML := zarfTypes.ZarfPackage{} zarfYAMLPath := filepath.Join(tmpDir, config.ZarfYAML) - err = zarfUtils.ReadYaml(zarfYAMLPath, &zarfYAML) + err = utils.ReadYAMLStrict(zarfYAMLPath, &zarfYAML) if err != nil { return zarfTypes.ZarfPackage{}, err } diff --git a/src/pkg/bundler/fetcher/remote.go b/src/pkg/bundler/fetcher/remote.go index 27cfe510..06f04a78 100644 --- a/src/pkg/bundler/fetcher/remote.go +++ b/src/pkg/bundler/fetcher/remote.go @@ -179,7 +179,7 @@ func (f *remoteFetcher) GetPkgMetadata() (zarfTypes.ZarfPackage, error) { } zarfYAML := zarfTypes.ZarfPackage{} zarfYAMLPath := filepath.Join(tmpDir, config.ZarfYAML) - err = zarfUtils.ReadYaml(zarfYAMLPath, &zarfYAML) + err = utils.ReadYAMLStrict(zarfYAMLPath, &zarfYAML) if err != nil { return zarfTypes.ZarfPackage{}, err } diff --git a/src/pkg/sources/remote.go b/src/pkg/sources/remote.go index 2b280c03..0dcb7198 100644 --- a/src/pkg/sources/remote.go +++ b/src/pkg/sources/remote.go @@ -48,7 +48,7 @@ func (r *RemoteBundle) LoadPackage(dst *layout.PackagePaths, filter filters.Comp } var pkg zarfTypes.ZarfPackage - if err = zarfUtils.ReadYaml(dst.ZarfYAML, &pkg); err != nil { + if err = utils.ReadYAMLStrict(dst.ZarfYAML, &pkg); err != nil { return zarfTypes.ZarfPackage{}, nil, err } diff --git a/src/pkg/sources/tarball.go b/src/pkg/sources/tarball.go index dcd22a5a..98af691b 100644 --- a/src/pkg/sources/tarball.go +++ b/src/pkg/sources/tarball.go @@ -18,7 +18,6 @@ import ( "github.com/defenseunicorns/zarf/src/pkg/message" "github.com/defenseunicorns/zarf/src/pkg/packager/filters" "github.com/defenseunicorns/zarf/src/pkg/packager/sources" - zarfUtils "github.com/defenseunicorns/zarf/src/pkg/utils" zarfTypes "github.com/defenseunicorns/zarf/src/types" av4 "github.com/mholt/archiver/v4" ocispec "github.com/opencontainers/image-spec/specs-go/v1" @@ -53,7 +52,7 @@ func (t *TarballBundle) LoadPackage(dst *layout.PackagePaths, filter filters.Com } var pkg zarfTypes.ZarfPackage - if err = zarfUtils.ReadYaml(dst.ZarfYAML, &pkg); err != nil { + if err = utils.ReadYAMLStrict(dst.ZarfYAML, &pkg); err != nil { return zarfTypes.ZarfPackage{}, nil, err } @@ -189,7 +188,7 @@ func (t *TarballBundle) LoadPackageMetadata(dst *layout.PackagePaths, _ bool, _ // deserialize zarf.yaml to grab checksum for validating pkg integrity var pkg zarfTypes.ZarfPackage - err = zarfUtils.ReadYaml(dst.ZarfYAML, &pkg) + err = utils.ReadYAMLStrict(dst.ZarfYAML, &pkg) if err != nil { return zarfTypes.ZarfPackage{}, nil, err } diff --git a/src/pkg/utils/utils.go b/src/pkg/utils/utils.go index 483e7eac..51e6440a 100644 --- a/src/pkg/utils/utils.go +++ b/src/pkg/utils/utils.go @@ -15,6 +15,8 @@ import ( "strconv" "strings" + goyaml "github.com/goccy/go-yaml" + "github.com/defenseunicorns/pkg/helpers" "github.com/defenseunicorns/uds-cli/src/config" "github.com/defenseunicorns/uds-cli/src/types" @@ -156,3 +158,19 @@ func IsRegistryURL(s string) bool { return false } + +// ReadYAMLStrict reads a YAML file into a struct, with strict parsing +func ReadYAMLStrict(path string, destConfig any) error { + message.Debugf("Reading YAML at %s", path) + + file, err := os.ReadFile(path) + if err != nil { + return fmt.Errorf("failed to read file at %s: %v", path, err) + } + + err = goyaml.UnmarshalWithOptions(file, destConfig, goyaml.Strict()) + if err != nil { + return fmt.Errorf("failed to unmarshal YAML at %s: %v", path, err) + } + return nil +} diff --git a/src/test/bundles/07-helm-overrides/invalid/uds-bundle.yaml b/src/test/bundles/07-helm-overrides/invalid/uds-bundle.yaml new file mode 100644 index 00000000..79ccbbd1 --- /dev/null +++ b/src/test/bundles/07-helm-overrides/invalid/uds-bundle.yaml @@ -0,0 +1,22 @@ +kind: UDSBundle +metadata: + name: helm-overrides + description: testing a bundle with Helm overrides + version: 0.0.1 + +packages: + - name: helm-overrides + path: "../../../packages/helm" + ref: 0.0.1 + + overrides: + podinfo-component: + unicorn-podinfo: + values: + - path: "podinfo.replicaCount" + value: 2 + # missing `variables:` key here should throw an error + - name: log_level + path: "podinfo.logLevel" + description: "Set the log level for podinfo" + default: "debug" # not overwritten! diff --git a/src/test/e2e/bundle_test.go b/src/test/e2e/bundle_test.go index 271ef814..06aa297a 100644 --- a/src/test/e2e/bundle_test.go +++ b/src/test/e2e/bundle_test.go @@ -601,3 +601,13 @@ func TestBundleTmpDir(t *testing.T) { err = os.RemoveAll("./customtmp") require.NoError(t, err) } + +func TestInvalidBundle(t *testing.T) { + deployZarfInit(t) + zarfPkgPath := "src/test/packages/helm" + e2e.HelmDepUpdate(t, fmt.Sprintf("%s/unicorn-podinfo", zarfPkgPath)) + e2e.CreateZarfPkg(t, zarfPkgPath, false) + bundleDir := "src/test/bundles/07-helm-overrides/invalid" + stderr := createLocalError(bundleDir, e2e.Arch) + require.Contains(t, stderr, "unknown field") +}