From a6502e45782bfa73c60b98716a5f23dbbf322d4e Mon Sep 17 00:00:00 2001 From: Philip Laine Date: Wed, 14 Aug 2024 21:19:46 +0200 Subject: [PATCH 01/18] refactor: findImages to return errors immediately (#2851) Signed-off-by: Philip Laine --- src/pkg/packager/prepare.go | 210 ++++++++---------- src/pkg/packager/prepare_test.go | 160 +++++++++++-- .../find-images/agent/deployment.yaml | 16 ++ .../testdata/find-images/agent/zarf.yaml | 12 + .../find-images/helm-chart/chart/.helmignore | 23 ++ .../find-images/helm-chart/chart/Chart.yaml | 24 ++ .../helm-chart/chart/templates/NOTES.txt | 22 ++ .../helm-chart/chart/templates/_helpers.tpl | 62 ++++++ .../chart/templates/deployment.yaml | 68 ++++++ .../helm-chart/chart/templates/hpa.yaml | 32 +++ .../helm-chart/chart/templates/ingress.yaml | 61 +++++ .../helm-chart/chart/templates/service.yaml | 15 ++ .../chart/templates/serviceaccount.yaml | 13 ++ .../templates/tests/test-connection.yaml | 15 ++ .../find-images/helm-chart/chart/values.yaml | 107 +++++++++ .../find-images/helm-chart/values.yaml | 1 + .../testdata/find-images/helm-chart/zarf.yaml | 18 ++ .../find-images/invalid-helm-repo/zarf.yaml | 9 + .../invalid-manifest-yaml/deployment.yaml | 17 ++ .../invalid-manifest-yaml/zarf.yaml | 12 + src/test/e2e/13_find_images_test.go | 3 +- 21 files changed, 769 insertions(+), 131 deletions(-) create mode 100644 src/pkg/packager/testdata/find-images/agent/deployment.yaml create mode 100644 src/pkg/packager/testdata/find-images/agent/zarf.yaml create mode 100644 src/pkg/packager/testdata/find-images/helm-chart/chart/.helmignore create mode 100644 src/pkg/packager/testdata/find-images/helm-chart/chart/Chart.yaml create mode 100644 src/pkg/packager/testdata/find-images/helm-chart/chart/templates/NOTES.txt create mode 100644 src/pkg/packager/testdata/find-images/helm-chart/chart/templates/_helpers.tpl create mode 100644 src/pkg/packager/testdata/find-images/helm-chart/chart/templates/deployment.yaml create mode 100644 src/pkg/packager/testdata/find-images/helm-chart/chart/templates/hpa.yaml create mode 100644 src/pkg/packager/testdata/find-images/helm-chart/chart/templates/ingress.yaml create mode 100644 src/pkg/packager/testdata/find-images/helm-chart/chart/templates/service.yaml create mode 100644 src/pkg/packager/testdata/find-images/helm-chart/chart/templates/serviceaccount.yaml create mode 100644 src/pkg/packager/testdata/find-images/helm-chart/chart/templates/tests/test-connection.yaml create mode 100644 src/pkg/packager/testdata/find-images/helm-chart/chart/values.yaml create mode 100644 src/pkg/packager/testdata/find-images/helm-chart/values.yaml create mode 100644 src/pkg/packager/testdata/find-images/helm-chart/zarf.yaml create mode 100644 src/pkg/packager/testdata/find-images/invalid-helm-repo/zarf.yaml create mode 100644 src/pkg/packager/testdata/find-images/invalid-manifest-yaml/deployment.yaml create mode 100644 src/pkg/packager/testdata/find-images/invalid-manifest-yaml/zarf.yaml diff --git a/src/pkg/packager/prepare.go b/src/pkg/packager/prepare.go index 0c1ef19f30..37b80f0ec4 100644 --- a/src/pkg/packager/prepare.go +++ b/src/pkg/packager/prepare.go @@ -35,8 +35,8 @@ import ( "github.com/zarf-dev/zarf/src/types" ) -// imageMap is a map of image/boolean pairs. -type imageMap map[string]bool +var imageCheck = regexp.MustCompile(`(?mi)"image":"([^"]+)"`) +var imageFuzzyCheck = regexp.MustCompile(`(?mi)["|=]([a-z0-9\-.\/:]+:[\w.\-]*[a-z\.\-][\w.\-]*)"`) // FindImages iterates over a Zarf.yaml and attempts to parse any images. func (p *Packager) FindImages(ctx context.Context) (map[string][]string, error) { @@ -65,43 +65,33 @@ func (p *Packager) FindImages(ctx context.Context) (map[string][]string, error) if err != nil { return nil, err } - p.cfg.Pkg = pkg - for _, warning := range warnings { message.Warn(warning) } + p.cfg.Pkg = pkg return p.findImages(ctx) } -func (p *Packager) findImages(ctx context.Context) (imgMap map[string][]string, err error) { - repoHelmChartPath := p.cfg.FindImagesOpts.RepoHelmChartPath - kubeVersionOverride := p.cfg.FindImagesOpts.KubeVersionOverride - whyImage := p.cfg.FindImagesOpts.Why - - imagesMap := make(map[string][]string) - erroredCharts := []string{} - erroredCosignLookups := []string{} - whyResources := []string{} - +// TODO: Refactor to return output string instead of printing inside of function. +func (p *Packager) findImages(ctx context.Context) (map[string][]string, error) { for _, component := range p.cfg.Pkg.Components { - if len(component.Repos) > 0 && repoHelmChartPath == "" { + if len(component.Repos) > 0 && p.cfg.FindImagesOpts.RepoHelmChartPath == "" { message.Note("This Zarf package contains git repositories, " + "if any repos contain helm charts you want to template and " + "search for images, make sure to specify the helm chart path " + "via the --repo-chart-path flag") + break } } - componentDefinition := "\ncomponents:\n" - if err := p.populatePackageVariableConfig(); err != nil { return nil, fmt.Errorf("unable to set the active variables: %w", err) } // Set default builtin values so they exist in case any helm charts rely on them registryInfo := types.RegistryInfo{Address: p.cfg.FindImagesOpts.RegistryURL} - err = registryInfo.FillInEmptyValues() + err := registryInfo.FillInEmptyValues() if err != nil { return nil, err } @@ -118,41 +108,34 @@ func (p *Packager) findImages(ctx context.Context) (imgMap map[string][]string, ArtifactServer: artifactServer, } + componentDefinition := "\ncomponents:\n" + imagesMap := map[string][]string{} + whyResources := []string{} for _, component := range p.cfg.Pkg.Components { if len(component.Charts)+len(component.Manifests)+len(component.Repos) < 1 { // Skip if it doesn't have what we need continue } - if repoHelmChartPath != "" { + if p.cfg.FindImagesOpts.RepoHelmChartPath != "" { // Also process git repos that have helm charts for _, repo := range component.Repos { matches := strings.Split(repo, "@") if len(matches) < 2 { - message.Warnf("Cannot convert git repo %s to helm chart without a version tag", repo) - continue + return nil, fmt.Errorf("cannot convert the Git repository %s to a Helm chart without a version tag", repo) } - // Trim the first char to match how the packager expects it, this is messy,need to clean up better - repoHelmChartPath = strings.TrimPrefix(repoHelmChartPath, "/") - // If a repo helm chart path is specified, component.Charts = append(component.Charts, v1alpha1.ZarfChart{ Name: repo, URL: matches[0], Version: matches[1], - GitPath: repoHelmChartPath, + // Trim the first char to match how the packager expects it, this is messy,need to clean up better + GitPath: strings.TrimPrefix(p.cfg.FindImagesOpts.RepoHelmChartPath, "/"), }) } } - // matchedImages holds the collection of images, reset per-component - matchedImages := make(imageMap) - maybeImages := make(imageMap) - - // resources are a slice of generic structs that represent parsed K8s resources - var resources []*unstructured.Unstructured - componentPaths, err := p.layout.Components.Create(component) if err != nil { return nil, err @@ -162,56 +145,61 @@ func (p *Packager) findImages(ctx context.Context) (imgMap map[string][]string, return nil, err } + resources := []*unstructured.Unstructured{} + matchedImages := map[string]bool{} + maybeImages := map[string]bool{} for _, chart := range component.Charts { + // Generate helm templates for this chart helmCfg := helm.New( chart, componentPaths.Charts, componentPaths.Values, - helm.WithKubeVersion(kubeVersionOverride), + helm.WithKubeVersion(p.cfg.FindImagesOpts.KubeVersionOverride), helm.WithVariableConfig(p.variableConfig), ) - err = helmCfg.PackageChart(ctx, component.DeprecatedCosignKeyPath) if err != nil { return nil, fmt.Errorf("unable to package the chart %s: %w", chart.Name, err) } - valuesFilePaths, _ := helpers.RecursiveFileList(componentPaths.Values, nil, false) + valuesFilePaths, err := helpers.RecursiveFileList(componentPaths.Values, nil, false) + // TODO: The values path should exist if the path is set, otherwise it should be empty. + if err != nil && !errors.Is(err, os.ErrNotExist) { + return nil, err + } for _, valueFilePath := range valuesFilePaths { - if err := p.variableConfig.ReplaceTextTemplate(valueFilePath); err != nil { + err := p.variableConfig.ReplaceTextTemplate(valueFilePath) + if err != nil { return nil, err } } - // Generate helm templates for this chart chartTemplate, chartValues, err := helmCfg.TemplateChart(ctx) if err != nil { - message.WarnErrf(err, "Problem rendering the helm template for %s: %s", chart.Name, err.Error()) - erroredCharts = append(erroredCharts, chart.Name) - continue + return nil, fmt.Errorf("could not render the Helm template for chart %s: %w", chart.Name, err) } // Break the template into separate resources - yamls, _ := utils.SplitYAML([]byte(chartTemplate)) + yamls, err := utils.SplitYAML([]byte(chartTemplate)) + if err != nil { + return nil, err + } resources = append(resources, yamls...) chartTarball := helm.StandardName(componentPaths.Charts, chart) + ".tgz" - annotatedImages, err := helm.FindAnnotatedImagesForChart(chartTarball, chartValues) if err != nil { - message.WarnErrf(err, "Problem looking for image annotations for %s: %s", chart.URL, err.Error()) - erroredCharts = append(erroredCharts, chart.URL) - continue + return nil, fmt.Errorf("could not look up image annotations for chart URL %s: %w", chart.URL, err) } for _, image := range annotatedImages { matchedImages[image] = true } // Check if the --why flag is set - if whyImage != "" { - whyResourcesChart, err := findWhyResources(yamls, whyImage, component.Name, chart.Name, true) + if p.cfg.FindImagesOpts.Why != "" { + whyResourcesChart, err := findWhyResources(yamls, p.cfg.FindImagesOpts.Why, component.Name, chart.Name, true) if err != nil { - message.WarnErrf(err, "Error finding why resources for chart %s: %s", chart.Name, err.Error()) + return nil, fmt.Errorf("could not determine why resource for the chart %s: %w", chart.Name, err) } whyResources = append(whyResources, whyResourcesChart...) } @@ -251,20 +239,22 @@ func (p *Packager) findImages(ctx context.Context) (imgMap map[string][]string, // Read the contents of each file contents, err := os.ReadFile(f) if err != nil { - message.WarnErrf(err, "Unable to read the file %s", f) - continue + return nil, fmt.Errorf("could not read the file %s: %w", f, err) } // Break the manifest into separate resources - // TODO: Do not dogsled error - yamls, _ := utils.SplitYAML(contents) + yamls, err := utils.SplitYAML(contents) + if err != nil { + fmt.Println("got this err") + return nil, err + } resources = append(resources, yamls...) // Check if the --why flag is set and if it is process the manifests - if whyImage != "" { - whyResourcesManifest, err := findWhyResources(yamls, whyImage, component.Name, manifest.Name, false) + if p.cfg.FindImagesOpts.Why != "" { + whyResourcesManifest, err := findWhyResources(yamls, p.cfg.FindImagesOpts.Why, component.Name, manifest.Name, false) if err != nil { - message.WarnErrf(err, "Error finding why resources for manifest %s: %s", manifest.Name, err.Error()) + return nil, fmt.Errorf("could not find why resources for manifest %s: %w", manifest.Name, err) } whyResources = append(whyResources, whyResourcesManifest...) } @@ -275,15 +265,17 @@ func (p *Packager) findImages(ctx context.Context) (imgMap map[string][]string, defer spinner.Stop() for _, resource := range resources { - if matchedImages, maybeImages, err = p.processUnstructuredImages(resource, matchedImages, maybeImages); err != nil { - message.WarnErrf(err, "Problem processing K8s resource %s", resource.GetName()) + if matchedImages, maybeImages, err = processUnstructuredImages(resource, matchedImages, maybeImages); err != nil { + return nil, fmt.Errorf("could not process the Kubernetes resource %s: %w", resource.GetName(), err) } } - if sortedImages := sortImages(matchedImages, nil); len(sortedImages) > 0 { + sortedMatchedImages, sortedExpectedImages := getSortedImages(matchedImages, maybeImages) + + if len(sortedMatchedImages) > 0 { // Log the header comment componentDefinition += fmt.Sprintf("\n - name: %s\n images:\n", component.Name) - for _, image := range sortedImages { + for _, image := range sortedMatchedImages { // Use print because we want this dumped to stdout imagesMap[component.Name] = append(imagesMap[component.Name], image) componentDefinition += fmt.Sprintf(" - %s\n", image) @@ -291,9 +283,9 @@ func (p *Packager) findImages(ctx context.Context) (imgMap map[string][]string, } // Handle the "maybes" - if sortedImages := sortImages(maybeImages, matchedImages); len(sortedImages) > 0 { + if len(sortedExpectedImages) > 0 { var validImages []string - for _, image := range sortedImages { + for _, image := range sortedExpectedImages { if descriptor, err := crane.Head(image, images.WithGlobalInsecureFlag()...); err != nil { // Test if this is a real image, if not just quiet log to debug, this is normal message.Debugf("Suspected image does not appear to be valid: %#v", err) @@ -326,8 +318,7 @@ func (p *Packager) findImages(ctx context.Context) (imgMap map[string][]string, spinner.Updatef("Looking up cosign artifacts for discovered images (%d/%d)", idx+1, len(imagesMap[component.Name])) cosignArtifacts, err := utils.GetCosignArtifacts(image) if err != nil { - message.WarnErrf(err, "Problem looking up cosign artifacts for %s: %s", image, err.Error()) - erroredCosignLookups = append(erroredCosignLookups, image) + return nil, fmt.Errorf("could not lookup the cosing artifacts for image %s: %w", image, err) } cosignArtifactList = append(cosignArtifactList, cosignArtifacts...) } @@ -345,80 +336,64 @@ func (p *Packager) findImages(ctx context.Context) (imgMap map[string][]string, } } - if whyImage != "" { + if p.cfg.FindImagesOpts.Why != "" { if len(whyResources) == 0 { - message.Warnf("image %q not found in any charts or manifests", whyImage) + return nil, fmt.Errorf("image %s not found in any charts or manifests", p.cfg.FindImagesOpts.Why) } return nil, nil } fmt.Println(componentDefinition) - if len(erroredCharts) > 0 || len(erroredCosignLookups) > 0 { - errMsg := "" - if len(erroredCharts) > 0 { - errMsg = fmt.Sprintf("the following charts had errors: %s", erroredCharts) - } - if len(erroredCosignLookups) > 0 { - if errMsg != "" { - errMsg += "\n" - } - errMsg += fmt.Sprintf("the following images errored on cosign lookups: %s", erroredCosignLookups) - } - return imagesMap, errors.New(errMsg) - } - return imagesMap, nil } -func (p *Packager) processUnstructuredImages(resource *unstructured.Unstructured, matchedImages, maybeImages imageMap) (imageMap, imageMap, error) { - var imageSanityCheck = regexp.MustCompile(`(?mi)"image":"([^"]+)"`) - var imageFuzzyCheck = regexp.MustCompile(`(?mi)["|=]([a-z0-9\-.\/:]+:[\w.\-]*[a-z\.\-][\w.\-]*)"`) - var json string - +func processUnstructuredImages(resource *unstructured.Unstructured, matchedImages, maybeImages map[string]bool) (map[string]bool, map[string]bool, error) { contents := resource.UnstructuredContent() - bytes, _ := resource.MarshalJSON() - json = string(bytes) + b, err := resource.MarshalJSON() + if err != nil { + return nil, nil, err + } switch resource.GetKind() { case "Deployment": var deployment v1.Deployment if err := runtime.DefaultUnstructuredConverter.FromUnstructured(contents, &deployment); err != nil { - return matchedImages, maybeImages, fmt.Errorf("could not parse deployment: %w", err) + return nil, nil, fmt.Errorf("could not parse deployment: %w", err) } - matchedImages = buildImageMap(matchedImages, deployment.Spec.Template.Spec) + matchedImages = appendToImageMap(matchedImages, deployment.Spec.Template.Spec) case "DaemonSet": var daemonSet v1.DaemonSet if err := runtime.DefaultUnstructuredConverter.FromUnstructured(contents, &daemonSet); err != nil { - return matchedImages, maybeImages, fmt.Errorf("could not parse daemonset: %w", err) + return nil, nil, fmt.Errorf("could not parse daemonset: %w", err) } - matchedImages = buildImageMap(matchedImages, daemonSet.Spec.Template.Spec) + matchedImages = appendToImageMap(matchedImages, daemonSet.Spec.Template.Spec) case "StatefulSet": var statefulSet v1.StatefulSet if err := runtime.DefaultUnstructuredConverter.FromUnstructured(contents, &statefulSet); err != nil { - return matchedImages, maybeImages, fmt.Errorf("could not parse statefulset: %w", err) + return nil, nil, fmt.Errorf("could not parse statefulset: %w", err) } - matchedImages = buildImageMap(matchedImages, statefulSet.Spec.Template.Spec) + matchedImages = appendToImageMap(matchedImages, statefulSet.Spec.Template.Spec) case "ReplicaSet": var replicaSet v1.ReplicaSet if err := runtime.DefaultUnstructuredConverter.FromUnstructured(contents, &replicaSet); err != nil { - return matchedImages, maybeImages, fmt.Errorf("could not parse replicaset: %w", err) + return nil, nil, fmt.Errorf("could not parse replicaset: %w", err) } - matchedImages = buildImageMap(matchedImages, replicaSet.Spec.Template.Spec) + matchedImages = appendToImageMap(matchedImages, replicaSet.Spec.Template.Spec) case "Job": var job batchv1.Job if err := runtime.DefaultUnstructuredConverter.FromUnstructured(contents, &job); err != nil { - return matchedImages, maybeImages, fmt.Errorf("could not parse job: %w", err) + return nil, nil, fmt.Errorf("could not parse job: %w", err) } - matchedImages = buildImageMap(matchedImages, job.Spec.Template.Spec) + matchedImages = appendToImageMap(matchedImages, job.Spec.Template.Spec) default: // Capture any custom images - matches := imageSanityCheck.FindAllStringSubmatch(json, -1) + matches := imageCheck.FindAllStringSubmatch(string(b), -1) for _, group := range matches { message.Debugf("Found unknown match, Kind: %s, Value: %s", resource.GetKind(), group[1]) matchedImages[group[1]] = true @@ -426,7 +401,7 @@ func (p *Packager) processUnstructuredImages(resource *unstructured.Unstructured } // Capture "maybe images" too for all kinds because they might be in unexpected places.... 👀 - matches := imageFuzzyCheck.FindAllStringSubmatch(json, -1) + matches := imageFuzzyCheck.FindAllStringSubmatch(string(b), -1) for _, group := range matches { message.Debugf("Found possible fuzzy match, Kind: %s, Value: %s", resource.GetKind(), group[1]) maybeImages[group[1]] = true @@ -438,11 +413,11 @@ func (p *Packager) processUnstructuredImages(resource *unstructured.Unstructured func findWhyResources(resources []*unstructured.Unstructured, whyImage, componentName, resourceName string, isChart bool) ([]string, error) { foundWhyResources := []string{} for _, resource := range resources { - bytes, err := yaml.Marshal(resource.Object) + b, err := yaml.Marshal(resource.Object) if err != nil { return nil, err } - yaml := string(bytes) + yaml := string(b) resourceTypeKey := "manifest" if isChart { resourceTypeKey = "chart" @@ -456,29 +431,34 @@ func findWhyResources(resources []*unstructured.Unstructured, whyImage, componen return foundWhyResources, nil } -// BuildImageMap looks for init container, ephemeral and regular container images. -func buildImageMap(images imageMap, pod corev1.PodSpec) imageMap { +func appendToImageMap(imgMap map[string]bool, pod corev1.PodSpec) map[string]bool { for _, container := range pod.InitContainers { - images[container.Image] = true + imgMap[container.Image] = true } for _, container := range pod.Containers { - images[container.Image] = true + imgMap[container.Image] = true } for _, container := range pod.EphemeralContainers { - images[container.Image] = true + imgMap[container.Image] = true } - return images + return imgMap } -// SortImages returns a sorted list of images. -func sortImages(images, compareWith imageMap) []string { - sortedImages := sort.StringSlice{} - for image := range images { - if !compareWith[image] || compareWith == nil { - // Check compareWith, if it exists only add if not in that list. - sortedImages = append(sortedImages, image) +func getSortedImages(matchedImages map[string]bool, maybeImages map[string]bool) ([]string, []string) { + sortedMatchedImages := sort.StringSlice{} + for image := range matchedImages { + sortedMatchedImages = append(sortedMatchedImages, image) + } + sort.Sort(sortedMatchedImages) + + sortedMaybeImages := sort.StringSlice{} + for image := range maybeImages { + if matchedImages[image] { + continue } + sortedMaybeImages = append(sortedMaybeImages, image) } - sort.Sort(sortedImages) - return sortedImages + sort.Sort(sortedMaybeImages) + + return sortedMatchedImages, sortedMaybeImages } diff --git a/src/pkg/packager/prepare_test.go b/src/pkg/packager/prepare_test.go index 8c43e194ac..f2fb760534 100644 --- a/src/pkg/packager/prepare_test.go +++ b/src/pkg/packager/prepare_test.go @@ -7,6 +7,7 @@ import ( "testing" "github.com/stretchr/testify/require" + corev1 "k8s.io/api/core/v1" "github.com/zarf-dev/zarf/src/pkg/lint" "github.com/zarf-dev/zarf/src/test/testutil" @@ -20,23 +21,154 @@ func TestFindImages(t *testing.T) { lint.ZarfSchema = testutil.LoadSchema(t, "../../../zarf.schema.json") - cfg := &types.PackagerConfig{ - CreateOpts: types.ZarfCreateOptions{ - BaseDir: "../../../examples/dos-games/", + tests := []struct { + name string + cfg *types.PackagerConfig + expectedErr string + expectedImages map[string][]string + }{ + { + name: "agent deployment", + cfg: &types.PackagerConfig{ + CreateOpts: types.ZarfCreateOptions{ + BaseDir: "./testdata/find-images/agent", + }, + }, + expectedImages: map[string][]string{ + "baseline": { + "ghcr.io/zarf-dev/zarf/agent:v0.38.1", + "ghcr.io/zarf-dev/zarf/agent:sha256-f8b1c2f99349516ae1bd0711a19697abcc41555076b0ae90f1a70ca6b50dcbd8.sig", + }, + }, }, + { + name: "helm chart", + cfg: &types.PackagerConfig{ + CreateOpts: types.ZarfCreateOptions{ + BaseDir: "./testdata/find-images/helm-chart", + }, + }, + expectedImages: map[string][]string{ + "baseline": { + "nginx:1.16.0", + "busybox", + }, + }, + }, + { + name: "image not found", + cfg: &types.PackagerConfig{ + CreateOpts: types.ZarfCreateOptions{ + BaseDir: "./testdata/find-images/agent", + }, + FindImagesOpts: types.ZarfFindImagesOptions{ + Why: "foobar", + }, + }, + expectedErr: "image foobar not found in any charts or manifests", + }, + { + name: "invalid helm repository", + cfg: &types.PackagerConfig{ + CreateOpts: types.ZarfCreateOptions{ + BaseDir: "./testdata/find-images/invalid-helm-repo", + }, + FindImagesOpts: types.ZarfFindImagesOptions{ + RepoHelmChartPath: "test", + }, + }, + expectedErr: "cannot convert the Git repository https://github.com/zarf-dev/zarf-public-test.git to a Helm chart without a version tag", + }, + { + name: "invalid manifest yaml", + cfg: &types.PackagerConfig{ + CreateOpts: types.ZarfCreateOptions{ + BaseDir: "./testdata/find-images/invalid-manifest-yaml", + }, + }, + expectedErr: "failed to unmarshal manifest: error converting YAML to JSON: yaml: line 12: could not find expected ':'", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + p, err := New(tt.cfg) + require.NoError(t, err) + images, err := p.FindImages(ctx) + if tt.expectedErr != "" { + require.EqualError(t, err, tt.expectedErr) + return + } + require.NoError(t, err) + require.Equal(t, len(tt.expectedImages), len(images)) + for k, v := range tt.expectedImages { + require.ElementsMatch(t, v, images[k]) + } + }) } - p, err := New(cfg) - require.NoError(t, err) - images, err := p.FindImages(ctx) - require.NoError(t, err) - expectedImages := map[string][]string{ - "baseline": { - "ghcr.io/zarf-dev/doom-game:0.0.1", - "ghcr.io/zarf-dev/doom-game:sha256-7464ecc8a7172fce5c2ad631fc2a1b8572c686f4bf15c4bd51d7d6c9f0c460a7.sig", +} + +func TestBuildImageMap(t *testing.T) { + t.Parallel() + + podSpec := corev1.PodSpec{ + InitContainers: []corev1.Container{ + { + Image: "init-image", + }, + { + Image: "duplicate-image", + }, }, + Containers: []corev1.Container{ + + { + Image: "container-image", + }, + { + Image: "alpine:latest", + }, + }, + EphemeralContainers: []corev1.EphemeralContainer{ + { + EphemeralContainerCommon: corev1.EphemeralContainerCommon{ + Image: "ephemeral-image", + }, + }, + { + EphemeralContainerCommon: corev1.EphemeralContainerCommon{ + Image: "duplicate-image", + }, + }, + }, + } + imgMap := appendToImageMap(map[string]bool{}, podSpec) + expectedImgMap := map[string]bool{ + "init-image": true, + "duplicate-image": true, + "container-image": true, + "alpine:latest": true, + "ephemeral-image": true, + } + require.Equal(t, expectedImgMap, imgMap) +} + +func TestGetSortedImages(t *testing.T) { + t.Parallel() + + matchedImages := map[string]bool{ + "C": true, + "A": true, + "E": true, + "D": true, } - require.Equal(t, len(expectedImages), len(images)) - for k, v := range expectedImages { - require.ElementsMatch(t, v, images[k]) + maybeImages := map[string]bool{ + "Z": true, + "A": true, + "B": true, } + sortedMatchedImages, sortedMaybeImages := getSortedImages(matchedImages, maybeImages) + expectedSortedMatchedImages := []string{"A", "C", "D", "E"} + require.Equal(t, expectedSortedMatchedImages, sortedMatchedImages) + expectedSortedMaybeImages := []string{"B", "Z"} + require.Equal(t, expectedSortedMaybeImages, sortedMaybeImages) } diff --git a/src/pkg/packager/testdata/find-images/agent/deployment.yaml b/src/pkg/packager/testdata/find-images/agent/deployment.yaml new file mode 100644 index 0000000000..d307843973 --- /dev/null +++ b/src/pkg/packager/testdata/find-images/agent/deployment.yaml @@ -0,0 +1,16 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: agent +spec: + selector: + matchLabels: + app: agent + template: + metadata: + labels: + app: agent + spec: + containers: + - name: agent + image: ghcr.io/zarf-dev/zarf/agent:v0.38.1 diff --git a/src/pkg/packager/testdata/find-images/agent/zarf.yaml b/src/pkg/packager/testdata/find-images/agent/zarf.yaml new file mode 100644 index 0000000000..1ac8c9ea82 --- /dev/null +++ b/src/pkg/packager/testdata/find-images/agent/zarf.yaml @@ -0,0 +1,12 @@ +kind: ZarfPackageConfig +metadata: + name: agent + version: 1.0.0 +components: + - name: baseline + required: true + manifests: + - name: agent + namespace: default + files: + - deployment.yaml diff --git a/src/pkg/packager/testdata/find-images/helm-chart/chart/.helmignore b/src/pkg/packager/testdata/find-images/helm-chart/chart/.helmignore new file mode 100644 index 0000000000..0e8a0eb36f --- /dev/null +++ b/src/pkg/packager/testdata/find-images/helm-chart/chart/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/src/pkg/packager/testdata/find-images/helm-chart/chart/Chart.yaml b/src/pkg/packager/testdata/find-images/helm-chart/chart/Chart.yaml new file mode 100644 index 0000000000..df2d97f9b0 --- /dev/null +++ b/src/pkg/packager/testdata/find-images/helm-chart/chart/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: chart +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "1.16.0" diff --git a/src/pkg/packager/testdata/find-images/helm-chart/chart/templates/NOTES.txt b/src/pkg/packager/testdata/find-images/helm-chart/chart/templates/NOTES.txt new file mode 100644 index 0000000000..b97199377a --- /dev/null +++ b/src/pkg/packager/testdata/find-images/helm-chart/chart/templates/NOTES.txt @@ -0,0 +1,22 @@ +1. Get the application URL by running these commands: +{{- if .Values.ingress.enabled }} +{{- range $host := .Values.ingress.hosts }} + {{- range .paths }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }} + {{- end }} +{{- end }} +{{- else if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "chart.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch its status by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "chart.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "chart.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + echo http://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "chart.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT +{{- end }} diff --git a/src/pkg/packager/testdata/find-images/helm-chart/chart/templates/_helpers.tpl b/src/pkg/packager/testdata/find-images/helm-chart/chart/templates/_helpers.tpl new file mode 100644 index 0000000000..7ba5edc272 --- /dev/null +++ b/src/pkg/packager/testdata/find-images/helm-chart/chart/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "chart.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "chart.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "chart.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "chart.labels" -}} +helm.sh/chart: {{ include "chart.chart" . }} +{{ include "chart.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "chart.selectorLabels" -}} +app.kubernetes.io/name: {{ include "chart.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "chart.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "chart.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/src/pkg/packager/testdata/find-images/helm-chart/chart/templates/deployment.yaml b/src/pkg/packager/testdata/find-images/helm-chart/chart/templates/deployment.yaml new file mode 100644 index 0000000000..9fa1767865 --- /dev/null +++ b/src/pkg/packager/testdata/find-images/helm-chart/chart/templates/deployment.yaml @@ -0,0 +1,68 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "chart.fullname" . }} + labels: + {{- include "chart.labels" . | nindent 4 }} +spec: + {{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} + selector: + matchLabels: + {{- include "chart.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "chart.labels" . | nindent 8 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "chart.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: http + containerPort: {{ .Values.service.port }} + protocol: TCP + livenessProbe: + {{- toYaml .Values.livenessProbe | nindent 12 }} + readinessProbe: + {{- toYaml .Values.readinessProbe | nindent 12 }} + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- with .Values.volumeMounts }} + volumeMounts: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.volumes }} + volumes: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/src/pkg/packager/testdata/find-images/helm-chart/chart/templates/hpa.yaml b/src/pkg/packager/testdata/find-images/helm-chart/chart/templates/hpa.yaml new file mode 100644 index 0000000000..a91f61bd5c --- /dev/null +++ b/src/pkg/packager/testdata/find-images/helm-chart/chart/templates/hpa.yaml @@ -0,0 +1,32 @@ +{{- if .Values.autoscaling.enabled }} +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "chart.fullname" . }} + labels: + {{- include "chart.labels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "chart.fullname" . }} + minReplicas: {{ .Values.autoscaling.minReplicas }} + maxReplicas: {{ .Values.autoscaling.maxReplicas }} + metrics: + {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + target: + type: Utilization + averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} + {{- end }} +{{- end }} diff --git a/src/pkg/packager/testdata/find-images/helm-chart/chart/templates/ingress.yaml b/src/pkg/packager/testdata/find-images/helm-chart/chart/templates/ingress.yaml new file mode 100644 index 0000000000..63c1311c95 --- /dev/null +++ b/src/pkg/packager/testdata/find-images/helm-chart/chart/templates/ingress.yaml @@ -0,0 +1,61 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include "chart.fullname" . -}} +{{- $svcPort := .Values.service.port -}} +{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} + {{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }} + {{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}} + {{- end }} +{{- end }} +{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1 +{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: {{ $fullName }} + labels: + {{- include "chart.labels" . | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.ingress.className }} + {{- end }} + {{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + {{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }} + pathType: {{ .pathType }} + {{- end }} + backend: + {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} + service: + name: {{ $fullName }} + port: + number: {{ $svcPort }} + {{- else }} + serviceName: {{ $fullName }} + servicePort: {{ $svcPort }} + {{- end }} + {{- end }} + {{- end }} +{{- end }} diff --git a/src/pkg/packager/testdata/find-images/helm-chart/chart/templates/service.yaml b/src/pkg/packager/testdata/find-images/helm-chart/chart/templates/service.yaml new file mode 100644 index 0000000000..dfc5b3a33d --- /dev/null +++ b/src/pkg/packager/testdata/find-images/helm-chart/chart/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "chart.fullname" . }} + labels: + {{- include "chart.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + {{- include "chart.selectorLabels" . | nindent 4 }} diff --git a/src/pkg/packager/testdata/find-images/helm-chart/chart/templates/serviceaccount.yaml b/src/pkg/packager/testdata/find-images/helm-chart/chart/templates/serviceaccount.yaml new file mode 100644 index 0000000000..1df935010a --- /dev/null +++ b/src/pkg/packager/testdata/find-images/helm-chart/chart/templates/serviceaccount.yaml @@ -0,0 +1,13 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "chart.serviceAccountName" . }} + labels: + {{- include "chart.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +automountServiceAccountToken: {{ .Values.serviceAccount.automount }} +{{- end }} diff --git a/src/pkg/packager/testdata/find-images/helm-chart/chart/templates/tests/test-connection.yaml b/src/pkg/packager/testdata/find-images/helm-chart/chart/templates/tests/test-connection.yaml new file mode 100644 index 0000000000..8dfed872de --- /dev/null +++ b/src/pkg/packager/testdata/find-images/helm-chart/chart/templates/tests/test-connection.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "chart.fullname" . }}-test-connection" + labels: + {{- include "chart.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": test +spec: + containers: + - name: wget + image: busybox + command: ['wget'] + args: ['{{ include "chart.fullname" . }}:{{ .Values.service.port }}'] + restartPolicy: Never diff --git a/src/pkg/packager/testdata/find-images/helm-chart/chart/values.yaml b/src/pkg/packager/testdata/find-images/helm-chart/chart/values.yaml new file mode 100644 index 0000000000..4d7ead8785 --- /dev/null +++ b/src/pkg/packager/testdata/find-images/helm-chart/chart/values.yaml @@ -0,0 +1,107 @@ +# Default values for chart. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +replicaCount: 1 + +image: + repository: nginx + pullPolicy: IfNotPresent + # Overrides the image tag whose default is the chart appVersion. + tag: "" + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +serviceAccount: + # Specifies whether a service account should be created + create: true + # Automatically mount a ServiceAccount's API credentials? + automount: true + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + +podAnnotations: {} +podLabels: {} + +podSecurityContext: {} + # fsGroup: 2000 + +securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + +service: + type: ClusterIP + port: 80 + +ingress: + enabled: false + className: "" + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hosts: + - host: chart-example.local + paths: + - path: / + pathType: ImplementationSpecific + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +livenessProbe: + httpGet: + path: / + port: http +readinessProbe: + httpGet: + path: / + port: http + +autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 100 + targetCPUUtilizationPercentage: 80 + # targetMemoryUtilizationPercentage: 80 + +# Additional volumes on the output Deployment definition. +volumes: [] +# - name: foo +# secret: +# secretName: mysecret +# optional: false + +# Additional volumeMounts on the output Deployment definition. +volumeMounts: [] +# - name: foo +# mountPath: "/etc/foo" +# readOnly: true + +nodeSelector: {} + +tolerations: [] + +affinity: {} diff --git a/src/pkg/packager/testdata/find-images/helm-chart/values.yaml b/src/pkg/packager/testdata/find-images/helm-chart/values.yaml new file mode 100644 index 0000000000..6bc803e90f --- /dev/null +++ b/src/pkg/packager/testdata/find-images/helm-chart/values.yaml @@ -0,0 +1 @@ +replicaCount: 3 diff --git a/src/pkg/packager/testdata/find-images/helm-chart/zarf.yaml b/src/pkg/packager/testdata/find-images/helm-chart/zarf.yaml new file mode 100644 index 0000000000..1e33cb9515 --- /dev/null +++ b/src/pkg/packager/testdata/find-images/helm-chart/zarf.yaml @@ -0,0 +1,18 @@ +kind: ZarfPackageConfig +metadata: + name: helm-chart + version: 1.0.0 +components: + - name: baseline + required: true + charts: + - name: with-values + version: 0.1.0 + namespace: with-values + localPath: chart + valuesFiles: + - values.yaml + - name: without-values + version: 0.1.0 + namespace: without-values + localPath: chart diff --git a/src/pkg/packager/testdata/find-images/invalid-helm-repo/zarf.yaml b/src/pkg/packager/testdata/find-images/invalid-helm-repo/zarf.yaml new file mode 100644 index 0000000000..71fd539d3f --- /dev/null +++ b/src/pkg/packager/testdata/find-images/invalid-helm-repo/zarf.yaml @@ -0,0 +1,9 @@ +kind: ZarfPackageConfig +metadata: + name: invalid-helm-repo + version: 1.0.0 +components: + - name: baseline + required: true + repos: + - https://github.com/zarf-dev/zarf-public-test.git diff --git a/src/pkg/packager/testdata/find-images/invalid-manifest-yaml/deployment.yaml b/src/pkg/packager/testdata/find-images/invalid-manifest-yaml/deployment.yaml new file mode 100644 index 0000000000..3e36e465cc --- /dev/null +++ b/src/pkg/packager/testdata/find-images/invalid-manifest-yaml/deployment.yaml @@ -0,0 +1,17 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: agent +spec: + selector: + matchLabels: + app: agent + template: + metadata: +asdasd + labels: + app: agent + spec: + containers: + - name: agent + image: ghcr.io/zarf-dev/zarf/agent:v0.38.1 diff --git a/src/pkg/packager/testdata/find-images/invalid-manifest-yaml/zarf.yaml b/src/pkg/packager/testdata/find-images/invalid-manifest-yaml/zarf.yaml new file mode 100644 index 0000000000..cd8390489e --- /dev/null +++ b/src/pkg/packager/testdata/find-images/invalid-manifest-yaml/zarf.yaml @@ -0,0 +1,12 @@ +kind: ZarfPackageConfig +metadata: + name: invalid-manifest-yaml + version: 1.0.0 +components: + - name: baseline + required: true + manifests: + - name: agent + namespace: default + files: + - deployment.yaml diff --git a/src/test/e2e/13_find_images_test.go b/src/test/e2e/13_find_images_test.go index 39f6691b16..6d01bdd569 100644 --- a/src/test/e2e/13_find_images_test.go +++ b/src/test/e2e/13_find_images_test.go @@ -42,8 +42,7 @@ func TestFindImages(t *testing.T) { // Test `zarf prepare find-images` with `--kube-version` specified and less than than the declared minimum (v1.21.0) stdOut, stdErr, err = e2e.Zarf(t, "prepare", "find-images", "--kube-version=v1.20.0", "src/test/packages/00-kube-version-override") require.Error(t, err, stdOut, stdErr) - require.Contains(t, stdErr, "Problem rendering the helm template for cert-manager", "The kubeVersion declaration should prevent this from templating") - require.Contains(t, stdErr, "following charts had errors: [cert-manager]", "Zarf should print an ending error message") + require.Contains(t, stdErr, "could not render the Helm template for chart cert-manager", "The kubeVersion declaration should prevent this from templating") }) t.Run("zarf dev find-images with helm or manifest vars", func(t *testing.T) { From 0afe63fccd00f557e967c4b7e87eccf1eb854854 Mon Sep 17 00:00:00 2001 From: Philip Laine Date: Thu, 15 Aug 2024 10:13:45 +0200 Subject: [PATCH 02/18] test: add workflow to make sure importing Zarf works (#2874) Signed-off-by: Philip Laine Co-authored-by: Austin Abro <37223396+AustinAbro321@users.noreply.github.com> --- .github/workflows/test-import.yaml | 50 ++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 .github/workflows/test-import.yaml diff --git a/.github/workflows/test-import.yaml b/.github/workflows/test-import.yaml new file mode 100644 index 0000000000..72ad5e770f --- /dev/null +++ b/.github/workflows/test-import.yaml @@ -0,0 +1,50 @@ +name: Test Import +on: + pull_request: + +permissions: + contents: read + +# Abort prior jobs in the same workflow / PR +concurrency: + group: import-${{ github.ref }} + cancel-in-progress: true + +jobs: + test-import: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + + - name: Setup Go + uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 + with: + go-version-file: 'go.mod' + cache: true + + - name: Run test Go program that imports Zarf + run: | + cd $(mktemp -d) + echo "$GO_MAIN" > main.go + go mod init github.com/zarf-dev/test-import + go mod edit -replace github.com/zarf-dev/zarf=github.com/${{ github.repository }}@${COMMIT_SHA:0:12} + go mod tidy + cat go.mod | grep -q ${COMMIT_SHA:0:12} + go run main.go + env: + COMMIT_SHA: ${{ github.event.pull_request.head.sha }} + GO_MAIN: | + package main + + import ( + "fmt" + + "github.com/zarf-dev/zarf/src/api/v1alpha1" + "github.com/zarf-dev/zarf/src/pkg/packager" + ) + + func main() { + fmt.Println(packager.Packager{}) + fmt.Println(v1alpha1.ZarfComponent{}) + } From 8100c698d92dd1e3fed450d548b2fea1d08cf32e Mon Sep 17 00:00:00 2001 From: Philip Laine Date: Thu, 15 Aug 2024 11:11:54 +0200 Subject: [PATCH 03/18] refactor: remove unnecessary retry logic from data injection (#2867) Signed-off-by: Philip Laine --- src/pkg/cluster/data.go | 181 +++++++++++++++++++--------------------- 1 file changed, 85 insertions(+), 96 deletions(-) diff --git a/src/pkg/cluster/data.go b/src/pkg/cluster/data.go index bd4b51aea5..68148003a7 100644 --- a/src/pkg/cluster/data.go +++ b/src/pkg/cluster/data.go @@ -60,109 +60,100 @@ func (c *Cluster) HandleDataInjection(ctx context.Context, data v1alpha1.ZarfDat return fmt.Errorf("unable to execute tar, ensure it is installed in the $PATH: %w", err) } - // TODO: Refactor to use retry. - for { - select { - case <-ctx.Done(): - return ctx.Err() - default: - message.Debugf("Attempting to inject data into %s", data.Target) - source := filepath.Join(componentPath.DataInjections, filepath.Base(data.Target.Path)) - if helpers.InvalidPath(source) { - // The path is likely invalid because of how we compose OCI components, add an index suffix to the filename - source = filepath.Join(componentPath.DataInjections, strconv.Itoa(dataIdx), filepath.Base(data.Target.Path)) - if helpers.InvalidPath(source) { - return fmt.Errorf("could not find the data injection source path %s", source) - } - } - - target := podLookup{ - Namespace: data.Target.Namespace, - Selector: data.Target.Selector, - Container: data.Target.Container, - } - - // Wait until the pod we are injecting data into becomes available - pods, err := waitForPodsAndContainers(ctx, c.Clientset, target, podFilterByInitContainer) - if err != nil { - return err - } - if len(pods) < 1 { - continue - } + message.Debugf("Attempting to inject data into %s", data.Target) + + source := filepath.Join(componentPath.DataInjections, filepath.Base(data.Target.Path)) + if helpers.InvalidPath(source) { + // The path is likely invalid because of how we compose OCI components, add an index suffix to the filename + source = filepath.Join(componentPath.DataInjections, strconv.Itoa(dataIdx), filepath.Base(data.Target.Path)) + if helpers.InvalidPath(source) { + return fmt.Errorf("could not find the data injection source path %s", source) + } + } - // Inject into all the pods - for _, pod := range pods { - // Try to use the embedded kubectl if we can - zarfCommand, err := utils.GetFinalExecutableCommand() - kubectlBinPath := "kubectl" - if err != nil { - message.Warnf("Unable to get the zarf executable path, falling back to host kubectl: %s", err) - } else { - kubectlBinPath = fmt.Sprintf("%s tools kubectl", zarfCommand) - } - kubectlCmd := fmt.Sprintf("%s exec -i -n %s %s -c %s ", kubectlBinPath, data.Target.Namespace, pod.Name, data.Target.Container) + // Wait until the pod we are injecting data into becomes available + target := podLookup{ + Namespace: data.Target.Namespace, + Selector: data.Target.Selector, + Container: data.Target.Container, + } + waitCtx, waitCancel := context.WithTimeout(ctx, 90*time.Second) + defer waitCancel() + pods, err := waitForPodsAndContainers(waitCtx, c.Clientset, target, podFilterByInitContainer) + if err != nil { + return err + } - // Note that each command flag is separated to provide the widest cross-platform tar support - tarCmd := fmt.Sprintf("tar -c %s -f -", tarCompressFlag) - untarCmd := fmt.Sprintf("tar -x %s -v -f - -C %s", tarCompressFlag, data.Target.Path) + // Inject into all the pods + for _, pod := range pods { + // Try to use the embedded kubectl if we can + zarfCommand, err := utils.GetFinalExecutableCommand() + kubectlBinPath := "kubectl" + if err != nil { + message.Warnf("Unable to get the zarf executable path, falling back to host kubectl: %s", err) + } else { + kubectlBinPath = fmt.Sprintf("%s tools kubectl", zarfCommand) + } + kubectlCmd := fmt.Sprintf("%s exec -i -n %s %s -c %s ", kubectlBinPath, data.Target.Namespace, pod.Name, data.Target.Container) - // Must create the target directory before trying to change to it for untar - mkdirCmd := fmt.Sprintf("%s -- mkdir -p %s", kubectlCmd, data.Target.Path) - if err := exec.CmdWithPrint(shell, append(shellArgs, mkdirCmd)...); err != nil { - return fmt.Errorf("unable to create the data injection target directory %s in pod %s: %w", data.Target.Path, pod.Name, err) - } + // Note that each command flag is separated to provide the widest cross-platform tar support + tarCmd := fmt.Sprintf("tar -c %s -f -", tarCompressFlag) + untarCmd := fmt.Sprintf("tar -x %s -v -f - -C %s", tarCompressFlag, data.Target.Path) - cpPodCmd := fmt.Sprintf("%s -C %s . | %s -- %s", - tarCmd, - source, - kubectlCmd, - untarCmd, - ) + // Must create the target directory before trying to change to it for untar + mkdirCmd := fmt.Sprintf("%s -- mkdir -p %s", kubectlCmd, data.Target.Path) + if err := exec.CmdWithPrint(shell, append(shellArgs, mkdirCmd)...); err != nil { + return fmt.Errorf("unable to create the data injection target directory %s in pod %s: %w", data.Target.Path, pod.Name, err) + } - // Do the actual data injection - if err := exec.CmdWithPrint(shell, append(shellArgs, cpPodCmd)...); err != nil { - return fmt.Errorf("could not copy data into the pod %s: %w", pod.Name, err) - } + cpPodCmd := fmt.Sprintf("%s -C %s . | %s -- %s", + tarCmd, + source, + kubectlCmd, + untarCmd, + ) - // Leave a marker in the target container for pods to track the sync action - cpPodCmd = fmt.Sprintf("%s -C %s %s | %s -- %s", - tarCmd, - componentPath.DataInjections, - config.GetDataInjectionMarker(), - kubectlCmd, - untarCmd, - ) - - if err := exec.CmdWithPrint(shell, append(shellArgs, cpPodCmd)...); err != nil { - return fmt.Errorf("could not save the Zarf sync completion file after injection into pod %s: %w", pod.Name, err) - } - } + // Do the actual data injection + if err := exec.CmdWithPrint(shell, append(shellArgs, cpPodCmd)...); err != nil { + return fmt.Errorf("could not copy data into the pod %s: %w", pod.Name, err) + } - // Do not look for a specific container after injection in case they are running an init container - podOnlyTarget := podLookup{ - Namespace: data.Target.Namespace, - Selector: data.Target.Selector, - } + // Leave a marker in the target container for pods to track the sync action + cpPodCmd = fmt.Sprintf("%s -C %s %s | %s -- %s", + tarCmd, + componentPath.DataInjections, + config.GetDataInjectionMarker(), + kubectlCmd, + untarCmd, + ) + + if err := exec.CmdWithPrint(shell, append(shellArgs, cpPodCmd)...); err != nil { + return fmt.Errorf("could not save the Zarf sync completion file after injection into pod %s: %w", pod.Name, err) + } + } - // Block one final time to make sure at least one pod has come up and injected the data - // Using only the pod as the final selector because we don't know what the container name will be - // Still using the init container filter to make sure we have the right running pod - _, err = waitForPodsAndContainers(ctx, c.Clientset, podOnlyTarget, podFilterByInitContainer) - if err != nil { - return err - } + // Do not look for a specific container after injection in case they are running an init container + podOnlyTarget := podLookup{ + Namespace: data.Target.Namespace, + Selector: data.Target.Selector, + } - // Cleanup now to reduce disk pressure - err = os.RemoveAll(source) - if err != nil { - return err - } + // Block one final time to make sure at least one pod has come up and injected the data + // Using only the pod as the final selector because we don't know what the container name will be + // Still using the init container filter to make sure we have the right running pod + _, err = waitForPodsAndContainers(ctx, c.Clientset, podOnlyTarget, podFilterByInitContainer) + if err != nil { + return err + } - // Return to stop the loop - return nil - } + // Cleanup now to reduce disk pressure + err = os.RemoveAll(source) + if err != nil { + return err } + + // Return to stop the loop + return nil } // podLookup is a struct for specifying a pod to target for data injection or lookups. @@ -180,13 +171,11 @@ type podFilter func(pod corev1.Pod) bool // If the timeout is reached, an empty list will be returned. // TODO: Test, refactor and/or remove. func waitForPodsAndContainers(ctx context.Context, clientset kubernetes.Interface, target podLookup, include podFilter) ([]corev1.Pod, error) { - waitCtx, cancel := context.WithTimeout(ctx, 90*time.Second) - defer cancel() readyPods, err := retry.DoWithData(func() ([]corev1.Pod, error) { listOpts := metav1.ListOptions{ LabelSelector: target.Selector, } - podList, err := clientset.CoreV1().Pods(target.Namespace).List(waitCtx, listOpts) + podList, err := clientset.CoreV1().Pods(target.Namespace).List(ctx, listOpts) if err != nil { return nil, err } @@ -241,7 +230,7 @@ func waitForPodsAndContainers(ctx context.Context, clientset kubernetes.Interfac return nil, fmt.Errorf("no ready pods found") } return readyPods, nil - }, retry.Context(waitCtx), retry.Attempts(0), retry.DelayType(retry.FixedDelay), retry.Delay(time.Second)) + }, retry.Context(ctx), retry.Attempts(0), retry.DelayType(retry.FixedDelay), retry.Delay(time.Second)) if err != nil { return nil, err } From 726879fb2a381da91279016792b7dca88e80667b Mon Sep 17 00:00:00 2001 From: Austin Abro <37223396+AustinAbro321@users.noreply.github.com> Date: Thu, 15 Aug 2024 14:36:26 -0400 Subject: [PATCH 04/18] docs: explain no wait & helm hooks interaction (#2895) Signed-off-by: Austin Abro --- site/src/content/docs/ref/deploy.mdx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/site/src/content/docs/ref/deploy.mdx b/site/src/content/docs/ref/deploy.mdx index dbb5dc1679..b0974485d6 100644 --- a/site/src/content/docs/ref/deploy.mdx +++ b/site/src/content/docs/ref/deploy.mdx @@ -140,6 +140,12 @@ By default, Zarf waits for all resources to deploy successfully during install, You can override this behavior during install and upgrade by setting the `noWait: true` key under the `charts` and `manifests` fields. +:::note + +Deployments will wait for helm [post-install hooks](https://helm.sh/docs/topics/charts_hooks/#the-available-hooks) to complete even with `noWait` set to `true` as Zarf follows the [Helm release lifecycle](https://helm.sh/docs/topics/charts_hooks/#hooks-and-the-release-lifecycle) + +::: + ### Timeout Settings The default timeout for Helm operations in Zarf is 15 minutes. From 546e6651d77ffd25fed422f41b596de7706071ac Mon Sep 17 00:00:00 2001 From: Philip Laine Date: Fri, 16 Aug 2024 04:58:52 +0200 Subject: [PATCH 05/18] refactor: store managed secrets and add tests (#2892) Signed-off-by: Philip Laine --- src/cmd/tools/zarf.go | 10 +- src/pkg/cluster/secrets.go | 112 ++++++------- src/pkg/cluster/secrets_test.go | 274 +++++++++++++++++++++----------- 3 files changed, 243 insertions(+), 153 deletions(-) diff --git a/src/cmd/tools/zarf.go b/src/cmd/tools/zarf.go index 7c6ba91e88..39c622c714 100644 --- a/src/cmd/tools/zarf.go +++ b/src/cmd/tools/zarf.go @@ -141,10 +141,16 @@ var updateCredsCmd = &cobra.Command{ if confirm { // Update registry and git pull secrets if slices.Contains(args, message.RegistryKey) { - c.UpdateZarfManagedImageSecrets(ctx, newState) + err := c.UpdateZarfManagedImageSecrets(ctx, newState) + if err != nil { + return err + } } if slices.Contains(args, message.GitKey) { - c.UpdateZarfManagedGitSecrets(ctx, newState) + err := c.UpdateZarfManagedGitSecrets(ctx, newState) + if err != nil { + return err + } } // Update artifact token (if internal) diff --git a/src/pkg/cluster/secrets.go b/src/pkg/cluster/secrets.go index 43c3402b64..aa693c6a44 100644 --- a/src/pkg/cluster/secrets.go +++ b/src/pkg/cluster/secrets.go @@ -13,6 +13,7 @@ import ( "maps" corev1 "k8s.io/api/core/v1" + kerrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/zarf-dev/zarf/src/config" @@ -112,78 +113,79 @@ func (c *Cluster) GenerateGitPullCreds(namespace, name string, gitServerInfo typ } // UpdateZarfManagedImageSecrets updates all Zarf-managed image secrets in all namespaces based on state -// TODO: Refactor to return errors properly. -func (c *Cluster) UpdateZarfManagedImageSecrets(ctx context.Context, state *types.ZarfState) { +func (c *Cluster) UpdateZarfManagedImageSecrets(ctx context.Context, state *types.ZarfState) error { spinner := message.NewProgressSpinner("Updating existing Zarf-managed image secrets") defer spinner.Stop() namespaceList, err := c.Clientset.CoreV1().Namespaces().List(ctx, metav1.ListOptions{}) if err != nil { - spinner.Errorf(err, "Unable to get k8s namespaces") - } else { - // Update all image pull secrets - for _, namespace := range namespaceList.Items { - currentRegistrySecret, err := c.Clientset.CoreV1().Secrets(namespace.Name).Get(ctx, config.ZarfImagePullSecretName, metav1.GetOptions{}) - if err != nil { - continue - } - - // Check if this is a Zarf managed secret or is in a namespace the Zarf agent will take action in - if currentRegistrySecret.Labels[ZarfManagedByLabel] == "zarf" || - (namespace.Labels[AgentLabel] != "skip" && namespace.Labels[AgentLabel] != "ignore") { - spinner.Updatef("Updating existing Zarf-managed image secret for namespace: '%s'", namespace.Name) - - newRegistrySecret, err := c.GenerateRegistryPullCreds(ctx, namespace.Name, config.ZarfImagePullSecretName, state.RegistryInfo) - if err != nil { - message.WarnErrf(err, "Unable to generate registry creds") - continue - } - if !maps.EqualFunc(currentRegistrySecret.Data, newRegistrySecret.Data, func(v1, v2 []byte) bool { return bytes.Equal(v1, v2) }) { - _, err := c.Clientset.CoreV1().Secrets(newRegistrySecret.Namespace).Update(ctx, newRegistrySecret, metav1.UpdateOptions{}) - if err != nil { - message.WarnErrf(err, "Problem creating registry secret for the %s namespace", namespace.Name) - } - } - } + return err + } + // Update all image pull secrets + for _, namespace := range namespaceList.Items { + currentRegistrySecret, err := c.Clientset.CoreV1().Secrets(namespace.Name).Get(ctx, config.ZarfImagePullSecretName, metav1.GetOptions{}) + if kerrors.IsNotFound(err) { + continue + } + if err != nil { + return err + } + // Skip if namespace is skipped and secret is not managed by Zarf. + if currentRegistrySecret.Labels[ZarfManagedByLabel] != "zarf" && (namespace.Labels[AgentLabel] == "skip" || namespace.Labels[AgentLabel] == "ignore") { + continue + } + newRegistrySecret, err := c.GenerateRegistryPullCreds(ctx, namespace.Name, config.ZarfImagePullSecretName, state.RegistryInfo) + if err != nil { + return err + } + if maps.EqualFunc(currentRegistrySecret.Data, newRegistrySecret.Data, func(v1, v2 []byte) bool { return bytes.Equal(v1, v2) }) { + continue + } + spinner.Updatef("Updating existing Zarf-managed image secret for namespace: '%s'", namespace.Name) + _, err = c.Clientset.CoreV1().Secrets(newRegistrySecret.Namespace).Update(ctx, newRegistrySecret, metav1.UpdateOptions{}) + if err != nil { + return err } - spinner.Success() } + + spinner.Success() + return nil } // UpdateZarfManagedGitSecrets updates all Zarf-managed git secrets in all namespaces based on state -// TODO: Refactor to return errors properly. -func (c *Cluster) UpdateZarfManagedGitSecrets(ctx context.Context, state *types.ZarfState) { +func (c *Cluster) UpdateZarfManagedGitSecrets(ctx context.Context, state *types.ZarfState) error { spinner := message.NewProgressSpinner("Updating existing Zarf-managed git secrets") defer spinner.Stop() namespaceList, err := c.Clientset.CoreV1().Namespaces().List(ctx, metav1.ListOptions{}) if err != nil { - spinner.Errorf(err, "Unable to get k8s namespaces") - } else { - // Update all git pull secrets - for _, namespace := range namespaceList.Items { - currentGitSecret, err := c.Clientset.CoreV1().Secrets(namespace.Name).Get(ctx, config.ZarfGitServerSecretName, metav1.GetOptions{}) - if err != nil { - continue - } - - // Check if this is a Zarf managed secret or is in a namespace the Zarf agent will take action in - if currentGitSecret.Labels[ZarfManagedByLabel] == "zarf" || - (namespace.Labels[AgentLabel] != "skip" && namespace.Labels[AgentLabel] != "ignore") { - spinner.Updatef("Updating existing Zarf-managed git secret for namespace: '%s'", namespace.Name) - - // Create the secret - newGitSecret := c.GenerateGitPullCreds(namespace.Name, config.ZarfGitServerSecretName, state.GitServer) - if !maps.Equal(currentGitSecret.StringData, newGitSecret.StringData) { - _, err := c.Clientset.CoreV1().Secrets(newGitSecret.Namespace).Update(ctx, newGitSecret, metav1.UpdateOptions{}) - if err != nil { - message.WarnErrf(err, "Problem creating git server secret for the %s namespace", namespace.Name) - } - } - } + return err + } + for _, namespace := range namespaceList.Items { + currentGitSecret, err := c.Clientset.CoreV1().Secrets(namespace.Name).Get(ctx, config.ZarfGitServerSecretName, metav1.GetOptions{}) + if kerrors.IsNotFound(err) { + continue + } + if err != nil { + continue + } + // Skip if namespace is skipped and secret is not managed by Zarf. + if currentGitSecret.Labels[ZarfManagedByLabel] != "zarf" && (namespace.Labels[AgentLabel] == "skip" || namespace.Labels[AgentLabel] == "ignore") { + continue + } + newGitSecret := c.GenerateGitPullCreds(namespace.Name, config.ZarfGitServerSecretName, state.GitServer) + if maps.Equal(currentGitSecret.StringData, newGitSecret.StringData) { + continue + } + spinner.Updatef("Updating existing Zarf-managed git secret for namespace: %s", namespace.Name) + _, err = c.Clientset.CoreV1().Secrets(newGitSecret.Namespace).Update(ctx, newGitSecret, metav1.UpdateOptions{}) + if err != nil { + return err } - spinner.Success() } + + spinner.Success() + return nil } // GetServiceInfoFromRegistryAddress gets the service info for a registry address if it is a NodePort diff --git a/src/pkg/cluster/secrets_test.go b/src/pkg/cluster/secrets_test.go index 80cd33b933..0ee731dfe9 100644 --- a/src/pkg/cluster/secrets_test.go +++ b/src/pkg/cluster/secrets_test.go @@ -4,7 +4,6 @@ package cluster import ( - "context" "testing" "github.com/stretchr/testify/require" @@ -12,114 +11,197 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes/fake" + "github.com/zarf-dev/zarf/src/config" + "github.com/zarf-dev/zarf/src/test/testutil" "github.com/zarf-dev/zarf/src/types" ) -func TestGenerateRegistryPullCredsWithOutSvc(t *testing.T) { - c := &Cluster{Clientset: fake.NewSimpleClientset()} - ctx := context.Background() - ri := types.RegistryInfo{ - PullUsername: "pull-user", - PullPassword: "pull-password", - Address: "example.com", - } - secret, err := c.GenerateRegistryPullCreds(ctx, "foo", "bar", ri) - require.NoError(t, err) - expectedSecret := corev1.Secret{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "Secret", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "bar", - Namespace: "foo", - Labels: map[string]string{ - ZarfManagedByLabel: "zarf", - }, - }, - Type: corev1.SecretTypeDockerConfigJson, - Data: map[string][]byte{ - ".dockerconfigjson": []byte(`{"auths":{"example.com":{"auth":"cHVsbC11c2VyOnB1bGwtcGFzc3dvcmQ="}}}`), - }, - } - require.Equal(t, expectedSecret, *secret) -} +func TestUpdateZarfManagedSecrets(t *testing.T) { + ctx := testutil.TestContext(t) -func TestGenerateRegistryPullCredsWithSvc(t *testing.T) { - c := &Cluster{Clientset: fake.NewSimpleClientset()} - ctx := context.Background() - svc := &corev1.Service{ - ObjectMeta: metav1.ObjectMeta{ - Name: "good-service", - Namespace: "whatever", + tests := []struct { + name string + namespaceLabels map[string]string + secretLabels map[string]string + updatedImageSecret bool + updatedGitSecret bool + }{ + { + name: "modify", + updatedImageSecret: true, + updatedGitSecret: true, }, - Spec: corev1.ServiceSpec{ - Type: corev1.ServiceTypeNodePort, - Ports: []corev1.ServicePort{ - { - NodePort: 30001, - Port: 3333, - }, + { + name: "skip namespace", + namespaceLabels: map[string]string{ + AgentLabel: "skip", }, - ClusterIP: "10.11.12.13", }, - } - - _, err := c.Clientset.CoreV1().Services("whatever").Create(ctx, svc, metav1.CreateOptions{}) - require.NoError(t, err) - - ri := types.RegistryInfo{ - PullUsername: "pull-user", - PullPassword: "pull-password", - Address: "127.0.0.1:30001", - } - secret, err := c.GenerateRegistryPullCreds(ctx, "foo", "bar", ri) - require.NoError(t, err) - expectedSecret := corev1.Secret{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "Secret", + { + name: "ignore namespace", + namespaceLabels: map[string]string{ + AgentLabel: "ignore", + }, }, - ObjectMeta: metav1.ObjectMeta{ - Name: "bar", - Namespace: "foo", - Labels: map[string]string{ + { + name: "skip namespace managed secret", + namespaceLabels: map[string]string{ + AgentLabel: "skip", + }, + secretLabels: map[string]string{ ZarfManagedByLabel: "zarf", }, + updatedImageSecret: true, + updatedGitSecret: true, }, - Type: corev1.SecretTypeDockerConfigJson, - Data: map[string][]byte{ - ".dockerconfigjson": []byte(`{"auths":{"10.11.12.13:3333":{"auth":"cHVsbC11c2VyOnB1bGwtcGFzc3dvcmQ="},"127.0.0.1:30001":{"auth":"cHVsbC11c2VyOnB1bGwtcGFzc3dvcmQ="}}}`), - }, - } - require.Equal(t, expectedSecret, *secret) -} - -func TestGenerateGitPullCreds(t *testing.T) { - c := &Cluster{} - gi := types.GitServerInfo{ - PullUsername: "pull-user", - PullPassword: "pull-password", - } - secret := c.GenerateGitPullCreds("foo", "bar", gi) - expectedSecret := corev1.Secret{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "Secret", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "bar", - Namespace: "foo", - Labels: map[string]string{ + { + name: "ignore namespace managed secret", + namespaceLabels: map[string]string{ + AgentLabel: "ignore", + }, + secretLabels: map[string]string{ ZarfManagedByLabel: "zarf", }, + updatedImageSecret: true, + updatedGitSecret: true, }, - Type: corev1.SecretTypeOpaque, - Data: map[string][]byte{}, - StringData: map[string]string{ - "username": "pull-user", - "password": "pull-password", - }, } - require.Equal(t, expectedSecret, *secret) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := &Cluster{ + Clientset: fake.NewSimpleClientset(), + } + + namespace := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test", + Labels: tt.namespaceLabels, + }, + } + _, err := c.Clientset.CoreV1().Namespaces().Create(ctx, namespace, metav1.CreateOptions{}) + require.NoError(t, err) + svc := &corev1.Service{ + ObjectMeta: metav1.ObjectMeta{ + Name: "good-service", + Namespace: namespace.ObjectMeta.Name, + }, + Spec: corev1.ServiceSpec{ + Type: corev1.ServiceTypeNodePort, + Ports: []corev1.ServicePort{ + { + NodePort: 30001, + Port: 3333, + }, + }, + ClusterIP: "10.11.12.13", + }, + } + _, err = c.Clientset.CoreV1().Services(namespace.ObjectMeta.Name).Create(ctx, svc, metav1.CreateOptions{}) + require.NoError(t, err) + imageSecret := &corev1.Secret{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "v1", + Kind: "Secret", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: config.ZarfImagePullSecretName, + Namespace: namespace.ObjectMeta.Name, + Labels: tt.secretLabels, + }, + } + _, err = c.Clientset.CoreV1().Secrets(imageSecret.ObjectMeta.Namespace).Create(ctx, imageSecret, metav1.CreateOptions{}) + require.NoError(t, err) + gitSecret := &corev1.Secret{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "v1", + Kind: "Secret", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: config.ZarfGitServerSecretName, + Namespace: namespace.ObjectMeta.Name, + Labels: tt.secretLabels, + }, + } + _, err = c.Clientset.CoreV1().Secrets(gitSecret.ObjectMeta.Namespace).Create(ctx, gitSecret, metav1.CreateOptions{}) + require.NoError(t, err) + + state := &types.ZarfState{ + GitServer: types.GitServerInfo{ + PullUsername: "pull-user", + PullPassword: "pull-password", + }, + RegistryInfo: types.RegistryInfo{ + PullUsername: "pull-user", + PullPassword: "pull-password", + Address: "127.0.0.1:30001", + }, + } + err = c.UpdateZarfManagedImageSecrets(ctx, state) + require.NoError(t, err) + err = c.UpdateZarfManagedGitSecrets(ctx, state) + require.NoError(t, err) + + // Make sure no new namespaces or secrets have been created. + namespaceList, err := c.Clientset.CoreV1().Namespaces().List(ctx, metav1.ListOptions{}) + require.NoError(t, err) + require.Len(t, namespaceList.Items, 1) + for _, ns := range namespaceList.Items { + secretList, err := c.Clientset.CoreV1().Secrets(ns.ObjectMeta.Name).List(ctx, metav1.ListOptions{}) + require.NoError(t, err) + require.Len(t, secretList.Items, 2) + } + + // Check image registry secret + updatedImageSecret, err := c.Clientset.CoreV1().Secrets(namespace.ObjectMeta.Name).Get(ctx, config.ZarfImagePullSecretName, metav1.GetOptions{}) + require.NoError(t, err) + expectedImageSecret := corev1.Secret{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "v1", + Kind: "Secret", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: config.ZarfImagePullSecretName, + Namespace: namespace.ObjectMeta.Name, + Labels: map[string]string{ + ZarfManagedByLabel: "zarf", + }, + }, + Type: corev1.SecretTypeDockerConfigJson, + Data: map[string][]byte{ + ".dockerconfigjson": []byte(`{"auths":{"10.11.12.13:3333":{"auth":"cHVsbC11c2VyOnB1bGwtcGFzc3dvcmQ="},"127.0.0.1:30001":{"auth":"cHVsbC11c2VyOnB1bGwtcGFzc3dvcmQ="}}}`), + }, + } + if !tt.updatedImageSecret { + expectedImageSecret = *imageSecret + } + require.Equal(t, expectedImageSecret, *updatedImageSecret) + + // Check git secret + updatedGitSecret, err := c.Clientset.CoreV1().Secrets(namespace.ObjectMeta.Name).Get(ctx, config.ZarfGitServerSecretName, metav1.GetOptions{}) + require.NoError(t, err) + expectedGitSecret := corev1.Secret{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "v1", + Kind: "Secret", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: config.ZarfGitServerSecretName, + Namespace: namespace.ObjectMeta.Name, + Labels: map[string]string{ + ZarfManagedByLabel: "zarf", + }, + }, + Type: corev1.SecretTypeOpaque, + Data: map[string][]byte{}, + StringData: map[string]string{ + "username": state.GitServer.PullUsername, + "password": state.GitServer.PullPassword, + }, + } + if !tt.updatedGitSecret { + expectedGitSecret = *gitSecret + } + require.Equal(t, expectedGitSecret, *updatedGitSecret) + }) + } } From 88370b6c770c64be930b3575ff08b36432ecc03f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 16 Aug 2024 12:15:49 -0400 Subject: [PATCH 06/18] chore(deps): bump github/codeql-action from 3.26.1 to 3.26.2 (#2888) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/scan-codeql.yml | 4 ++-- .github/workflows/scorecard.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/scan-codeql.yml b/.github/workflows/scan-codeql.yml index 3c7bff10ec..6303f782c2 100644 --- a/.github/workflows/scan-codeql.yml +++ b/.github/workflows/scan-codeql.yml @@ -53,7 +53,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@29d86d22a34ea372b1bbf3b2dced2e25ca6b3384 # v3.26.1 + uses: github/codeql-action/init@429e1977040da7a23b6822b13c129cd1ba93dbb2 # v3.26.2 with: languages: ${{ matrix.language }} config-file: ./.github/codeql.yaml @@ -62,6 +62,6 @@ jobs: run: make build-cli-linux-amd - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@29d86d22a34ea372b1bbf3b2dced2e25ca6b3384 # v3.26.1 + uses: github/codeql-action/analyze@429e1977040da7a23b6822b13c129cd1ba93dbb2 # v3.26.2 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/scorecard.yaml b/.github/workflows/scorecard.yaml index 9ece5ff012..f677160391 100644 --- a/.github/workflows/scorecard.yaml +++ b/.github/workflows/scorecard.yaml @@ -44,6 +44,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@29d86d22a34ea372b1bbf3b2dced2e25ca6b3384 # v3.26.1 + uses: github/codeql-action/upload-sarif@429e1977040da7a23b6822b13c129cd1ba93dbb2 # v3.26.2 with: sarif_file: results.sarif From 3103295efcfb05470177141d1f0cf944841fc817 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 16 Aug 2024 12:16:04 -0400 Subject: [PATCH 07/18] chore(deps): bump actions/setup-go from 5.0.0 to 5.0.2 (#2901) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/test-import.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-import.yaml b/.github/workflows/test-import.yaml index 72ad5e770f..1cc6784f04 100644 --- a/.github/workflows/test-import.yaml +++ b/.github/workflows/test-import.yaml @@ -18,7 +18,7 @@ jobs: uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Setup Go - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 + uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 with: go-version-file: 'go.mod' cache: true From 4d3bf5d59eb9638d7aba6fad342a0daf7727d836 Mon Sep 17 00:00:00 2001 From: Austin Abro <37223396+AustinAbro321@users.noreply.github.com> Date: Tue, 20 Aug 2024 12:16:44 -0400 Subject: [PATCH 08/18] fix: update injector (#2910) Signed-off-by: Austin Abro --- packages/zarf-registry/zarf.yaml | 4 ++-- src/test/e2e/00_use_cli_test.go | 4 ++-- zarf-config.toml | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/zarf-registry/zarf.yaml b/packages/zarf-registry/zarf.yaml index 2da03ccda6..190eeba4c0 100644 --- a/packages/zarf-registry/zarf.yaml +++ b/packages/zarf-registry/zarf.yaml @@ -111,7 +111,7 @@ components: architecture: amd64 files: # Rust Injector Binary - - source: https://zarf-public.s3-us-gov-west-1.amazonaws.com/injector/###ZARF_PKG_TMPL_INJECTOR_VERSION###/zarf-injector-amd64 + - source: https://zarf-init.s3.us-east-2.amazonaws.com/injector/###ZARF_PKG_TMPL_INJECTOR_VERSION###/zarf-injector-amd64 target: "###ZARF_TEMP###/zarf-injector" shasum: "###ZARF_PKG_TMPL_INJECTOR_AMD64_SHASUM###" executable: true @@ -126,7 +126,7 @@ components: architecture: arm64 files: # Rust Injector Binary - - source: https://zarf-public.s3-us-gov-west-1.amazonaws.com/injector/###ZARF_PKG_TMPL_INJECTOR_VERSION###/zarf-injector-arm64 + - source: https://zarf-init.s3.us-east-2.amazonaws.com/injector/###ZARF_PKG_TMPL_INJECTOR_VERSION###/zarf-injector-arm64 target: "###ZARF_TEMP###/zarf-injector" shasum: "###ZARF_PKG_TMPL_INJECTOR_ARM64_SHASUM###" executable: true diff --git a/src/test/e2e/00_use_cli_test.go b/src/test/e2e/00_use_cli_test.go index b663d58454..de0c5a7a51 100644 --- a/src/test/e2e/00_use_cli_test.go +++ b/src/test/e2e/00_use_cli_test.go @@ -43,9 +43,9 @@ func TestUseCLI(t *testing.T) { t.Run("zarf prepare sha256sum ", func(t *testing.T) { t.Parallel() // Test `zarf prepare sha256sum` for a remote asset - expectedShasum := "c3cdea0573ba5a058ec090b5d2683bf398e8b1614c37ec81136ed03b78167617\n" + expectedShasum := "b905e647e0d7876cfd5b665632cfc43ad919dc60408f7236c5b541c53277b503\n" - stdOut, stdErr, err := e2e.Zarf(t, "prepare", "sha256sum", "https://zarf-public.s3-us-gov-west-1.amazonaws.com/pipelines/zarf-prepare-shasum-remote-test-file.txt") + stdOut, stdErr, err := e2e.Zarf(t, "prepare", "sha256sum", "https://zarf-init.s3.us-east-2.amazonaws.com/injector/2024-07-22/zarf-injector-arm64") require.NoError(t, err, stdOut, stdErr) require.Contains(t, stdOut, expectedShasum, "The expected SHASUM should equal the actual SHASUM") }) diff --git a/zarf-config.toml b/zarf-config.toml index 09afb3eed3..70f2ac615a 100644 --- a/zarf-config.toml +++ b/zarf-config.toml @@ -5,9 +5,9 @@ agent_image = 'zarf-dev/zarf/agent' agent_image_tag = 'local' # Tag for the zarf injector binary to use -injector_version = '2024-05-15' -injector_amd64_shasum = '1b34519ac30daf0e5a4a2f0a0766dbcd0852c0b5364b35576eea4ac9e22d9e82' -injector_arm64_shasum = 'ca20f427f9cf91ff42646a785c4772be5892a6752fa14924c5085b2d0109b008' +injector_version = '2024-07-22' +injector_amd64_shasum = '8463bfd66930a4b26c665b51f25e8a32ed5948068bae49987013c89173394478' +injector_arm64_shasum = 'b905e647e0d7876cfd5b665632cfc43ad919dc60408f7236c5b541c53277b503' # The image reference to use for the registry that Zarf deploys into the cluster From c34906bfde46eba140fe5152a6211356df192fd3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 22 Aug 2024 10:20:16 -0400 Subject: [PATCH 09/18] chore(deps): bump github/codeql-action from 3.26.2 to 3.26.4 (#2916) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/scan-codeql.yml | 4 ++-- .github/workflows/scorecard.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/scan-codeql.yml b/.github/workflows/scan-codeql.yml index 6303f782c2..9ac8ca9b44 100644 --- a/.github/workflows/scan-codeql.yml +++ b/.github/workflows/scan-codeql.yml @@ -53,7 +53,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@429e1977040da7a23b6822b13c129cd1ba93dbb2 # v3.26.2 + uses: github/codeql-action/init@f0f3afee809481da311ca3a6ff1ff51d81dbeb24 # v3.26.4 with: languages: ${{ matrix.language }} config-file: ./.github/codeql.yaml @@ -62,6 +62,6 @@ jobs: run: make build-cli-linux-amd - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@429e1977040da7a23b6822b13c129cd1ba93dbb2 # v3.26.2 + uses: github/codeql-action/analyze@f0f3afee809481da311ca3a6ff1ff51d81dbeb24 # v3.26.4 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/scorecard.yaml b/.github/workflows/scorecard.yaml index f677160391..09c0be4927 100644 --- a/.github/workflows/scorecard.yaml +++ b/.github/workflows/scorecard.yaml @@ -44,6 +44,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@429e1977040da7a23b6822b13c129cd1ba93dbb2 # v3.26.2 + uses: github/codeql-action/upload-sarif@f0f3afee809481da311ca3a6ff1ff51d81dbeb24 # v3.26.4 with: sarif_file: results.sarif From db367cdcdd013415c4f3cd421c96de52dff71b0b Mon Sep 17 00:00:00 2001 From: Austin Abro <37223396+AustinAbro321@users.noreply.github.com> Date: Thu, 22 Aug 2024 10:56:29 -0400 Subject: [PATCH 10/18] fix: update creds not breaking when internal git server not deployed (#2904) Signed-off-by: Austin Abro --- src/cmd/tools/zarf.go | 72 ++++++--------------------- src/config/lang/english.go | 2 - src/pkg/cluster/zarf.go | 70 ++++++++++++++++++++++++++ src/pkg/cluster/zarf_test.go | 38 ++++++++++++++ src/test/e2e/21_connect_creds_test.go | 13 ++++- 5 files changed, 134 insertions(+), 61 deletions(-) diff --git a/src/cmd/tools/zarf.go b/src/cmd/tools/zarf.go index 39c622c714..5a9cd11718 100644 --- a/src/cmd/tools/zarf.go +++ b/src/cmd/tools/zarf.go @@ -21,7 +21,6 @@ import ( "github.com/zarf-dev/zarf/src/cmd/common" "github.com/zarf-dev/zarf/src/config" "github.com/zarf-dev/zarf/src/config/lang" - "github.com/zarf-dev/zarf/src/internal/gitea" "github.com/zarf-dev/zarf/src/internal/packager/helm" "github.com/zarf-dev/zarf/src/internal/packager/template" "github.com/zarf-dev/zarf/src/pkg/cluster" @@ -70,7 +69,7 @@ var getCredsCmd = &cobra.Command{ } // TODO: Determine if this is actually needed. if state.Distro == "" { - return errors.New("Zarf state secret did not load properly") + return errors.New("zarf state secret did not load properly") } if len(args) > 0 { @@ -97,7 +96,7 @@ var updateCredsCmd = &cobra.Command{ } else { if !slices.Contains(validKeys, args[0]) { cmd.Help() - return fmt.Errorf("invalid service key specified, valid keys are: %s, %s, and %s", message.RegistryKey, message.GitKey, message.ArtifactKey) + return fmt.Errorf("invalid service key specified, valid key choices are: %v", validKeys) } } @@ -116,7 +115,7 @@ var updateCredsCmd = &cobra.Command{ } // TODO: Determine if this is actually needed. if oldState.Distro == "" { - return errors.New("Zarf state secret did not load properly") + return errors.New("zarf state secret did not load properly") } newState, err := cluster.MergeZarfState(oldState, updateCredsInitOpts, args) if err != nil { @@ -152,34 +151,18 @@ var updateCredsCmd = &cobra.Command{ return err } } + // TODO once Zarf is changed so the default state is empty for a service when it is not deployed + // and sufficient time has passed for users state to get updated we can remove this check + internalGitServerExists, err := c.InternalGitServerExists(cmd.Context()) + if err != nil { + return err + } // Update artifact token (if internal) - if slices.Contains(args, message.ArtifactKey) && newState.ArtifactServer.PushToken == "" && newState.ArtifactServer.IsInternal() { - tunnel, err := c.NewTunnel(cluster.ZarfNamespaceName, cluster.SvcResource, cluster.ZarfGitServerName, "", 0, cluster.ZarfGitServerPort) + if slices.Contains(args, message.ArtifactKey) && newState.ArtifactServer.PushToken == "" && newState.ArtifactServer.IsInternal() && internalGitServerExists { + newState.ArtifactServer.PushToken, err = c.UpdateInternalArtifactServerToken(ctx, oldState.GitServer) if err != nil { - return err - } - _, err = tunnel.Connect(cmd.Context()) - if err != nil { - return err - } - defer tunnel.Close() - tunnelURL := tunnel.HTTPEndpoint() - giteaClient, err := gitea.NewClient(tunnelURL, oldState.GitServer.PushUsername, oldState.GitServer.PushPassword) - if err != nil { - return err - } - err = tunnel.Wrap(func() error { - tokenSha1, err := giteaClient.CreatePackageRegistryToken(ctx) - if err != nil { - return err - } - newState.ArtifactServer.PushToken = tokenSha1 - return nil - }) - if err != nil { - // Warn if we couldn't actually update the git server (it might not be installed and we should try to continue) - message.Warnf(lang.CmdToolsUpdateCredsUnableCreateToken, err.Error()) + return fmt.Errorf("unable to create the new Gitea artifact token: %w", err) } } @@ -199,35 +182,10 @@ var updateCredsCmd = &cobra.Command{ message.Warnf(lang.CmdToolsUpdateCredsUnableUpdateRegistry, err.Error()) } } - if slices.Contains(args, message.GitKey) && newState.GitServer.IsInternal() { - tunnel, err := c.NewTunnel(cluster.ZarfNamespaceName, cluster.SvcResource, cluster.ZarfGitServerName, "", 0, cluster.ZarfGitServerPort) - if err != nil { - return err - } - _, err = tunnel.Connect(cmd.Context()) - if err != nil { - return err - } - defer tunnel.Close() - tunnelURL := tunnel.HTTPEndpoint() - giteaClient, err := gitea.NewClient(tunnelURL, oldState.GitServer.PushUsername, oldState.GitServer.PushPassword) - if err != nil { - return err - } - err = tunnel.Wrap(func() error { - err := giteaClient.UpdateGitUser(ctx, newState.GitServer.PullUsername, newState.GitServer.PullPassword) - if err != nil { - return err - } - err = giteaClient.UpdateGitUser(ctx, newState.GitServer.PushUsername, newState.GitServer.PushPassword) - if err != nil { - return err - } - return nil - }) + if slices.Contains(args, message.GitKey) && newState.GitServer.IsInternal() && internalGitServerExists { + err := c.UpdateInternalGitServerSecret(cmd.Context(), oldState.GitServer, newState.GitServer) if err != nil { - // Warn if we couldn't actually update the git server (it might not be installed and we should try to continue) - message.Warnf(lang.CmdToolsUpdateCredsUnableUpdateGit, err.Error()) + return fmt.Errorf("unable to update Zarf Git Server values: %w", err) } } if slices.Contains(args, message.AgentKey) { diff --git a/src/config/lang/english.go b/src/config/lang/english.go index 1bca5f773a..50ce790c44 100644 --- a/src/config/lang/english.go +++ b/src/config/lang/english.go @@ -576,9 +576,7 @@ $ zarf tools update-creds artifact --artifact-push-username={USERNAME} --artifac CmdToolsUpdateCredsConfirmFlag = "Confirm updating credentials without prompting" CmdToolsUpdateCredsConfirmProvided = "Confirm flag specified, continuing without prompting." CmdToolsUpdateCredsConfirmContinue = "Continue with these changes?" - CmdToolsUpdateCredsUnableCreateToken = "Unable to create the new Gitea artifact token: %s" CmdToolsUpdateCredsUnableUpdateRegistry = "Unable to update Zarf Registry values: %s" - CmdToolsUpdateCredsUnableUpdateGit = "Unable to update Zarf Git Server values: %s" CmdToolsUpdateCredsUnableUpdateAgent = "Unable to update Zarf Agent TLS secrets: %s" CmdToolsUpdateCredsUnableUpdateCreds = "Unable to update Zarf credentials" diff --git a/src/pkg/cluster/zarf.go b/src/pkg/cluster/zarf.go index 7145349fea..14c3e2f31a 100644 --- a/src/pkg/cluster/zarf.go +++ b/src/pkg/cluster/zarf.go @@ -20,6 +20,7 @@ import ( "github.com/avast/retry-go/v4" "github.com/zarf-dev/zarf/src/api/v1alpha1" "github.com/zarf-dev/zarf/src/config" + "github.com/zarf-dev/zarf/src/internal/gitea" "github.com/zarf-dev/zarf/src/pkg/message" "github.com/zarf-dev/zarf/src/types" ) @@ -288,3 +289,72 @@ func (c *Cluster) GetInstalledChartsForComponent(ctx context.Context, packageNam return installedCharts, nil } + +// UpdateInternalArtifactServerToken updates the the artifact server token on the internal gitea server and returns it +func (c *Cluster) UpdateInternalArtifactServerToken(ctx context.Context, oldGitServer types.GitServerInfo) (string, error) { + tunnel, err := c.NewTunnel(ZarfNamespaceName, SvcResource, ZarfGitServerName, "", 0, ZarfGitServerPort) + if err != nil { + return "", err + } + _, err = tunnel.Connect(ctx) + if err != nil { + return "", err + } + defer tunnel.Close() + tunnelURL := tunnel.HTTPEndpoint() + giteaClient, err := gitea.NewClient(tunnelURL, oldGitServer.PushUsername, oldGitServer.PushPassword) + if err != nil { + return "", err + } + var newToken string + err = tunnel.Wrap(func() error { + newToken, err = giteaClient.CreatePackageRegistryToken(ctx) + if err != nil { + return err + } + return nil + }) + return newToken, err +} + +// UpdateInternalGitServerSecret updates the internal gitea server secrets with the new git server info +func (c *Cluster) UpdateInternalGitServerSecret(ctx context.Context, oldGitServer types.GitServerInfo, newGitServer types.GitServerInfo) error { + tunnel, err := c.NewTunnel(ZarfNamespaceName, SvcResource, ZarfGitServerName, "", 0, ZarfGitServerPort) + if err != nil { + return err + } + _, err = tunnel.Connect(ctx) + if err != nil { + return err + } + defer tunnel.Close() + tunnelURL := tunnel.HTTPEndpoint() + giteaClient, err := gitea.NewClient(tunnelURL, oldGitServer.PushUsername, oldGitServer.PushPassword) + if err != nil { + return err + } + err = tunnel.Wrap(func() error { + err := giteaClient.UpdateGitUser(ctx, newGitServer.PullUsername, newGitServer.PullPassword) + if err != nil { + return err + } + err = giteaClient.UpdateGitUser(ctx, newGitServer.PushUsername, newGitServer.PushPassword) + if err != nil { + return err + } + return nil + }) + if err != nil { + return err + } + return nil +} + +// InternalGitServerExists checks if the Zarf internal git server exists in the cluster. +func (c *Cluster) InternalGitServerExists(ctx context.Context) (bool, error) { + _, err := c.Clientset.CoreV1().Services(ZarfNamespaceName).Get(ctx, ZarfGitServerName, metav1.GetOptions{}) + if err != nil && !kerrors.IsNotFound(err) { + return false, err + } + return !kerrors.IsNotFound(err), nil +} diff --git a/src/pkg/cluster/zarf_test.go b/src/pkg/cluster/zarf_test.go index fe8b91d188..d2f3aefcde 100644 --- a/src/pkg/cluster/zarf_test.go +++ b/src/pkg/cluster/zarf_test.go @@ -285,3 +285,41 @@ func TestRegistryHPA(t *testing.T) { require.NoError(t, err) require.Equal(t, autoscalingv2.DisabledPolicySelect, *disableHpa.Spec.Behavior.ScaleDown.SelectPolicy) } + +func TestInternalGitServerExists(t *testing.T) { + tests := []struct { + name string + svc *corev1.Service + expectedExist bool + expectedErr error + }{ + { + name: "Git server exists", + svc: &corev1.Service{ObjectMeta: metav1.ObjectMeta{Name: ZarfGitServerName, Namespace: ZarfNamespaceName}}, + expectedExist: true, + expectedErr: nil, + }, + { + name: "Git server does not exist", + svc: nil, + expectedExist: false, + expectedErr: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + cs := fake.NewSimpleClientset() + cluster := &Cluster{Clientset: cs} + ctx := context.Background() + if tt.svc != nil { + _, err := cs.CoreV1().Services(tt.svc.Namespace).Create(ctx, tt.svc, metav1.CreateOptions{}) + require.NoError(t, err) + } + + exists, err := cluster.InternalGitServerExists(ctx) + require.Equal(t, tt.expectedExist, exists) + require.Equal(t, tt.expectedErr, err) + }) + } +} diff --git a/src/test/e2e/21_connect_creds_test.go b/src/test/e2e/21_connect_creds_test.go index e794de3f3e..c58244a736 100644 --- a/src/test/e2e/21_connect_creds_test.go +++ b/src/test/e2e/21_connect_creds_test.go @@ -23,11 +23,16 @@ type RegistryResponse struct { func TestConnectAndCreds(t *testing.T) { t.Log("E2E: Connect") + ctx := context.Background() prevAgentSecretData, _, err := e2e.Kubectl(t, "get", "secret", "agent-hook-tls", "-n", "zarf", "-o", "jsonpath={.data}") require.NoError(t, err) - ctx := context.Background() + c, err := cluster.NewCluster() + require.NoError(t, err) + // Init the state variable + oldState, err := c.LoadZarfState(ctx) + require.NoError(t, err) connectToZarfServices(ctx, t) @@ -36,7 +41,11 @@ func TestConnectAndCreds(t *testing.T) { newAgentSecretData, _, err := e2e.Kubectl(t, "get", "secret", "agent-hook-tls", "-n", "zarf", "-o", "jsonpath={.data}") require.NoError(t, err) - require.NotEqual(t, prevAgentSecretData, newAgentSecretData, "agent secrets should not be the same") + newState, err := c.LoadZarfState(ctx) + require.NoError(t, err) + require.NotEqual(t, prevAgentSecretData, newAgentSecretData) + require.NotEqual(t, oldState.ArtifactServer.PushToken, newState.ArtifactServer.PushToken) + require.NotEqual(t, oldState.GitServer.PushPassword, newState.GitServer.PushPassword) connectToZarfServices(ctx, t) } From e90d5c8c4a4a4e20df64c0d972983fec28e19ba9 Mon Sep 17 00:00:00 2001 From: Austin Abro <37223396+AustinAbro321@users.noreply.github.com> Date: Thu, 22 Aug 2024 13:28:39 -0400 Subject: [PATCH 11/18] feat: better error message on helm fail (#2914) Signed-off-by: Austin Abro --- src/cmd/root.go | 3 ++- src/internal/packager/helm/chart.go | 12 ++++++------ src/test/e2e/09_component_compose_test.go | 2 +- src/test/e2e/20_zarf_init_test.go | 2 +- src/test/e2e/31_checksum_and_signature_test.go | 2 +- src/test/e2e/34_custom_init_package_test.go | 2 +- 6 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/cmd/root.go b/src/cmd/root.go index 876efdf20e..62e0582c8e 100644 --- a/src/cmd/root.go +++ b/src/cmd/root.go @@ -96,7 +96,8 @@ func Execute(ctx context.Context) { if len(comps) > 1 && comps[1] == "tools" && slices.Contains(defaultPrintCmds, comps[2]) { cmd.PrintErrln(cmd.ErrPrefix(), err.Error()) } else { - pterm.Error.Println(err.Error()) + errParagraph := message.Paragraph(err.Error()) + pterm.Error.Println(errParagraph) } os.Exit(1) } diff --git a/src/internal/packager/helm/chart.go b/src/internal/packager/helm/chart.go index 134bb4c493..daf59902e5 100644 --- a/src/internal/packager/helm/chart.go +++ b/src/internal/packager/helm/chart.go @@ -91,6 +91,9 @@ func (h *Helm) InstallOrUpgradeChart(ctx context.Context) (types.ConnectStrings, return nil }, retry.Context(ctx), retry.Attempts(uint(h.retries)), retry.Delay(500*time.Millisecond)) if err != nil { + removeMsg := "if you need to remove the failed chart, use `zarf package remove`" + installErr := fmt.Errorf("unable to install chart after %d attempts: %w: %s", h.retries, err, removeMsg) + releases, _ := histClient.Run(h.chart.ReleaseName) previouslyDeployedVersion := 0 @@ -101,21 +104,18 @@ func (h *Helm) InstallOrUpgradeChart(ctx context.Context) (types.ConnectStrings, } } - removeMsg := "if you need to remove the failed chart, use `zarf package remove`" - // No prior releases means this was an initial install. if previouslyDeployedVersion == 0 { - return nil, "", fmt.Errorf("unable to install chart after %d attempts: %s", h.retries, removeMsg) + return nil, "", installErr } // Attempt to rollback on a failed upgrade. spinner.Updatef("Performing chart rollback") err = h.rollbackChart(h.chart.ReleaseName, previouslyDeployedVersion) if err != nil { - return nil, "", fmt.Errorf("unable to upgrade chart after %d attempts and unable to rollback: %s", h.retries, removeMsg) + return nil, "", fmt.Errorf("%w: unable to rollback: %w", installErr, err) } - - return nil, "", fmt.Errorf("unable to upgrade chart after %d attempts: %s", h.retries, removeMsg) + return nil, "", installErr } // return any collected connect strings for zarf connect. diff --git a/src/test/e2e/09_component_compose_test.go b/src/test/e2e/09_component_compose_test.go index 37a905456a..e5809df6eb 100644 --- a/src/test/e2e/09_component_compose_test.go +++ b/src/test/e2e/09_component_compose_test.go @@ -185,7 +185,7 @@ func (suite *CompositionSuite) Test_2_ComposabilityBadLocalOS() { _, stdErr, err := e2e.Zarf(suite.T(), "package", "create", composeTestBadLocalOS, "-o", "build", "--no-color", "--confirm") suite.Error(err) - suite.Contains(stdErr, "\"only.localOS\" \"linux\" cannot be redefined as \"windows\" during compose") + suite.Contains(e2e.StripMessageFormatting(stdErr), "\"only.localOS\" \"linux\" cannot be redefined as \"windows\" during compose") } func TestCompositionSuite(t *testing.T) { diff --git a/src/test/e2e/20_zarf_init_test.go b/src/test/e2e/20_zarf_init_test.go index 6f788ef3b1..c94bfa4226 100644 --- a/src/test/e2e/20_zarf_init_test.go +++ b/src/test/e2e/20_zarf_init_test.go @@ -44,7 +44,7 @@ func TestZarfInit(t *testing.T) { // We need to use the --architecture flag here to force zarf to find the package. _, stdErr, err = e2e.Zarf(t, "init", "--architecture", mismatchedArch, "--components=k3s", "--confirm") require.Error(t, err, stdErr) - require.Contains(t, stdErr, expectedErrorMessage) + require.Contains(t, e2e.StripMessageFormatting(stdErr), expectedErrorMessage) } if !e2e.ApplianceMode { diff --git a/src/test/e2e/31_checksum_and_signature_test.go b/src/test/e2e/31_checksum_and_signature_test.go index e8aed4c1cb..b80e83e699 100644 --- a/src/test/e2e/31_checksum_and_signature_test.go +++ b/src/test/e2e/31_checksum_and_signature_test.go @@ -37,7 +37,7 @@ func TestChecksumAndSignature(t *testing.T) { // Test that we get an error when trying to deploy a package without providing the public key stdOut, stdErr, err = e2e.Zarf(t, "package", "deploy", pkgName, "--confirm") require.Error(t, err, stdOut, stdErr) - require.Contains(t, stdErr, "failed to deploy package: unable to load the package: package is signed but no key was provided - add a key with the --key flag or use the --insecure flag and run the command again") + require.Contains(t, e2e.StripMessageFormatting(stdErr), "failed to deploy package: unable to load the package: package is signed but no key was provided - add a key with the --key flag or use the --insecure flag and run the command again") // Test that we don't get an error when we remember to provide the public key stdOut, stdErr, err = e2e.Zarf(t, "package", "deploy", pkgName, publicKeyFlag, "--confirm") diff --git a/src/test/e2e/34_custom_init_package_test.go b/src/test/e2e/34_custom_init_package_test.go index c61cf91e2d..e4d3307fc4 100644 --- a/src/test/e2e/34_custom_init_package_test.go +++ b/src/test/e2e/34_custom_init_package_test.go @@ -38,7 +38,7 @@ func TestCustomInit(t *testing.T) { // Test that we get an error when trying to deploy a package without providing the public key stdOut, stdErr, err = e2e.Zarf(t, "init", "--confirm") require.Error(t, err, stdOut, stdErr) - require.Contains(t, stdErr, "unable to load the package: package is signed but no key was provided - add a key with the --key flag or use the --insecure flag and run the command again") + require.Contains(t, e2e.StripMessageFormatting(stdErr), "unable to load the package: package is signed but no key was provided - add a key with the --key flag or use the --insecure flag and run the command again") /* Test operations during package deploy */ // Test that we can deploy the package with the public key From 46ddb3ba85e7fb1a00319559dc17a5b7a4192af1 Mon Sep 17 00:00:00 2001 From: Austin Abro <37223396+AustinAbro321@users.noreply.github.com> Date: Thu, 22 Aug 2024 14:04:11 -0400 Subject: [PATCH 12/18] ci: increase lint timeout (#2919) Signed-off-by: Austin Abro --- .golangci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.golangci.yaml b/.golangci.yaml index 6f46337df5..6423df7732 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -1,5 +1,5 @@ run: - timeout: 5m + timeout: 10m linters: disable-all: true enable: From 15fa1198bb14a3749d57092b09fe56e3855fe223 Mon Sep 17 00:00:00 2001 From: Austin Abro <37223396+AustinAbro321@users.noreply.github.com> Date: Thu, 22 Aug 2024 14:44:21 -0400 Subject: [PATCH 13/18] fix: evaulate templates on schema check (#2911) Signed-off-by: Austin Abro --- .pre-commit-config.yaml | 12 ----------- src/pkg/lint/lint.go | 14 ++++++------- src/pkg/lint/lint_test.go | 12 +++++------ src/pkg/lint/schema.go | 7 ++++++- src/pkg/lint/schema_test.go | 20 +++++++++++++++++++ .../testdata/package-with-templates/zarf.yaml | 5 +++++ src/pkg/packager/creator/normal.go | 2 +- src/pkg/packager/creator/skeleton.go | 2 +- src/pkg/packager/creator/utils.go | 4 ++-- src/pkg/packager/dev.go | 2 +- 10 files changed, 48 insertions(+), 32 deletions(-) create mode 100644 src/pkg/lint/testdata/package-with-templates/zarf.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ad9ea6d447..22ea750052 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -40,15 +40,3 @@ repos: types: [go] language: golang pass_filenames: false - - repo: https://github.com/python-jsonschema/check-jsonschema - rev: 0.14.0 - hooks: - - id: check-jsonschema - name: "Validate Zarf Configs Against Schema" - files: "zarf.yaml" - types: [yaml] - args: ["--schemafile", "zarf.schema.json"] - exclude: | - (?x)^( - src/test/packages/12-lint/.* - )$ diff --git a/src/pkg/lint/lint.go b/src/pkg/lint/lint.go index 9c0132f2e8..3c4be87eaf 100644 --- a/src/pkg/lint/lint.go +++ b/src/pkg/lint/lint.go @@ -36,7 +36,7 @@ func Validate(ctx context.Context, createOpts types.ZarfCreateOptions) error { return err } findings = append(findings, compFindings...) - schemaFindings, err := ValidatePackageSchema() + schemaFindings, err := ValidatePackageSchema(createOpts.SetVariables) if err != nil { return err } @@ -71,7 +71,7 @@ func lintComponents(ctx context.Context, pkg v1alpha1.ZarfPackage, createOpts ty node := chain.Head() for node != nil { component := node.ZarfComponent - compFindings, err := fillComponentTemplate(&component, createOpts) + compFindings, err := templateZarfObj(&component, createOpts.SetVariables) if err != nil { return nil, err } @@ -87,12 +87,12 @@ func lintComponents(ctx context.Context, pkg v1alpha1.ZarfPackage, createOpts ty return findings, nil } -func fillComponentTemplate(c *v1alpha1.ZarfComponent, createOpts types.ZarfCreateOptions) ([]PackageFinding, error) { +func templateZarfObj(zarfObj any, setVariables map[string]string) ([]PackageFinding, error) { var findings []PackageFinding templateMap := map[string]string{} setVarsAndWarn := func(templatePrefix string, deprecated bool) error { - yamlTemplates, err := utils.FindYamlTemplates(c, templatePrefix, "###") + yamlTemplates, err := utils.FindYamlTemplates(zarfObj, templatePrefix, "###") if err != nil { return err } @@ -105,7 +105,7 @@ func fillComponentTemplate(c *v1alpha1.ZarfComponent, createOpts types.ZarfCreat Severity: SevWarn, }) } - if _, present := createOpts.SetVariables[key]; !present { + if _, present := setVariables[key]; !present { unSetTemplates = true } } @@ -115,7 +115,7 @@ func fillComponentTemplate(c *v1alpha1.ZarfComponent, createOpts types.ZarfCreat Severity: SevWarn, }) } - for key, value := range createOpts.SetVariables { + for key, value := range setVariables { templateMap[fmt.Sprintf("%s%s###", templatePrefix, key)] = value } return nil @@ -130,7 +130,7 @@ func fillComponentTemplate(c *v1alpha1.ZarfComponent, createOpts types.ZarfCreat return nil, err } - if err := utils.ReloadYamlTemplate(c, templateMap); err != nil { + if err := utils.ReloadYamlTemplate(zarfObj, templateMap); err != nil { return nil, err } return findings, nil diff --git a/src/pkg/lint/lint_test.go b/src/pkg/lint/lint_test.go index d6ad24ad82..d499ba6e45 100644 --- a/src/pkg/lint/lint_test.go +++ b/src/pkg/lint/lint_test.go @@ -32,12 +32,10 @@ func TestLintComponents(t *testing.T) { require.Error(t, err) }) } -func TestFillComponentTemplate(t *testing.T) { - createOpts := types.ZarfCreateOptions{ - SetVariables: map[string]string{ - "KEY1": "value1", - "KEY2": "value2", - }, +func TestFillObjTemplate(t *testing.T) { + SetVariables := map[string]string{ + "KEY1": "value1", + "KEY2": "value2", } component := v1alpha1.ZarfComponent{ @@ -48,7 +46,7 @@ func TestFillComponentTemplate(t *testing.T) { }, } - findings, err := fillComponentTemplate(&component, createOpts) + findings, err := templateZarfObj(&component, SetVariables) require.NoError(t, err) expectedFindings := []PackageFinding{ { diff --git a/src/pkg/lint/schema.go b/src/pkg/lint/schema.go index ae3e991863..adf41e935b 100644 --- a/src/pkg/lint/schema.go +++ b/src/pkg/lint/schema.go @@ -18,7 +18,7 @@ import ( var ZarfSchema fs.ReadFileFS // ValidatePackageSchema checks the Zarf package in the current directory against the Zarf schema -func ValidatePackageSchema() ([]PackageFinding, error) { +func ValidatePackageSchema(setVariables map[string]string) ([]PackageFinding, error) { var untypedZarfPackage interface{} if err := utils.ReadYaml(layout.ZarfYAML, &untypedZarfPackage); err != nil { return nil, err @@ -29,6 +29,11 @@ func ValidatePackageSchema() ([]PackageFinding, error) { return nil, err } + _, err = templateZarfObj(&untypedZarfPackage, setVariables) + if err != nil { + return nil, err + } + return getSchemaFindings(jsonSchema, untypedZarfPackage) } diff --git a/src/pkg/lint/schema_test.go b/src/pkg/lint/schema_test.go index bd8b576a83..8ebcdc26bf 100644 --- a/src/pkg/lint/schema_test.go +++ b/src/pkg/lint/schema_test.go @@ -7,11 +7,13 @@ package lint import ( "fmt" "os" + "path/filepath" "testing" goyaml "github.com/goccy/go-yaml" "github.com/stretchr/testify/require" "github.com/zarf-dev/zarf/src/api/v1alpha1" + "github.com/zarf-dev/zarf/src/test/testutil" ) func TestZarfSchema(t *testing.T) { @@ -190,6 +192,24 @@ components: }) } +func TestValidatePackageSchema(t *testing.T) { + ZarfSchema = testutil.LoadSchema(t, "../../../zarf.schema.json") + setVariables := map[string]string{ + "PACKAGE_NAME": "test-package", + "MY_COMP_NAME": "test-comp", + } + cwd, err := os.Getwd() + require.NoError(t, err) + err = os.Chdir(filepath.Join("testdata", "package-with-templates")) + require.NoError(t, err) + defer func() { + require.NoError(t, os.Chdir(cwd)) + }() + findings, err := ValidatePackageSchema(setVariables) + require.Empty(t, findings) + require.NoError(t, err) +} + func TestYqCompat(t *testing.T) { t.Parallel() t.Run("Wrap standalone numbers in bracket", func(t *testing.T) { diff --git a/src/pkg/lint/testdata/package-with-templates/zarf.yaml b/src/pkg/lint/testdata/package-with-templates/zarf.yaml new file mode 100644 index 0000000000..f32ec32bab --- /dev/null +++ b/src/pkg/lint/testdata/package-with-templates/zarf.yaml @@ -0,0 +1,5 @@ +kind: ZarfPackageConfig +metadata: + name: "###ZARF_PKG_VAR_PACKAGE_NAME###" +components: + - name: "###ZARF_PKG_TMPL_MY_COMP_NAME###" diff --git a/src/pkg/packager/creator/normal.go b/src/pkg/packager/creator/normal.go index 79c58250c0..847a22003e 100644 --- a/src/pkg/packager/creator/normal.go +++ b/src/pkg/packager/creator/normal.go @@ -119,7 +119,7 @@ func (pc *PackageCreator) LoadPackageDefinition(ctx context.Context, src *layout } } - if err := Validate(pkg, pc.createOpts.BaseDir); err != nil { + if err := Validate(pkg, pc.createOpts.BaseDir, pc.createOpts.SetVariables); err != nil { return v1alpha1.ZarfPackage{}, nil, err } diff --git a/src/pkg/packager/creator/skeleton.go b/src/pkg/packager/creator/skeleton.go index 218830b75f..648fb562b3 100644 --- a/src/pkg/packager/creator/skeleton.go +++ b/src/pkg/packager/creator/skeleton.go @@ -71,7 +71,7 @@ func (sc *SkeletonCreator) LoadPackageDefinition(ctx context.Context, src *layou message.Warn(warning) } - if err := Validate(pkg, sc.createOpts.BaseDir); err != nil { + if err := Validate(pkg, sc.createOpts.BaseDir, sc.createOpts.SetVariables); err != nil { return v1alpha1.ZarfPackage{}, nil, err } diff --git a/src/pkg/packager/creator/utils.go b/src/pkg/packager/creator/utils.go index b138ce7af2..1bb88750e0 100644 --- a/src/pkg/packager/creator/utils.go +++ b/src/pkg/packager/creator/utils.go @@ -19,12 +19,12 @@ import ( // Validate errors if a package violates the schema or any runtime validations // This must be run while in the parent directory of the zarf.yaml being validated -func Validate(pkg v1alpha1.ZarfPackage, baseDir string) error { +func Validate(pkg v1alpha1.ZarfPackage, baseDir string, setVariables map[string]string) error { if err := lint.ValidatePackage(pkg); err != nil { return fmt.Errorf("package validation failed: %w", err) } - findings, err := lint.ValidatePackageSchema() + findings, err := lint.ValidatePackageSchema(setVariables) if err != nil { return fmt.Errorf("unable to check schema: %w", err) } diff --git a/src/pkg/packager/dev.go b/src/pkg/packager/dev.go index 1c1208be14..49232ddc1b 100644 --- a/src/pkg/packager/dev.go +++ b/src/pkg/packager/dev.go @@ -53,7 +53,7 @@ func (p *Packager) DevDeploy(ctx context.Context) error { return err } - if err := creator.Validate(p.cfg.Pkg, p.cfg.CreateOpts.BaseDir); err != nil { + if err := creator.Validate(p.cfg.Pkg, p.cfg.CreateOpts.BaseDir, p.cfg.CreateOpts.SetVariables); err != nil { return fmt.Errorf("package validation failed: %w", err) } From 186c5d05d61fb057516d9b182602e32aa7bccff8 Mon Sep 17 00:00:00 2001 From: Austin Abro <37223396+AustinAbro321@users.noreply.github.com> Date: Thu, 22 Aug 2024 15:54:47 -0400 Subject: [PATCH 14/18] chore: update workflow to use new key (#2920) Signed-off-by: Austin Abro --- .../publish-application-packages.yml | 13 +++++++--- .github/workflows/release.yml | 12 ++++++--- cosign.pub | 26 +++++++++---------- src/pkg/utils/cosign.go | 8 ------ src/test/e2e/11_oci_pull_inspect_test.go | 2 +- src/test/e2e/27_deploy_regression_test.go | 16 +----------- 6 files changed, 33 insertions(+), 44 deletions(-) diff --git a/.github/workflows/publish-application-packages.yml b/.github/workflows/publish-application-packages.yml index 3944aa0abb..de96965506 100644 --- a/.github/workflows/publish-application-packages.yml +++ b/.github/workflows/publish-application-packages.yml @@ -1,6 +1,7 @@ name: Zarf Application Package Publishing permissions: + id-token: write contents: read on: @@ -22,6 +23,14 @@ jobs: with: ref: ${{ github.event.inputs.branchName }} + - name: Auth with AWS + uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2 + with: + role-to-assume: ${{ secrets.AWS_KMS_ROLE }} + role-session-name: ${{ github.job || github.event.client_payload.pull_request.head.sha || github.sha }} + aws-region: us-east-2 + role-duration-seconds: 3600 + - name: Install The Latest Release Version of Zarf uses: defenseunicorns/setup-zarf@10e539efed02f75ec39eb8823e22a5c795f492ae #v1.0.1 @@ -44,7 +53,3 @@ jobs: # Publish a skeleton of the dos-games package zarf package publish examples/dos-games oci://ghcr.io/zarf-dev/packages - env: - AWS_REGION: ${{ secrets.COSIGN_AWS_REGION }} - AWS_ACCESS_KEY_ID: ${{ secrets.COSIGN_AWS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.COSIGN_AWS_ACCESS_KEY }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 52b3d38b31..f7af1a32de 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,6 +1,7 @@ name: Release CLI and Packages on Tag permissions: + id-token: write contents: read on: @@ -53,13 +54,18 @@ jobs: rm build/zarf-linux-arm64 echo ZARF_AGENT_IMAGE_DIGEST=$(docker buildx imagetools inspect ghcr.io/zarf-dev/zarf/agent:$GITHUB_REF_NAME --format '{{ json . }}' | jq -r .manifest.digest) >> $GITHUB_ENV + - name: Auth with AWS + uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2 + with: + role-to-assume: ${{ secrets.AWS_KMS_ROLE }} + role-session-name: ${{ github.job || github.event.client_payload.pull_request.head.sha || github.sha }} + aws-region: us-east-2 + role-duration-seconds: 3600 + - name: "Zarf Agent: Sign the Image" run: cosign sign --key awskms:///${{ secrets.COSIGN_AWS_KMS_KEY }} -a release-engineer=https://github.com/${{ github.actor }} -a version=$GITHUB_REF_NAME ghcr.io/zarf-dev/zarf/agent@$ZARF_AGENT_IMAGE_DIGEST -y env: COSIGN_EXPERIMENTAL: 1 - AWS_REGION: ${{ secrets.COSIGN_AWS_REGION }} - AWS_ACCESS_KEY_ID: ${{ secrets.COSIGN_AWS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.COSIGN_AWS_ACCESS_KEY }} # Builds init packages since GoReleaser won't handle this for us - name: Build init-packages For Release diff --git a/cosign.pub b/cosign.pub index 6c8e8e4eb5..a2677f32b0 100644 --- a/cosign.pub +++ b/cosign.pub @@ -1,14 +1,14 @@ -----BEGIN PUBLIC KEY----- -MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA9u472y/wY0tjIiR2T6rY -zOG1q4qwx5ZdmnoGsiG0Zc3rYo2DMiuKciG0MI4opCf4IID7kfYOD4aWILymwFID -xW0L6pEbxknHRQacWZSf/qfA+aAcjbKOY3ZWU8/uLJJeq37Y4OLc17ThJ7ZOj1Yf -Uvj81Uz9ZWVW7kYY31vWCruJh4VxZLsUAmFc6CsQUtzSGordLhh1b1rDP6ZRAaIP -mQnniULogwIBqnUTkIVwxiRYG+V2a3IC5vqlBLQRQ3UOWQ9mgZcfcXuTA6Fh8bwO -2lG768UfI1RBYioXAgXbPwXK+kM3Idvjcr+X2F3VpYWhHTscMIQF0ERzK7BkRqRI -x9l/RRm5lP+9a1kt6giYtvX2OqEsWaG3lTen3ocwblaHRlmqnaiVBtAnVny6QDHX -9p1HPMD/NjWjZucxWMjtdL5FZxBywbJVlxhe7sFByMoBZYhea9vGGSn2M2Q9kPiq -Bgl6bKZdeYIhaKQ7wrNkS6YVHMIqqpCIUI6/YGYwnu0hodbjR0yA2LFx4TgFZAuY -uGEiRP4Oi7WEOPkjRjP7kPXGpEBB7ulZ/Wohq1B6pB1Odo8WlfJRAek319F2aqqh -J1c3YdZ/w3EvCLKd+Inp1UNbamb79UN6jtwhqwKw72YbZh/yP0rim49lQ++umwPX -JWqG8iY/UzGB/3ch4/Wb09UCAwEAAQ== ------END PUBLIC KEY----- \ No newline at end of file +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAr6pqXju3qrkVae35GIuG +F58+zMd5XGMVgPkxFrdrJZ/3Ag65y7j4QsrcCFkXYAYNIy9iZliXypsxrr3oajJv +EgLDAc0CqtWYa0tuT2kAP4YHzxVkLC8MZLhQ1fuj9QKylm3OIMf18ZAnp12upmK8 +SBvrYxtWfTOv4KBgRGdIO0U9M/dwNnodGosY0znyHD9dp1G7qRA7BNpOsuXoaLa/ +aSQ2X0icoq5N8BLLOl3/23w6nCV+G32HFD0/AurDZVMC8o6N91AkX3smfWINkNk+ +QUrCkjhlAMxtBPi2TCYB4PimOKLpO/q/hwfixkHJcx8zPY/UZCCJGrsOcdFdvN/M +FkxqVZ2vBv+8LaElSAmbzsjVpg4w3QMk/6fVuU2rBtwog7DekuV/J5SwGCyTfC/4 +R8SetTsEpYgtDWp8+vugcfZTg5+7rPnMfNG16HdwJoC+LnWbeot6X2ZepTu4CrkV +qCAfFlu9G9sy2ZrwT5gnFT9JoKPVRTgkYmADgSfF0njKjuFKfk+aEVIrKRCVbExe +VtfmM1A9OfP4vCtCKw7tE5fFhmAa5v2D6LS/rG2m99fbZjDdeK9y22OZZyUCZaUN +TM+VQTuY1bwXY0/XEhUHxP0Fzk2VGQVslwXgW305SzR8Yh/bTbE4pkNGpOta+4s2 +E5ZMlZgQX8x4gSfbxmBHgP0CAwEAAQ== +-----END PUBLIC KEY----- diff --git a/src/pkg/utils/cosign.go b/src/pkg/utils/cosign.go index eb16d6159f..1e129ffb5c 100644 --- a/src/pkg/utils/cosign.go +++ b/src/pkg/utils/cosign.go @@ -8,7 +8,6 @@ import ( "context" "fmt" "io" - "os" "strings" "github.com/defenseunicorns/pkg/helpers/v2" @@ -16,7 +15,6 @@ import ( "github.com/google/go-containerregistry/pkg/name" "github.com/google/go-containerregistry/pkg/v1/remote" "github.com/pkg/errors" - "github.com/zarf-dev/zarf/src/config" "github.com/zarf-dev/zarf/src/config/lang" "github.com/zarf-dev/zarf/src/pkg/message" @@ -41,12 +39,6 @@ import ( func Sget(ctx context.Context, image, key string, out io.Writer) error { message.Warnf(lang.WarnSGetDeprecation) - // If this is a DefenseUnicorns package, use an internal sget public key - if strings.HasPrefix(image, fmt.Sprintf("%s://defenseunicorns", helpers.SGETURLScheme)) { - os.Setenv("DU_SGET_KEY", config.CosignPublicKey) - key = "env://DU_SGET_KEY" - } - // Remove the custom protocol header from the url image = strings.TrimPrefix(image, helpers.SGETURLPrefix) diff --git a/src/test/e2e/11_oci_pull_inspect_test.go b/src/test/e2e/11_oci_pull_inspect_test.go index a992a50f55..cd045ae0a6 100644 --- a/src/test/e2e/11_oci_pull_inspect_test.go +++ b/src/test/e2e/11_oci_pull_inspect_test.go @@ -55,7 +55,7 @@ func (suite *PullInspectTestSuite) Test_0_Pull() { // Verify the package was pulled correctly. suite.FileExists(out) - stdOut, stdErr, err = e2e.Zarf(suite.T(), "package", "inspect", out, "--key", "https://zarf.dev/cosign.pub", "--sbom-out", sbomTmp) + stdOut, stdErr, err = e2e.Zarf(suite.T(), "package", "inspect", out, "--key", "https://raw.githubusercontent.com/zarf-dev/zarf/v0.38.2/cosign.pub", "--sbom-out", sbomTmp) suite.NoError(err, stdOut, stdErr) suite.Contains(stdErr, "Validating SBOM checksums") suite.Contains(stdErr, "Package signature validated!") diff --git a/src/test/e2e/27_deploy_regression_test.go b/src/test/e2e/27_deploy_regression_test.go index f16c3d243a..87663469f9 100644 --- a/src/test/e2e/27_deploy_regression_test.go +++ b/src/test/e2e/27_deploy_regression_test.go @@ -9,7 +9,6 @@ import ( "testing" "github.com/stretchr/testify/require" - "github.com/zarf-dev/zarf/src/pkg/utils/exec" ) func TestGHCRDeploy(t *testing.T) { @@ -25,20 +24,7 @@ func TestGHCRDeploy(t *testing.T) { } // Test with command from https://docs.zarf.dev/getting-started/install/ - stdOut, stdErr, err := e2e.Zarf(t, "package", "deploy", fmt.Sprintf("oci://🦄/dos-games:1.0.0-%s@sha256:%s", e2e.Arch, sha), "--key=https://zarf.dev/cosign.pub", "--confirm") - require.NoError(t, err, stdOut, stdErr) - - stdOut, stdErr, err = e2e.Zarf(t, "package", "remove", "dos-games", "--confirm") - require.NoError(t, err, stdOut, stdErr) -} - -func TestCosignDeploy(t *testing.T) { - t.Log("E2E: Cosign deploy") - - // Test with command from https://docs.zarf.dev/getting-started/install/ - command := fmt.Sprintf("%s package deploy sget://defenseunicorns/zarf-hello-world:$(uname -m) --confirm", e2e.ZarfBinPath) - - stdOut, stdErr, err := exec.CmdWithTesting(t, exec.PrintCfg(), "sh", "-c", command) + stdOut, stdErr, err := e2e.Zarf(t, "package", "deploy", fmt.Sprintf("oci://🦄/dos-games:1.0.0-%s@sha256:%s", e2e.Arch, sha), "--key=https://raw.githubusercontent.com/zarf-dev/zarf/v0.38.2/cosign.pub", "--confirm") require.NoError(t, err, stdOut, stdErr) stdOut, stdErr, err = e2e.Zarf(t, "package", "remove", "dos-games", "--confirm") From 4f0c94974752c6b62c343a6a074f9244fdc62057 Mon Sep 17 00:00:00 2001 From: Austin Abro <37223396+AustinAbro321@users.noreply.github.com> Date: Thu, 22 Aug 2024 16:55:03 -0400 Subject: [PATCH 15/18] ci: permission at job level (#2922) Signed-off-by: Austin Abro --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f7af1a32de..dd5943aeb6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,7 +1,6 @@ name: Release CLI and Packages on Tag permissions: - id-token: write contents: read on: @@ -13,6 +12,7 @@ jobs: build-release: runs-on: ubuntu-latest permissions: + id-token: write packages: write steps: # Checkout the repo and setup the tooling for this job From db13db9ff7478a70d5fa3dd05e36ba2ca3eacc11 Mon Sep 17 00:00:00 2001 From: Austin Abro <37223396+AustinAbro321@users.noreply.github.com> Date: Thu, 22 Aug 2024 17:12:02 -0400 Subject: [PATCH 16/18] chore: update dos games release (#2921) Signed-off-by: Austin Abro --- .github/workflows/publish-application-packages.yml | 11 ++--------- examples/dos-games/zarf.yaml | 2 +- src/test/e2e/05_tarball_test.go | 2 +- src/test/e2e/06_create_sbom_test.go | 2 +- src/test/e2e/25_helm_test.go | 4 ++-- src/test/e2e/26_simple_packages_test.go | 2 +- src/test/e2e/31_checksum_and_signature_test.go | 2 +- src/test/e2e/32_component_webhooks_test.go | 2 +- 8 files changed, 10 insertions(+), 17 deletions(-) diff --git a/.github/workflows/publish-application-packages.yml b/.github/workflows/publish-application-packages.yml index de96965506..d8e1c34d05 100644 --- a/.github/workflows/publish-application-packages.yml +++ b/.github/workflows/publish-application-packages.yml @@ -6,11 +6,6 @@ permissions: on: workflow_dispatch: - inputs: - branchName: - description: "Branch to build the packages from" - required: true - default: "main" jobs: publish-packages: @@ -20,8 +15,6 @@ jobs: steps: - name: "Checkout Repo" uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - with: - ref: ${{ github.event.inputs.branchName }} - name: Auth with AWS uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2 @@ -48,8 +41,8 @@ jobs: zarf package create -o build -a arm64 examples/dos-games --signing-key=awskms:///${{ secrets.COSIGN_AWS_KMS_KEY }} --confirm # Publish a the signed dos-games package - zarf package publish ./build/zarf-package-dos-games-amd64-1.0.0.tar.zst oci://ghcr.io/zarf-dev/packages --key=https://zarf.dev/cosign.pub - zarf package publish ./build/zarf-package-dos-games-arm64-1.0.0.tar.zst oci://ghcr.io/zarf-dev/packages --key=https://zarf.dev/cosign.pub + zarf package publish ./build/zarf-package-dos-games-amd64-1.1.0.tar.zst oci://ghcr.io/zarf-dev/packages --key=https://zarf.dev/cosign.pub + zarf package publish ./build/zarf-package-dos-games-arm64-1.1.0.tar.zst oci://ghcr.io/zarf-dev/packages --key=https://zarf.dev/cosign.pub # Publish a skeleton of the dos-games package zarf package publish examples/dos-games oci://ghcr.io/zarf-dev/packages diff --git a/examples/dos-games/zarf.yaml b/examples/dos-games/zarf.yaml index 49d49f5be8..87042ca58d 100644 --- a/examples/dos-games/zarf.yaml +++ b/examples/dos-games/zarf.yaml @@ -2,7 +2,7 @@ kind: ZarfPackageConfig metadata: name: dos-games description: Simple example to load classic DOS games into K8s in the airgap - version: 1.0.0 + version: 1.1.0 components: - name: baseline diff --git a/src/test/e2e/05_tarball_test.go b/src/test/e2e/05_tarball_test.go index a9af583002..d1646899cf 100644 --- a/src/test/e2e/05_tarball_test.go +++ b/src/test/e2e/05_tarball_test.go @@ -83,7 +83,7 @@ func TestReproducibleTarballs(t *testing.T) { var ( createPath = filepath.Join("examples", "dos-games") tmp = t.TempDir() - tb = filepath.Join(tmp, fmt.Sprintf("zarf-package-dos-games-%s-1.0.0.tar.zst", e2e.Arch)) + tb = filepath.Join(tmp, fmt.Sprintf("zarf-package-dos-games-%s-1.1.0.tar.zst", e2e.Arch)) unpack1 = filepath.Join(tmp, "unpack1") unpack2 = filepath.Join(tmp, "unpack2") ) diff --git a/src/test/e2e/06_create_sbom_test.go b/src/test/e2e/06_create_sbom_test.go index 26890ccaf9..a3ee3b4118 100644 --- a/src/test/e2e/06_create_sbom_test.go +++ b/src/test/e2e/06_create_sbom_test.go @@ -18,7 +18,7 @@ func TestCreateSBOM(t *testing.T) { tmpdir := t.TempDir() sbomPath := filepath.Join(tmpdir, ".sbom-location") - pkgName := fmt.Sprintf("zarf-package-dos-games-%s-1.0.0.tar.zst", e2e.Arch) + pkgName := fmt.Sprintf("zarf-package-dos-games-%s-1.1.0.tar.zst", e2e.Arch) stdOut, stdErr, err := e2e.Zarf(t, "package", "create", "examples/dos-games", "--sbom-out", sbomPath, "--confirm") require.NoError(t, err, stdOut, stdErr) diff --git a/src/test/e2e/25_helm_test.go b/src/test/e2e/25_helm_test.go index 322d3c89dd..b37c3ad39a 100644 --- a/src/test/e2e/25_helm_test.go +++ b/src/test/e2e/25_helm_test.go @@ -115,7 +115,7 @@ func testHelmEscaping(t *testing.T) { func testHelmUninstallRollback(t *testing.T) { t.Log("E2E: Helm Uninstall and Rollback") - goodPath := fmt.Sprintf("build/zarf-package-dos-games-%s-1.0.0.tar.zst", e2e.Arch) + goodPath := fmt.Sprintf("build/zarf-package-dos-games-%s-1.1.0.tar.zst", e2e.Arch) evilPath := fmt.Sprintf("zarf-package-dos-games-%s.tar.zst", e2e.Arch) // Create the evil package (with the bad service). @@ -172,7 +172,7 @@ func testHelmUninstallRollback(t *testing.T) { func testHelmAdoption(t *testing.T) { t.Log("E2E: Helm Adopt a Deployment") - packagePath := fmt.Sprintf("build/zarf-package-dos-games-%s-1.0.0.tar.zst", e2e.Arch) + packagePath := fmt.Sprintf("build/zarf-package-dos-games-%s-1.1.0.tar.zst", e2e.Arch) deploymentManifest := "src/test/packages/25-manifest-adoption/deployment.yaml" // Deploy dos-games manually into the cluster without Zarf diff --git a/src/test/e2e/26_simple_packages_test.go b/src/test/e2e/26_simple_packages_test.go index 6e4c20bd8a..08df1d709b 100644 --- a/src/test/e2e/26_simple_packages_test.go +++ b/src/test/e2e/26_simple_packages_test.go @@ -18,7 +18,7 @@ import ( func TestDosGames(t *testing.T) { t.Log("E2E: Dos games") - path := filepath.Join("build", fmt.Sprintf("zarf-package-dos-games-%s-1.0.0.tar.zst", e2e.Arch)) + path := filepath.Join("build", fmt.Sprintf("zarf-package-dos-games-%s-1.1.0.tar.zst", e2e.Arch)) // Deploy the game stdOut, stdErr, err := e2e.Zarf(t, "package", "deploy", path, "--confirm") diff --git a/src/test/e2e/31_checksum_and_signature_test.go b/src/test/e2e/31_checksum_and_signature_test.go index b80e83e699..c83888fe00 100644 --- a/src/test/e2e/31_checksum_and_signature_test.go +++ b/src/test/e2e/31_checksum_and_signature_test.go @@ -15,7 +15,7 @@ func TestChecksumAndSignature(t *testing.T) { t.Log("E2E: Checksum and Signature") testPackageDirPath := "examples/dos-games" - pkgName := fmt.Sprintf("zarf-package-dos-games-%s-1.0.0.tar.zst", e2e.Arch) + pkgName := fmt.Sprintf("zarf-package-dos-games-%s-1.1.0.tar.zst", e2e.Arch) privateKeyFlag := "--signing-key=src/test/packages/zarf-test.prv-key" publicKeyFlag := "--key=src/test/packages/zarf-test.pub" diff --git a/src/test/e2e/32_component_webhooks_test.go b/src/test/e2e/32_component_webhooks_test.go index 7d6d761835..18c9ed33cc 100644 --- a/src/test/e2e/32_component_webhooks_test.go +++ b/src/test/e2e/32_component_webhooks_test.go @@ -23,7 +23,7 @@ func TestComponentWebhooks(t *testing.T) { defer e2e.CleanFiles(webhookPath) // Ensure package deployments wait for webhooks to complete. - gamesPath := fmt.Sprintf("build/zarf-package-dos-games-%s-1.0.0.tar.zst", e2e.Arch) + gamesPath := fmt.Sprintf("build/zarf-package-dos-games-%s-1.1.0.tar.zst", e2e.Arch) stdOut, stdErr, err = e2e.Zarf(t, "package", "deploy", gamesPath, "--confirm") require.NoError(t, err, stdOut, stdErr) require.Contains(t, stdErr, "Waiting for webhook \"test-webhook\" to complete for component \"baseline\"") From 72e833488cfed3f1f374039fb2fd239d11c0ed31 Mon Sep 17 00:00:00 2001 From: Austin Abro <37223396+AustinAbro321@users.noreply.github.com> Date: Thu, 22 Aug 2024 18:33:50 -0400 Subject: [PATCH 17/18] ci: id-token write application packages (#2923) Signed-off-by: Austin Abro --- .github/workflows/publish-application-packages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/publish-application-packages.yml b/.github/workflows/publish-application-packages.yml index d8e1c34d05..680fd2eee4 100644 --- a/.github/workflows/publish-application-packages.yml +++ b/.github/workflows/publish-application-packages.yml @@ -1,7 +1,6 @@ name: Zarf Application Package Publishing permissions: - id-token: write contents: read on: @@ -11,6 +10,7 @@ jobs: publish-packages: runs-on: ubuntu-latest permissions: + id-token: write packages: write steps: - name: "Checkout Repo" From 951b4e6893c0143f3ae5c813dfa726a7bc22ca69 Mon Sep 17 00:00:00 2001 From: Austin Abro <37223396+AustinAbro321@users.noreply.github.com> Date: Fri, 23 Aug 2024 09:01:10 -0400 Subject: [PATCH 18/18] docs: update dos games example (#2924) Signed-off-by: Austin Abro --- examples/composable-packages/zarf.yaml | 2 +- site/src/content/docs/getting-started/index.mdx | 4 ++-- src/test/e2e/09_component_compose_test.go | 2 +- src/test/e2e/12_lint_test.go | 4 ++-- src/test/e2e/27_deploy_regression_test.go | 6 +++--- src/test/packages/12-lint/linted-import/zarf.yaml | 2 +- src/test/packages/12-lint/zarf.yaml | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/examples/composable-packages/zarf.yaml b/examples/composable-packages/zarf.yaml index 35dab0b33e..e1cca3388d 100644 --- a/examples/composable-packages/zarf.yaml +++ b/examples/composable-packages/zarf.yaml @@ -31,7 +31,7 @@ components: # default: false # the initial value overrides the child component import: # The URL to the skeleton package containing this component's package definition - url: oci://🦄/dos-games:1.0.0 + url: oci://ghcr.io/zarf-dev/packages/dos-games:1.1.0 # Example optional custom name to point to in the imported package (default is to use this component's name) name: baseline # Un'name'd Zarf primitives will be appended to the end of the primitive's list for that component. diff --git a/site/src/content/docs/getting-started/index.mdx b/site/src/content/docs/getting-started/index.mdx index 2e294ab9b3..c2f4ca042b 100644 --- a/site/src/content/docs/getting-started/index.mdx +++ b/site/src/content/docs/getting-started/index.mdx @@ -23,7 +23,7 @@ import { Tabs, TabItem, LinkCard, CardGrid } from '@astrojs/starlight/components # (Select optional components as desired) # Now you are ready to deploy any Zarf Package, try out our Retro Arcade!! - zarf package deploy oci://🦄/dos-games:1.0.0 --key=https://zarf.dev/cosign.pub + zarf package deploy oci://ghcr.io/zarf-dev/packages/dos-games:1.1.0 --key=https://zarf.dev/cosign.pub # (Select 'Y' to confirm deployment) ``` @@ -39,7 +39,7 @@ import { Tabs, TabItem, LinkCard, CardGrid } from '@astrojs/starlight/components zarf init --confirm # Deploy the DOS Games package - zarf package deploy oci://🦄/dos-games:1.0.0 \ + zarf package deploy oci://ghcr.io/zarf-dev/packages/dos-games:1.1.0 \ --key=https://zarf.dev/cosign.pub \ --confirm ``` diff --git a/src/test/e2e/09_component_compose_test.go b/src/test/e2e/09_component_compose_test.go index e5809df6eb..8c369feab9 100644 --- a/src/test/e2e/09_component_compose_test.go +++ b/src/test/e2e/09_component_compose_test.go @@ -61,7 +61,7 @@ func (suite *CompositionSuite) Test_0_ComposabilityExample() { // Ensure that the action was appended suite.Contains(stdErr, ` - - defenseunicorns/zarf-game:multi-tile-dark + - ghcr.io/zarf-dev/doom-game:0.0.1 actions: onDeploy: before: diff --git a/src/test/e2e/12_lint_test.go b/src/test/e2e/12_lint_test.go index 58e19536ce..dea06dd678 100644 --- a/src/test/e2e/12_lint_test.go +++ b/src/test/e2e/12_lint_test.go @@ -46,14 +46,14 @@ func TestLint(t *testing.T) { // Testing import / compose + variables are working require.Contains(t, strippedStderr, ".components.[2].images.[3] | Image not pinned with digest - busybox:latest") // Testing OCI imports get linted - require.Contains(t, strippedStderr, ".components.[0].images.[0] | Image not pinned with digest - defenseunicorns/zarf-game:multi-tile-dark") + require.Contains(t, strippedStderr, ".components.[0].images.[0] | Image not pinned with digest - ghcr.io/zarf-dev/doom-game:0.0.1") // Check flavors require.NotContains(t, strippedStderr, "image-in-bad-flavor-component:unpinned") require.Contains(t, strippedStderr, "image-in-good-flavor-component:unpinned") // Check reported filepaths - require.Contains(t, strippedStderr, "Linting package \"dos-games\" at oci://🦄/dos-games:1.0.0") + require.Contains(t, strippedStderr, "Linting package \"dos-games\" at oci://ghcr.io/zarf-dev/packages/dos-games:1.1.0") require.Contains(t, strippedStderr, fmt.Sprintf("Linting package \"lint\" at %s", testPackagePath)) }) } diff --git a/src/test/e2e/27_deploy_regression_test.go b/src/test/e2e/27_deploy_regression_test.go index 87663469f9..a4ba8e014f 100644 --- a/src/test/e2e/27_deploy_regression_test.go +++ b/src/test/e2e/27_deploy_regression_test.go @@ -18,13 +18,13 @@ func TestGHCRDeploy(t *testing.T) { // shas for package published 2023-08-08T22:13:51Z switch e2e.Arch { case "arm64": - sha = "ac7d7684ca9b4edb061a7732aefc17cfb7b7c983fec23e1fe319cf535618a8b6" + sha = "844dff9aa60345c67b597d5315db5e263cbda01b50643a8d0b7f5ec721f8a16f" case "amd64": - sha = "aca4d4cf24532d69a8941a446067fc3d8474581507236b37bb7188836d93bf89" + sha = "a44d17160cd6ce7b7b6d4687e7d3f75dad4fedba6670c79665af2e8665a7868e" } // Test with command from https://docs.zarf.dev/getting-started/install/ - stdOut, stdErr, err := e2e.Zarf(t, "package", "deploy", fmt.Sprintf("oci://🦄/dos-games:1.0.0-%s@sha256:%s", e2e.Arch, sha), "--key=https://raw.githubusercontent.com/zarf-dev/zarf/v0.38.2/cosign.pub", "--confirm") + stdOut, stdErr, err := e2e.Zarf(t, "package", "deploy", fmt.Sprintf("oci://ghcr.io/zarf-dev/packages/dos-games:1.1.0@sha256:%s", sha), "--key=https://zarf.dev/cosign.pub", "--confirm") require.NoError(t, err, stdOut, stdErr) stdOut, stdErr, err = e2e.Zarf(t, "package", "remove", "dos-games", "--confirm") diff --git a/src/test/packages/12-lint/linted-import/zarf.yaml b/src/test/packages/12-lint/linted-import/zarf.yaml index 04fdcd47f2..d4a190f9e6 100644 --- a/src/test/packages/12-lint/linted-import/zarf.yaml +++ b/src/test/packages/12-lint/linted-import/zarf.yaml @@ -19,5 +19,5 @@ components: - name: oci-games-url import: - url: oci://🦄/dos-games:1.0.0 + url: oci://ghcr.io/zarf-dev/packages/dos-games:1.1.0 name: baseline diff --git a/src/test/packages/12-lint/zarf.yaml b/src/test/packages/12-lint/zarf.yaml index c4c80ba6ea..8d4d9cd1d1 100644 --- a/src/test/packages/12-lint/zarf.yaml +++ b/src/test/packages/12-lint/zarf.yaml @@ -32,7 +32,7 @@ components: - name: oci-games-url import: - url: oci://🦄/dos-games:1.0.0 + url: oci://ghcr.io/zarf-dev/packages/dos-games:1.1.0 name: baseline - name: oci-games-url