From 891e96ee754dd16dea7c598fc8f3c688c9172336 Mon Sep 17 00:00:00 2001 From: David E Worth Date: Sat, 13 Jul 2024 16:11:50 -0600 Subject: [PATCH 01/68] fix: fix link to CONTRIBUTING.md in PR template (#2726) --- .github/pull_request_template.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index cee28d19f1..370d4faa9a 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -11,4 +11,4 @@ Relates to # ## Checklist before merging - [ ] Test, docs, adr added or updated as needed -- [ ] [Contributor Guide Steps](https://github.com/defenseunicorns/zarf/blob/main/.github/CONTRIBUTING.md#developer-workflow) followed +- [ ] [Contributor Guide Steps](https://github.com/defenseunicorns/zarf/blob/main/CONTRIBUTING.md#developer-workflow) followed From ff50f77bd652a3034fb82e4ebb1da3b739793562 Mon Sep 17 00:00:00 2001 From: Matias Insaurralde Date: Wed, 17 Jul 2024 12:00:02 -0300 Subject: [PATCH 02/68] refactor: compile local cluster service format regexp just once (#2727) --- src/pkg/packager/deploy.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/pkg/packager/deploy.go b/src/pkg/packager/deploy.go index 8c0eb6b7a4..9044772169 100644 --- a/src/pkg/packager/deploy.go +++ b/src/pkg/packager/deploy.go @@ -38,6 +38,11 @@ import ( "github.com/defenseunicorns/zarf/src/types" ) +var ( + // localClusterServiceRegex is used to match the local cluster service format: + localClusterServiceRegex = regexp.MustCompile(`^(?P[^\.]+)\.(?P[^\.]+)\.svc\.cluster\.local$`) +) + func (p *Packager) resetRegistryHPA(ctx context.Context) { if p.isConnectedToCluster() && p.hpaModified { if err := p.cluster.EnableRegHPAScaleDown(ctx); err != nil { @@ -742,11 +747,7 @@ func serviceInfoFromServiceURL(serviceURL string) (string, string, int, error) { } // Match hostname against local cluster service format. - pattern, err := regexp.Compile(`^(?P[^\.]+)\.(?P[^\.]+)\.svc\.cluster\.local$`) - if err != nil { - return "", "", 0, err - } - get, err := helpers.MatchRegex(pattern, parsedURL.Hostname()) + get, err := helpers.MatchRegex(localClusterServiceRegex, parsedURL.Hostname()) // If incomplete match, return an error. if err != nil { From 37aa79da4c93023ff593da39a603ebe5352de6f2 Mon Sep 17 00:00:00 2001 From: Austin Abro <37223396+AustinAbro321@users.noreply.github.com> Date: Wed, 17 Jul 2024 15:54:39 -0400 Subject: [PATCH 03/68] chore: update s3 injector (#2730) --- .github/workflows/build-rust-injector.yml | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build-rust-injector.yml b/.github/workflows/build-rust-injector.yml index 270a091fcf..77d939f6f7 100644 --- a/.github/workflows/build-rust-injector.yml +++ b/.github/workflows/build-rust-injector.yml @@ -9,9 +9,6 @@ on: versionTag: description: "Version tag" required: true - branchName: - description: "Branch to build the injector from" - required: true jobs: build-injector: @@ -19,8 +16,6 @@ jobs: steps: - name: "Checkout Repo" uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - ref: ${{ github.event.inputs.branchName }} - name: Install tools uses: ./.github/actions/install-tools @@ -37,13 +32,14 @@ jobs: shasum zarf-injector-amd64 >> checksums.txt shasum zarf-injector-arm64 >> checksums.txt - - name: Set AWS Credentials + - name: Auth with AWS uses: aws-actions/configure-aws-credentials@010d0da01d0b5a38af31e9c3470dbfdabdecca3a # v4.0.1 with: - aws-access-key-id: ${{ secrets.AWS_GOV_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ secrets.AWS_GOV_SECRET_ACCESS_KEY }} - aws-region: us-gov-west-1 + role-to-assume: ${{ secrets.AWS_WRITE_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: Sync Artifacts to S3 run: | - aws s3 sync src/injector/dist/ s3://zarf-public/injector/${{ github.event.inputs.versionTag }}/ + aws s3 sync src/injector/dist/ s3://zarf-init/injector/${{ github.event.inputs.versionTag }}/ From 6d7e90ad42c3858f69557b20761a8c9bf7fdc65d Mon Sep 17 00:00:00 2001 From: Xander Grzywinski Date: Thu, 18 Jul 2024 11:40:56 -0400 Subject: [PATCH 04/68] docs: fix codeowners file Signed-off-by: Xander Grzywinski --- CODEOWNERS | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index c713375a0d..976d425740 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,5 +1,5 @@ -* @defenseunicorns/zarf @dgershman +* @zarf-dev/maintainers @zarf-dev/reviewers -/CODEOWNERS @jeff-mccoy @austenbryan -/cosign.pub @jeff-mccoy @austenbryan -/LICENSE @jeff-mccoy @austenbryan +/CODEOWNERS @zarf-dev/tsc +/cosign.pub @zarf-dev/tsc +/LICENSE @zarf-dev/tsc From 62253cecc6b94cd2d42d79caacf57061dad8548a Mon Sep 17 00:00:00 2001 From: Philip Laine Date: Wed, 17 Jul 2024 19:20:44 +0200 Subject: [PATCH 05/68] Rename org name in image references Signed-off-by: Philip Laine --- .github/workflows/publish-application-packages.yml | 8 ++++---- .github/workflows/release.yml | 10 +++++----- .github/workflows/test-upgrade.yml | 2 +- Makefile | 2 +- src/config/config.go | 2 +- src/pkg/zoci/utils.go | 2 +- src/test/e2e/08_create_differential_test.go | 2 +- src/test/e2e/11_oci_pull_inspect_test.go | 4 ++-- src/test/e2e/13_find_images_test.go | 2 +- src/test/e2e/14_create_sha_index_test.go | 2 +- src/test/e2e/21_connect_creds_test.go | 2 +- src/test/packages/00-remote-pull-fail/zarf.yaml | 2 +- src/test/packages/08-differential-package/zarf.yaml | 2 +- src/test/packages/14-index-sha/image-index/zarf.yaml | 2 +- zarf-config.toml | 2 +- 15 files changed, 23 insertions(+), 23 deletions(-) diff --git a/.github/workflows/publish-application-packages.yml b/.github/workflows/publish-application-packages.yml index c30c7105fa..59be8e3ff3 100644 --- a/.github/workflows/publish-application-packages.yml +++ b/.github/workflows/publish-application-packages.yml @@ -23,7 +23,7 @@ jobs: ref: ${{ github.event.inputs.branchName }} - name: Install The Latest Release Version of Zarf - uses: defenseunicorns/setup-zarf@f95763914e20e493bb5d45d63e30e17138f981d6 # v1.0.0 + uses: defenseunicorns/setup-zarf@10e539efed02f75ec39eb8823e22a5c795f492ae #v1.0.1 - name: "Login to GHCR" uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0 @@ -39,11 +39,11 @@ 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/defenseunicorns/packages --key=https://zarf.dev/cosign.pub - zarf package publish ./build/zarf-package-dos-games-arm64-1.0.0.tar.zst oci://ghcr.io/defenseunicorns/packages --key=https://zarf.dev/cosign.pub + 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 # Publish a skeleton of the dos-games package - zarf package publish examples/dos-games oci://ghcr.io/defenseunicorns/packages + 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 }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2f23f8c9c3..f8e6e36604 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -42,13 +42,13 @@ jobs: run: | cp build/zarf build/zarf-linux-amd64 cp build/zarf-arm build/zarf-linux-arm64 - docker buildx build --push --platform linux/arm64/v8,linux/amd64 --tag ghcr.io/defenseunicorns/zarf/agent:$GITHUB_REF_NAME . + docker buildx build --push --platform linux/arm64/v8,linux/amd64 --tag ghcr.io/zarf-dev/zarf/agent:$GITHUB_REF_NAME . rm build/zarf-linux-amd64 rm build/zarf-linux-arm64 - echo ZARF_AGENT_IMAGE_DIGEST=$(docker buildx imagetools inspect ghcr.io/defenseunicorns/zarf/agent:$GITHUB_REF_NAME --format '{{ json . }}' | jq -r .manifest.digest) >> $GITHUB_ENV + 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: "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/defenseunicorns/zarf/agent@$ZARF_AGENT_IMAGE_DIGEST -y + 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 }} @@ -63,8 +63,8 @@ jobs: - name: Publish Init Package as OCI and Skeleton run: | - make publish-init-package ARCH=amd64 REPOSITORY_URL=ghcr.io/defenseunicorns/packages - make publish-init-package ARCH=arm64 REPOSITORY_URL=ghcr.io/defenseunicorns/packages + make publish-init-package ARCH=amd64 REPOSITORY_URL=ghcr.io/zerf-dev/packages + make publish-init-package ARCH=arm64 REPOSITORY_URL=ghcr.io/zarf-dev/packages # Create a CVE report based on this build - name: Create release time CVE report diff --git a/.github/workflows/test-upgrade.yml b/.github/workflows/test-upgrade.yml index 4bbcf170b5..552d79e103 100644 --- a/.github/workflows/test-upgrade.yml +++ b/.github/workflows/test-upgrade.yml @@ -73,7 +73,7 @@ jobs: chmod +x build/zarf - name: Install release version of Zarf - uses: defenseunicorns/setup-zarf@f95763914e20e493bb5d45d63e30e17138f981d6 # v1.0.0 + uses: defenseunicorns/setup-zarf@10e539efed02f75ec39eb8823e22a5c795f492ae #v1.0.1 with: download-init-package: true diff --git a/Makefile b/Makefile index 9a4fa4e58e..0f2deebcaf 100644 --- a/Makefile +++ b/Makefile @@ -121,7 +121,7 @@ build-local-agent-image: ## Build the Zarf agent image to be used in a locally b @ if [ "$(ARCH)" = "amd64" ]; then cp build/zarf build/zarf-linux-amd64; fi @ if [ "$(ARCH)" = "arm64" ] && [ ! -s ./build/zarf-arm ]; then $(MAKE) build-cli-linux-arm; fi @ if [ "$(ARCH)" = "arm64" ]; then cp build/zarf-arm build/zarf-linux-arm64; fi - docker buildx build --load --platform linux/$(ARCH) --tag ghcr.io/defenseunicorns/zarf/agent:local . + docker buildx build --load --platform linux/$(ARCH) --tag ghcr.io/zarf-dev/zarf/agent:local . @ if [ "$(ARCH)" = "amd64" ]; then rm build/zarf-linux-amd64; fi @ if [ "$(ARCH)" = "arm64" ]; then rm build/zarf-linux-arm64; fi diff --git a/src/config/config.go b/src/config/config.go index f9dfc580ab..203767f6d8 100644 --- a/src/config/config.go +++ b/src/config/config.go @@ -17,7 +17,7 @@ import ( // Zarf Global Configuration Constants. const ( - GithubProject = "defenseunicorns/zarf" + GithubProject = "zarf-dev/zarf" ZarfAgentHost = "agent-hook.zarf.svc" diff --git a/src/pkg/zoci/utils.go b/src/pkg/zoci/utils.go index e63910a738..bcd5da45d4 100644 --- a/src/pkg/zoci/utils.go +++ b/src/pkg/zoci/utils.go @@ -43,5 +43,5 @@ func ReferenceFromMetadata(registryLocation string, metadata *types.ZarfMetadata // GetInitPackageURL returns the URL for the init package for the given version. func GetInitPackageURL(version string) string { - return fmt.Sprintf("ghcr.io/defenseunicorns/packages/init:%s", version) + return fmt.Sprintf("ghcr.io/zarf-dev/packages/init:%s", version) } diff --git a/src/test/e2e/08_create_differential_test.go b/src/test/e2e/08_create_differential_test.go index 042ed2e185..ff0a1a698c 100644 --- a/src/test/e2e/08_create_differential_test.go +++ b/src/test/e2e/08_create_differential_test.go @@ -73,7 +73,7 @@ func TestCreateDifferential(t *testing.T) { /* Validate we have ONLY the images we expect to have */ expectedImages := []string{ "ghcr.io/stefanprodan/podinfo:latest", - "ghcr.io/defenseunicorns/zarf/agent:v0.26.0", + "ghcr.io/zarf-dev/zarf/agent:v0.26.0", } require.Len(t, actualImages, 2, "zarf.yaml from the differential package does not contain the correct number of images") for _, expectedImage := range expectedImages { diff --git a/src/test/e2e/11_oci_pull_inspect_test.go b/src/test/e2e/11_oci_pull_inspect_test.go index 47d31232fb..98e5e4ff52 100644 --- a/src/test/e2e/11_oci_pull_inspect_test.go +++ b/src/test/e2e/11_oci_pull_inspect_test.go @@ -42,7 +42,7 @@ func (suite *PullInspectTestSuite) Test_0_Pull() { out := fmt.Sprintf("zarf-package-dos-games-%s-1.0.0.tar.zst", e2e.Arch) // Build the fully qualified reference. - ref := fmt.Sprintf("oci://ghcr.io/defenseunicorns/packages/dos-games:1.0.0-%s", e2e.Arch) + ref := fmt.Sprintf("oci://ghcr.io/zarf-dev/packages/dos-games:1.0.0-%s", e2e.Arch) // Pull the package via OCI. stdOut, stdErr, err := e2e.Zarf("package", "pull", ref) @@ -74,7 +74,7 @@ func (suite *PullInspectTestSuite) Test_1_Remote_Inspect() { // Test inspect on a public package. // NOTE: This also makes sure that Zarf does not attempt auth when inspecting a public package. - ref := fmt.Sprintf("oci://ghcr.io/defenseunicorns/packages/dos-games:1.0.0-%s", e2e.Arch) + ref := fmt.Sprintf("oci://ghcr.io/zarf-dev/packages/dos-games:1.0.0-%s", e2e.Arch) _, stdErr, err = e2e.Zarf("package", "inspect", ref) suite.NoError(err, stdErr) } diff --git a/src/test/e2e/13_find_images_test.go b/src/test/e2e/13_find_images_test.go index fbb0185320..27e7bbe715 100644 --- a/src/test/e2e/13_find_images_test.go +++ b/src/test/e2e/13_find_images_test.go @@ -53,7 +53,7 @@ func TestFindImages(t *testing.T) { stdOut, _, err := e2e.Zarf("prepare", "find-images", ".", "--registry-url", registry, "--create-set", fmt.Sprintf("agent_image_tag=%s", agentTag)) require.NoError(t, err) - internalRegistryImage := fmt.Sprintf("%s/%s:%s", registry, "defenseunicorns/zarf/agent", agentTag) + internalRegistryImage := fmt.Sprintf("%s/%s:%s", registry, "zarf-dev/zarf/agent", agentTag) require.Contains(t, stdOut, internalRegistryImage, "registry image should be found with registry url") require.Contains(t, stdOut, "busybox:latest", "Busybox image should be found as long as helm chart doesn't error") diff --git a/src/test/e2e/14_create_sha_index_test.go b/src/test/e2e/14_create_sha_index_test.go index 9dee622c85..59993c5874 100644 --- a/src/test/e2e/14_create_sha_index_test.go +++ b/src/test/e2e/14_create_sha_index_test.go @@ -21,7 +21,7 @@ func TestCreateIndexShaErrors(t *testing.T) { { name: "Image Index", packagePath: "src/test/packages/14-index-sha/image-index", - expectedImageInStderr: "ghcr.io/defenseunicorns/zarf/agent:v0.32.6@sha256:b3fabdc7d4ecd0f396016ef78da19002c39e3ace352ea0ae4baa2ce9d5958376", + expectedImageInStderr: "ghcr.io/zarf-dev/zarf/agent:v0.32.6@sha256:b3fabdc7d4ecd0f396016ef78da19002c39e3ace352ea0ae4baa2ce9d5958376", }, { name: "Manifest List", diff --git a/src/test/e2e/21_connect_creds_test.go b/src/test/e2e/21_connect_creds_test.go index 3a929ac596..8a2a1f65ba 100644 --- a/src/test/e2e/21_connect_creds_test.go +++ b/src/test/e2e/21_connect_creds_test.go @@ -88,7 +88,7 @@ func connectToZarfServices(ctx context.Context, t *testing.T) { // We assert greater than or equal to since the base init has 8 images // HOWEVER during an upgrade we could have mismatched versions/names resulting in more images require.GreaterOrEqual(t, len(registryList), 3) - require.Contains(t, stdOut, "defenseunicorns/zarf/agent") + require.Contains(t, stdOut, "zarf-dev/zarf/agent") require.Contains(t, stdOut, "gitea/gitea") require.Contains(t, stdOut, "library/registry") diff --git a/src/test/packages/00-remote-pull-fail/zarf.yaml b/src/test/packages/00-remote-pull-fail/zarf.yaml index f44d99d4b1..b2212b15d6 100644 --- a/src/test/packages/00-remote-pull-fail/zarf.yaml +++ b/src/test/packages/00-remote-pull-fail/zarf.yaml @@ -5,4 +5,4 @@ components: - name: doesnotexist-docker required: true images: - - ghcr.io/defenseunicorns/doesnotexist:1.3.3.7 + - ghcr.io/zarf-dev/doesnotexist:1.3.3.7 diff --git a/src/test/packages/08-differential-package/zarf.yaml b/src/test/packages/08-differential-package/zarf.yaml index 9d911a66d0..c1e5d4ab71 100644 --- a/src/test/packages/08-differential-package/zarf.yaml +++ b/src/test/packages/08-differential-package/zarf.yaml @@ -9,7 +9,7 @@ components: required: true images: - ghcr.io/stefanprodan/podinfo:6.0.0 - - ghcr.io/defenseunicorns/zarf/agent:###ZARF_PKG_TMPL_PACKAGE_VERSION### + - ghcr.io/zarf-dev/zarf/agent:###ZARF_PKG_TMPL_PACKAGE_VERSION### repos: - https://github.com/defenseunicorns/zarf.git@c74e2e9626da0400e0a41e78319b3054c53a5d4e - https://github.com/defenseunicorns/zarf.git@refs/tags/###ZARF_PKG_TMPL_PACKAGE_VERSION### diff --git a/src/test/packages/14-index-sha/image-index/zarf.yaml b/src/test/packages/14-index-sha/image-index/zarf.yaml index a29c4380b9..76d3e6ab4f 100644 --- a/src/test/packages/14-index-sha/image-index/zarf.yaml +++ b/src/test/packages/14-index-sha/image-index/zarf.yaml @@ -6,4 +6,4 @@ components: - name: baseline required: true images: - - ghcr.io/defenseunicorns/zarf/agent:v0.32.6@sha256:05a82656df5466ce17c3e364c16792ae21ce68438bfe06eeab309d0520c16b48 + - ghcr.io/zarf-dev/zarf/agent:v0.32.6@sha256:05a82656df5466ce17c3e364c16792ae21ce68438bfe06eeab309d0520c16b48 diff --git a/zarf-config.toml b/zarf-config.toml index eb549dac54..09afb3eed3 100644 --- a/zarf-config.toml +++ b/zarf-config.toml @@ -1,7 +1,7 @@ [package.create.set] # The image reference to use for the Zarf agent, defaults to a locally built image agent_image_domain = 'ghcr.io/' -agent_image = 'defenseunicorns/zarf/agent' +agent_image = 'zarf-dev/zarf/agent' agent_image_tag = 'local' # Tag for the zarf injector binary to use From a550ac14d2fe9ac1fea86c30c13c01688743b359 Mon Sep 17 00:00:00 2001 From: Austin Abro <37223396+AustinAbro321@users.noreply.github.com> Date: Fri, 19 Jul 2024 12:24:15 -0400 Subject: [PATCH 06/68] chore: move public test repo (#2739) Signed-off-by: Austin Abro --- .github/workflows/build-rust-injector.yml | 1 + .github/workflows/dummy-dco.yaml | 12 ++++++++++++ examples/git-data/zarf.yaml | 10 +++++----- src/pkg/packager/lint/lint_test.go | 2 +- src/test/e2e/07_create_git_test.go | 10 +++++----- src/test/e2e/09_component_compose_test.go | 4 ++-- src/test/e2e/22_git_and_gitops_test.go | 4 ++-- .../09-composable-packages/sub-package/zarf.yaml | 2 +- src/test/packages/09-composable-packages/zarf.yaml | 2 +- src/test/packages/12-lint/zarf.yaml | 2 +- src/test/packages/22-git-data/zarf.yaml | 12 +++++------- 11 files changed, 36 insertions(+), 25 deletions(-) create mode 100644 .github/workflows/dummy-dco.yaml diff --git a/.github/workflows/build-rust-injector.yml b/.github/workflows/build-rust-injector.yml index 77d939f6f7..eb41af52c7 100644 --- a/.github/workflows/build-rust-injector.yml +++ b/.github/workflows/build-rust-injector.yml @@ -2,6 +2,7 @@ name: Zarf Injector Rust Binaries permissions: contents: read + id-token: write on: workflow_dispatch: diff --git a/.github/workflows/dummy-dco.yaml b/.github/workflows/dummy-dco.yaml new file mode 100644 index 0000000000..25f022c804 --- /dev/null +++ b/.github/workflows/dummy-dco.yaml @@ -0,0 +1,12 @@ +name: DCO +on: + merge_group: + +permissions: + contents: read + +jobs: + DCO: + runs-on: ubuntu-latest + steps: + - run: echo "dummy DCO workflow (it won't run any check actually) to trigger by merge_group in order to enable merge queue" diff --git a/examples/git-data/zarf.yaml b/examples/git-data/zarf.yaml index 01e2c5d4eb..f2294f7c09 100644 --- a/examples/git-data/zarf.yaml +++ b/examples/git-data/zarf.yaml @@ -8,30 +8,30 @@ components: - name: full-repo repos: # The following performs a full Git Repo Mirror with `go-git` (internal to Zarf) - - https://github.com/defenseunicorns/zarf-public-test.git + - https://github.com/zarf-dev/zarf-public-test.git # The following performs a full Git Repo Mirror forcing a fallback to host `git` - https://dev.azure.com/defenseunicorns/zarf-public-test/_git/zarf-public-test - name: specific-tag repos: # The following performs a tag Git Repo Mirror with `go-git` (internal to Zarf) - - https://github.com/defenseunicorns/zarf-public-test.git@v0.0.1 + - https://github.com/zarf-dev/zarf-public-test.git@v0.0.1 # The following performs a refspec tag Git Repo Mirror with `go-git` - - https://github.com/defenseunicorns/zarf-public-test.git@refs/tags/v0.0.1 + - https://github.com/zarf-dev/zarf-public-test.git@refs/tags/v0.0.1 # The following performs a tag Git Repo Mirror forcing a fallback to host `git` - https://dev.azure.com/defenseunicorns/zarf-public-test/_git/zarf-public-test@v0.0.1 - name: specific-branch repos: # The following performs a branch Git Repo Mirror with `go-git` (internal to Zarf) - - https://github.com/defenseunicorns/zarf-public-test.git@refs/heads/dragons + - https://github.com/zarf-dev/zarf-public-test.git@refs/heads/dragons # The following performs a branch Git Repo Mirror forcing a fallback to host `git` - https://dev.azure.com/defenseunicorns/zarf-public-test/_git/zarf-public-test@refs/heads/dragons - name: specific-hash repos: # The following performs a SHA Git Repo Mirror with `go-git` (internal to Zarf) - - https://github.com/defenseunicorns/zarf-public-test.git@01a23218923f24194133b5eb11268cf8d73ff1bb + - https://github.com/zarf-dev/zarf-public-test.git@01a23218923f24194133b5eb11268cf8d73ff1bb # The following performs a SHA Git Repo Mirror forcing a fallback to host `git` - https://dev.azure.com/defenseunicorns/zarf-public-test/_git/zarf-public-test@01a23218923f24194133b5eb11268cf8d73ff1bb diff --git a/src/pkg/packager/lint/lint_test.go b/src/pkg/packager/lint/lint_test.go index d20257b23a..67af529a8d 100644 --- a/src/pkg/packager/lint/lint_test.go +++ b/src/pkg/packager/lint/lint_test.go @@ -196,7 +196,7 @@ func TestValidateComponent(t *testing.T) { t.Run("Unpinnned repo warning", func(t *testing.T) { t.Parallel() - unpinnedRepo := "https://github.com/defenseunicorns/zarf-public-test.git" + unpinnedRepo := "https://github.com/zarf-dev/zarf-public-test.git" component := types.ZarfComponent{Repos: []string{ unpinnedRepo, "https://dev.azure.com/defenseunicorns/zarf-public-test/_git/zarf-public-test@v0.0.1", diff --git a/src/test/e2e/07_create_git_test.go b/src/test/e2e/07_create_git_test.go index 115558ace9..6c1e3a38c6 100644 --- a/src/test/e2e/07_create_git_test.go +++ b/src/test/e2e/07_create_git_test.go @@ -26,7 +26,7 @@ func TestCreateGit(t *testing.T) { defer e2e.CleanFiles(extractDir) // Verify the full-repo component - gitDir := fmt.Sprintf("%s/components/full-repo/repos/zarf-public-test-1143224168/.git", extractDir) + gitDir := fmt.Sprintf("%s/components/full-repo/repos/zarf-public-test-2395699829/.git", extractDir) verifyGitRepo(t, gitDir, "0a6b587", "(HEAD -> main, online-upstream/main)", "Adjust dragon spacing", "v0.0.1\n", " dragons\n* main\n") @@ -38,13 +38,13 @@ func TestCreateGit(t *testing.T) { "v0.0.1\n", " dragons\n* main\n") // Verify specific tag component shorthand tag - gitDir = fmt.Sprintf("%s/components/specific-tag/repos/zarf-public-test-443792367/.git", extractDir) + gitDir = fmt.Sprintf("%s/components/specific-tag/repos/zarf-public-test-470731282/.git", extractDir) verifyGitRepo(t, gitDir, "5249809", "(HEAD -> zarf-ref-v0.0.1, tag: v0.0.1)", "Added README.md", "v0.0.1\n", "* zarf-ref-v0.0.1\n") // Verify specific tag component refspec tag - gitDir = fmt.Sprintf("%s/components/specific-tag/repos/zarf-public-test-1981411475/.git", extractDir) + gitDir = fmt.Sprintf("%s/components/specific-tag/repos/zarf-public-test-482869567/.git", extractDir) verifyGitRepo(t, gitDir, "5249809", "(HEAD -> zarf-ref-v0.0.1, tag: v0.0.1)", "Added README.md", "v0.0.1\n", "* zarf-ref-v0.0.1\n") @@ -56,7 +56,7 @@ func TestCreateGit(t *testing.T) { "v0.0.1\n", "* zarf-ref-v0.0.1\n") // Verify specific branch component - gitDir = fmt.Sprintf("%s/components/specific-branch/repos/zarf-public-test-1670574289/.git", extractDir) + gitDir = fmt.Sprintf("%s/components/specific-branch/repos/zarf-public-test-2265377406/.git", extractDir) verifyGitRepo(t, gitDir, "01a2321", "(HEAD -> dragons, online-upstream/dragons)", "Explain what this repo does", "", "* dragons\n") @@ -68,7 +68,7 @@ func TestCreateGit(t *testing.T) { "", "* dragons\n") // Verify specific hash component - gitDir = fmt.Sprintf("%s/components/specific-hash/repos/zarf-public-test-2357350897/.git", extractDir) + gitDir = fmt.Sprintf("%s/components/specific-hash/repos/zarf-public-test-3231174532/.git", extractDir) verifyGitRepo(t, gitDir, "01a2321", "(HEAD -> zarf-ref-01a23218923f24194133b5eb11268cf8d73ff1bb, online-upstream/dragons)", "Explain what this repo does", "v0.0.1\n", " main\n* zarf-ref-01a23218923f24194133b5eb11268cf8d73ff1bb\n") diff --git a/src/test/e2e/09_component_compose_test.go b/src/test/e2e/09_component_compose_test.go index c5edaeb682..176b96207e 100644 --- a/src/test/e2e/09_component_compose_test.go +++ b/src/test/e2e/09_component_compose_test.go @@ -139,8 +139,8 @@ func (suite *CompositionSuite) Test_1_FullComposability() { - ghcr.io/stefanprodan/podinfo:6.4.0 - ghcr.io/stefanprodan/podinfo:6.4.1 repos: - - https://github.com/defenseunicorns/zarf-public-test.git - - https://github.com/defenseunicorns/zarf-public-test.git@refs/heads/dragons + - https://github.com/zarf-dev/zarf-public-test.git + - https://github.com/zarf-dev/zarf-public-test.git@refs/heads/dragons `) // Check dataInjections diff --git a/src/test/e2e/22_git_and_gitops_test.go b/src/test/e2e/22_git_and_gitops_test.go index 956ded5ed9..572702dbe4 100644 --- a/src/test/e2e/22_git_and_gitops_test.go +++ b/src/test/e2e/22_git_and_gitops_test.go @@ -77,7 +77,7 @@ func testGitServerReadOnly(ctx context.Context, t *testing.T, gitURL string) { gitCfg := git.New(zarfState.GitServer) // Get the repo as the readonly user - repoName := "zarf-public-test-2469062884" + repoName := "zarf-public-test-2363058019" getRepoRequest, _ := http.NewRequest("GET", fmt.Sprintf("%s/api/v1/repos/%s/%s", gitURL, zarfState.GitServer.PushUsername, repoName), nil) getRepoResponseBody, _, err := gitCfg.DoHTTPThings(getRepoRequest, types.ZarfGitReadUser, zarfState.GitServer.PullPassword) require.NoError(t, err) @@ -101,7 +101,7 @@ func testGitServerTagAndHash(ctx context.Context, t *testing.T, gitURL string) { // Init the state variable zarfState, err := c.LoadZarfState(ctx) require.NoError(t, err, "Failed to load Zarf state") - repoName := "zarf-public-test-2469062884" + repoName := "zarf-public-test-2363058019" gitCfg := git.New(zarfState.GitServer) diff --git a/src/test/packages/09-composable-packages/sub-package/zarf.yaml b/src/test/packages/09-composable-packages/sub-package/zarf.yaml index 20b0a5b323..a749d669fb 100644 --- a/src/test/packages/09-composable-packages/sub-package/zarf.yaml +++ b/src/test/packages/09-composable-packages/sub-package/zarf.yaml @@ -26,7 +26,7 @@ components: images: - ghcr.io/stefanprodan/podinfo:6.4.0 repos: - - https://github.com/defenseunicorns/zarf-public-test.git + - https://github.com/zarf-dev/zarf-public-test.git files: - source: ../files/coffee-ipsum.txt target: coffee-ipsum.txt diff --git a/src/test/packages/09-composable-packages/zarf.yaml b/src/test/packages/09-composable-packages/zarf.yaml index cf121120e6..6ec2dd49b8 100644 --- a/src/test/packages/09-composable-packages/zarf.yaml +++ b/src/test/packages/09-composable-packages/zarf.yaml @@ -40,7 +40,7 @@ components: images: - ghcr.io/stefanprodan/podinfo:6.4.1 repos: - - https://github.com/defenseunicorns/zarf-public-test.git@refs/heads/dragons + - https://github.com/zarf-dev/zarf-public-test.git@refs/heads/dragons files: - source: files/coffee-ipsum.txt target: coffee-ipsum.txt diff --git a/src/test/packages/12-lint/zarf.yaml b/src/test/packages/12-lint/zarf.yaml index 84f5b53c72..a77e3f89c9 100644 --- a/src/test/packages/12-lint/zarf.yaml +++ b/src/test/packages/12-lint/zarf.yaml @@ -14,7 +14,7 @@ components: - name: full-repo repos: - - https://github.com/defenseunicorns/zarf-public-test.git + - https://github.com/zarf-dev/zarf-public-test.git - https://dev.azure.com/defenseunicorns/zarf-public-test/_git/zarf-public-test@v0.0.1 - https://gitlab.com/gitlab-org/build/omnibus-mirror/pcre2/-/tree/vreverse?ref_type=heads images: diff --git a/src/test/packages/22-git-data/zarf.yaml b/src/test/packages/22-git-data/zarf.yaml index 2e3b56d75c..8051918672 100644 --- a/src/test/packages/22-git-data/zarf.yaml +++ b/src/test/packages/22-git-data/zarf.yaml @@ -9,19 +9,17 @@ components: required: true repos: # Do a full Git Repo Mirror - - https://github.com/defenseunicorns/zarf-public-test.git + - https://github.com/zarf-dev/zarf-public-test.git # The following performs a full Git Repo Mirror forcing a fallback to host `git` - https://dev.azure.com/defenseunicorns/zarf-public-test/_git/zarf-public-test - # Perform a full repo mirror of a simple repository with a single branch - (this causes an "already up to date" error in go-git) - - https://github.com/defenseunicorns/golang-tekton-hello-world.git - name: specific-tag required: true repos: # The following performs a tag Git Repo Mirror with `go-git` (internal to Zarf) - - https://github.com/defenseunicorns/zarf-public-test.git@v0.0.1 + - https://github.com/zarf-dev/zarf-public-test.git@v0.0.1 # The following performs a refspec tag Git Repo Mirror with `go-git` - - https://github.com/defenseunicorns/zarf-public-test.git@refs/tags/v0.0.1 + - https://github.com/zarf-dev/zarf-public-test.git@refs/tags/v0.0.1 # The following performs a tag Git Repo Mirror forcing a fallback to host `git` - https://dev.azure.com/defenseunicorns/zarf-public-test/_git/zarf-public-test@v0.0.1 actions: @@ -36,7 +34,7 @@ components: required: true repos: # The following performs a branch Git Repo Mirror with `go-git` (internal to Zarf) - - https://github.com/defenseunicorns/zarf-public-test.git@refs/heads/dragons + - https://github.com/zarf-dev/zarf-public-test.git@refs/heads/dragons # The following performs a branch Git Repo Mirror forcing a fallback to host `git` - https://dev.azure.com/defenseunicorns/zarf-public-test/_git/zarf-public-test@refs/heads/dragons actions: @@ -51,7 +49,7 @@ components: required: true repos: # The following performs a SHA Git Repo Mirror with `go-git` (internal to Zarf) - - https://github.com/defenseunicorns/zarf-public-test.git@01a23218923f24194133b5eb11268cf8d73ff1bb + - https://github.com/zarf-dev/zarf-public-test.git@01a23218923f24194133b5eb11268cf8d73ff1bb # The following performs a SHA Git Repo Mirror forcing a fallback to host `git` - https://dev.azure.com/defenseunicorns/zarf-public-test/_git/zarf-public-test@01a23218923f24194133b5eb11268cf8d73ff1bb actions: From 0a5d54c883ca48e1dea441b0071a2368d13d63e7 Mon Sep 17 00:00:00 2001 From: schristoff-du <167717759+schristoff-du@users.noreply.github.com> Date: Fri, 19 Jul 2024 12:51:48 -0400 Subject: [PATCH 07/68] fix: update README.md (#2729) --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 221ac84ae0..88385564ce 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,6 @@ [![Latest Release](https://img.shields.io/github/v/release/defenseunicorns/zarf)](https://github.com/defenseunicorns/zarf/releases) [![Go version](https://img.shields.io/github/go-mod/go-version/defenseunicorns/zarf?filename=go.mod)](https://go.dev/) [![Build Status](https://img.shields.io/github/actions/workflow/status/defenseunicorns/zarf/release.yml)](https://github.com/defenseunicorns/zarf/actions/workflows/release.yml) -[![Zarf Documentation Status](https://api.netlify.com/api/v1/badges/fe846ae4-25fb-4274-9968-90782640ee9f/deploy-status)](https://app.netlify.com/sites/zarf-docs/deploys) [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/defenseunicorns/zarf/badge)](https://securityscorecards.dev/viewer/?uri=github.com/defenseunicorns/zarf) zarf logo From 4bd52447194a771d38f6694027d90b6ee8c4aa2b Mon Sep 17 00:00:00 2001 From: Xander Grzywinski Date: Fri, 19 Jul 2024 13:23:57 -0400 Subject: [PATCH 08/68] docs: update to openssf code of conduct (#2734) Signed-off-by: Xander Grzywinski Co-authored-by: schristoff <28318173+schristoff@users.noreply.github.com> --- CODE_OF_CONDUCT.md | 133 +-------------------------------------------- README.md | 1 - 2 files changed, 1 insertion(+), 133 deletions(-) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index a7d8c48f7e..6dd1456839 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,132 +1 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -We as members, contributors, and leaders pledge to make participation in our -community a harassment-free experience for everyone, regardless of age, body -size, visible or invisible disability, ethnicity, sex characteristics, gender -identity and expression, level of experience, education, socio-economic status, -nationality, personal appearance, race, caste, color, religion, or sexual -identity and orientation. - -We pledge to act and interact in ways that contribute to an open, welcoming, -diverse, inclusive, and healthy community. - -## Our Standards - -Examples of behavior that contributes to a positive environment for our -community include: - -* Demonstrating empathy and kindness toward other people -* Being respectful of differing opinions, viewpoints, and experiences -* Giving and gracefully accepting constructive feedback -* Accepting responsibility and apologizing to those affected by our mistakes, - and learning from the experience -* Focusing on what is best not just for us as individuals, but for the overall - community - -Examples of unacceptable behavior include: - -* The use of sexualized language or imagery, and sexual attention or advances of - any kind -* Trolling, insulting or derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or email address, - without their explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting - -## Enforcement Responsibilities - -Community leaders are responsible for clarifying and enforcing our standards of -acceptable behavior and will take appropriate and fair corrective action in -response to any behavior that they deem inappropriate, threatening, offensive, -or harmful. - -Community leaders have the right and responsibility to remove, edit, or reject -comments, commits, code, wiki edits, issues, and other contributions that are -not aligned to this Code of Conduct, and will communicate reasons for moderation -decisions when appropriate. - -## Scope - -This Code of Conduct applies within all community spaces, and also applies when -an individual is officially representing the community in public spaces. -Examples of representing our community include using an official email address, -posting via an official social media account, or acting as an appointed -representative at an online or offline event. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported to the community leaders responsible for enforcement at -zarf-dev-private@googlegroups.com. -All complaints will be reviewed and investigated promptly and fairly. - -All community leaders are obligated to respect the privacy and security of the -reporter of any incident. - -## Enforcement Guidelines - -Community leaders will follow these Community Impact Guidelines in determining -the consequences for any action they deem in violation of this Code of Conduct: - -### 1. Correction - -**Community Impact**: Use of inappropriate language or other behavior deemed -unprofessional or unwelcome in the community. - -**Consequence**: A private, written warning from community leaders, providing -clarity around the nature of the violation and an explanation of why the -behavior was inappropriate. A public apology may be requested. - -### 2. Warning - -**Community Impact**: A violation through a single incident or series of -actions. - -**Consequence**: A warning with consequences for continued behavior. No -interaction with the people involved, including unsolicited interaction with -those enforcing the Code of Conduct, for a specified period of time. This -includes avoiding interactions in community spaces as well as external channels -like social media. Violating these terms may lead to a temporary or permanent -ban. - -### 3. Temporary Ban - -**Community Impact**: A serious violation of community standards, including -sustained inappropriate behavior. - -**Consequence**: A temporary ban from any sort of interaction or public -communication with the community for a specified period of time. No public or -private interaction with the people involved, including unsolicited interaction -with those enforcing the Code of Conduct, is allowed during this period. -Violating these terms may lead to a permanent ban. - -### 4. Permanent Ban - -**Community Impact**: Demonstrating a pattern of violation of community -standards, including sustained inappropriate behavior, harassment of an -individual, or aggression toward or disparagement of classes of individuals. - -**Consequence**: A permanent ban from any sort of public interaction within the -community. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], -version 2.1, available at -[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. - -Community Impact Guidelines were inspired by -[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. - -For answers to common questions about this code of conduct, see the FAQ at -[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at -[https://www.contributor-covenant.org/translations][translations]. - -[homepage]: https://www.contributor-covenant.org -[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html -[Mozilla CoC]: https://github.com/mozilla/diversity -[FAQ]: https://www.contributor-covenant.org/faq -[translations]: https://www.contributor-covenant.org/translations \ No newline at end of file +Community members are required to abide by the [OpenSSF Code of Conduct](https://openssf.org/community/code-of-conduct/) in all project spaces including (but not limited to) GitHub, Slack, social media, and conferences. \ No newline at end of file diff --git a/README.md b/README.md index 88385564ce..e51160774f 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,6 @@ [![Zarf Documentation](https://img.shields.io/badge/docs-docs.zarf.dev-775ba1)](https://docs.zarf.dev/) [![Zarf Slack Channel](https://img.shields.io/badge/k8s%20slack-zarf-40a3dd)](https://kubernetes.slack.com/archives/C03B6BJAUJ3) [![Community Meetups](https://img.shields.io/badge/community-meetups-22aebb)](https://github.com/defenseunicorns/zarf/issues/2202) -[![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg)](CODE_OF_CONDUCT.md) Zarf eliminates the [complexity of air gap software delivery](https://www.itopstimes.com/contain/air-gap-kubernetes-considerations-for-running-cloud-native-applications-without-the-cloud/) for Kubernetes clusters and cloud-native workloads using a declarative packaging strategy to support DevSecOps in offline and semi-connected environments. From 1e4399ebeca84789666b938d76ed10351da939d0 Mon Sep 17 00:00:00 2001 From: Lucas Rodriguez Date: Fri, 19 Jul 2024 14:03:57 -0500 Subject: [PATCH 09/68] chore: update project name references (#2741) Signed-off-by: Lucas Rodriguez --- .github/ISSUE_TEMPLATE/tech_debt.md | 2 +- .github/SECURITY.md | 2 +- .github/pull_request_template.md | 2 +- .goreleaser.yaml | 8 +- CONTRIBUTING.md | 8 +- Makefile | 10 +- README.md | 14 +-- SUPPORT.md | 4 +- examples/big-bang/zarf.yaml | 2 +- go.mod | 2 +- main.go | 6 +- packages/README.md | 2 +- packages/zarf-registry/configmap.yaml | 2 +- site/astro.config.ts | 4 +- site/hack/copy-examples.js | 2 +- site/public/architecture.drawio.svg | 2 +- .../public/tutorials/package_create_init.html | 2 +- .../publish_and_deploy_manifest.html | 2 +- .../tutorials/resource_adoption_deploy.html | 2 +- .../tutorials/resource_adoption_package.html | 2 +- .../content/docs/contribute/nerd-notes.mdx | 6 +- site/src/content/docs/contribute/testing.mdx | 2 +- site/src/content/docs/faq.mdx | 10 +- .../content/docs/getting-started/install.mdx | 14 +-- site/src/content/docs/index.mdx | 2 +- site/src/content/docs/ref/components.mdx | 8 +- site/src/content/docs/ref/dev.mdx | 8 +- site/src/content/docs/ref/init-package.mdx | 10 +- site/src/content/docs/ref/packages.mdx | 2 +- site/src/content/docs/roadmap.mdx | 8 +- site/src/content/docs/support.mdx | 2 +- .../tutorials/0-creating-a-zarf-package.mdx | 4 +- .../1-initializing-a-k8s-cluster.mdx | 4 +- .../tutorials/3-deploy-a-retro-arcade.mdx | 2 +- .../4-creating-a-k8s-cluster-with-zarf.mdx | 4 +- .../src/content/docs/tutorials/5-big-bang.mdx | 4 +- .../docs/tutorials/7-custom-init-packages.mdx | 2 +- .../9-package-create-differential.mdx | 2 +- site/src/content/docs/tutorials/index.mdx | 4 +- src/cmd/common/setup.go | 6 +- src/cmd/common/vendor.go | 2 +- src/cmd/common/viper.go | 6 +- src/cmd/connect.go | 8 +- src/cmd/destroy.go | 12 +-- src/cmd/dev.go | 16 +-- src/cmd/initialize.go | 18 ++-- src/cmd/internal.go | 14 +-- src/cmd/package.go | 16 +-- src/cmd/root.go | 14 +-- src/cmd/tools/archiver.go | 6 +- src/cmd/tools/common.go | 6 +- src/cmd/tools/crane.go | 14 +-- src/cmd/tools/helm.go | 6 +- src/cmd/tools/helm/repo_add.go | 2 +- src/cmd/tools/k9s.go | 2 +- src/cmd/tools/kubectl.go | 6 +- src/cmd/tools/syft.go | 4 +- src/cmd/tools/wait.go | 6 +- src/cmd/tools/yq.go | 2 +- src/cmd/tools/zarf.go | 24 ++--- src/cmd/version.go | 4 +- src/config/config.go | 2 +- src/extensions/bigbang/banner.go | 2 +- src/extensions/bigbang/bigbang.go | 14 +-- src/extensions/bigbang/flux.go | 8 +- src/extensions/bigbang/manifests.go | 2 +- src/extensions/bigbang/test/bigbang_test.go | 6 +- .../agent/hooks/argocd-application.go | 12 +-- .../agent/hooks/argocd-application_test.go | 6 +- src/internal/agent/hooks/argocd-repository.go | 12 +-- .../agent/hooks/argocd-repository_test.go | 6 +- src/internal/agent/hooks/common.go | 2 +- src/internal/agent/hooks/flux-gitrepo.go | 12 +-- src/internal/agent/hooks/flux-gitrepo_test.go | 8 +- src/internal/agent/hooks/flux-helmrepo.go | 12 +-- .../agent/hooks/flux-helmrepo_test.go | 8 +- src/internal/agent/hooks/flux-ocirepo.go | 12 +-- src/internal/agent/hooks/flux-ocirepo_test.go | 8 +- src/internal/agent/hooks/pods.go | 12 +-- src/internal/agent/hooks/pods_test.go | 8 +- src/internal/agent/hooks/utils_test.go | 6 +- src/internal/agent/http/admission/handler.go | 6 +- src/internal/agent/http/proxy.go | 8 +- src/internal/agent/http/server.go | 8 +- src/internal/agent/operations/hook.go | 4 +- src/internal/agent/start.go | 6 +- src/internal/packager/git/checkout.go | 2 +- src/internal/packager/git/clone.go | 6 +- src/internal/packager/git/common.go | 4 +- src/internal/packager/git/gitea.go | 8 +- src/internal/packager/git/pull.go | 6 +- src/internal/packager/git/push.go | 6 +- src/internal/packager/helm/chart.go | 6 +- src/internal/packager/helm/common.go | 10 +- src/internal/packager/helm/destroy.go | 4 +- src/internal/packager/helm/images.go | 2 +- src/internal/packager/helm/post-render.go | 10 +- src/internal/packager/helm/repo.go | 14 +-- src/internal/packager/helm/utils.go | 2 +- src/internal/packager/helm/zarf.go | 14 +-- src/internal/packager/images/common.go | 10 +- src/internal/packager/images/pull.go | 14 +-- src/internal/packager/images/pull_test.go | 2 +- src/internal/packager/images/push.go | 8 +- src/internal/packager/sbom/catalog.go | 10 +- src/internal/packager/sbom/tools.go | 4 +- src/internal/packager/sbom/viewer.go | 4 +- src/internal/packager/template/template.go | 12 +-- src/pkg/cluster/cluster.go | 2 +- src/pkg/cluster/data.go | 12 +-- src/pkg/cluster/injector.go | 8 +- src/pkg/cluster/namespace.go | 2 +- src/pkg/cluster/secrets.go | 6 +- src/pkg/cluster/secrets_test.go | 2 +- src/pkg/cluster/state.go | 10 +- src/pkg/cluster/state_test.go | 6 +- src/pkg/cluster/tunnel.go | 4 +- src/pkg/cluster/tunnel_test.go | 2 +- src/pkg/cluster/zarf.go | 6 +- src/pkg/cluster/zarf_test.go | 4 +- src/pkg/interactive/components.go | 6 +- src/pkg/interactive/prompt.go | 4 +- src/pkg/layout/component.go | 4 +- src/pkg/layout/image.go | 2 +- src/pkg/layout/package.go | 10 +- src/pkg/layout/split.go | 4 +- src/pkg/layout/split_test.go | 2 +- src/pkg/message/connect.go | 2 +- src/pkg/message/credentials.go | 2 +- src/pkg/message/message.go | 2 +- src/pkg/packager/actions/actions.go | 12 +-- src/pkg/packager/common.go | 22 ++-- src/pkg/packager/common_test.go | 6 +- src/pkg/packager/composer/list.go | 14 +-- src/pkg/packager/composer/list_test.go | 6 +- src/pkg/packager/composer/oci.go | 10 +- src/pkg/packager/composer/override.go | 2 +- src/pkg/packager/composer/pathfixer.go | 2 +- src/pkg/packager/create.go | 8 +- src/pkg/packager/creator/compose.go | 6 +- src/pkg/packager/creator/compose_test.go | 2 +- src/pkg/packager/creator/creator.go | 4 +- src/pkg/packager/creator/creator_test.go | 4 +- src/pkg/packager/creator/differential.go | 10 +- src/pkg/packager/creator/normal.go | 34 +++--- src/pkg/packager/creator/skeleton.go | 20 ++-- src/pkg/packager/creator/template.go | 12 +-- src/pkg/packager/creator/utils.go | 6 +- src/pkg/packager/deploy.go | 26 ++--- src/pkg/packager/deploy_test.go | 6 +- src/pkg/packager/deprecated/common.go | 6 +- src/pkg/packager/deprecated/common_test.go | 2 +- .../deprecated/pluralize-set-variable.go | 4 +- .../packager/deprecated/scripts-to-actions.go | 2 +- src/pkg/packager/dev.go | 16 +-- src/pkg/packager/filters/deploy.go | 4 +- src/pkg/packager/filters/deploy_test.go | 2 +- src/pkg/packager/filters/diff.go | 6 +- src/pkg/packager/filters/diff_test.go | 2 +- src/pkg/packager/filters/empty.go | 2 +- src/pkg/packager/filters/empty_test.go | 2 +- src/pkg/packager/filters/os.go | 2 +- src/pkg/packager/filters/os_test.go | 2 +- src/pkg/packager/filters/select.go | 2 +- src/pkg/packager/filters/select_test.go | 2 +- src/pkg/packager/filters/strat.go | 2 +- src/pkg/packager/filters/strat_test.go | 2 +- src/pkg/packager/generate.go | 8 +- src/pkg/packager/inspect.go | 4 +- src/pkg/packager/interactive.go | 8 +- src/pkg/packager/lint/findings.go | 2 +- src/pkg/packager/lint/findings_test.go | 2 +- src/pkg/packager/lint/lint.go | 16 +-- src/pkg/packager/lint/lint_test.go | 4 +- src/pkg/packager/mirror.go | 8 +- src/pkg/packager/prepare.go | 18 ++-- src/pkg/packager/publish.go | 18 ++-- src/pkg/packager/remove.go | 16 +-- src/pkg/packager/sources/cluster.go | 10 +- src/pkg/packager/sources/new.go | 12 +-- src/pkg/packager/sources/new_test.go | 10 +- src/pkg/packager/sources/oci.go | 14 +-- src/pkg/packager/sources/split.go | 8 +- src/pkg/packager/sources/tarball.go | 10 +- src/pkg/packager/sources/url.go | 10 +- src/pkg/packager/sources/utils.go | 8 +- src/pkg/packager/sources/validate.go | 8 +- src/pkg/pki/pki.go | 2 +- src/pkg/transform/git_test.go | 102 +++++++++--------- src/pkg/transform/image_test.go | 24 ++--- src/pkg/utils/auth.go | 2 +- src/pkg/utils/auth_test.go | 2 +- src/pkg/utils/bytes.go | 2 +- src/pkg/utils/cosign.go | 6 +- src/pkg/utils/image.go | 2 +- src/pkg/utils/io.go | 4 +- src/pkg/utils/network.go | 4 +- src/pkg/utils/network_test.go | 2 +- src/pkg/utils/wait.go | 4 +- src/pkg/utils/wait_test.go | 2 +- src/pkg/utils/yaml.go | 4 +- src/pkg/variables/types.go | 2 +- src/pkg/zoci/common.go | 4 +- src/pkg/zoci/copier.go | 2 +- src/pkg/zoci/fetch.go | 4 +- src/pkg/zoci/pull.go | 8 +- src/pkg/zoci/push.go | 6 +- src/pkg/zoci/utils.go | 2 +- src/test/common.go | 2 +- src/test/e2e/05_tarball_test.go | 6 +- src/test/e2e/07_create_git_test.go | 2 +- src/test/e2e/08_create_differential_test.go | 10 +- src/test/e2e/12_lint_test.go | 2 +- src/test/e2e/13_zarf_package_generate_test.go | 6 +- src/test/e2e/20_zarf_init_test.go | 2 +- src/test/e2e/21_connect_creds_test.go | 2 +- src/test/e2e/22_git_and_gitops_test.go | 6 +- src/test/e2e/23_data_injection_test.go | 4 +- src/test/e2e/25_helm_test.go | 2 +- src/test/e2e/26_simple_packages_test.go | 2 +- src/test/e2e/27_deploy_regression_test.go | 2 +- src/test/e2e/28_wait_test.go | 2 +- src/test/e2e/50_oci_publish_deploy_test.go | 2 +- src/test/e2e/51_oci_compose_test.go | 8 +- src/test/e2e/99_yolo_test.go | 2 +- src/test/e2e/main_test.go | 6 +- src/test/external/common.go | 4 +- src/test/external/ext_in_cluster_test.go | 4 +- src/test/external/ext_out_cluster_test.go | 4 +- src/test/nightly/ecr_publish_test.go | 4 +- .../08-differential-package/zarf.yaml | 6 +- .../packages/51-import-everything/zarf.yaml | 2 +- src/test/upgrade/previously_built_test.go | 4 +- src/types/component.go | 6 +- src/types/k8s.go | 2 +- src/types/package.go | 2 +- src/types/validate.go | 2 +- src/types/validate_test.go | 4 +- zarf.schema.json | 2 +- 239 files changed, 796 insertions(+), 796 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/tech_debt.md b/.github/ISSUE_TEMPLATE/tech_debt.md index 8d862c65b9..aa19a1fdfc 100644 --- a/.github/ISSUE_TEMPLATE/tech_debt.md +++ b/.github/ISSUE_TEMPLATE/tech_debt.md @@ -10,7 +10,7 @@ assignees: '' A clear and concise description of what should be changed/researched. Ex. This piece of the code is not DRY enough [...] ### Links to any relevant code -(optional) i.e. - https://github.com/defenseunicorns/zarf/blob/main/README.md?plain=1#L1 +(optional) i.e. - https://github.com/zarf-dev/zarf/blob/main/README.md?plain=1#L1 ### Additional context Add any other context or screenshots about the technical debt here. diff --git a/.github/SECURITY.md b/.github/SECURITY.md index 6fd559327f..53776bbac6 100644 --- a/.github/SECURITY.md +++ b/.github/SECURITY.md @@ -1,6 +1,6 @@ # Reporting Security Issues -To report a security issue or vulnerability in Zarf, please use the confidential GitHub Security Advisory ["Report a Vulnerability"](https://github.com/defenseunicorns/zarf/security/advisories) tab. The Zarf team will send a response indicating the next steps in handling your report. After the initial reply to your report, the team will keep you informed of the progress towards a fix and full announcement, and may ask for additional information or guidance. +To report a security issue or vulnerability in Zarf, please use the confidential GitHub Security Advisory ["Report a Vulnerability"](https://github.com/zarf-dev/zarf/security/advisories) tab. The Zarf team will send a response indicating the next steps in handling your report. After the initial reply to your report, the team will keep you informed of the progress towards a fix and full announcement, and may ask for additional information or guidance. ### When Should I Report a Vulnerability? diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 370d4faa9a..00544265c2 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -11,4 +11,4 @@ Relates to # ## Checklist before merging - [ ] Test, docs, adr added or updated as needed -- [ ] [Contributor Guide Steps](https://github.com/defenseunicorns/zarf/blob/main/CONTRIBUTING.md#developer-workflow) followed +- [ ] [Contributor Guide Steps](https://github.com/zarf-dev/zarf/blob/main/CONTRIBUTING.md#developer-workflow) followed diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 8743d5d263..8af7ee7d5b 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -17,7 +17,7 @@ builds: - darwin - windows ldflags: - - -s -w -X github.com/defenseunicorns/zarf/src/config.CLIVersion={{.Tag}} + - -s -w -X github.com/zarf-dev/zarf/src/config.CLIVersion={{.Tag}} - -X k8s.io/component-base/version.gitVersion=v{{.Env.K8S_MODULES_MAJOR_VER}}.{{.Env.K8S_MODULES_MINOR_VER}}.{{.Env.K8S_MODULES_PATCH_VER}} - -X k8s.io/component-base/version.gitCommit={{.FullCommit}} - -X k8s.io/component-base/version.buildDate={{.Date}} @@ -27,9 +27,9 @@ builds: - -X helm.sh/helm/v3/pkg/chartutil.k8sVersionMinor={{.Env.K8S_MODULES_MINOR_VER}} - -X github.com/derailed/k9s/cmd.version={{.Env.K9S_VERSION}} - -X github.com/google/go-containerregistry/cmd/crane/cmd.Version={{.Env.CRANE_VERSION}} - - -X github.com/defenseunicorns/zarf/src/cmd/tools.syftVersion={{.Env.SYFT_VERSION}} - - -X github.com/defenseunicorns/zarf/src/cmd/tools.archiverVersion={{.Env.ARCHIVER_VERSION}} - - -X github.com/defenseunicorns/zarf/src/cmd/tools.helmVersion={{.Env.HELM_VERSION}} + - -X github.com/zarf-dev/zarf/src/cmd/tools.syftVersion={{.Env.SYFT_VERSION}} + - -X github.com/zarf-dev/zarf/src/cmd/tools.archiverVersion={{.Env.ARCHIVER_VERSION}} + - -X github.com/zarf-dev/zarf/src/cmd/tools.helmVersion={{.Env.HELM_VERSION}} goarch: - amd64 - arm64 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 700f161b7a..2434cba024 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -33,7 +33,7 @@ Now every time you commit, the hooks will run and format your code, linting can :key: == Required by automation -1. Look at the next due [release milestone](https://github.com/defenseunicorns/zarf/milestones) and pick an issue that you want to work on. If you don't see anything that interests you, create an issue and assign it to yourself. +1. Look at the next due [release milestone](https://github.com/zarf-dev/zarf/milestones) and pick an issue that you want to work on. If you don't see anything that interests you, create an issue and assign it to yourself. 1. Drop a comment in the issue to let everyone know you're working on it and submit a Draft PR (step 4) as soon as you are able. If you have any questions as you work through the code, reach out in the [Zarf Dev Kubernetes Slack Channel](https://kubernetes.slack.com/archives/C03BP9Z3CMA). 1. :key: Set up your Git config to GPG sign all commits. [Here's some documentation on how to set it up](https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits). You won't be able to merge your PR if you have any unverified commits. 1. Create a Draft Pull Request as soon as you can, even if it is just 5 minutes after you started working on it. We lean towards working in the open as much as we can. If you're not sure what to put in the PR description, just put a link to the issue you're working on. @@ -41,8 +41,8 @@ Now every time you commit, the hooks will run and format your code, linting can - :key: We follow the [conventional commits spec](https://www.conventionalcommits.org/en/v1.0.0/) with the [commitlint conventional config](https://github.com/conventional-changelog/commitlint/tree/master/%40commitlint/config-conventional) as extended types for PR titles. 1. :key: Automated tests will begin based on the paths you have edited in your Pull Request. - > ⚠️ **NOTE:** _If you are an external third-party contributor, the pipelines won't run until a [CODEOWNER](https://github.com/defenseunicorns/zarf/blob/main/CODEOWNERS) approves the pipeline run._ -1. :key: Be sure to use the [needs-adr,needs-docs,needs-tests](https://github.com/defenseunicorns/zarf/labels?q=needs) labels as appropriate for the PR. Once you have addressed all of the needs, remove the label. + > ⚠️ **NOTE:** _If you are an external third-party contributor, the pipelines won't run until a [CODEOWNER](https://github.com/zarf-dev/zarf/blob/main/CODEOWNERS) approves the pipeline run._ +1. :key: Be sure to use the [needs-adr,needs-docs,needs-tests](https://github.com/zarf-dev/zarf/labels?q=needs) labels as appropriate for the PR. Once you have addressed all of the needs, remove the label. 1. Once the review is complete and approved, a core member of the zarf project will merge your PR. If you are an external third-party contributor, two core members of the zarf project will be required to approve the PR. 1. Close the issue if it is fully resolved by your PR. _Hint: You can add "Fixes #XX" to the PR description to automatically close an issue when the PR is merged._ @@ -56,7 +56,7 @@ Our unit tests can be found as `*_test.go` files inside the package that they ar ## Documentation -The CLI docs (located at `site/src/content/docs/commands`), and [`zarf.schema.json`](https://github.com/defenseunicorns/zarf/blob/main/zarf.schema.json) are autogenerated from `make docs-and-schema`. Run this make target locally to regenerate the schema and documentation each time you make a change to the CLI commands or the schema, otherwise CI will fail. +The CLI docs (located at `site/src/content/docs/commands`), and [`zarf.schema.json`](https://github.com/zarf-dev/zarf/blob/main/zarf.schema.json) are autogenerated from `make docs-and-schema`. Run this make target locally to regenerate the schema and documentation each time you make a change to the CLI commands or the schema, otherwise CI will fail. We do this so that there is a git commit signature from a person on the commit for better traceability, rather than a non-person entity (e.g. GitHub CI token). diff --git a/Makefile b/Makefile index 0f2deebcaf..bdce6970d3 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,7 @@ else endif CLI_VERSION ?= $(if $(shell git describe --tags),$(shell git describe --tags),"UnknownVersion") -BUILD_ARGS := -s -w -X github.com/defenseunicorns/zarf/src/config.CLIVersion=$(CLI_VERSION) +BUILD_ARGS := -s -w -X github.com/zarf-dev/zarf/src/config.CLIVersion=$(CLI_VERSION) K8S_MODULES_VER=$(subst ., ,$(subst v,,$(shell go list -f '{{.Version}}' -m k8s.io/client-go))) K8S_MODULES_MAJOR_VER=$(shell echo $$(($(firstword $(K8S_MODULES_VER)) + 1))) K8S_MODULES_MINOR_VER=$(word 2,$(K8S_MODULES_VER)) @@ -48,9 +48,9 @@ BUILD_ARGS += -X helm.sh/helm/v3/pkg/chartutil.k8sVersionMinor=$(K8S_MODULES_MIN BUILD_ARGS += -X k8s.io/component-base/version.gitVersion=v$(K8S_MODULES_MAJOR_VER).$(K8S_MODULES_MINOR_VER).$(K8S_MODULES_PATCH_VER) BUILD_ARGS += -X github.com/derailed/k9s/cmd.version=$(K9S_VERSION) BUILD_ARGS += -X github.com/google/go-containerregistry/cmd/crane/cmd.Version=$(CRANE_VERSION) -BUILD_ARGS += -X github.com/defenseunicorns/zarf/src/cmd/tools.syftVersion=$(SYFT_VERSION) -BUILD_ARGS += -X github.com/defenseunicorns/zarf/src/cmd/tools.archiverVersion=$(ARCHIVER_VERSION) -BUILD_ARGS += -X github.com/defenseunicorns/zarf/src/cmd/tools.helmVersion=$(HELM_VERSION) +BUILD_ARGS += -X github.com/zarf-dev/zarf/src/cmd/tools.syftVersion=$(SYFT_VERSION) +BUILD_ARGS += -X github.com/zarf-dev/zarf/src/cmd/tools.archiverVersion=$(ARCHIVER_VERSION) +BUILD_ARGS += -X github.com/zarf-dev/zarf/src/cmd/tools.helmVersion=$(HELM_VERSION) GIT_SHA := $(if $(shell git rev-parse HEAD),$(shell git rev-parse HEAD),"") BUILD_DATE := $(shell date -u +'%Y-%m-%dT%H:%M:%SZ') @@ -210,7 +210,7 @@ test-upgrade: ## Run the Zarf CLI E2E tests for an external registry and cluster .PHONY: test-unit test-unit: ## Run unit tests - go test -failfast -v -coverprofile=coverage.out -covermode=atomic $$(go list ./... | grep -v '^github.com/defenseunicorns/zarf/src/test' | grep -v 'github.com/defenseunicorns/zarf/src/extensions/bigbang/test') + go test -failfast -v -coverprofile=coverage.out -covermode=atomic $$(go list ./... | grep -v '^github.com/zarf-dev/zarf/src/test' | grep -v 'github.com/zarf-dev/zarf/src/extensions/bigbang/test') # INTERNAL: used to test that a dev has ran `make docs-and-schema` in their PR test-docs-and-schema: diff --git a/README.md b/README.md index e51160774f..c49b2ade6c 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,16 @@ # Zarf - DevSecOps for Air Gap -[![Latest Release](https://img.shields.io/github/v/release/defenseunicorns/zarf)](https://github.com/defenseunicorns/zarf/releases) -[![Go version](https://img.shields.io/github/go-mod/go-version/defenseunicorns/zarf?filename=go.mod)](https://go.dev/) -[![Build Status](https://img.shields.io/github/actions/workflow/status/defenseunicorns/zarf/release.yml)](https://github.com/defenseunicorns/zarf/actions/workflows/release.yml) -[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/defenseunicorns/zarf/badge)](https://securityscorecards.dev/viewer/?uri=github.com/defenseunicorns/zarf) +[![Latest Release](https://img.shields.io/github/v/release/zarf-dev/zarf)](https://github.com/zarf-dev/zarf/releases) +[![Go version](https://img.shields.io/github/go-mod/go-version/zarf-dev/zarf?filename=go.mod)](https://go.dev/) +[![Build Status](https://img.shields.io/github/actions/workflow/status/zarf-dev/zarf/release.yml)](https://github.com/zarf-dev/zarf/actions/workflows/release.yml) +[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/zarf-dev/zarf/badge)](https://securityscorecards.dev/viewer/?uri=github.com/zarf-dev/zarf) zarf logo [![Zarf Website](https://img.shields.io/badge/web-zarf.dev-6d87c3)](https://zarf.dev/) [![Zarf Documentation](https://img.shields.io/badge/docs-docs.zarf.dev-775ba1)](https://docs.zarf.dev/) [![Zarf Slack Channel](https://img.shields.io/badge/k8s%20slack-zarf-40a3dd)](https://kubernetes.slack.com/archives/C03B6BJAUJ3) -[![Community Meetups](https://img.shields.io/badge/community-meetups-22aebb)](https://github.com/defenseunicorns/zarf/issues/2202) +[![Community Meetups](https://img.shields.io/badge/community-meetups-22aebb)](https://github.com/zarf-dev/zarf/issues/2202) Zarf eliminates the [complexity of air gap software delivery](https://www.itopstimes.com/contain/air-gap-kubernetes-considerations-for-running-cloud-native-applications-without-the-cloud/) for Kubernetes clusters and cloud-native workloads using a declarative packaging strategy to support DevSecOps in offline and semi-connected environments. @@ -77,8 +77,8 @@ Join us on the [Kubernetes Slack](https://kubernetes.slack.com/) in the [_#zarf_ We are so grateful to our Zarf community for contributing bug fixes and collaborating on new features: - - Zarf contributors + + Zarf contributors Made with [contrib.rocks](https://contrib.rocks). diff --git a/SUPPORT.md b/SUPPORT.md index ad6ce504bd..27d362cb58 100644 --- a/SUPPORT.md +++ b/SUPPORT.md @@ -4,10 +4,10 @@ We strive to create clear guidelines on communication to the Zarf team to provid ## Questions For guidance on using Zarf, [the documentation](https://docs.zarf.dev/) should cover most use cases. -For all questions documentation may not cover, we suggest utilizing [Github Discussions](https://github.com/defenseunicorns/zarf/discussions). +For all questions documentation may not cover, we suggest utilizing [Github Discussions](https://github.com/zarf-dev/zarf/discussions). ## Standard Process -All code issues should be a [Github Issue](https://github.com/defenseunicorns/zarf/issues/new/choose) that follows the issue template. +All code issues should be a [Github Issue](https://github.com/zarf-dev/zarf/issues/new/choose) that follows the issue template. Following the templates provides the Zarf community a foundation of understanding to be able to assist quickly. After an issue is made, this issue can be brought into other channels such as the [Kubernetes Slack #Zarf](https://zarf.dev/slack) channel or the [bi-weekly Zarf Community Meeting](https://docs.zarf.dev/contribute/contributor-guide/). diff --git a/examples/big-bang/zarf.yaml b/examples/big-bang/zarf.yaml index 534ebd0ea4..672ec4f8d1 100644 --- a/examples/big-bang/zarf.yaml +++ b/examples/big-bang/zarf.yaml @@ -96,4 +96,4 @@ x-mdx: | You can learn about YOLO mode in the [FAQ](/faq#what-is-yolo-mode-and-why-would-i-use-it) or the [YOLO mode example](/ref/examples/yolo/). - [Big Bang YOLO Mode Example](https://github.com/defenseunicorns/zarf/tree/main/examples/big-bang/yolo). + [Big Bang YOLO Mode Example](https://github.com/zarf-dev/zarf/tree/main/examples/big-bang/yolo). diff --git a/go.mod b/go.mod index b8cee0d6d6..9bf35fbbba 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/defenseunicorns/zarf +module github.com/zarf-dev/zarf go 1.22.4 diff --git a/main.go b/main.go index 8068f4b4fc..70feb480f4 100644 --- a/main.go +++ b/main.go @@ -11,9 +11,9 @@ import ( "os/signal" "syscall" - "github.com/defenseunicorns/zarf/src/cmd" - "github.com/defenseunicorns/zarf/src/config" - "github.com/defenseunicorns/zarf/src/pkg/packager/lint" + "github.com/zarf-dev/zarf/src/cmd" + "github.com/zarf-dev/zarf/src/config" + "github.com/zarf-dev/zarf/src/pkg/packager/lint" ) //go:embed cosign.pub diff --git a/packages/README.md b/packages/README.md index 1776860ba4..be4516cf68 100644 --- a/packages/README.md +++ b/packages/README.md @@ -1,6 +1,6 @@ # Zarf Packages -This folder contains packages maintained by the [Zarf team](https://github.com/defenseunicorns/zarf/graphs/contributors). Some of these packages are used by `zarf init` for new cluster initialization. +This folder contains packages maintained by the [Zarf team](https://github.com/zarf-dev/zarf/graphs/contributors). Some of these packages are used by `zarf init` for new cluster initialization. ## Distros diff --git a/packages/zarf-registry/configmap.yaml b/packages/zarf-registry/configmap.yaml index 02c9b9bb0b..fe3e7bf235 100644 --- a/packages/zarf-registry/configmap.yaml +++ b/packages/zarf-registry/configmap.yaml @@ -7,4 +7,4 @@ metadata: data: localRegistryHosting.v1: | host: "###ZARF_REGISTRY###" - help: "https://github.com/defenseunicorns/zarf" + help: "https://github.com/zarf-dev/zarf" diff --git a/site/astro.config.ts b/site/astro.config.ts index d787bd08c6..d00b26b4af 100644 --- a/site/astro.config.ts +++ b/site/astro.config.ts @@ -39,12 +39,12 @@ export default defineConfig({ SkipLink: "./src/components/SkipLink.astro", }, social: { - github: "https://github.com/defenseunicorns/zarf", + github: "https://github.com/zarf-dev/zarf", slack: "https://kubernetes.slack.com/archives/C03B6BJAUJ3", }, favicon: "/favicon.svg", editLink: { - baseUrl: "https://github.com/defenseunicorns/zarf/edit/main/site", + baseUrl: "https://github.com/zarf-dev/zarf/edit/main/site", }, logo: { src: "./src/assets/zarf-logo-header.svg", diff --git a/site/hack/copy-examples.js b/site/hack/copy-examples.js index a3cda64641..77abf23104 100644 --- a/site/hack/copy-examples.js +++ b/site/hack/copy-examples.js @@ -25,7 +25,7 @@ async function copyExamples() { } const mdx = parsed.get("x-mdx").trim(); examples.push(dir); - const repo = "https://github.com/defenseunicorns/zarf"; + const repo = "https://github.com/zarf-dev/zarf"; const link = new URL(`${repo}/edit/main/examples/${dir}/zarf.yaml`).toString(); const fm = `--- title: "${dir}" diff --git a/site/public/architecture.drawio.svg b/site/public/architecture.drawio.svg index 4fa51a8850..aced8942e9 100644 --- a/site/public/architecture.drawio.svg +++ b/site/public/architecture.drawio.svg @@ -1,4 +1,4 @@ -
%3CmxGraphModel%3E%3Croot%3E%3CmxCell%20id%3D%220%22%2F%3E%3CmxCell%20id%3D%221%22%20parent%3D%220%22%2F%3E%3CmxCell%20id%3D%222%22%20value%3D%22%22%20style%3D%22rounded%3D1%3BwhiteSpace%3Dwrap%3Bhtml%3D1%3BlabelBorderColor%3Dnone%3BfillColor%3D%23bac8d3%3BstrokeColor%3D%2323445d%3BgradientColor%3Dnone%3Bglass%3D0%3Bshadow%3D0%3Bsketch%3D0%3B%22%20vertex%3D%221%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%22210%22%20y%3D%22-60%22%20width%3D%22770%22%20height%3D%22908%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3C%2Froot%3E%3C%2FmxGraphModel%3E
%3CmxGraphModel%3E%3Croot%3...
%3CmxGraphModel%3E%3Croot%3E%3CmxCell%20id%3D%220%22%2F%3E%3CmxCell%20id%3D%221%22%20parent%3D%220%22%2F%3E%3CmxCell%20id%3D%222%22%20value%3D%22%22%20style%3D%22rounded%3D1%3BwhiteSpace%3Dwrap%3Bhtml%3D1%3BlabelBorderColor%3Dnone%3BfillColor%3D%23bac8d3%3BstrokeColor%3D%2323445d%3BgradientColor%3Dnone%3Bglass%3D0%3Bshadow%3D0%3Bsketch%3D0%3B%22%20vertex%3D%221%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%22210%22%20y%3D%22-60%22%20width%3D%22770%22%20height%3D%22908%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3C%2Froot%3E%3C%2FmxGraphModel%3E
%3CmxGraphModel%3E%3Croot%3...
%3CmxGraphModel%3E%3Croot%3E%3CmxCell%20id%3D%220%22%2F%3E%3CmxCell%20id%3D%221%22%20parent%3D%220%22%2F%3E%3CmxCell%20id%3D%222%22%20value%3D%22%22%20style%3D%22rounded%3D1%3BwhiteSpace%3Dwrap%3Bhtml%3D1%3BlabelBorderColor%3Dnone%3BfillColor%3D%23bac8d3%3BstrokeColor%3D%2323445d%3BgradientColor%3Dnone%3Bglass%3D0%3Bshadow%3D0%3Bsketch%3D0%3B%22%20vertex%3D%221%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%22210%22%20y%3D%22-60%22%20width%3D%22770%22%20height%3D%22908%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3C%2Froot%3E%3C%2FmxGraphModel%3E
%3CmxGraphModel%3E%3Croot%3...
ns
ns
ns
ns
pod
pod
rs
rs
deploy
deploy
Zarf-Managed Deployments
Zarf-Managed Deployments
ns
ns
%3CmxGraphModel%3E%3Croot%3E%3CmxCell%20id%3D%220%22%2F%3E%3CmxCell%20id%3D%221%22%20parent%3D%220%22%2F%3E%3CmxCell%20id%3D%222%22%20value%3D%22%22%20style%3D%22rounded%3D1%3BwhiteSpace%3Dwrap%3Bhtml%3D1%3BlabelBorderColor%3Dnone%3BfillColor%3D%23bac8d3%3BstrokeColor%3D%2323445d%3BgradientColor%3Dnone%3Bglass%3D0%3Bshadow%3D0%3Bsketch%3D0%3B%22%20vertex%3D%221%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%22210%22%20y%3D%22-60%22%20width%3D%22770%22%20height%3D%22908%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3C%2Froot%3E%3C%2FmxGraphModel%3E
%3CmxGraphModel%3E%3Croot%3E%3CmxCell%20id%3D%220%22%2F%3E%3CmxCell%20id%3D%221%22%20parent%3D%220%22%2F%3E%3CmxCell%20id%3D%222...
pod
pod
pvc
pvc
nodeport
svc
nodeport...
rs
rs
deploy
deploy
Zarf Registry 
Zarf Registry 
clusterip
svc
clusteri...
rs
rs
deploy
deploy
Zarf Agent
(Mutating Webhook)
Zarf Agent...
pod
pod
pvc
pvc
clusterip
svc
clusteri...
rs
rs
deploy
deploy
Zarf Gitops Service
Zarf Gitops Service
pod
pod
ns
ns
zarf-state
zarf-sta...
NodePort
31999
NodePort...
zarf
zarf
pv
pv
sc
sc
nodeport
svc
nodeport...
Zarf Injector
Zarf Injector
pod
from existing
image
pod...
Dynamic configmaps:
n = tarball size / 512 KB
Dynamic configmaps:...
Dynamic
NodePort

Dynamic...
pv
pv
sc
sc
Zarf Resource
Zarf Resource
Zarf Temporary Resource
Zarf Temporary Resource
Zarf-Managed Resource
Zarf-Managed Resource
Zarf CLI to Cluster Comms
Zarf CLI to Cluster Comms
Image Pull From Zarf Registry
Image Pull From Zarf Registry
Standard K8s Comms
Standard K8s Comms
Standard K8s Controller Comms
Standard K8s Controller Comms
Initial image pulled from zarf-injector nodeport
Initial image pulled from zarf-injector nodep...
Post registry boot all images pull from the registry
Post registry boot all images pull from the regi...
POD Create / Flux GitRepository Create Webhook
POD Create / Flux GitRepository Create Webhook
https://github.com/defenseunicorns/zarf
https://github.com/defenseunicorns/zarf
   1. Create the Zarf State in the cluster
1. Create the Zarf State in the clu...
   2. Launch the injector system
   2. Launch the injector system
   3. Deploy the Zarf Registry
   3. Deploy the Zarf Registry
   4. Deploy the Zarf Agent
   4. Deploy the Zarf Agent
   5. (Optional) Deploy the Zarf Git Server
5. (Optional) Deploy the Zarf Git S...
   6. Push package assets to the cluster
6. Push package assets to the clust...
Text is not SVG - cannot display
+
%3CmxGraphModel%3E%3Croot%3E%3CmxCell%20id%3D%220%22%2F%3E%3CmxCell%20id%3D%221%22%20parent%3D%220%22%2F%3E%3CmxCell%20id%3D%222%22%20value%3D%22%22%20style%3D%22rounded%3D1%3BwhiteSpace%3Dwrap%3Bhtml%3D1%3BlabelBorderColor%3Dnone%3BfillColor%3D%23bac8d3%3BstrokeColor%3D%2323445d%3BgradientColor%3Dnone%3Bglass%3D0%3Bshadow%3D0%3Bsketch%3D0%3B%22%20vertex%3D%221%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%22210%22%20y%3D%22-60%22%20width%3D%22770%22%20height%3D%22908%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3C%2Froot%3E%3C%2FmxGraphModel%3E
%3CmxGraphModel%3E%3Croot%3...
%3CmxGraphModel%3E%3Croot%3E%3CmxCell%20id%3D%220%22%2F%3E%3CmxCell%20id%3D%221%22%20parent%3D%220%22%2F%3E%3CmxCell%20id%3D%222%22%20value%3D%22%22%20style%3D%22rounded%3D1%3BwhiteSpace%3Dwrap%3Bhtml%3D1%3BlabelBorderColor%3Dnone%3BfillColor%3D%23bac8d3%3BstrokeColor%3D%2323445d%3BgradientColor%3Dnone%3Bglass%3D0%3Bshadow%3D0%3Bsketch%3D0%3B%22%20vertex%3D%221%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%22210%22%20y%3D%22-60%22%20width%3D%22770%22%20height%3D%22908%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3C%2Froot%3E%3C%2FmxGraphModel%3E
%3CmxGraphModel%3E%3Croot%3...
%3CmxGraphModel%3E%3Croot%3E%3CmxCell%20id%3D%220%22%2F%3E%3CmxCell%20id%3D%221%22%20parent%3D%220%22%2F%3E%3CmxCell%20id%3D%222%22%20value%3D%22%22%20style%3D%22rounded%3D1%3BwhiteSpace%3Dwrap%3Bhtml%3D1%3BlabelBorderColor%3Dnone%3BfillColor%3D%23bac8d3%3BstrokeColor%3D%2323445d%3BgradientColor%3Dnone%3Bglass%3D0%3Bshadow%3D0%3Bsketch%3D0%3B%22%20vertex%3D%221%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%22210%22%20y%3D%22-60%22%20width%3D%22770%22%20height%3D%22908%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3C%2Froot%3E%3C%2FmxGraphModel%3E
%3CmxGraphModel%3E%3Croot%3...
ns
ns
ns
ns
pod
pod
rs
rs
deploy
deploy
Zarf-Managed Deployments
Zarf-Managed Deployments
ns
ns
%3CmxGraphModel%3E%3Croot%3E%3CmxCell%20id%3D%220%22%2F%3E%3CmxCell%20id%3D%221%22%20parent%3D%220%22%2F%3E%3CmxCell%20id%3D%222%22%20value%3D%22%22%20style%3D%22rounded%3D1%3BwhiteSpace%3Dwrap%3Bhtml%3D1%3BlabelBorderColor%3Dnone%3BfillColor%3D%23bac8d3%3BstrokeColor%3D%2323445d%3BgradientColor%3Dnone%3Bglass%3D0%3Bshadow%3D0%3Bsketch%3D0%3B%22%20vertex%3D%221%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%22210%22%20y%3D%22-60%22%20width%3D%22770%22%20height%3D%22908%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3C%2Froot%3E%3C%2FmxGraphModel%3E
%3CmxGraphModel%3E%3Croot%3E%3CmxCell%20id%3D%220%22%2F%3E%3CmxCell%20id%3D%221%22%20parent%3D%220%22%2F%3E%3CmxCell%20id%3D%222...
pod
pod
pvc
pvc
nodeport
svc
nodeport...
rs
rs
deploy
deploy
Zarf Registry 
Zarf Registry 
clusterip
svc
clusteri...
rs
rs
deploy
deploy
Zarf Agent
(Mutating Webhook)
Zarf Agent...
pod
pod
pvc
pvc
clusterip
svc
clusteri...
rs
rs
deploy
deploy
Zarf Gitops Service
Zarf Gitops Service
pod
pod
ns
ns
zarf-state
zarf-sta...
NodePort
31999
NodePort...
zarf
zarf
pv
pv
sc
sc
nodeport
svc
nodeport...
Zarf Injector
Zarf Injector
pod
from existing
image
pod...
Dynamic configmaps:
n = tarball size / 512 KB
Dynamic configmaps:...
Dynamic
NodePort

Dynamic...
pv
pv
sc
sc
Zarf Resource
Zarf Resource
Zarf Temporary Resource
Zarf Temporary Resource
Zarf-Managed Resource
Zarf-Managed Resource
Zarf CLI to Cluster Comms
Zarf CLI to Cluster Comms
Image Pull From Zarf Registry
Image Pull From Zarf Registry
Standard K8s Comms
Standard K8s Comms
Standard K8s Controller Comms
Standard K8s Controller Comms
Initial image pulled from zarf-injector nodeport
Initial image pulled from zarf-injector nodep...
Post registry boot all images pull from the registry
Post registry boot all images pull from the regi...
POD Create / Flux GitRepository Create Webhook
POD Create / Flux GitRepository Create Webhook
https://github.com/zarf-dev/zarf
https://github.com/zarf-dev/zarf
   1. Create the Zarf State in the cluster
1. Create the Zarf State in the clu...
   2. Launch the injector system
   2. Launch the injector system
   3. Deploy the Zarf Registry
   3. Deploy the Zarf Registry
   4. Deploy the Zarf Agent
   4. Deploy the Zarf Agent
   5. (Optional) Deploy the Zarf Git Server
5. (Optional) Deploy the Zarf Git S...
   6. Push package assets to the cluster
6. Push package assets to the clust...
Text is not SVG - cannot display
diff --git a/site/public/tutorials/package_create_init.html b/site/public/tutorials/package_create_init.html index 6a21effc08..9c8e80e906 100644 --- a/site/public/tutorials/package_create_init.html +++ b/site/public/tutorials/package_create_init.html @@ -158,7 +158,7 @@ - packages/zarf-agent/manifests/deployment.yaml - packages/zarf-agent/manifests/webhook.yaml images: - - ghcr.io/defenseunicorns/zarf/agent:local + - ghcr.io/zarf-dev/zarf/agent:local - name: git-server description: | Deploys Gitea to provide git repositories for Kubernetes configurations. diff --git a/site/public/tutorials/publish_and_deploy_manifest.html b/site/public/tutorials/publish_and_deploy_manifest.html index 74e8928a4a..19977b88e0 100644 --- a/site/public/tutorials/publish_and_deploy_manifest.html +++ b/site/public/tutorials/publish_and_deploy_manifest.html @@ -51,7 +51,7 @@ $ mkdir -p zarf-publish-tutorial && cd zarf-publish-tutorial # For this tutorial we will use the example package -# located here: https://github.com/defenseunicorns/zarf/blob/main/examples/helm-oci-chart/zarf.yaml +# located here: https://github.com/zarf-dev/zarf/blob/main/examples/helm-oci-chart/zarf.yaml $ cat <<EOF > zarf.yaml kind: ZarfPackageConfig metadata: diff --git a/site/public/tutorials/resource_adoption_deploy.html b/site/public/tutorials/resource_adoption_deploy.html index dac25e7967..814f4c541f 100644 --- a/site/public/tutorials/resource_adoption_deploy.html +++ b/site/public/tutorials/resource_adoption_deploy.html @@ -88,7 +88,7 @@ This package has 1 artifacts with software bill-of-materials (SBOM) included. You can view them now in the zarf-sbom folder in this directory or to go directly to one, open this in your browser: -/Users/jason/src/github.com/defenseunicorns/zarf/zarf-sbom/sbom-viewer-defenseunicorns_zarf-game_multi-tile-dark.html +/Users/jason/src/github.com/zarf-dev/zarf/zarf-sbom/sbom-viewer-defenseunicorns_zarf-game_multi-tile-dark.html * This directory will be removed after package deployment. diff --git a/site/public/tutorials/resource_adoption_package.html b/site/public/tutorials/resource_adoption_package.html index a252ad6632..5a4c744f2e 100644 --- a/site/public/tutorials/resource_adoption_package.html +++ b/site/public/tutorials/resource_adoption_package.html @@ -49,7 +49,7 @@
 $ zarf package create examples/dos-games
 
-Using config file /Users/jason/src/github.com/defenseunicorns/zarf/zarf-config.toml
+Using config file /Users/jason/src/github.com/zarf-dev/zarf/zarf-config.toml
 
 Saving log file to
 /var/folders/bk/rz1xx2sd5zn134c0_j1s2n5r0000gp/T/zarf-2023-05-10-11-24-25-3678510320.log
diff --git a/site/src/content/docs/contribute/nerd-notes.mdx b/site/src/content/docs/contribute/nerd-notes.mdx
index 6264dd5266..33dd73b35d 100644
--- a/site/src/content/docs/contribute/nerd-notes.mdx
+++ b/site/src/content/docs/contribute/nerd-notes.mdx
@@ -10,10 +10,10 @@ Zarf is written entirely in [go](https://go.dev/), except for a single 868Kb bin
 
 - All workloads are installed in the cluster via the [Helm SDK](https://helm.sh/docs/topics/advanced/#go-sdk)
 - The OCI Registries used are both from [Docker](https://github.com/distribution/distribution)
-- Currently, the Registry and Git servers _are not HA_, see [#375](https://github.com/defenseunicorns/zarf/issues/375) and [#376](https://github.com/defenseunicorns/zarf/issues/376) for discussion on this
+- Currently, the Registry and Git servers _are not HA_, see [#375](https://github.com/zarf-dev/zarf/issues/375) and [#376](https://github.com/zarf-dev/zarf/issues/376) for discussion on this
 - To avoid TLS issues, Zarf binds to `127.0.0.1:31999` on each node as a [NodePort](https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport) to allow all nodes to access the pod(s) in the cluster
-- Zarf utilizes a [mutating admission webhook](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#mutatingadmissionwebhook) called the [`zarf-agent`](https://github.com/defenseunicorns/zarf/tree/main/src/internal/agent) to modify the image property within the `PodSpec`. The purpose is to redirect it to Zarf's configured registry instead of the the original registry (such as DockerHub, GCR, or Quay). Additionally, the webhook attaches the appropriate [ImagePullSecret](https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod) for the seed registry to the pod. This configuration allows the pod to successfully retrieve the image from the seed registry, even when operating in an air-gapped environment.
-- Zarf uses a custom injector system to bootstrap a new cluster. See the PR [#329](https://github.com/defenseunicorns/zarf/pull/329) and [ADR](https://github.com/defenseunicorns/zarf/blob/main/adr/0003-image-injection-into-remote-clusters-without-native-support.md) for more details on how we came to this solution.  The general steps are listed below:
+- Zarf utilizes a [mutating admission webhook](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/#mutatingadmissionwebhook) called the [`zarf-agent`](https://github.com/zarf-dev/zarf/tree/main/src/internal/agent) to modify the image property within the `PodSpec`. The purpose is to redirect it to Zarf's configured registry instead of the the original registry (such as DockerHub, GCR, or Quay). Additionally, the webhook attaches the appropriate [ImagePullSecret](https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod) for the seed registry to the pod. This configuration allows the pod to successfully retrieve the image from the seed registry, even when operating in an air-gapped environment.
+- Zarf uses a custom injector system to bootstrap a new cluster. See the PR [#329](https://github.com/zarf-dev/zarf/pull/329) and [ADR](https://github.com/zarf-dev/zarf/blob/main/adr/0003-image-injection-into-remote-clusters-without-native-support.md) for more details on how we came to this solution.  The general steps are listed below:
   - Get a list of images in the cluster
   - Attempt to create an ephemeral pod using an image from the list
   - A small rust binary that is compiled using [musl](https://www.musl-libc.org/) to keep the max binary size as minimal as possible
diff --git a/site/src/content/docs/contribute/testing.mdx b/site/src/content/docs/contribute/testing.mdx
index c64c643aa6..6805190229 100644
--- a/site/src/content/docs/contribute/testing.mdx
+++ b/site/src/content/docs/contribute/testing.mdx
@@ -2,7 +2,7 @@
 title: Running Tests
 ---
 
-Currently, we primarily test Zarf through a series of [end-to-end tests](https://github.com/defenseunicorns/zarf/tree/main/src/test/e2e). These tests are called in the `test-*.yml` workflows and undergo automatic execution against several K8s distros whenever a pull request is created or updated.
+Currently, we primarily test Zarf through a series of [end-to-end tests](https://github.com/zarf-dev/zarf/tree/main/src/test/e2e). These tests are called in the `test-*.yml` workflows and undergo automatic execution against several K8s distros whenever a pull request is created or updated.
 
 In addition, Zarf implements unit tests for specific functions where edge cases prove difficult to cover through end-to-end testing alone. Unit tests follow standard Go convention and are `*_test.go` files.
 
diff --git a/site/src/content/docs/faq.mdx b/site/src/content/docs/faq.mdx
index e4bca91bba..5f57435ea2 100644
--- a/site/src/content/docs/faq.mdx
+++ b/site/src/content/docs/faq.mdx
@@ -10,7 +10,7 @@ Defense Unicorns' mission is to advance freedom and independence globally throug
 
 ## What license is Zarf under?
 
-Zarf is under the [Apache License 2.0](https://github.com/defenseunicorns/zarf/blob/main/LICENSE). This is one of the most commonly used licenses for open-source software.
+Zarf is under the [Apache License 2.0](https://github.com/zarf-dev/zarf/blob/main/LICENSE). This is one of the most commonly used licenses for open-source software.
 
 ## Is Zarf free to use?
 
@@ -18,7 +18,7 @@ Yes! Zarf is Free and Open-Source Software (FOSS). And will remain free forever.
 
 ## Do I have to use Homebrew to install Zarf?
 
-No, the Zarf binary and init package can be downloaded from the [Releases Page](https://github.com/defenseunicorns/zarf/releases). Zarf does not need to be installed or available to all users on the system, but it does need to be executable for the current user (i.e. `chmod +x zarf` for Linux/Mac).
+No, the Zarf binary and init package can be downloaded from the [Releases Page](https://github.com/zarf-dev/zarf/releases). Zarf does not need to be installed or available to all users on the system, but it does need to be executable for the current user (i.e. `chmod +x zarf` for Linux/Mac).
 
 ## What dependencies does Zarf have?
 
@@ -26,7 +26,7 @@ Zarf is statically compiled and written in [Go](https://golang.org/) and [Rust](
 
 ## How can I improve the speed of loading large images from Docker on `zarf package create`?
 
-Due to some limitations with how Docker provides access to local image layers, `zarf package create` has to rely on `docker save` under the hood which is [very slow overall](https://github.com/defenseunicorns/zarf/issues/1214) and also takes a long time to report progress. We experimented with many ways to improve this, but for now recommend leveraging a local docker registry to speed up the process.
+Due to some limitations with how Docker provides access to local image layers, `zarf package create` has to rely on `docker save` under the hood which is [very slow overall](https://github.com/zarf-dev/zarf/issues/1214) and also takes a long time to report progress. We experimented with many ways to improve this, but for now recommend leveraging a local docker registry to speed up the process.
 
 This can be done by running a local registry and pushing the images to it before running `zarf package create`. This will allow `zarf package create` to pull the images from the local registry instead of Docker. This can also be combined with [component actions](/ref/actions/) and [`--registry-override`](/commands/zarf_package_create/) to make the process automatic. Given an example image of `registry.enterprise.corp/my-giant-image:v2` you could do something like this:
 
@@ -74,8 +74,8 @@ metadata:
 
 components:
   repos:
-    - https://github.com/defenseunicorns/zarf.git
-    - ssh://git@github.com/defenseunicorns/zarf.git
+    - https://github.com/zarf-dev/zarf.git
+    - ssh://git@github.com/zarf-dev/zarf.git
     - file:///home/zarf/workspace/zarf
     - git://somegithost.com/zarf.git
 ```
diff --git a/site/src/content/docs/getting-started/install.mdx b/site/src/content/docs/getting-started/install.mdx
index 7c115d8cfb..c92b7ba0ef 100644
--- a/site/src/content/docs/getting-started/install.mdx
+++ b/site/src/content/docs/getting-started/install.mdx
@@ -14,12 +14,12 @@ brew tap defenseunicorns/tap && brew install zarf
 
 ## GitHub Releases
 
-All [Zarf releases](https://github.com/defenseunicorns/zarf/releases) on GitHub include prebuilt binaries that you can download and use. We offer range of combinations of OS and architecture for you to choose from.
+All [Zarf releases](https://github.com/zarf-dev/zarf/releases) on GitHub include prebuilt binaries that you can download and use. We offer range of combinations of OS and architecture for you to choose from.
 
 export const downloadScript = (os, arch) => `
-ZARF_VERSION=$(curl -sIX HEAD https://github.com/defenseunicorns/zarf/releases/latest | grep -i ^location: | grep -Eo 'v[0-9]+.[0-9]+.[0-9]+')
+ZARF_VERSION=$(curl -sIX HEAD https://github.com/zarf-dev/zarf/releases/latest | grep -i ^location: | grep -Eo 'v[0-9]+.[0-9]+.[0-9]+')
 
-curl -sL "https://github.com/defenseunicorns/zarf/releases/download/\${ZARF_VERSION}/zarf_\${ZARF_VERSION}_${os}_${arch}" -o zarf
+curl -sL "https://github.com/zarf-dev/zarf/releases/download/\${ZARF_VERSION}/zarf_\${ZARF_VERSION}_${os}_${arch}" -o zarf
 chmod +x zarf
 `
 
@@ -66,9 +66,9 @@ sudo mv zarf /usr/local/bin/zarf
 To download Zarf on Windows you can run the following (replacing `$ZarfVersion` with any release version of Zarf):
 
 export const downloadPowerShellScript = (arch) => `
-$ZarfVersion = (Invoke-RestMethod https://api.github.com/repos/defenseunicorns/zarf/releases/latest).tag_name
+$ZarfVersion = (Invoke-RestMethod https://api.github.com/repos/zarf-dev/zarf/releases/latest).tag_name
 
-Start-BitsTransfer -Source "https://github.com/defenseunicorns/zarf/releases/download/$($ZarfVersion)/zarf_$($ZarfVersion)_Windows_${arch}.exe" -Destination zarf.exe
+Start-BitsTransfer -Source "https://github.com/zarf-dev/zarf/releases/download/$($ZarfVersion)/zarf_$($ZarfVersion)_Windows_${arch}.exe" -Destination zarf.exe
 `
 
 
@@ -96,7 +96,7 @@ The following are unofficial methods of installing Zarf that are maintained by t
 If you want to build the CLI from scratch, you can do that too. Our local builds depend on [Go](https://golang.org/doc/install) and [make](https://www.gnu.org/software/make/).
 
 ```bash
-git clone https://github.com/defenseunicorns/zarf
+git clone https://github.com/zarf-dev/zarf
 cd zarf
 # build the CLI for your current OS and architecture
 make
@@ -134,7 +134,7 @@ $ zarf tools download-init
 $ zarf init --confirm
 ```
 
-The default 'init' package can also be obtained by visiting the [Zarf releases](https://github.com/defenseunicorns/zarf/releases) page and downloading it into your working directory or into `~/.zarf-cache/zarf-init--vX.X.X.tar.zst`.
+The default 'init' package can also be obtained by visiting the [Zarf releases](https://github.com/zarf-dev/zarf/releases) page and downloading it into your working directory or into `~/.zarf-cache/zarf-init--vX.X.X.tar.zst`.
 
 :::tip
 
diff --git a/site/src/content/docs/index.mdx b/site/src/content/docs/index.mdx
index 48ac086e1c..abf11bc393 100644
--- a/site/src/content/docs/index.mdx
+++ b/site/src/content/docs/index.mdx
@@ -45,7 +45,7 @@ Zarf provides a way to package and deploy software in a way that is **repeatable
 - Builtin Git server with [Gitea](https://gitea.com/)
 - Builtin Docker registry
 - Builtin [K9s Dashboard](https://k9scli.io/) for managing a cluster from the terminal
-- [Mutating Webhook](https://github.com/defenseunicorns/zarf/blob/main/adr/0005-mutating-webhook.md) to automatically update Kubernetes pod's image path and pull secrets as well as [Flux Git Repository](https://fluxcd.io/docs/components/source/gitrepositories/) URLs and secret references
+- [Mutating Webhook](https://github.com/zarf-dev/zarf/blob/main/adr/0005-mutating-webhook.md) to automatically update Kubernetes pod's image path and pull secrets as well as [Flux Git Repository](https://fluxcd.io/docs/components/source/gitrepositories/) URLs and secret references
 - Builtin [command to find images](/commands/zarf_dev_find-images/) and resources from a Helm chart
 - Tunneling capability to [connect to Kubernetes resources](/commands/zarf_connect/) without network routing, DNS, TLS or Ingress configuration required
 
diff --git a/site/src/content/docs/ref/components.mdx b/site/src/content/docs/ref/components.mdx
index b8f85d6fc6..50be327f1b 100644
--- a/site/src/content/docs/ref/components.mdx
+++ b/site/src/content/docs/ref/components.mdx
@@ -162,19 +162,19 @@ The [`podinfo-flux`](/ref/examples/podinfo-flux/) example showcases a simple Git
 
 #### Tag-Based Git Repository Clone
 
-Tag-based `git` repository cloning is the **recommended** way of cloning a `git` repository for air-gapped deployments because it wraps meaning around a specific point in git history that can easily be traced back to the online world. Tag-based clones are defined using the `scheme://host/repo@tag` format as seen in the example of the `defenseunicorns/zarf` repository (`https://github.com/defenseunicorns/zarf.git@v0.15.0`).
+Tag-based `git` repository cloning is the **recommended** way of cloning a `git` repository for air-gapped deployments because it wraps meaning around a specific point in git history that can easily be traced back to the online world. Tag-based clones are defined using the `scheme://host/repo@tag` format as seen in the example of the `zarf-dev/zarf` repository (`https://github.com/zarf-dev/zarf.git@v0.15.0`).
 
 A tag-based clone only mirrors the tag defined in the Zarf definition. The tag will be applied on the `git` mirror to a zarf-specific branch name based on the tag name (e.g. the tag `v0.1.0` will be pushed to the `zarf-ref-v0.1.0` branch).  This ensures that this tag will be pushed and received properly by the airgap `git` server.
 
 :::note
 
-If you would like to use a protocol scheme other than http/https, you can do so with something like the following: `ssh://git@github.com/defenseunicorns/zarf.git@v0.15.0`.  Using this you can also clone from a local repo to help you manage larger git repositories: `file:///home/zarf/workspace/zarf@v0.15.0`.
+If you would like to use a protocol scheme other than http/https, you can do so with something like the following: `ssh://git@github.com/zarf-dev/zarf.git@v0.15.0`.  Using this you can also clone from a local repo to help you manage larger git repositories: `file:///home/zarf/workspace/zarf@v0.15.0`.
 
 :::
 
 :::caution
 
-Because Zarf creates long-lived mirrors of repositories in the air gap, it does not support shallow clones (i.e. `git clone --depth x`).  These may be present in build environments (i.e. [GitLab runners](https://github.com/defenseunicorns/zarf/issues/1698)) and should be avoided.  To learn more about shallow and partial clones see the [GitHub blog on the topic](https://github.blog/2020-12-21-get-up-to-speed-with-partial-clone-and-shallow-clone).
+Because Zarf creates long-lived mirrors of repositories in the air gap, it does not support shallow clones (i.e. `git clone --depth x`).  These may be present in build environments (i.e. [GitLab runners](https://github.com/zarf-dev/zarf/issues/1698)) and should be avoided.  To learn more about shallow and partial clones see the [GitHub blog on the topic](https://github.blog/2020-12-21-get-up-to-speed-with-partial-clone-and-shallow-clone).
 
 :::
 
@@ -182,7 +182,7 @@ Because Zarf creates long-lived mirrors of repositories in the air gap, it does
 
 #### SHA-Based Git Repository Clone
 
-In addition to tags, Zarf also supports cloning and pushing a specific SHA hash from a `git` repository, but this is **not recommended** as it is less readable/understandable than tag cloning.  Commit SHAs are defined using the same `scheme://host/repo@shasum` format as seen in the example of the `defenseunicorns/zarf` repository (`https://github.com/defenseunicorns/zarf.git@c74e2e9626da0400e0a41e78319b3054c53a5d4e`).
+In addition to tags, Zarf also supports cloning and pushing a specific SHA hash from a `git` repository, but this is **not recommended** as it is less readable/understandable than tag cloning.  Commit SHAs are defined using the same `scheme://host/repo@shasum` format as seen in the example of the `zarf-dev/zarf` repository (`https://github.com/zarf-dev/zarf.git@c74e2e9626da0400e0a41e78319b3054c53a5d4e`).
 
 A SHA-based clone only mirrors the SHA hash defined in the Zarf definition. The SHA will be applied on the `git` mirror to a zarf-specific branch name based on the SHA hash (e.g. the SHA `c74e2e9626da0400e0a41e78319b3054c53a5d4e` will be pushed to the `zarf-ref-c74e2e9626da0400e0a41e78319b3054c53a5d4e` branch).  This ensures that this tag will be pushed and received properly by the airgap `git` server.
 
diff --git a/site/src/content/docs/ref/dev.mdx b/site/src/content/docs/ref/dev.mdx
index 10fdf34a31..bdf0fe50f7 100644
--- a/site/src/content/docs/ref/dev.mdx
+++ b/site/src/content/docs/ref/dev.mdx
@@ -8,7 +8,7 @@ tableOfContents:
 
 ## Schema Validation
 
-Zarf uses the [Zarf package schema](https://github.com/defenseunicorns/zarf/blob/main/zarf.schema.json) to define its configuration files. This schema is used to describe package configuration options and enable the validation of configuration files prior to their use in building a Zarf Package.
+Zarf uses the [Zarf package schema](https://github.com/zarf-dev/zarf/blob/main/zarf.schema.json) to define its configuration files. This schema is used to describe package configuration options and enable the validation of configuration files prior to their use in building a Zarf Package.
 
 ### `zarf dev lint`
 
@@ -28,7 +28,7 @@ zarf dev lint 
 
 ```json
   "yaml.schemas": {
-    "https://raw.githubusercontent.com/defenseunicorns/zarf/main/zarf.schema.json": "zarf.yaml"
+    "https://raw.githubusercontent.com/zarf-dev/zarf/main/zarf.schema.json": "zarf.yaml"
   }
 ```
 
@@ -43,10 +43,10 @@ When successfully installed, the `yaml.schema` line will match the color of the
 To ensure consistent validation of the Zarf schema version in a `zarf.yaml` file, it can be beneficial to lock it to a specific version. This can be achieved by appending the following statement to the **first line** of any given `zarf.yaml` file:
 
 ```yaml
-# yaml-language-server: $schema=https://raw.githubusercontent.com/defenseunicorns/zarf//zarf.schema.json
+# yaml-language-server: $schema=https://raw.githubusercontent.com/zarf-dev/zarf//zarf.schema.json
 ```
 
-In the above example, `` should be replaced with the specific [Zarf release](https://github.com/defenseunicorns/zarf/releases).
+In the above example, `` should be replaced with the specific [Zarf release](https://github.com/zarf-dev/zarf/releases).
 
 ![yaml schema](https://user-images.githubusercontent.com/92826525/226490465-1e6a56f7-41c4-45bf-923b-5242fa4ab64e.png)
 
diff --git a/site/src/content/docs/ref/init-package.mdx b/site/src/content/docs/ref/init-package.mdx
index 8a8daa55de..1af8d3d18e 100644
--- a/site/src/content/docs/ref/init-package.mdx
+++ b/site/src/content/docs/ref/init-package.mdx
@@ -51,7 +51,7 @@ While there is no distro-agnostic method to inject images into a cluster, every
 
 But then we have another problem of how to reassemble the image on the other side, as we don't have any consistent image that exists in the cluster that would have such utilities. This is where the `zarf-injector` Rust binary comes in.
 
-> For compiling the `zarf-injector` binary, refer to its [README.md](https://github.com/defenseunicorns/zarf/tree/main/src/injector/README.md).
+> For compiling the `zarf-injector` binary, refer to its [README.md](https://github.com/zarf-dev/zarf/tree/main/src/injector/README.md).
 
 The `zarf-injector` binary is statically compiled and injected into the cluster as a `configmap` along with the chunks of the `registry:2` image. During the `zarf-seed-registry`'s deployment, the `zarf-injector` binary is run in a pod that mounts the `configmaps` and reassembles the `registry:2` image. It then hosts a temporary, pull-only Docker registry implemented in Rust so that a real registry can be deployed into the cluster from the hosted `registry:2` image.
 
@@ -76,7 +76,7 @@ Doing this keeps Zarf cluster agnostic, however does require that the kubelet be
 
 :::note
 
-The `registry:2` image and the Zarf Agent image can be configured with a custom init package using the `registry_image_*` and `agent_image_*` templates defined in the Zarf repo's [zarf-config.toml](https://github.com/defenseunicorns/zarf/blob/main/zarf-config.toml).  This allows you to swap them for enterprise provided / hardened versions if desired such as those provided by [Iron Bank](https://repo1.dso.mil/dsop/opensource/defenseunicorns/zarf/zarf-agent).
+The `registry:2` image and the Zarf Agent image can be configured with a custom init package using the `registry_image_*` and `agent_image_*` templates defined in the Zarf repo's [zarf-config.toml](https://github.com/zarf-dev/zarf/blob/main/zarf-config.toml).  This allows you to swap them for enterprise provided / hardened versions if desired such as those provided by [Iron Bank](https://repo1.dso.mil/dsop/opensource/defenseunicorns/zarf/zarf-agent).
 
 :::
 
@@ -95,7 +95,7 @@ It leverages the same `docker-registry` chart used in `zarf-seed-registry` but w
 
 You can further customize how the registry behaves by setting variables such as `REGISTRY_PVC_SIZE` with a [config file](/ref/config-files/) or `--set` on `zarf init`.
 
-To see a full list of `variables` you can view the [`zarf.yaml` that defines the registry](https://github.com/defenseunicorns/zarf/blob/main/packages/zarf-registry/zarf.yaml).
+To see a full list of `variables` you can view the [`zarf.yaml` that defines the registry](https://github.com/zarf-dev/zarf/blob/main/packages/zarf-registry/zarf.yaml).
 
 :::
 
@@ -216,7 +216,7 @@ root@machine ~ # zarf init --components k3s --set K3S_ARGS="" --confirm
 
 You can further customize how the git-server behaves by setting variables such as `GIT_SERVER_PVC_SIZE` with a [config file](/ref/config-files/) or `--set` on `zarf init`.
 
-To see a full list of `variables` you can view the [zarf.yaml that defines the git-server](https://github.com/defenseunicorns/zarf/blob/main/packages/gitea/zarf.yaml).
+To see a full list of `variables` you can view the [zarf.yaml that defines the git-server](https://github.com/zarf-dev/zarf/blob/main/packages/gitea/zarf.yaml).
 
 :::
 
@@ -273,7 +273,7 @@ components:
 In order to reproduce / build the following example, you will need to have the Zarf repository cloned locally.
 
 ```bash
-git clone https://github.com/defenseunicorns/zarf.git
+git clone https://github.com/zarf-dev/zarf.git
 cd zarf
 mv zarf.yaml zarf.yaml.bak
 ```
diff --git a/site/src/content/docs/ref/packages.mdx b/site/src/content/docs/ref/packages.mdx
index 723c6ed845..5a2e3562ad 100644
--- a/site/src/content/docs/ref/packages.mdx
+++ b/site/src/content/docs/ref/packages.mdx
@@ -28,7 +28,7 @@ Typically, an init package is the first Zarf Package to be deployed on a cluster
 
 :::tip
 
-Check out our [K3s cluster package](https://github.com/defenseunicorns/zarf/blob/main/packages/distros/k3s/zarf.yaml) to see an example of a Zarf Package that installs a Kubernetes distribution
+Check out our [K3s cluster package](https://github.com/zarf-dev/zarf/blob/main/packages/distros/k3s/zarf.yaml) to see an example of a Zarf Package that installs a Kubernetes distribution
 
 :::
 
diff --git a/site/src/content/docs/roadmap.mdx b/site/src/content/docs/roadmap.mdx
index 68878e6dbb..43a80e41ad 100644
--- a/site/src/content/docs/roadmap.mdx
+++ b/site/src/content/docs/roadmap.mdx
@@ -6,15 +6,15 @@ title: Roadmap
 
 The issue board for Zarf is hosted on a [GitHub Project Board](https://github.com/orgs/defenseunicorns/projects/1) that tracks the issues the Zarf team is working along with future work we are prioritizing.
 
-If you would like to add bug reports or feature requests, please [add an issue](https://github.com/defenseunicorns/zarf/issues) to the GitHub repository under the appropriate template. If you have a more general question about a feature, feel free to ask the team in the [Zarf Kubernetes Slack Channel](https://kubernetes.slack.com/archives/C03B6BJAUJ3).
+If you would like to add bug reports or feature requests, please [add an issue](https://github.com/zarf-dev/zarf/issues) to the GitHub repository under the appropriate template. If you have a more general question about a feature, feel free to ask the team in the [Zarf Kubernetes Slack Channel](https://kubernetes.slack.com/archives/C03B6BJAUJ3).
 
-We also accept contributions from the community (regardless of where a particular bug or feature is in the queue), so feel free to read our [contributing guidelines](/contribute/contributor-guide) and [submit a PR](https://github.com/defenseunicorns/zarf/pulls)!  You can also ask any development related questions in the [Zarf Dev Kubernetes Slack Channel](https://kubernetes.slack.com/archives/C03BP9Z3CMA).
+We also accept contributions from the community (regardless of where a particular bug or feature is in the queue), so feel free to read our [contributing guidelines](/contribute/contributor-guide) and [submit a PR](https://github.com/zarf-dev/zarf/pulls)!  You can also ask any development related questions in the [Zarf Dev Kubernetes Slack Channel](https://kubernetes.slack.com/archives/C03BP9Z3CMA).
 
 ## 2024 General Roadmap
 
 ### Q1: Community Building and Refactoring
 
-- [X] - Establish a [monthly community meetup](https://github.com/defenseunicorns/zarf/issues/2202) to engage members of the community and answer questions.
+- [X] - Establish a [monthly community meetup](https://github.com/zarf-dev/zarf/issues/2202) to engage members of the community and answer questions.
 - [ ] - Refactor and add tests to library code shared with [UDS-CLI](https://github.com/defenseunicorns/uds-cli) and split into a new GitHub repository.
 - [ ] - Gather OpenSSF donation requirements and clear off pre-reqs (additional maintainers and sponsor working group).
 
@@ -81,6 +81,6 @@ Deprecated features are features that are no longer recommended for use and:
 
 ## General Availability (GA) Release
 
-Right now, Zarf itself is still in its 'beta' phase. We are working on some final things before we release the official 1.0 General Availability (GA) release. The work still needed for the GA release can be found in our issues with [this filter](https://github.com/defenseunicorns/zarf/issues?q=is%3Aopen+is%3Aissue+label%3Aga).
+Right now, Zarf itself is still in its 'beta' phase. We are working on some final things before we release the official 1.0 General Availability (GA) release. The work still needed for the GA release can be found in our issues with [this filter](https://github.com/zarf-dev/zarf/issues?q=is%3Aopen+is%3Aissue+label%3Aga).
 
 We are currently targeting Q4 2024 to have Zarf be generally available and will be pushing weekly releases until then to add necessary features and fix bugs as well as improve docs, architecture and test coverage behind the scenes.
diff --git a/site/src/content/docs/support.mdx b/site/src/content/docs/support.mdx
index 2cf650b416..b3d8aa75f1 100644
--- a/site/src/content/docs/support.mdx
+++ b/site/src/content/docs/support.mdx
@@ -8,4 +8,4 @@ title: Support
    - [Getting Started](/getting-started)
 2. Look for an answer in the [Frequently Asked Questions](/faq).
 3. Ask a question in [the Zarf Slack Channel](https://kubernetes.slack.com/archives/C03B6BJAUJ3)
-4. [Read issues, report a bug, or request a new feature](https://github.com/defenseunicorns/zarf/issues)
+4. [Read issues, report a bug, or request a new feature](https://github.com/zarf-dev/zarf/issues)
diff --git a/site/src/content/docs/tutorials/0-creating-a-zarf-package.mdx b/site/src/content/docs/tutorials/0-creating-a-zarf-package.mdx
index 84634b4386..4300d8c72f 100644
--- a/site/src/content/docs/tutorials/0-creating-a-zarf-package.mdx
+++ b/site/src/content/docs/tutorials/0-creating-a-zarf-package.mdx
@@ -27,7 +27,7 @@ In order to create a Zarf package you first need to have an idea of what applica
 
 ### Creating the Package Definition
 
-A `zarf.yaml` file follows the [Zarf Package Schema](https://github.com/defenseunicorns/zarf/blob/main/zarf.schema.json) and allows us to specify package metadata and a set of components for us to deploy. We start a package definition with the `kind` of package we are making and `metadata` that describes the package.  You can start our WordPress package by creating a new `zarf.yaml` with the following content:
+A `zarf.yaml` file follows the [Zarf Package Schema](https://github.com/zarf-dev/zarf/blob/main/zarf.schema.json) and allows us to specify package metadata and a set of components for us to deploy. We start a package definition with the `kind` of package we are making and `metadata` that describes the package.  You can start our WordPress package by creating a new `zarf.yaml` with the following content:
 
 ```yaml
 kind: ZarfPackageConfig # ZarfPackageConfig is the package kind for most normal zarf packages
@@ -40,7 +40,7 @@ metadata:
 
 :::tip
 
-You can run [`zarf dev lint `](/commands/zarf_dev_lint/) to validate against the [`zarf.schema.json`](https://github.com/defenseunicorns/zarf/blob/main/zarf.schema.json), or setup [VSCode](/ref/dev/#vscode) to see errors in real-time.
+You can run [`zarf dev lint `](/commands/zarf_dev_lint/) to validate against the [`zarf.schema.json`](https://github.com/zarf-dev/zarf/blob/main/zarf.schema.json), or setup [VSCode](/ref/dev/#vscode) to see errors in real-time.
 
 :::
 
diff --git a/site/src/content/docs/tutorials/1-initializing-a-k8s-cluster.mdx b/site/src/content/docs/tutorials/1-initializing-a-k8s-cluster.mdx
index 006d3a5743..deb26aa0ce 100644
--- a/site/src/content/docs/tutorials/1-initializing-a-k8s-cluster.mdx
+++ b/site/src/content/docs/tutorials/1-initializing-a-k8s-cluster.mdx
@@ -12,9 +12,9 @@ In this tutorial, we will demonstrate how to initialize Zarf onto a K8s cluster.
 
 Before beginning this tutorial you will need the following:
 
-- The [Zarf](https://github.com/defenseunicorns/zarf) repository cloned: ([`git clone` Instructions](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository))
+- The [Zarf](https://github.com/zarf-dev/zarf) repository cloned: ([`git clone` Instructions](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository))
 - Zarf binary installed on your $PATH: ([Installing Zarf](/getting-started/install/))
-- An init-package downloaded: ([init-package Build Instructions](/tutorials/0-creating-a-zarf-package/)) or ([Download Location](https://github.com/defenseunicorns/zarf/releases))
+- An init-package downloaded: ([init-package Build Instructions](/tutorials/0-creating-a-zarf-package/)) or ([Download Location](https://github.com/zarf-dev/zarf/releases))
 - A local Kubernetes cluster
 
 ## Initializing the Cluster
diff --git a/site/src/content/docs/tutorials/3-deploy-a-retro-arcade.mdx b/site/src/content/docs/tutorials/3-deploy-a-retro-arcade.mdx
index 9364e98bbe..abfcd55b42 100644
--- a/site/src/content/docs/tutorials/3-deploy-a-retro-arcade.mdx
+++ b/site/src/content/docs/tutorials/3-deploy-a-retro-arcade.mdx
@@ -16,7 +16,7 @@ In previous tutorials, we learned how to [create a package](/tutorials/0-creatin
 
 Before beginning this tutorial you will need the following:
 
-- The [Zarf](https://github.com/defenseunicorns/zarf) repository cloned: ([git clone instructions](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository))
+- The [Zarf](https://github.com/zarf-dev/zarf) repository cloned: ([git clone instructions](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository))
 - Zarf binary installed on your $PATH: ([Installing Zarf](/getting-started/install/))
 - [An initialized cluster](/tutorials/1-initializing-a-k8s-cluster/)
 
diff --git a/site/src/content/docs/tutorials/4-creating-a-k8s-cluster-with-zarf.mdx b/site/src/content/docs/tutorials/4-creating-a-k8s-cluster-with-zarf.mdx
index 81492468d7..2ca6056dbf 100644
--- a/site/src/content/docs/tutorials/4-creating-a-k8s-cluster-with-zarf.mdx
+++ b/site/src/content/docs/tutorials/4-creating-a-k8s-cluster-with-zarf.mdx
@@ -20,9 +20,9 @@ The 'k3s' component requires root access (not just `sudo`!) when deploying as it
 
 Before beginning this tutorial you will need the following:
 
-- The [Zarf](https://github.com/defenseunicorns/zarf) repository cloned: ([`git clone` Instructions](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository))
+- The [Zarf](https://github.com/zarf-dev/zarf) repository cloned: ([`git clone` Instructions](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository))
 - Zarf binary installed on your $PATH: ([Installing Zarf](/getting-started/install/))
-- An init-package built/downloaded: ([init-package Build Instructions](/tutorials/0-creating-a-zarf-package/)) or ([Download Location](https://github.com/defenseunicorns/zarf/releases))
+- An init-package built/downloaded: ([init-package Build Instructions](/tutorials/0-creating-a-zarf-package/)) or ([Download Location](https://github.com/zarf-dev/zarf/releases))
 
 ## Creating the Cluster
 
diff --git a/site/src/content/docs/tutorials/5-big-bang.mdx b/site/src/content/docs/tutorials/5-big-bang.mdx
index b239f73ea3..bf073df59a 100644
--- a/site/src/content/docs/tutorials/5-big-bang.mdx
+++ b/site/src/content/docs/tutorials/5-big-bang.mdx
@@ -36,7 +36,7 @@ To learn more about Big Bang's requirements in general, see their documentation:
 Before beginning this tutorial you will need the following:
 
 - A local copy of the Zarf repository
-  - `git clone https://github.com/defenseunicorns/zarf.git`
+  - `git clone https://github.com/zarf-dev/zarf.git`
 - A kubernetes cluster onto which you can deploy Zarf and Big Bang
 - The latest version of the Zarf `cli`
   - Follow instructions on https://docs.zarf.dev/getting-started/install/
@@ -208,4 +208,4 @@ See the Troubleshooting section of the Big Bang Quick Start for help troubleshoo
 
 Also, ensure that you have followed all of the steps required in the [pre-requisites](#prerequisites) section.
 
-If you feel that the error you are encountering is one with Zarf feel free to [open an issue](https://github.com/defenseunicorns/zarf/issues/new/choose) or reach out via [slack](https://kubernetes.slack.com/archives/C03B6BJAUJ3).
+If you feel that the error you are encountering is one with Zarf feel free to [open an issue](https://github.com/zarf-dev/zarf/issues/new/choose) or reach out via [slack](https://kubernetes.slack.com/archives/C03B6BJAUJ3).
diff --git a/site/src/content/docs/tutorials/7-custom-init-packages.mdx b/site/src/content/docs/tutorials/7-custom-init-packages.mdx
index e99c8f08b6..1f1e78cad9 100644
--- a/site/src/content/docs/tutorials/7-custom-init-packages.mdx
+++ b/site/src/content/docs/tutorials/7-custom-init-packages.mdx
@@ -20,7 +20,7 @@ When creating a Zarf 'init' package, you must have a network connection so that
 
 Before beginning this tutorial you will need the following:
 
-- The [Zarf](https://github.com/defenseunicorns/zarf) repository cloned: ([git clone instructions](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository))
+- The [Zarf](https://github.com/zarf-dev/zarf) repository cloned: ([git clone instructions](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository))
 - Zarf binary installed on your $PATH: ([Installing Zarf](/getting-started/install/))
 - (if building a local [`zarf-agent`](/faq#what-is-the-zarf-agent)) The [Docker CLI](https://docs.docker.com/desktop/) installed and the tools to [Build your own CLI](/getting-started/install/#building-from-source)
 
diff --git a/site/src/content/docs/tutorials/9-package-create-differential.mdx b/site/src/content/docs/tutorials/9-package-create-differential.mdx
index 176424805c..56207fab42 100644
--- a/site/src/content/docs/tutorials/9-package-create-differential.mdx
+++ b/site/src/content/docs/tutorials/9-package-create-differential.mdx
@@ -18,7 +18,7 @@ In this tutorial, you will create a differential package using Zarf.  This is us
 For following along locally, please ensure the following prerequisites are met:
 
 - Zarf binary installed on your `$PATH`: ([Installing Zarf](/getting-started/install/))
-- The [Zarf](https://github.com/defenseunicorns/zarf) repository cloned: ([`git clone` Instructions](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository))
+- The [Zarf](https://github.com/zarf-dev/zarf) repository cloned: ([`git clone` Instructions](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository))
 
 ## Create a Differential Package
 
diff --git a/site/src/content/docs/tutorials/index.mdx b/site/src/content/docs/tutorials/index.mdx
index 9c0b43ef6d..c8db1f80e5 100644
--- a/site/src/content/docs/tutorials/index.mdx
+++ b/site/src/content/docs/tutorials/index.mdx
@@ -11,9 +11,9 @@ This section of the documentation has a collection of tutorials that will help y
 If a tutorial has any prerequisites, they will be listed at the beginning of the tutorial with instructions on how to fulfill them.
 Almost all tutorials will have the following prerequisites/assumptions:
 
-1. The [Zarf](https://github.com/defenseunicorns/zarf) repository cloned: ([git clone instructions](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository))
+1. The [Zarf](https://github.com/zarf-dev/zarf) repository cloned: ([git clone instructions](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository))
 1. You have a Zarf binary installed on your $PATH: ([Installing Zarf](/getting-started/install))
-1. You have an init-package built/downloaded: ([init-package Build Instructions](/tutorials/0-creating-a-zarf-package)) or ([Download Location](https://github.com/defenseunicorns/zarf/releases))
+1. You have an init-package built/downloaded: ([init-package Build Instructions](/tutorials/0-creating-a-zarf-package)) or ([Download Location](https://github.com/zarf-dev/zarf/releases))
 1. Have a kubernetes cluster running/available (ex. [k3s](https://k3s.io/)/[k3d](https://k3d.io/v5.4.1/)/[Kind](https://kind.sigs.k8s.io/docs/user/quick-start#installation))
 
 ## Setting Up a Local Kubernetes Cluster
diff --git a/src/cmd/common/setup.go b/src/cmd/common/setup.go
index 6fab6e134b..703d9355bf 100644
--- a/src/cmd/common/setup.go
+++ b/src/cmd/common/setup.go
@@ -10,10 +10,10 @@ import (
 	"os"
 	"time"
 
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/config/lang"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
 	"github.com/pterm/pterm"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/config/lang"
+	"github.com/zarf-dev/zarf/src/pkg/message"
 )
 
 // LogLevelCLI holds the log level as input from a command
diff --git a/src/cmd/common/vendor.go b/src/cmd/common/vendor.go
index 5f10726204..a8ff1db5ad 100644
--- a/src/cmd/common/vendor.go
+++ b/src/cmd/common/vendor.go
@@ -10,8 +10,8 @@ import (
 
 	"slices"
 
-	"github.com/defenseunicorns/zarf/src/config"
 	"github.com/spf13/cobra"
+	"github.com/zarf-dev/zarf/src/config"
 )
 
 var vendorCmds = []string{
diff --git a/src/cmd/common/viper.go b/src/cmd/common/viper.go
index b852800611..bbd0f64c0c 100644
--- a/src/cmd/common/viper.go
+++ b/src/cmd/common/viper.go
@@ -8,10 +8,10 @@ import (
 	"os"
 	"strings"
 
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/config/lang"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
 	"github.com/spf13/viper"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/config/lang"
+	"github.com/zarf-dev/zarf/src/pkg/message"
 )
 
 // Constants for use when loading configurations from viper config files
diff --git a/src/cmd/connect.go b/src/cmd/connect.go
index 89eb341b45..26f012660e 100644
--- a/src/cmd/connect.go
+++ b/src/cmd/connect.go
@@ -9,10 +9,10 @@ import (
 
 	"github.com/spf13/cobra"
 
-	"github.com/defenseunicorns/zarf/src/config/lang"
-	"github.com/defenseunicorns/zarf/src/pkg/cluster"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/utils/exec"
+	"github.com/zarf-dev/zarf/src/config/lang"
+	"github.com/zarf-dev/zarf/src/pkg/cluster"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/utils/exec"
 )
 
 var (
diff --git a/src/cmd/destroy.go b/src/cmd/destroy.go
index 0faa1d5c3e..a6c45519b0 100644
--- a/src/cmd/destroy.go
+++ b/src/cmd/destroy.go
@@ -12,12 +12,12 @@ import (
 	"regexp"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/config/lang"
-	"github.com/defenseunicorns/zarf/src/internal/packager/helm"
-	"github.com/defenseunicorns/zarf/src/pkg/cluster"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/utils/exec"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/config/lang"
+	"github.com/zarf-dev/zarf/src/internal/packager/helm"
+	"github.com/zarf-dev/zarf/src/pkg/cluster"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/utils/exec"
 
 	"github.com/spf13/cobra"
 )
diff --git a/src/cmd/dev.go b/src/cmd/dev.go
index e304ca2edf..c31e0d5fe8 100644
--- a/src/cmd/dev.go
+++ b/src/cmd/dev.go
@@ -14,19 +14,19 @@ import (
 
 	"github.com/AlecAivazis/survey/v2"
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/cmd/common"
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/config/lang"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/packager"
-	"github.com/defenseunicorns/zarf/src/pkg/transform"
-	"github.com/defenseunicorns/zarf/src/pkg/utils"
-	"github.com/defenseunicorns/zarf/src/types"
 	"github.com/mholt/archiver/v3"
 	"github.com/pterm/pterm"
 	"github.com/sergi/go-diff/diffmatchpatch"
 	"github.com/spf13/cobra"
 	"github.com/spf13/viper"
+	"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/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/packager"
+	"github.com/zarf-dev/zarf/src/pkg/transform"
+	"github.com/zarf-dev/zarf/src/pkg/utils"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 var extractPath string
diff --git a/src/cmd/initialize.go b/src/cmd/initialize.go
index 2262454866..4d1c61363b 100644
--- a/src/cmd/initialize.go
+++ b/src/cmd/initialize.go
@@ -16,15 +16,15 @@ import (
 	"github.com/AlecAivazis/survey/v2"
 	"github.com/defenseunicorns/pkg/helpers/v2"
 	"github.com/defenseunicorns/pkg/oci"
-	"github.com/defenseunicorns/zarf/src/cmd/common"
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/config/lang"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/packager"
-	"github.com/defenseunicorns/zarf/src/pkg/packager/sources"
-	"github.com/defenseunicorns/zarf/src/pkg/utils"
-	"github.com/defenseunicorns/zarf/src/pkg/zoci"
-	"github.com/defenseunicorns/zarf/src/types"
+	"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/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/packager"
+	"github.com/zarf-dev/zarf/src/pkg/packager/sources"
+	"github.com/zarf-dev/zarf/src/pkg/utils"
+	"github.com/zarf-dev/zarf/src/pkg/zoci"
+	"github.com/zarf-dev/zarf/src/types"
 
 	"github.com/spf13/cobra"
 )
diff --git a/src/cmd/internal.go b/src/cmd/internal.go
index b385564151..7ff0315356 100644
--- a/src/cmd/internal.go
+++ b/src/cmd/internal.go
@@ -13,17 +13,17 @@ import (
 	"strings"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/cmd/common"
-	"github.com/defenseunicorns/zarf/src/config/lang"
-	"github.com/defenseunicorns/zarf/src/internal/agent"
-	"github.com/defenseunicorns/zarf/src/internal/packager/git"
-	"github.com/defenseunicorns/zarf/src/pkg/cluster"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/types"
 	"github.com/invopop/jsonschema"
 	"github.com/spf13/cobra"
 	"github.com/spf13/cobra/doc"
 	"github.com/spf13/pflag"
+	"github.com/zarf-dev/zarf/src/cmd/common"
+	"github.com/zarf-dev/zarf/src/config/lang"
+	"github.com/zarf-dev/zarf/src/internal/agent"
+	"github.com/zarf-dev/zarf/src/internal/packager/git"
+	"github.com/zarf-dev/zarf/src/pkg/cluster"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 var (
diff --git a/src/cmd/package.go b/src/cmd/package.go
index fa939e10bb..8b1405e25c 100644
--- a/src/cmd/package.go
+++ b/src/cmd/package.go
@@ -12,21 +12,21 @@ import (
 	"regexp"
 	"strings"
 
-	"github.com/defenseunicorns/zarf/src/cmd/common"
-	"github.com/defenseunicorns/zarf/src/config/lang"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/packager/sources"
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/cmd/common"
+	"github.com/zarf-dev/zarf/src/config/lang"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/packager/sources"
+	"github.com/zarf-dev/zarf/src/types"
 
 	"oras.land/oras-go/v2/registry"
 
 	"github.com/AlecAivazis/survey/v2"
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/pkg/cluster"
-	"github.com/defenseunicorns/zarf/src/pkg/packager"
 	"github.com/spf13/cobra"
 	"github.com/spf13/viper"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/pkg/cluster"
+	"github.com/zarf-dev/zarf/src/pkg/packager"
 )
 
 var packageCmd = &cobra.Command{
diff --git a/src/cmd/root.go b/src/cmd/root.go
index ee40254fe0..086a1cab6c 100644
--- a/src/cmd/root.go
+++ b/src/cmd/root.go
@@ -14,13 +14,13 @@ import (
 	"github.com/pterm/pterm"
 	"github.com/spf13/cobra"
 
-	"github.com/defenseunicorns/zarf/src/cmd/common"
-	"github.com/defenseunicorns/zarf/src/cmd/tools"
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/config/lang"
-	"github.com/defenseunicorns/zarf/src/pkg/layout"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/cmd/common"
+	"github.com/zarf-dev/zarf/src/cmd/tools"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/config/lang"
+	"github.com/zarf-dev/zarf/src/pkg/layout"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 var (
diff --git a/src/cmd/tools/archiver.go b/src/cmd/tools/archiver.go
index d62ce32785..e3bf2f2629 100644
--- a/src/cmd/tools/archiver.go
+++ b/src/cmd/tools/archiver.go
@@ -10,13 +10,13 @@ import (
 	"path/filepath"
 	"strings"
 
-	"github.com/defenseunicorns/zarf/src/config/lang"
-	"github.com/defenseunicorns/zarf/src/pkg/layout"
 	"github.com/mholt/archiver/v3"
 	"github.com/spf13/cobra"
+	"github.com/zarf-dev/zarf/src/config/lang"
+	"github.com/zarf-dev/zarf/src/pkg/layout"
 )
 
-// ldflags github.com/defenseunicorns/zarf/src/cmd/tools.archiverVersion=x.x.x
+// ldflags github.com/zarf-dev/zarf/src/cmd/tools.archiverVersion=x.x.x
 var archiverVersion string
 
 var archiverCmd = &cobra.Command{
diff --git a/src/cmd/tools/common.go b/src/cmd/tools/common.go
index 0844df9801..7f8f375be0 100644
--- a/src/cmd/tools/common.go
+++ b/src/cmd/tools/common.go
@@ -7,10 +7,10 @@ package tools
 import (
 	"fmt"
 
-	"github.com/defenseunicorns/zarf/src/cmd/common"
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/config/lang"
 	"github.com/spf13/cobra"
+	"github.com/zarf-dev/zarf/src/cmd/common"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/config/lang"
 )
 
 var toolsCmd = &cobra.Command{
diff --git a/src/cmd/tools/crane.go b/src/cmd/tools/crane.go
index ea8924be61..4df8daebb3 100644
--- a/src/cmd/tools/crane.go
+++ b/src/cmd/tools/crane.go
@@ -11,18 +11,18 @@ import (
 	"strings"
 
 	"github.com/AlecAivazis/survey/v2"
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/config/lang"
-	"github.com/defenseunicorns/zarf/src/internal/packager/images"
-	"github.com/defenseunicorns/zarf/src/pkg/cluster"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/transform"
-	"github.com/defenseunicorns/zarf/src/types"
 	craneCmd "github.com/google/go-containerregistry/cmd/crane/cmd"
 	"github.com/google/go-containerregistry/pkg/crane"
 	"github.com/google/go-containerregistry/pkg/logs"
 	v1 "github.com/google/go-containerregistry/pkg/v1"
 	"github.com/spf13/cobra"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/config/lang"
+	"github.com/zarf-dev/zarf/src/internal/packager/images"
+	"github.com/zarf-dev/zarf/src/pkg/cluster"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/transform"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 func init() {
diff --git a/src/cmd/tools/helm.go b/src/cmd/tools/helm.go
index dd2bf30d76..0d37f8d017 100644
--- a/src/cmd/tools/helm.go
+++ b/src/cmd/tools/helm.go
@@ -7,12 +7,12 @@ package tools
 import (
 	"os"
 
-	"github.com/defenseunicorns/zarf/src/cmd/tools/helm"
-	"github.com/defenseunicorns/zarf/src/config/lang"
+	"github.com/zarf-dev/zarf/src/cmd/tools/helm"
+	"github.com/zarf-dev/zarf/src/config/lang"
 	"helm.sh/helm/v3/pkg/action"
 )
 
-// ldflags github.com/defenseunicorns/zarf/src/cmd/tools.helmVersion=x.x.x
+// ldflags github.com/zarf-dev/zarf/src/cmd/tools.helmVersion=x.x.x
 var helmVersion string
 
 func init() {
diff --git a/src/cmd/tools/helm/repo_add.go b/src/cmd/tools/helm/repo_add.go
index de695bff5c..1d73a05467 100644
--- a/src/cmd/tools/helm/repo_add.go
+++ b/src/cmd/tools/helm/repo_add.go
@@ -31,10 +31,10 @@ import (
 	"time"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/pkg/cluster"
 	"github.com/gofrs/flock"
 	"github.com/pkg/errors"
 	"github.com/spf13/cobra"
+	"github.com/zarf-dev/zarf/src/pkg/cluster"
 	"golang.org/x/term"
 	"sigs.k8s.io/yaml"
 
diff --git a/src/cmd/tools/k9s.go b/src/cmd/tools/k9s.go
index ceabe6a547..4866548ce8 100644
--- a/src/cmd/tools/k9s.go
+++ b/src/cmd/tools/k9s.go
@@ -7,9 +7,9 @@ package tools
 import (
 	"os"
 
-	"github.com/defenseunicorns/zarf/src/config/lang"
 	k9s "github.com/derailed/k9s/cmd"
 	"github.com/spf13/cobra"
+	"github.com/zarf-dev/zarf/src/config/lang"
 
 	// This allows for go linkname to be used in this file.  Go linkname is used so that we can pull the CLI flags from k9s and generate proper docs for the vendored tool.
 	_ "unsafe"
diff --git a/src/cmd/tools/kubectl.go b/src/cmd/tools/kubectl.go
index e9eb820ff5..bccabe89f1 100644
--- a/src/cmd/tools/kubectl.go
+++ b/src/cmd/tools/kubectl.go
@@ -7,10 +7,10 @@ package tools
 import (
 	"os"
 
-	"github.com/defenseunicorns/zarf/src/cmd/common"
-	"github.com/defenseunicorns/zarf/src/config/lang"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
 	"github.com/spf13/cobra"
+	"github.com/zarf-dev/zarf/src/cmd/common"
+	"github.com/zarf-dev/zarf/src/config/lang"
+	"github.com/zarf-dev/zarf/src/pkg/message"
 	kubeCLI "k8s.io/component-base/cli"
 	kubeCmd "k8s.io/kubectl/pkg/cmd"
 
diff --git a/src/cmd/tools/syft.go b/src/cmd/tools/syft.go
index 1b466027a3..57051021a0 100644
--- a/src/cmd/tools/syft.go
+++ b/src/cmd/tools/syft.go
@@ -7,10 +7,10 @@ package tools
 import (
 	"github.com/anchore/clio"
 	syftCLI "github.com/anchore/syft/cmd/syft/cli"
-	"github.com/defenseunicorns/zarf/src/config/lang"
+	"github.com/zarf-dev/zarf/src/config/lang"
 )
 
-// ldflags github.com/defenseunicorns/zarf/src/cmd/tools.syftVersion=x.x.x
+// ldflags github.com/zarf-dev/zarf/src/cmd/tools.syftVersion=x.x.x
 var syftVersion string
 
 func init() {
diff --git a/src/cmd/tools/wait.go b/src/cmd/tools/wait.go
index bb767ec972..fda0344fbc 100644
--- a/src/cmd/tools/wait.go
+++ b/src/cmd/tools/wait.go
@@ -8,10 +8,10 @@ import (
 	"fmt"
 	"time"
 
-	"github.com/defenseunicorns/zarf/src/config/lang"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/utils"
 	"github.com/spf13/cobra"
+	"github.com/zarf-dev/zarf/src/config/lang"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/utils"
 
 	// Import to initialize client auth plugins.
 	_ "k8s.io/client-go/plugin/pkg/client/auth"
diff --git a/src/cmd/tools/yq.go b/src/cmd/tools/yq.go
index 4dbf43ddff..85d72ab767 100644
--- a/src/cmd/tools/yq.go
+++ b/src/cmd/tools/yq.go
@@ -5,8 +5,8 @@
 package tools
 
 import (
-	"github.com/defenseunicorns/zarf/src/config/lang"
 	yq "github.com/mikefarah/yq/v4/cmd"
+	"github.com/zarf-dev/zarf/src/config/lang"
 )
 
 func init() {
diff --git a/src/cmd/tools/zarf.go b/src/cmd/tools/zarf.go
index f911b2ec40..3f97be20eb 100644
--- a/src/cmd/tools/zarf.go
+++ b/src/cmd/tools/zarf.go
@@ -18,18 +18,18 @@ import (
 	"github.com/defenseunicorns/pkg/helpers/v2"
 	"github.com/defenseunicorns/pkg/oci"
 
-	"github.com/defenseunicorns/zarf/src/cmd/common"
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/config/lang"
-	"github.com/defenseunicorns/zarf/src/internal/packager/git"
-	"github.com/defenseunicorns/zarf/src/internal/packager/helm"
-	"github.com/defenseunicorns/zarf/src/internal/packager/template"
-	"github.com/defenseunicorns/zarf/src/pkg/cluster"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/packager/sources"
-	"github.com/defenseunicorns/zarf/src/pkg/pki"
-	"github.com/defenseunicorns/zarf/src/pkg/zoci"
-	"github.com/defenseunicorns/zarf/src/types"
+	"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/packager/git"
+	"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"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/packager/sources"
+	"github.com/zarf-dev/zarf/src/pkg/pki"
+	"github.com/zarf-dev/zarf/src/pkg/zoci"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 var subAltNames []string
diff --git a/src/cmd/version.go b/src/cmd/version.go
index 589cab9929..26299c7db5 100644
--- a/src/cmd/version.go
+++ b/src/cmd/version.go
@@ -15,8 +15,8 @@ import (
 	goyaml "github.com/goccy/go-yaml"
 	"github.com/spf13/cobra"
 
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/config/lang"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/config/lang"
 )
 
 var outputFormat string
diff --git a/src/config/config.go b/src/config/config.go
index 203767f6d8..4f55f48e61 100644
--- a/src/config/config.go
+++ b/src/config/config.go
@@ -12,7 +12,7 @@ import (
 	"strings"
 	"time"
 
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 // Zarf Global Configuration Constants.
diff --git a/src/extensions/bigbang/banner.go b/src/extensions/bigbang/banner.go
index 07314b3141..e6791eec58 100644
--- a/src/extensions/bigbang/banner.go
+++ b/src/extensions/bigbang/banner.go
@@ -5,8 +5,8 @@
 package bigbang
 
 import (
-	"github.com/defenseunicorns/zarf/src/pkg/message"
 	"github.com/pterm/pterm"
+	"github.com/zarf-dev/zarf/src/pkg/message"
 )
 
 func printBanner() {
diff --git a/src/extensions/bigbang/bigbang.go b/src/extensions/bigbang/bigbang.go
index b89b61f460..b97c8f6e25 100644
--- a/src/extensions/bigbang/bigbang.go
+++ b/src/extensions/bigbang/bigbang.go
@@ -14,15 +14,15 @@ import (
 
 	"github.com/Masterminds/semver/v3"
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/internal/packager/helm"
-	"github.com/defenseunicorns/zarf/src/pkg/layout"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/utils"
-	"github.com/defenseunicorns/zarf/src/pkg/variables"
-	"github.com/defenseunicorns/zarf/src/types"
-	"github.com/defenseunicorns/zarf/src/types/extensions"
 	fluxHelmCtrl "github.com/fluxcd/helm-controller/api/v2beta1"
 	fluxSrcCtrl "github.com/fluxcd/source-controller/api/v1beta2"
+	"github.com/zarf-dev/zarf/src/internal/packager/helm"
+	"github.com/zarf-dev/zarf/src/pkg/layout"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/utils"
+	"github.com/zarf-dev/zarf/src/pkg/variables"
+	"github.com/zarf-dev/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/types/extensions"
 	"helm.sh/helm/v3/pkg/chartutil"
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
diff --git a/src/extensions/bigbang/flux.go b/src/extensions/bigbang/flux.go
index e67129c07c..d67097f26c 100644
--- a/src/extensions/bigbang/flux.go
+++ b/src/extensions/bigbang/flux.go
@@ -11,11 +11,11 @@ import (
 	"path/filepath"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/internal/packager/kustomize"
-	"github.com/defenseunicorns/zarf/src/pkg/utils"
-	"github.com/defenseunicorns/zarf/src/types"
-	"github.com/defenseunicorns/zarf/src/types/extensions"
 	fluxHelmCtrl "github.com/fluxcd/helm-controller/api/v2beta1"
+	"github.com/zarf-dev/zarf/src/internal/packager/kustomize"
+	"github.com/zarf-dev/zarf/src/pkg/utils"
+	"github.com/zarf-dev/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/types/extensions"
 	"helm.sh/helm/v3/pkg/chartutil"
 	v1 "k8s.io/api/apps/v1"
 	corev1 "k8s.io/api/core/v1"
diff --git a/src/extensions/bigbang/manifests.go b/src/extensions/bigbang/manifests.go
index cec481d6cb..3eb88bee6c 100644
--- a/src/extensions/bigbang/manifests.go
+++ b/src/extensions/bigbang/manifests.go
@@ -11,9 +11,9 @@ import (
 	"strings"
 
 	"github.com/Masterminds/semver/v3"
-	"github.com/defenseunicorns/zarf/src/types/extensions"
 	fluxHelmCtrl "github.com/fluxcd/helm-controller/api/v2beta1"
 	fluxSrcCtrl "github.com/fluxcd/source-controller/api/v1"
+	"github.com/zarf-dev/zarf/src/types/extensions"
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
diff --git a/src/extensions/bigbang/test/bigbang_test.go b/src/extensions/bigbang/test/bigbang_test.go
index 4e016c6a6f..641ba566d1 100644
--- a/src/extensions/bigbang/test/bigbang_test.go
+++ b/src/extensions/bigbang/test/bigbang_test.go
@@ -14,10 +14,10 @@ import (
 	"strings"
 	"testing"
 
-	"github.com/defenseunicorns/zarf/src/pkg/cluster"
-	"github.com/defenseunicorns/zarf/src/pkg/utils/exec"
-	test "github.com/defenseunicorns/zarf/src/test"
 	"github.com/stretchr/testify/require"
+	"github.com/zarf-dev/zarf/src/pkg/cluster"
+	"github.com/zarf-dev/zarf/src/pkg/utils/exec"
+	test "github.com/zarf-dev/zarf/src/test"
 )
 
 // The Big Bang project ID on Repo1
diff --git a/src/internal/agent/hooks/argocd-application.go b/src/internal/agent/hooks/argocd-application.go
index b9197bae51..8886ba2ff9 100644
--- a/src/internal/agent/hooks/argocd-application.go
+++ b/src/internal/agent/hooks/argocd-application.go
@@ -10,12 +10,12 @@ import (
 	"fmt"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/config/lang"
-	"github.com/defenseunicorns/zarf/src/internal/agent/operations"
-	"github.com/defenseunicorns/zarf/src/pkg/cluster"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/transform"
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/config/lang"
+	"github.com/zarf-dev/zarf/src/internal/agent/operations"
+	"github.com/zarf-dev/zarf/src/pkg/cluster"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/transform"
+	"github.com/zarf-dev/zarf/src/types"
 	v1 "k8s.io/api/admission/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
diff --git a/src/internal/agent/hooks/argocd-application_test.go b/src/internal/agent/hooks/argocd-application_test.go
index 6ef39b2730..31ec452959 100644
--- a/src/internal/agent/hooks/argocd-application_test.go
+++ b/src/internal/agent/hooks/argocd-application_test.go
@@ -9,10 +9,10 @@ import (
 	"net/http"
 	"testing"
 
-	"github.com/defenseunicorns/zarf/src/internal/agent/http/admission"
-	"github.com/defenseunicorns/zarf/src/internal/agent/operations"
-	"github.com/defenseunicorns/zarf/src/types"
 	"github.com/stretchr/testify/require"
+	"github.com/zarf-dev/zarf/src/internal/agent/http/admission"
+	"github.com/zarf-dev/zarf/src/internal/agent/operations"
+	"github.com/zarf-dev/zarf/src/types"
 	v1 "k8s.io/api/admission/v1"
 	"k8s.io/apimachinery/pkg/runtime"
 )
diff --git a/src/internal/agent/hooks/argocd-repository.go b/src/internal/agent/hooks/argocd-repository.go
index 23e05df999..2311b50511 100644
--- a/src/internal/agent/hooks/argocd-repository.go
+++ b/src/internal/agent/hooks/argocd-repository.go
@@ -11,12 +11,12 @@ import (
 	"fmt"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/config/lang"
-	"github.com/defenseunicorns/zarf/src/internal/agent/operations"
-	"github.com/defenseunicorns/zarf/src/pkg/cluster"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/transform"
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/config/lang"
+	"github.com/zarf-dev/zarf/src/internal/agent/operations"
+	"github.com/zarf-dev/zarf/src/pkg/cluster"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/transform"
+	"github.com/zarf-dev/zarf/src/types"
 	v1 "k8s.io/api/admission/v1"
 	corev1 "k8s.io/api/core/v1"
 )
diff --git a/src/internal/agent/hooks/argocd-repository_test.go b/src/internal/agent/hooks/argocd-repository_test.go
index 4506b682e1..fdc99fe1c2 100644
--- a/src/internal/agent/hooks/argocd-repository_test.go
+++ b/src/internal/agent/hooks/argocd-repository_test.go
@@ -10,10 +10,10 @@ import (
 	"net/http"
 	"testing"
 
-	"github.com/defenseunicorns/zarf/src/internal/agent/http/admission"
-	"github.com/defenseunicorns/zarf/src/internal/agent/operations"
-	"github.com/defenseunicorns/zarf/src/types"
 	"github.com/stretchr/testify/require"
+	"github.com/zarf-dev/zarf/src/internal/agent/http/admission"
+	"github.com/zarf-dev/zarf/src/internal/agent/operations"
+	"github.com/zarf-dev/zarf/src/types"
 	v1 "k8s.io/api/admission/v1"
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
diff --git a/src/internal/agent/hooks/common.go b/src/internal/agent/hooks/common.go
index ed1de69797..52ea3bb509 100644
--- a/src/internal/agent/hooks/common.go
+++ b/src/internal/agent/hooks/common.go
@@ -4,7 +4,7 @@
 // Package hooks contains the mutation hooks for the Zarf agent.
 package hooks
 
-import "github.com/defenseunicorns/zarf/src/internal/agent/operations"
+import "github.com/zarf-dev/zarf/src/internal/agent/operations"
 
 func getLabelPatch(currLabels map[string]string) operations.PatchOperation {
 	if currLabels == nil {
diff --git a/src/internal/agent/hooks/flux-gitrepo.go b/src/internal/agent/hooks/flux-gitrepo.go
index 8256b40aae..079ee6a8e0 100644
--- a/src/internal/agent/hooks/flux-gitrepo.go
+++ b/src/internal/agent/hooks/flux-gitrepo.go
@@ -10,14 +10,14 @@ import (
 	"fmt"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/config/lang"
-	"github.com/defenseunicorns/zarf/src/internal/agent/operations"
-	"github.com/defenseunicorns/zarf/src/pkg/cluster"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/transform"
 	fluxmeta "github.com/fluxcd/pkg/apis/meta"
 	flux "github.com/fluxcd/source-controller/api/v1"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/config/lang"
+	"github.com/zarf-dev/zarf/src/internal/agent/operations"
+	"github.com/zarf-dev/zarf/src/pkg/cluster"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/transform"
 	v1 "k8s.io/api/admission/v1"
 )
 
diff --git a/src/internal/agent/hooks/flux-gitrepo_test.go b/src/internal/agent/hooks/flux-gitrepo_test.go
index a68cbfe591..dc9c17a093 100644
--- a/src/internal/agent/hooks/flux-gitrepo_test.go
+++ b/src/internal/agent/hooks/flux-gitrepo_test.go
@@ -9,13 +9,13 @@ import (
 	"net/http"
 	"testing"
 
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/internal/agent/http/admission"
-	"github.com/defenseunicorns/zarf/src/internal/agent/operations"
-	"github.com/defenseunicorns/zarf/src/types"
 	fluxmeta "github.com/fluxcd/pkg/apis/meta"
 	flux "github.com/fluxcd/source-controller/api/v1"
 	"github.com/stretchr/testify/require"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/internal/agent/http/admission"
+	"github.com/zarf-dev/zarf/src/internal/agent/operations"
+	"github.com/zarf-dev/zarf/src/types"
 	v1 "k8s.io/api/admission/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
diff --git a/src/internal/agent/hooks/flux-helmrepo.go b/src/internal/agent/hooks/flux-helmrepo.go
index 6fb0e7e712..90aab22f7a 100644
--- a/src/internal/agent/hooks/flux-helmrepo.go
+++ b/src/internal/agent/hooks/flux-helmrepo.go
@@ -11,14 +11,14 @@ import (
 	"strings"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/config/lang"
-	"github.com/defenseunicorns/zarf/src/internal/agent/operations"
-	"github.com/defenseunicorns/zarf/src/pkg/cluster"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/transform"
 	"github.com/fluxcd/pkg/apis/meta"
 	flux "github.com/fluxcd/source-controller/api/v1"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/config/lang"
+	"github.com/zarf-dev/zarf/src/internal/agent/operations"
+	"github.com/zarf-dev/zarf/src/pkg/cluster"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/transform"
 	v1 "k8s.io/api/admission/v1"
 )
 
diff --git a/src/internal/agent/hooks/flux-helmrepo_test.go b/src/internal/agent/hooks/flux-helmrepo_test.go
index 85895bd31b..d0e48a0074 100644
--- a/src/internal/agent/hooks/flux-helmrepo_test.go
+++ b/src/internal/agent/hooks/flux-helmrepo_test.go
@@ -9,13 +9,13 @@ import (
 	"net/http"
 	"testing"
 
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/internal/agent/http/admission"
-	"github.com/defenseunicorns/zarf/src/internal/agent/operations"
-	"github.com/defenseunicorns/zarf/src/types"
 	fluxmeta "github.com/fluxcd/pkg/apis/meta"
 	flux "github.com/fluxcd/source-controller/api/v1"
 	"github.com/stretchr/testify/require"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/internal/agent/http/admission"
+	"github.com/zarf-dev/zarf/src/internal/agent/operations"
+	"github.com/zarf-dev/zarf/src/types"
 	v1 "k8s.io/api/admission/v1"
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
diff --git a/src/internal/agent/hooks/flux-ocirepo.go b/src/internal/agent/hooks/flux-ocirepo.go
index 00d7ded917..045b315e3a 100644
--- a/src/internal/agent/hooks/flux-ocirepo.go
+++ b/src/internal/agent/hooks/flux-ocirepo.go
@@ -10,14 +10,14 @@ import (
 	"fmt"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/config/lang"
-	"github.com/defenseunicorns/zarf/src/internal/agent/operations"
-	"github.com/defenseunicorns/zarf/src/pkg/cluster"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/transform"
 	"github.com/fluxcd/pkg/apis/meta"
 	flux "github.com/fluxcd/source-controller/api/v1beta2"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/config/lang"
+	"github.com/zarf-dev/zarf/src/internal/agent/operations"
+	"github.com/zarf-dev/zarf/src/pkg/cluster"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/transform"
 	v1 "k8s.io/api/admission/v1"
 )
 
diff --git a/src/internal/agent/hooks/flux-ocirepo_test.go b/src/internal/agent/hooks/flux-ocirepo_test.go
index 4b2ff6cf57..5cab4d2530 100644
--- a/src/internal/agent/hooks/flux-ocirepo_test.go
+++ b/src/internal/agent/hooks/flux-ocirepo_test.go
@@ -9,13 +9,13 @@ import (
 	"net/http"
 	"testing"
 
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/internal/agent/http/admission"
-	"github.com/defenseunicorns/zarf/src/internal/agent/operations"
-	"github.com/defenseunicorns/zarf/src/types"
 	fluxmeta "github.com/fluxcd/pkg/apis/meta"
 	flux "github.com/fluxcd/source-controller/api/v1beta2"
 	"github.com/stretchr/testify/require"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/internal/agent/http/admission"
+	"github.com/zarf-dev/zarf/src/internal/agent/operations"
+	"github.com/zarf-dev/zarf/src/types"
 	v1 "k8s.io/api/admission/v1"
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
diff --git a/src/internal/agent/hooks/pods.go b/src/internal/agent/hooks/pods.go
index a152aa4a8a..1eaccb5fbb 100644
--- a/src/internal/agent/hooks/pods.go
+++ b/src/internal/agent/hooks/pods.go
@@ -9,12 +9,12 @@ import (
 	"encoding/json"
 	"fmt"
 
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/config/lang"
-	"github.com/defenseunicorns/zarf/src/internal/agent/operations"
-	"github.com/defenseunicorns/zarf/src/pkg/cluster"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/transform"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/config/lang"
+	"github.com/zarf-dev/zarf/src/internal/agent/operations"
+	"github.com/zarf-dev/zarf/src/pkg/cluster"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/transform"
 	v1 "k8s.io/api/admission/v1"
 
 	corev1 "k8s.io/api/core/v1"
diff --git a/src/internal/agent/hooks/pods_test.go b/src/internal/agent/hooks/pods_test.go
index 3a41f9227c..dafa786f8c 100644
--- a/src/internal/agent/hooks/pods_test.go
+++ b/src/internal/agent/hooks/pods_test.go
@@ -9,11 +9,11 @@ import (
 	"net/http"
 	"testing"
 
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/internal/agent/http/admission"
-	"github.com/defenseunicorns/zarf/src/internal/agent/operations"
-	"github.com/defenseunicorns/zarf/src/types"
 	"github.com/stretchr/testify/require"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/internal/agent/http/admission"
+	"github.com/zarf-dev/zarf/src/internal/agent/operations"
+	"github.com/zarf-dev/zarf/src/types"
 	v1 "k8s.io/api/admission/v1"
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
diff --git a/src/internal/agent/hooks/utils_test.go b/src/internal/agent/hooks/utils_test.go
index f2d4ed6136..84ee8a4c47 100644
--- a/src/internal/agent/hooks/utils_test.go
+++ b/src/internal/agent/hooks/utils_test.go
@@ -11,10 +11,10 @@ import (
 	"net/http/httptest"
 	"testing"
 
-	"github.com/defenseunicorns/zarf/src/internal/agent/operations"
-	"github.com/defenseunicorns/zarf/src/pkg/cluster"
-	"github.com/defenseunicorns/zarf/src/types"
 	"github.com/stretchr/testify/require"
+	"github.com/zarf-dev/zarf/src/internal/agent/operations"
+	"github.com/zarf-dev/zarf/src/pkg/cluster"
+	"github.com/zarf-dev/zarf/src/types"
 	v1 "k8s.io/api/admission/v1"
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
diff --git a/src/internal/agent/http/admission/handler.go b/src/internal/agent/http/admission/handler.go
index f1d3cd8ead..56589a7c73 100644
--- a/src/internal/agent/http/admission/handler.go
+++ b/src/internal/agent/http/admission/handler.go
@@ -12,9 +12,9 @@ import (
 	"io"
 	"net/http"
 
-	"github.com/defenseunicorns/zarf/src/config/lang"
-	"github.com/defenseunicorns/zarf/src/internal/agent/operations"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/config/lang"
+	"github.com/zarf-dev/zarf/src/internal/agent/operations"
+	"github.com/zarf-dev/zarf/src/pkg/message"
 	corev1 "k8s.io/api/admission/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
diff --git a/src/internal/agent/http/proxy.go b/src/internal/agent/http/proxy.go
index 2a78b88eea..8a9d939507 100644
--- a/src/internal/agent/http/proxy.go
+++ b/src/internal/agent/http/proxy.go
@@ -14,10 +14,10 @@ import (
 	"net/url"
 	"strings"
 
-	"github.com/defenseunicorns/zarf/src/config/lang"
-	"github.com/defenseunicorns/zarf/src/pkg/cluster"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/transform"
+	"github.com/zarf-dev/zarf/src/config/lang"
+	"github.com/zarf-dev/zarf/src/pkg/cluster"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/transform"
 )
 
 // ProxyHandler constructs a new httputil.ReverseProxy and returns an http handler.
diff --git a/src/internal/agent/http/server.go b/src/internal/agent/http/server.go
index 62fb72c59d..b5953ee0e2 100644
--- a/src/internal/agent/http/server.go
+++ b/src/internal/agent/http/server.go
@@ -10,11 +10,11 @@ import (
 	"net/http"
 	"time"
 
-	"github.com/defenseunicorns/zarf/src/internal/agent/hooks"
-	"github.com/defenseunicorns/zarf/src/internal/agent/http/admission"
-	"github.com/defenseunicorns/zarf/src/pkg/cluster"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
 	"github.com/prometheus/client_golang/prometheus/promhttp"
+	"github.com/zarf-dev/zarf/src/internal/agent/hooks"
+	"github.com/zarf-dev/zarf/src/internal/agent/http/admission"
+	"github.com/zarf-dev/zarf/src/pkg/cluster"
+	"github.com/zarf-dev/zarf/src/pkg/message"
 )
 
 // NewAdmissionServer creates a http.Server for the mutating webhook admission handler.
diff --git a/src/internal/agent/operations/hook.go b/src/internal/agent/operations/hook.go
index 5ce42b8810..627ce58094 100644
--- a/src/internal/agent/operations/hook.go
+++ b/src/internal/agent/operations/hook.go
@@ -7,8 +7,8 @@ package operations
 import (
 	"fmt"
 
-	"github.com/defenseunicorns/zarf/src/config/lang"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/config/lang"
+	"github.com/zarf-dev/zarf/src/pkg/message"
 	admission "k8s.io/api/admission/v1"
 )
 
diff --git a/src/internal/agent/start.go b/src/internal/agent/start.go
index 9acd2afcc4..80a04c642f 100644
--- a/src/internal/agent/start.go
+++ b/src/internal/agent/start.go
@@ -12,9 +12,9 @@ import (
 
 	"golang.org/x/sync/errgroup"
 
-	"github.com/defenseunicorns/zarf/src/config/lang"
-	agentHttp "github.com/defenseunicorns/zarf/src/internal/agent/http"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/config/lang"
+	agentHttp "github.com/zarf-dev/zarf/src/internal/agent/http"
+	"github.com/zarf-dev/zarf/src/pkg/message"
 )
 
 // Heavily influenced by https://github.com/douglasmakey/admissioncontroller and
diff --git a/src/internal/packager/git/checkout.go b/src/internal/packager/git/checkout.go
index 2a39382cda..4441e48873 100644
--- a/src/internal/packager/git/checkout.go
+++ b/src/internal/packager/git/checkout.go
@@ -7,10 +7,10 @@ package git
 import (
 	"fmt"
 
-	"github.com/defenseunicorns/zarf/src/pkg/message"
 	"github.com/go-git/go-git/v5"
 	"github.com/go-git/go-git/v5/plumbing"
 	"github.com/go-git/go-git/v5/plumbing/object"
+	"github.com/zarf-dev/zarf/src/pkg/message"
 )
 
 // CheckoutTag performs a `git checkout` of the provided tag to a detached HEAD.
diff --git a/src/internal/packager/git/clone.go b/src/internal/packager/git/clone.go
index 0123b81f2f..6e70077511 100644
--- a/src/internal/packager/git/clone.go
+++ b/src/internal/packager/git/clone.go
@@ -9,12 +9,12 @@ import (
 	"errors"
 	"strings"
 
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/utils"
-	"github.com/defenseunicorns/zarf/src/pkg/utils/exec"
 	"github.com/go-git/go-git/v5"
 	goConfig "github.com/go-git/go-git/v5/config"
 	"github.com/go-git/go-git/v5/plumbing"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/utils"
+	"github.com/zarf-dev/zarf/src/pkg/utils/exec"
 )
 
 // clone performs a `git clone` of a given repo.
diff --git a/src/internal/packager/git/common.go b/src/internal/packager/git/common.go
index 1c03fd3343..6864d3dea5 100644
--- a/src/internal/packager/git/common.go
+++ b/src/internal/packager/git/common.go
@@ -8,9 +8,9 @@ import (
 	"fmt"
 	"strings"
 
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/types"
 	"github.com/go-git/go-git/v5/plumbing"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 // Git is the main struct for managing git repositories.
diff --git a/src/internal/packager/git/gitea.go b/src/internal/packager/git/gitea.go
index 7bf9afe53f..a6c2f4b48a 100644
--- a/src/internal/packager/git/gitea.go
+++ b/src/internal/packager/git/gitea.go
@@ -16,10 +16,10 @@ import (
 
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/pkg/cluster"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/pkg/cluster"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 // CreateTokenResponse is the response given from creating a token in Gitea
diff --git a/src/internal/packager/git/pull.go b/src/internal/packager/git/pull.go
index 79313cde32..bd2472c08c 100644
--- a/src/internal/packager/git/pull.go
+++ b/src/internal/packager/git/pull.go
@@ -9,10 +9,10 @@ import (
 	"path"
 	"strings"
 
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/pkg/transform"
-	"github.com/defenseunicorns/zarf/src/pkg/utils"
 	"github.com/go-git/go-git/v5/plumbing"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/pkg/transform"
+	"github.com/zarf-dev/zarf/src/pkg/utils"
 )
 
 // DownloadRepoToTemp clones or updates a repo into a temp folder to perform ephemeral actions (i.e. process chart repos).
diff --git a/src/internal/packager/git/push.go b/src/internal/packager/git/push.go
index 9bd52e2c79..494ee40db6 100644
--- a/src/internal/packager/git/push.go
+++ b/src/internal/packager/git/push.go
@@ -10,13 +10,13 @@ import (
 	"os"
 	"path"
 
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/transform"
 	"github.com/go-git/go-git/v5"
 	goConfig "github.com/go-git/go-git/v5/config"
 	"github.com/go-git/go-git/v5/plumbing"
 	"github.com/go-git/go-git/v5/plumbing/transport"
 	"github.com/go-git/go-git/v5/plumbing/transport/http"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/transform"
 )
 
 // PushRepo pushes a git repository from the local path to the configured git server.
@@ -145,7 +145,7 @@ func (g *Git) push(repo *git.Repository, spinner *message.Spinner) error {
 		RemoteName: offlineRemoteName,
 		Auth:       &gitCred,
 		Progress:   spinner,
-		// TODO: (@JEFFMCCOY) add the parsing for the `+` force prefix (see https://github.com/defenseunicorns/zarf/issues/1410)
+		// TODO: (@JEFFMCCOY) add the parsing for the `+` force prefix (see https://github.com/zarf-dev/zarf/issues/1410)
 		//Force: isForce,
 		// If a provided refspec doesn't push anything, it is just ignored
 		RefSpecs: []goConfig.RefSpec{
diff --git a/src/internal/packager/helm/chart.go b/src/internal/packager/helm/chart.go
index 0ff647b60a..f9ac5eefe0 100644
--- a/src/internal/packager/helm/chart.go
+++ b/src/internal/packager/helm/chart.go
@@ -24,9 +24,9 @@ import (
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
 
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 // InstallOrUpgradeChart performs a helm install of the given chart.
diff --git a/src/internal/packager/helm/common.go b/src/internal/packager/helm/common.go
index 6fba4d364e..e4dd729a19 100644
--- a/src/internal/packager/helm/common.go
+++ b/src/internal/packager/helm/common.go
@@ -14,11 +14,11 @@ import (
 	"strconv"
 	"time"
 
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/pkg/cluster"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/variables"
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/pkg/cluster"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/variables"
+	"github.com/zarf-dev/zarf/src/types"
 	"helm.sh/helm/v3/pkg/action"
 	"helm.sh/helm/v3/pkg/chart"
 	"helm.sh/helm/v3/pkg/cli"
diff --git a/src/internal/packager/helm/destroy.go b/src/internal/packager/helm/destroy.go
index 8f7060c7c7..44c519a00a 100644
--- a/src/internal/packager/helm/destroy.go
+++ b/src/internal/packager/helm/destroy.go
@@ -7,8 +7,8 @@ package helm
 import (
 	"regexp"
 
-	"github.com/defenseunicorns/zarf/src/pkg/cluster"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/cluster"
+	"github.com/zarf-dev/zarf/src/pkg/message"
 	"helm.sh/helm/v3/pkg/action"
 )
 
diff --git a/src/internal/packager/helm/images.go b/src/internal/packager/helm/images.go
index 447aefc780..390ce5c8be 100644
--- a/src/internal/packager/helm/images.go
+++ b/src/internal/packager/helm/images.go
@@ -5,8 +5,8 @@ package helm
 
 import (
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
 	"github.com/goccy/go-yaml"
+	"github.com/zarf-dev/zarf/src/pkg/message"
 	"helm.sh/helm/v3/pkg/chart/loader"
 	"helm.sh/helm/v3/pkg/chartutil"
 )
diff --git a/src/internal/packager/helm/post-render.go b/src/internal/packager/helm/post-render.go
index b03aa6a93a..5f45b437a0 100644
--- a/src/internal/packager/helm/post-render.go
+++ b/src/internal/packager/helm/post-render.go
@@ -14,11 +14,11 @@ import (
 	"slices"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/pkg/cluster"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/utils"
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/pkg/cluster"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/utils"
+	"github.com/zarf-dev/zarf/src/types"
 	"helm.sh/helm/v3/pkg/releaseutil"
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/client-go/dynamic"
diff --git a/src/internal/packager/helm/repo.go b/src/internal/packager/helm/repo.go
index 6bc19c8e50..c3ea9c646f 100644
--- a/src/internal/packager/helm/repo.go
+++ b/src/internal/packager/helm/repo.go
@@ -11,13 +11,13 @@ import (
 	"strings"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/config/lang"
-	"github.com/defenseunicorns/zarf/src/internal/packager/git"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/transform"
-	"github.com/defenseunicorns/zarf/src/pkg/utils"
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/config/lang"
+	"github.com/zarf-dev/zarf/src/internal/packager/git"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/transform"
+	"github.com/zarf-dev/zarf/src/pkg/utils"
+	"github.com/zarf-dev/zarf/src/types"
 	"helm.sh/helm/v3/pkg/action"
 	"helm.sh/helm/v3/pkg/chart"
 	"helm.sh/helm/v3/pkg/cli"
diff --git a/src/internal/packager/helm/utils.go b/src/internal/packager/helm/utils.go
index 4f6119de8e..8d3d5f3202 100644
--- a/src/internal/packager/helm/utils.go
+++ b/src/internal/packager/helm/utils.go
@@ -8,7 +8,7 @@ import (
 	"fmt"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/message"
 	"helm.sh/helm/v3/pkg/action"
 	"helm.sh/helm/v3/pkg/chart"
 	"helm.sh/helm/v3/pkg/chartutil"
diff --git a/src/internal/packager/helm/zarf.go b/src/internal/packager/helm/zarf.go
index 91d3fe917f..0381ef4b52 100644
--- a/src/internal/packager/helm/zarf.go
+++ b/src/internal/packager/helm/zarf.go
@@ -17,13 +17,13 @@ import (
 
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
-	"github.com/defenseunicorns/zarf/src/internal/packager/template"
-	"github.com/defenseunicorns/zarf/src/pkg/cluster"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/transform"
-	"github.com/defenseunicorns/zarf/src/pkg/utils"
-	"github.com/defenseunicorns/zarf/src/pkg/variables"
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/internal/packager/template"
+	"github.com/zarf-dev/zarf/src/pkg/cluster"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/transform"
+	"github.com/zarf-dev/zarf/src/pkg/utils"
+	"github.com/zarf-dev/zarf/src/pkg/variables"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 // UpdateZarfRegistryValues updates the Zarf registry deployment with the new state values
diff --git a/src/internal/packager/images/common.go b/src/internal/packager/images/common.go
index 8efb18f12d..3e2ad406ff 100644
--- a/src/internal/packager/images/common.go
+++ b/src/internal/packager/images/common.go
@@ -9,13 +9,13 @@ import (
 	"time"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/transform"
-	"github.com/defenseunicorns/zarf/src/types"
 	"github.com/google/go-containerregistry/pkg/authn"
 	"github.com/google/go-containerregistry/pkg/crane"
 	v1 "github.com/google/go-containerregistry/pkg/v1"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/transform"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 // PullConfig is the configuration for pulling images.
@@ -104,7 +104,7 @@ func createPushOpts(cfg PushConfig, pb *message.ProgressBar) []crane.Option {
 
 	transport := http.DefaultTransport.(*http.Transport).Clone()
 	transport.TLSClientConfig.InsecureSkipVerify = config.CommonOptions.Insecure
-	// TODO (@WSTARR) This is set to match the TLSHandshakeTimeout to potentially mitigate effects of https://github.com/defenseunicorns/zarf/issues/1444
+	// TODO (@WSTARR) This is set to match the TLSHandshakeTimeout to potentially mitigate effects of https://github.com/zarf-dev/zarf/issues/1444
 	transport.ResponseHeaderTimeout = 10 * time.Second
 
 	transportWithProgressBar := helpers.NewTransport(transport, pb)
diff --git a/src/internal/packager/images/pull.go b/src/internal/packager/images/pull.go
index 5636e7229d..7a313c5db0 100644
--- a/src/internal/packager/images/pull.go
+++ b/src/internal/packager/images/pull.go
@@ -19,11 +19,6 @@ import (
 	"time"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/pkg/layout"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/transform"
-	"github.com/defenseunicorns/zarf/src/pkg/utils"
 	"github.com/google/go-containerregistry/pkg/crane"
 	"github.com/google/go-containerregistry/pkg/logs"
 	"github.com/google/go-containerregistry/pkg/name"
@@ -37,6 +32,11 @@ import (
 	"github.com/google/go-containerregistry/pkg/v1/types"
 	"github.com/moby/moby/client"
 	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/pkg/layout"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/transform"
+	"github.com/zarf-dev/zarf/src/pkg/utils"
 	"golang.org/x/sync/errgroup"
 )
 
@@ -132,7 +132,7 @@ func Pull(ctx context.Context, cfg PullConfig) (map[transform.Image]v1.Image, er
 							ref, utils.ByteFormat(float64(rawImg.Size), 2))
 					}
 
-					// Use unbuffered opener to avoid OOM Kill issues https://github.com/defenseunicorns/zarf/issues/1214.
+					// Use unbuffered opener to avoid OOM Kill issues https://github.com/zarf-dev/zarf/issues/1214.
 					// This will also take forever to load large images.
 					img, err = daemon.Image(reference, daemon.WithUnbufferedOpener())
 					if err != nil {
@@ -254,7 +254,7 @@ func Pull(ctx context.Context, cfg PullConfig) (map[transform.Image]v1.Image, er
 
 	// Needed because when pulling from the local docker daemon, while using the docker containerd runtime
 	// Crane incorrectly names the blob of the docker image config to a sha that does not match the contents
-	// https://github.com/defenseunicorns/zarf/issues/2584
+	// https://github.com/zarf-dev/zarf/issues/2584
 	// This is a band aid fix while we wait for crane and or docker to create the permanent fix
 	blobDir := filepath.Join(cfg.DestinationDirectory, "blobs", "sha256")
 	err = filepath.Walk(blobDir, func(path string, fi os.FileInfo, err error) error {
diff --git a/src/internal/packager/images/pull_test.go b/src/internal/packager/images/pull_test.go
index 4ee0ca5478..eef8bbc9e8 100644
--- a/src/internal/packager/images/pull_test.go
+++ b/src/internal/packager/images/pull_test.go
@@ -10,8 +10,8 @@ import (
 	"path/filepath"
 	"testing"
 
-	"github.com/defenseunicorns/zarf/src/pkg/transform"
 	"github.com/stretchr/testify/require"
+	"github.com/zarf-dev/zarf/src/pkg/transform"
 )
 
 func TestPull(t *testing.T) {
diff --git a/src/internal/packager/images/push.go b/src/internal/packager/images/push.go
index 3048218662..08625ab385 100644
--- a/src/internal/packager/images/push.go
+++ b/src/internal/packager/images/push.go
@@ -10,13 +10,13 @@ import (
 	"time"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/pkg/cluster"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/transform"
-	"github.com/defenseunicorns/zarf/src/pkg/utils"
 	"github.com/google/go-containerregistry/pkg/crane"
 	"github.com/google/go-containerregistry/pkg/logs"
 	v1 "github.com/google/go-containerregistry/pkg/v1"
+	"github.com/zarf-dev/zarf/src/pkg/cluster"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/transform"
+	"github.com/zarf-dev/zarf/src/pkg/utils"
 )
 
 // Push pushes images to a registry.
diff --git a/src/internal/packager/sbom/catalog.go b/src/internal/packager/sbom/catalog.go
index d60d7a70b7..aadeeea257 100755
--- a/src/internal/packager/sbom/catalog.go
+++ b/src/internal/packager/sbom/catalog.go
@@ -24,12 +24,12 @@ import (
 	"github.com/anchore/syft/syft/sbom"
 	"github.com/anchore/syft/syft/source"
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/pkg/layout"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/transform"
-	"github.com/defenseunicorns/zarf/src/pkg/utils"
 	v1 "github.com/google/go-containerregistry/pkg/v1"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/pkg/layout"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/transform"
+	"github.com/zarf-dev/zarf/src/pkg/utils"
 )
 
 // Builder is the main struct used to build SBOM artifacts.
diff --git a/src/internal/packager/sbom/tools.go b/src/internal/packager/sbom/tools.go
index 860b50e879..60aa998958 100644
--- a/src/internal/packager/sbom/tools.go
+++ b/src/internal/packager/sbom/tools.go
@@ -9,8 +9,8 @@ import (
 	"path/filepath"
 
 	"github.com/AlecAivazis/survey/v2"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/utils/exec"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/utils/exec"
 )
 
 // ViewSBOMFiles opens a browser to view the SBOM files and pauses for user input.
diff --git a/src/internal/packager/sbom/viewer.go b/src/internal/packager/sbom/viewer.go
index 3362d251ac..8bc9fd9e0e 100644
--- a/src/internal/packager/sbom/viewer.go
+++ b/src/internal/packager/sbom/viewer.go
@@ -9,8 +9,8 @@ import (
 	"fmt"
 	"html/template"
 
-	"github.com/defenseunicorns/zarf/src/pkg/layout"
-	"github.com/defenseunicorns/zarf/src/pkg/transform"
+	"github.com/zarf-dev/zarf/src/pkg/layout"
+	"github.com/zarf-dev/zarf/src/pkg/transform"
 )
 
 func (b *Builder) createSBOMViewerAsset(identifier string, jsonData []byte) error {
diff --git a/src/internal/packager/template/template.go b/src/internal/packager/template/template.go
index 8b76252aa1..70f7808cc2 100644
--- a/src/internal/packager/template/template.go
+++ b/src/internal/packager/template/template.go
@@ -10,14 +10,14 @@ import (
 	"log/slog"
 	"strings"
 
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/types"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/pkg/interactive"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/utils"
-	"github.com/defenseunicorns/zarf/src/pkg/variables"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/pkg/interactive"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/utils"
+	"github.com/zarf-dev/zarf/src/pkg/variables"
 )
 
 const (
diff --git a/src/pkg/cluster/cluster.go b/src/pkg/cluster/cluster.go
index 5d15550482..b4eb28051b 100644
--- a/src/pkg/cluster/cluster.go
+++ b/src/pkg/cluster/cluster.go
@@ -18,7 +18,7 @@ import (
 
 	pkgkubernetes "github.com/defenseunicorns/pkg/kubernetes"
 
-	"github.com/defenseunicorns/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/message"
 )
 
 const (
diff --git a/src/pkg/cluster/data.go b/src/pkg/cluster/data.go
index 21a060742e..7b19257040 100644
--- a/src/pkg/cluster/data.go
+++ b/src/pkg/cluster/data.go
@@ -22,12 +22,12 @@ import (
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
 
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/pkg/layout"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/utils"
-	"github.com/defenseunicorns/zarf/src/pkg/utils/exec"
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/pkg/layout"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/utils"
+	"github.com/zarf-dev/zarf/src/pkg/utils/exec"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 // HandleDataInjection waits for the target pod(s) to come up and inject the data into them
diff --git a/src/pkg/cluster/injector.go b/src/pkg/cluster/injector.go
index 52824843bf..48552ac5e1 100644
--- a/src/pkg/cluster/injector.go
+++ b/src/pkg/cluster/injector.go
@@ -26,10 +26,10 @@ import (
 	"github.com/defenseunicorns/pkg/helpers/v2"
 	pkgkubernetes "github.com/defenseunicorns/pkg/kubernetes"
 
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/transform"
-	"github.com/defenseunicorns/zarf/src/pkg/utils"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/transform"
+	"github.com/zarf-dev/zarf/src/pkg/utils"
 )
 
 // StartInjection initializes a Zarf injection into the cluster.
diff --git a/src/pkg/cluster/namespace.go b/src/pkg/cluster/namespace.go
index c65c968d0e..6d4256ef83 100644
--- a/src/pkg/cluster/namespace.go
+++ b/src/pkg/cluster/namespace.go
@@ -12,7 +12,7 @@ import (
 	kerrors "k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
-	"github.com/defenseunicorns/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/message"
 )
 
 // DeleteZarfNamespace deletes the Zarf namespace from the connected cluster.
diff --git a/src/pkg/cluster/secrets.go b/src/pkg/cluster/secrets.go
index d083f6bbf4..3cdeabe826 100644
--- a/src/pkg/cluster/secrets.go
+++ b/src/pkg/cluster/secrets.go
@@ -15,9 +15,9 @@ import (
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 // DockerConfig contains the authentication information from the machine's docker config.
diff --git a/src/pkg/cluster/secrets_test.go b/src/pkg/cluster/secrets_test.go
index 20d3fe70f9..80cd33b933 100644
--- a/src/pkg/cluster/secrets_test.go
+++ b/src/pkg/cluster/secrets_test.go
@@ -12,7 +12,7 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/client-go/kubernetes/fake"
 
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 func TestGenerateRegistryPullCredsWithOutSvc(t *testing.T) {
diff --git a/src/pkg/cluster/state.go b/src/pkg/cluster/state.go
index 65fba1431a..bdc14e5989 100644
--- a/src/pkg/cluster/state.go
+++ b/src/pkg/cluster/state.go
@@ -17,11 +17,11 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/config/lang"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/pki"
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/config/lang"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/pki"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 // Zarf Cluster Constants.
diff --git a/src/pkg/cluster/state_test.go b/src/pkg/cluster/state_test.go
index 524b0e3295..cf52d195dc 100644
--- a/src/pkg/cluster/state_test.go
+++ b/src/pkg/cluster/state_test.go
@@ -17,9 +17,9 @@ import (
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
 
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/pki"
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/pki"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 func TestInitZarfState(t *testing.T) {
diff --git a/src/pkg/cluster/tunnel.go b/src/pkg/cluster/tunnel.go
index 3f8433ed9f..f0a1a660e0 100644
--- a/src/pkg/cluster/tunnel.go
+++ b/src/pkg/cluster/tunnel.go
@@ -23,8 +23,8 @@ import (
 	"k8s.io/client-go/transport/spdy"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 // Zarf specific connect strings
diff --git a/src/pkg/cluster/tunnel_test.go b/src/pkg/cluster/tunnel_test.go
index fd1866da19..9ce09770e9 100644
--- a/src/pkg/cluster/tunnel_test.go
+++ b/src/pkg/cluster/tunnel_test.go
@@ -12,7 +12,7 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/client-go/kubernetes/fake"
 
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 func TestListConnections(t *testing.T) {
diff --git a/src/pkg/cluster/zarf.go b/src/pkg/cluster/zarf.go
index 93d8406ced..7320e4610b 100644
--- a/src/pkg/cluster/zarf.go
+++ b/src/pkg/cluster/zarf.go
@@ -17,9 +17,9 @@ import (
 	kerrors "k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 // GetDeployedZarfPackages gets metadata information about packages that have been deployed to the cluster.
diff --git a/src/pkg/cluster/zarf_test.go b/src/pkg/cluster/zarf_test.go
index 4abfb81e8f..f7e9b481ec 100644
--- a/src/pkg/cluster/zarf_test.go
+++ b/src/pkg/cluster/zarf_test.go
@@ -16,8 +16,8 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/client-go/kubernetes/fake"
 
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 // TestPackageSecretNeedsWait verifies that Zarf waits for webhooks to complete correctly.
diff --git a/src/pkg/interactive/components.go b/src/pkg/interactive/components.go
index 4e24f3f083..f48db25043 100644
--- a/src/pkg/interactive/components.go
+++ b/src/pkg/interactive/components.go
@@ -8,10 +8,10 @@ import (
 	"fmt"
 
 	"github.com/AlecAivazis/survey/v2"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/utils"
-	"github.com/defenseunicorns/zarf/src/types"
 	"github.com/pterm/pterm"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/utils"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 // SelectOptionalComponent prompts to confirm optional components
diff --git a/src/pkg/interactive/prompt.go b/src/pkg/interactive/prompt.go
index d832982538..759f520948 100644
--- a/src/pkg/interactive/prompt.go
+++ b/src/pkg/interactive/prompt.go
@@ -8,8 +8,8 @@ import (
 	"fmt"
 
 	"github.com/AlecAivazis/survey/v2"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/variables"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/variables"
 )
 
 // PromptSigPassword prompts the user for the password to their private key
diff --git a/src/pkg/layout/component.go b/src/pkg/layout/component.go
index c933fce6f6..f52e6bbe06 100644
--- a/src/pkg/layout/component.go
+++ b/src/pkg/layout/component.go
@@ -11,9 +11,9 @@ import (
 	"path/filepath"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/types"
 	"github.com/mholt/archiver/v3"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 // ComponentPaths contains paths for a component.
diff --git a/src/pkg/layout/image.go b/src/pkg/layout/image.go
index 7d236410bf..13ed0af43d 100644
--- a/src/pkg/layout/image.go
+++ b/src/pkg/layout/image.go
@@ -49,7 +49,7 @@ func (i *Images) AddV1Image(img v1.Image) error {
 		return err
 	}
 	// Cannot use img.ConfigName to get this value because of an upstream bug in crane / docker using the containerd runtime
-	// https://github.com/defenseunicorns/zarf/issues/2584
+	// https://github.com/zarf-dev/zarf/issues/2584
 	i.AddBlob(manifest.Config.Digest.Hex)
 	manifestSha, err := img.Digest()
 	if err != nil {
diff --git a/src/pkg/layout/package.go b/src/pkg/layout/package.go
index 1b99379e81..aef5e849d6 100644
--- a/src/pkg/layout/package.go
+++ b/src/pkg/layout/package.go
@@ -13,14 +13,14 @@ import (
 
 	"github.com/Masterminds/semver/v3"
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/pkg/interactive"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/packager/deprecated"
-	"github.com/defenseunicorns/zarf/src/pkg/utils"
-	"github.com/defenseunicorns/zarf/src/types"
 	"github.com/google/go-containerregistry/pkg/crane"
 	"github.com/mholt/archiver/v3"
 	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+	"github.com/zarf-dev/zarf/src/pkg/interactive"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/packager/deprecated"
+	"github.com/zarf-dev/zarf/src/pkg/utils"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 // PackagePaths is the default package layout.
diff --git a/src/pkg/layout/split.go b/src/pkg/layout/split.go
index aecf295dad..4668107405 100644
--- a/src/pkg/layout/split.go
+++ b/src/pkg/layout/split.go
@@ -13,8 +13,8 @@ import (
 	"os"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 // splitFile will split the file into chunks and remove the original file.
diff --git a/src/pkg/layout/split_test.go b/src/pkg/layout/split_test.go
index b7f48fc9f6..718dc7bfee 100644
--- a/src/pkg/layout/split_test.go
+++ b/src/pkg/layout/split_test.go
@@ -10,8 +10,8 @@ import (
 	"path/filepath"
 	"testing"
 
-	"github.com/defenseunicorns/zarf/src/types"
 	"github.com/stretchr/testify/require"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 func TestSplitFile(t *testing.T) {
diff --git a/src/pkg/message/connect.go b/src/pkg/message/connect.go
index 75f87fdd64..499a9e3602 100644
--- a/src/pkg/message/connect.go
+++ b/src/pkg/message/connect.go
@@ -7,7 +7,7 @@ package message
 import (
 	"fmt"
 
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 // PrintConnectStringTable prints a table of connect strings.
diff --git a/src/pkg/message/credentials.go b/src/pkg/message/credentials.go
index 19f86f8516..74b127a1c6 100644
--- a/src/pkg/message/credentials.go
+++ b/src/pkg/message/credentials.go
@@ -8,8 +8,8 @@ import (
 	"fmt"
 	"strings"
 
-	"github.com/defenseunicorns/zarf/src/types"
 	"github.com/pterm/pterm"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 // Common constants for printing credentials
diff --git a/src/pkg/message/message.go b/src/pkg/message/message.go
index 0ead8b0e01..f9d7d48c3c 100644
--- a/src/pkg/message/message.go
+++ b/src/pkg/message/message.go
@@ -12,9 +12,9 @@ import (
 	"time"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/config"
 	"github.com/fatih/color"
 	"github.com/pterm/pterm"
+	"github.com/zarf-dev/zarf/src/config"
 )
 
 // LogLevel is the level of logging to display.
diff --git a/src/pkg/packager/actions/actions.go b/src/pkg/packager/actions/actions.go
index 2f01757d6c..c92457675c 100644
--- a/src/pkg/packager/actions/actions.go
+++ b/src/pkg/packager/actions/actions.go
@@ -13,12 +13,12 @@ import (
 	"time"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/internal/packager/template"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/utils"
-	"github.com/defenseunicorns/zarf/src/pkg/utils/exec"
-	"github.com/defenseunicorns/zarf/src/pkg/variables"
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/internal/packager/template"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/utils"
+	"github.com/zarf-dev/zarf/src/pkg/utils/exec"
+	"github.com/zarf-dev/zarf/src/pkg/variables"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 // Run runs all provided actions.
diff --git a/src/pkg/packager/common.go b/src/pkg/packager/common.go
index 0f59319ae6..3b7f59f968 100644
--- a/src/pkg/packager/common.go
+++ b/src/pkg/packager/common.go
@@ -15,17 +15,17 @@ import (
 	"github.com/Masterminds/semver/v3"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/config/lang"
-	"github.com/defenseunicorns/zarf/src/internal/packager/template"
-	"github.com/defenseunicorns/zarf/src/pkg/cluster"
-	"github.com/defenseunicorns/zarf/src/pkg/layout"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/packager/deprecated"
-	"github.com/defenseunicorns/zarf/src/pkg/packager/sources"
-	"github.com/defenseunicorns/zarf/src/pkg/utils"
-	"github.com/defenseunicorns/zarf/src/pkg/variables"
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/config/lang"
+	"github.com/zarf-dev/zarf/src/internal/packager/template"
+	"github.com/zarf-dev/zarf/src/pkg/cluster"
+	"github.com/zarf-dev/zarf/src/pkg/layout"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/packager/deprecated"
+	"github.com/zarf-dev/zarf/src/pkg/packager/sources"
+	"github.com/zarf-dev/zarf/src/pkg/utils"
+	"github.com/zarf-dev/zarf/src/pkg/variables"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 // Packager is the main struct for managing packages.
diff --git a/src/pkg/packager/common_test.go b/src/pkg/packager/common_test.go
index 6927082f9b..ac47544515 100644
--- a/src/pkg/packager/common_test.go
+++ b/src/pkg/packager/common_test.go
@@ -13,9 +13,9 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/client-go/kubernetes/fake"
 
-	"github.com/defenseunicorns/zarf/src/config/lang"
-	"github.com/defenseunicorns/zarf/src/pkg/cluster"
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/config/lang"
+	"github.com/zarf-dev/zarf/src/pkg/cluster"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 func TestValidatePackageArchitecture(t *testing.T) {
diff --git a/src/pkg/packager/composer/list.go b/src/pkg/packager/composer/list.go
index 69aa5fdb8e..06f67ec816 100644
--- a/src/pkg/packager/composer/list.go
+++ b/src/pkg/packager/composer/list.go
@@ -11,13 +11,13 @@ import (
 	"strings"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/extensions/bigbang"
-	"github.com/defenseunicorns/zarf/src/pkg/layout"
-	"github.com/defenseunicorns/zarf/src/pkg/packager/deprecated"
-	"github.com/defenseunicorns/zarf/src/pkg/utils"
-	"github.com/defenseunicorns/zarf/src/pkg/variables"
-	"github.com/defenseunicorns/zarf/src/pkg/zoci"
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/extensions/bigbang"
+	"github.com/zarf-dev/zarf/src/pkg/layout"
+	"github.com/zarf-dev/zarf/src/pkg/packager/deprecated"
+	"github.com/zarf-dev/zarf/src/pkg/utils"
+	"github.com/zarf-dev/zarf/src/pkg/variables"
+	"github.com/zarf-dev/zarf/src/pkg/zoci"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 // Node is a node in the import chain
diff --git a/src/pkg/packager/composer/list_test.go b/src/pkg/packager/composer/list_test.go
index 0f96e0beb0..e720fdf57c 100644
--- a/src/pkg/packager/composer/list_test.go
+++ b/src/pkg/packager/composer/list_test.go
@@ -11,10 +11,10 @@ import (
 	"path/filepath"
 	"testing"
 
-	"github.com/defenseunicorns/zarf/src/pkg/variables"
-	"github.com/defenseunicorns/zarf/src/types"
-	"github.com/defenseunicorns/zarf/src/types/extensions"
 	"github.com/stretchr/testify/require"
+	"github.com/zarf-dev/zarf/src/pkg/variables"
+	"github.com/zarf-dev/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/types/extensions"
 )
 
 func TestNewImportChain(t *testing.T) {
diff --git a/src/pkg/packager/composer/oci.go b/src/pkg/packager/composer/oci.go
index f4f02fbaf3..129013d487 100644
--- a/src/pkg/packager/composer/oci.go
+++ b/src/pkg/packager/composer/oci.go
@@ -13,13 +13,13 @@ import (
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
 	"github.com/defenseunicorns/pkg/oci"
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/pkg/layout"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/utils"
-	"github.com/defenseunicorns/zarf/src/pkg/zoci"
 	"github.com/mholt/archiver/v3"
 	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/pkg/layout"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/utils"
+	"github.com/zarf-dev/zarf/src/pkg/zoci"
 	ocistore "oras.land/oras-go/v2/content/oci"
 )
 
diff --git a/src/pkg/packager/composer/override.go b/src/pkg/packager/composer/override.go
index 4a07a1d936..feb4b4b6f3 100644
--- a/src/pkg/packager/composer/override.go
+++ b/src/pkg/packager/composer/override.go
@@ -7,7 +7,7 @@ package composer
 import (
 	"fmt"
 
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 func overrideMetadata(c *types.ZarfComponent, override types.ZarfComponent) error {
diff --git a/src/pkg/packager/composer/pathfixer.go b/src/pkg/packager/composer/pathfixer.go
index fac110c47c..f13537dfd9 100644
--- a/src/pkg/packager/composer/pathfixer.go
+++ b/src/pkg/packager/composer/pathfixer.go
@@ -8,7 +8,7 @@ import (
 	"path/filepath"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 func makePathRelativeTo(path, relativeTo string) string {
diff --git a/src/pkg/packager/create.go b/src/pkg/packager/create.go
index ee9a7fd2bc..517726eba4 100755
--- a/src/pkg/packager/create.go
+++ b/src/pkg/packager/create.go
@@ -10,10 +10,10 @@ import (
 	"os"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/pkg/layout"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/packager/creator"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/pkg/layout"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/packager/creator"
 )
 
 // Create generates a Zarf package tarball for a given PackageConfig and optional base directory.
diff --git a/src/pkg/packager/creator/compose.go b/src/pkg/packager/creator/compose.go
index 6cd5277388..8844c0305f 100644
--- a/src/pkg/packager/creator/compose.go
+++ b/src/pkg/packager/creator/compose.go
@@ -7,9 +7,9 @@ package creator
 import (
 	"context"
 
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/packager/composer"
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/packager/composer"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 // ComposeComponents composes components and their dependencies into a single Zarf package using an import chain.
diff --git a/src/pkg/packager/creator/compose_test.go b/src/pkg/packager/creator/compose_test.go
index 35e298f553..a4dd2fdf9e 100644
--- a/src/pkg/packager/creator/compose_test.go
+++ b/src/pkg/packager/creator/compose_test.go
@@ -8,8 +8,8 @@ import (
 	"context"
 	"testing"
 
-	"github.com/defenseunicorns/zarf/src/types"
 	"github.com/stretchr/testify/require"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 func TestComposeComponents(t *testing.T) {
diff --git a/src/pkg/packager/creator/creator.go b/src/pkg/packager/creator/creator.go
index aae86172c6..34e511458f 100644
--- a/src/pkg/packager/creator/creator.go
+++ b/src/pkg/packager/creator/creator.go
@@ -7,8 +7,8 @@ package creator
 import (
 	"context"
 
-	"github.com/defenseunicorns/zarf/src/pkg/layout"
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/pkg/layout"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 // Creator is an interface for creating Zarf packages.
diff --git a/src/pkg/packager/creator/creator_test.go b/src/pkg/packager/creator/creator_test.go
index 18a4a64c0a..1c2e3b7153 100644
--- a/src/pkg/packager/creator/creator_test.go
+++ b/src/pkg/packager/creator/creator_test.go
@@ -9,9 +9,9 @@ import (
 	"path/filepath"
 	"testing"
 
-	"github.com/defenseunicorns/zarf/src/pkg/layout"
-	"github.com/defenseunicorns/zarf/src/types"
 	"github.com/stretchr/testify/require"
+	"github.com/zarf-dev/zarf/src/pkg/layout"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 func TestLoadPackageDefinition(t *testing.T) {
diff --git a/src/pkg/packager/creator/differential.go b/src/pkg/packager/creator/differential.go
index d2c3c80480..a373bcc4f2 100644
--- a/src/pkg/packager/creator/differential.go
+++ b/src/pkg/packager/creator/differential.go
@@ -8,11 +8,11 @@ import (
 	"context"
 	"os"
 
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/pkg/layout"
-	"github.com/defenseunicorns/zarf/src/pkg/packager/sources"
-	"github.com/defenseunicorns/zarf/src/pkg/utils"
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/pkg/layout"
+	"github.com/zarf-dev/zarf/src/pkg/packager/sources"
+	"github.com/zarf-dev/zarf/src/pkg/utils"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 // loadDifferentialData sets any images and repos from the existing reference package in the DifferentialData and returns it.
diff --git a/src/pkg/packager/creator/normal.go b/src/pkg/packager/creator/normal.go
index 027df385fa..b8135a8c2f 100644
--- a/src/pkg/packager/creator/normal.go
+++ b/src/pkg/packager/creator/normal.go
@@ -17,24 +17,24 @@ import (
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
 	"github.com/defenseunicorns/pkg/oci"
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/config/lang"
-	"github.com/defenseunicorns/zarf/src/extensions/bigbang"
-	"github.com/defenseunicorns/zarf/src/internal/packager/git"
-	"github.com/defenseunicorns/zarf/src/internal/packager/helm"
-	"github.com/defenseunicorns/zarf/src/internal/packager/images"
-	"github.com/defenseunicorns/zarf/src/internal/packager/kustomize"
-	"github.com/defenseunicorns/zarf/src/internal/packager/sbom"
-	"github.com/defenseunicorns/zarf/src/pkg/layout"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/packager/actions"
-	"github.com/defenseunicorns/zarf/src/pkg/packager/filters"
-	"github.com/defenseunicorns/zarf/src/pkg/packager/sources"
-	"github.com/defenseunicorns/zarf/src/pkg/transform"
-	"github.com/defenseunicorns/zarf/src/pkg/utils"
-	"github.com/defenseunicorns/zarf/src/pkg/zoci"
-	"github.com/defenseunicorns/zarf/src/types"
 	"github.com/mholt/archiver/v3"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/config/lang"
+	"github.com/zarf-dev/zarf/src/extensions/bigbang"
+	"github.com/zarf-dev/zarf/src/internal/packager/git"
+	"github.com/zarf-dev/zarf/src/internal/packager/helm"
+	"github.com/zarf-dev/zarf/src/internal/packager/images"
+	"github.com/zarf-dev/zarf/src/internal/packager/kustomize"
+	"github.com/zarf-dev/zarf/src/internal/packager/sbom"
+	"github.com/zarf-dev/zarf/src/pkg/layout"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/packager/actions"
+	"github.com/zarf-dev/zarf/src/pkg/packager/filters"
+	"github.com/zarf-dev/zarf/src/pkg/packager/sources"
+	"github.com/zarf-dev/zarf/src/pkg/transform"
+	"github.com/zarf-dev/zarf/src/pkg/utils"
+	"github.com/zarf-dev/zarf/src/pkg/zoci"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 var (
diff --git a/src/pkg/packager/creator/skeleton.go b/src/pkg/packager/creator/skeleton.go
index e0e86126b4..091874c84f 100644
--- a/src/pkg/packager/creator/skeleton.go
+++ b/src/pkg/packager/creator/skeleton.go
@@ -13,17 +13,17 @@ import (
 	"strings"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/config/lang"
-	"github.com/defenseunicorns/zarf/src/extensions/bigbang"
-	"github.com/defenseunicorns/zarf/src/internal/packager/helm"
-	"github.com/defenseunicorns/zarf/src/internal/packager/kustomize"
-	"github.com/defenseunicorns/zarf/src/pkg/layout"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/utils"
-	"github.com/defenseunicorns/zarf/src/pkg/zoci"
-	"github.com/defenseunicorns/zarf/src/types"
 	"github.com/mholt/archiver/v3"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/config/lang"
+	"github.com/zarf-dev/zarf/src/extensions/bigbang"
+	"github.com/zarf-dev/zarf/src/internal/packager/helm"
+	"github.com/zarf-dev/zarf/src/internal/packager/kustomize"
+	"github.com/zarf-dev/zarf/src/pkg/layout"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/utils"
+	"github.com/zarf-dev/zarf/src/pkg/zoci"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 var (
diff --git a/src/pkg/packager/creator/template.go b/src/pkg/packager/creator/template.go
index df2fc86038..5a06651c53 100644
--- a/src/pkg/packager/creator/template.go
+++ b/src/pkg/packager/creator/template.go
@@ -7,12 +7,12 @@ package creator
 import (
 	"fmt"
 
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/config/lang"
-	"github.com/defenseunicorns/zarf/src/pkg/interactive"
-	"github.com/defenseunicorns/zarf/src/pkg/utils"
-	"github.com/defenseunicorns/zarf/src/pkg/variables"
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/config/lang"
+	"github.com/zarf-dev/zarf/src/pkg/interactive"
+	"github.com/zarf-dev/zarf/src/pkg/utils"
+	"github.com/zarf-dev/zarf/src/pkg/variables"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 // FillActiveTemplate merges user-specified variables into the configuration templates of a zarf.yaml.
diff --git a/src/pkg/packager/creator/utils.go b/src/pkg/packager/creator/utils.go
index 43ab469565..5c3f962766 100644
--- a/src/pkg/packager/creator/utils.go
+++ b/src/pkg/packager/creator/utils.go
@@ -9,9 +9,9 @@ import (
 	"runtime"
 	"time"
 
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/pkg/packager/deprecated"
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/pkg/packager/deprecated"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 // recordPackageMetadata records various package metadata during package create.
diff --git a/src/pkg/packager/deploy.go b/src/pkg/packager/deploy.go
index 9044772169..35f31514fd 100644
--- a/src/pkg/packager/deploy.go
+++ b/src/pkg/packager/deploy.go
@@ -23,19 +23,19 @@ import (
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
 
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/config/lang"
-	"github.com/defenseunicorns/zarf/src/internal/packager/git"
-	"github.com/defenseunicorns/zarf/src/internal/packager/helm"
-	"github.com/defenseunicorns/zarf/src/internal/packager/images"
-	"github.com/defenseunicorns/zarf/src/internal/packager/template"
-	"github.com/defenseunicorns/zarf/src/pkg/cluster"
-	"github.com/defenseunicorns/zarf/src/pkg/layout"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/packager/actions"
-	"github.com/defenseunicorns/zarf/src/pkg/packager/filters"
-	"github.com/defenseunicorns/zarf/src/pkg/transform"
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/config/lang"
+	"github.com/zarf-dev/zarf/src/internal/packager/git"
+	"github.com/zarf-dev/zarf/src/internal/packager/helm"
+	"github.com/zarf-dev/zarf/src/internal/packager/images"
+	"github.com/zarf-dev/zarf/src/internal/packager/template"
+	"github.com/zarf-dev/zarf/src/pkg/cluster"
+	"github.com/zarf-dev/zarf/src/pkg/layout"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/packager/actions"
+	"github.com/zarf-dev/zarf/src/pkg/packager/filters"
+	"github.com/zarf-dev/zarf/src/pkg/transform"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 var (
diff --git a/src/pkg/packager/deploy_test.go b/src/pkg/packager/deploy_test.go
index 5bb21bfcca..6e82cbcb10 100644
--- a/src/pkg/packager/deploy_test.go
+++ b/src/pkg/packager/deploy_test.go
@@ -6,10 +6,10 @@ package packager
 import (
 	"testing"
 
-	"github.com/defenseunicorns/zarf/src/pkg/packager/sources"
-	"github.com/defenseunicorns/zarf/src/pkg/variables"
-	"github.com/defenseunicorns/zarf/src/types"
 	"github.com/stretchr/testify/require"
+	"github.com/zarf-dev/zarf/src/pkg/packager/sources"
+	"github.com/zarf-dev/zarf/src/pkg/variables"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 func TestGenerateValuesOverrides(t *testing.T) {
diff --git a/src/pkg/packager/deprecated/common.go b/src/pkg/packager/deprecated/common.go
index 4867ac52b2..f97e07bce0 100644
--- a/src/pkg/packager/deprecated/common.go
+++ b/src/pkg/packager/deprecated/common.go
@@ -12,9 +12,9 @@ import (
 	"slices"
 
 	"github.com/Masterminds/semver/v3"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/types"
 	"github.com/pterm/pterm"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 // BreakingChange represents a breaking change that happened on a specified Zarf version.
@@ -35,7 +35,7 @@ func (bc BreakingChange) String() string {
 
 // List of migrations tracked in the zarf.yaml build data.
 const (
-	// This should be updated when a breaking change is introduced to the Zarf package structure.  See: https://github.com/defenseunicorns/zarf/releases/tag/v0.27.0
+	// This should be updated when a breaking change is introduced to the Zarf package structure.  See: https://github.com/zarf-dev/zarf/releases/tag/v0.27.0
 	LastNonBreakingVersion   = "v0.27.0"
 	ScriptsToActionsMigrated = "scripts-to-actions"
 	PluralizeSetVariable     = "pluralize-set-variable"
diff --git a/src/pkg/packager/deprecated/common_test.go b/src/pkg/packager/deprecated/common_test.go
index 6dec381554..b789f0c2ce 100644
--- a/src/pkg/packager/deprecated/common_test.go
+++ b/src/pkg/packager/deprecated/common_test.go
@@ -9,8 +9,8 @@ import (
 	"testing"
 
 	"github.com/Masterminds/semver/v3"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
 	"github.com/stretchr/testify/require"
+	"github.com/zarf-dev/zarf/src/pkg/message"
 )
 
 func TestPrintBreakingChanges(t *testing.T) {
diff --git a/src/pkg/packager/deprecated/pluralize-set-variable.go b/src/pkg/packager/deprecated/pluralize-set-variable.go
index c3dc13e06c..44ea9c7f9c 100644
--- a/src/pkg/packager/deprecated/pluralize-set-variable.go
+++ b/src/pkg/packager/deprecated/pluralize-set-variable.go
@@ -7,8 +7,8 @@ package deprecated
 import (
 	"fmt"
 
-	"github.com/defenseunicorns/zarf/src/pkg/variables"
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/pkg/variables"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 func migrateSetVariableToSetVariables(c types.ZarfComponent) (types.ZarfComponent, string) {
diff --git a/src/pkg/packager/deprecated/scripts-to-actions.go b/src/pkg/packager/deprecated/scripts-to-actions.go
index 2040e7eb90..f296e49ec3 100644
--- a/src/pkg/packager/deprecated/scripts-to-actions.go
+++ b/src/pkg/packager/deprecated/scripts-to-actions.go
@@ -8,7 +8,7 @@ import (
 	"fmt"
 	"math"
 
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 // migrateScriptsToActions coverts the deprecated scripts to the new actions
diff --git a/src/pkg/packager/dev.go b/src/pkg/packager/dev.go
index 138d175109..4363c0b49a 100644
--- a/src/pkg/packager/dev.go
+++ b/src/pkg/packager/dev.go
@@ -13,15 +13,15 @@ import (
 	"runtime"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/pkg/layout"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/packager/creator"
-	"github.com/defenseunicorns/zarf/src/pkg/packager/filters"
-	"github.com/defenseunicorns/zarf/src/pkg/packager/lint"
-	"github.com/defenseunicorns/zarf/src/pkg/utils"
-	"github.com/defenseunicorns/zarf/src/types"
 	"github.com/fatih/color"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/pkg/layout"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/packager/creator"
+	"github.com/zarf-dev/zarf/src/pkg/packager/filters"
+	"github.com/zarf-dev/zarf/src/pkg/packager/lint"
+	"github.com/zarf-dev/zarf/src/pkg/utils"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 // DevDeploy creates + deploys a package in one shot
diff --git a/src/pkg/packager/filters/deploy.go b/src/pkg/packager/filters/deploy.go
index f5ac17916f..40555fb9a2 100644
--- a/src/pkg/packager/filters/deploy.go
+++ b/src/pkg/packager/filters/deploy.go
@@ -11,8 +11,8 @@ import (
 
 	"github.com/agnivade/levenshtein"
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/pkg/interactive"
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/pkg/interactive"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 // ForDeploy creates a new deployment filter.
diff --git a/src/pkg/packager/filters/deploy_test.go b/src/pkg/packager/filters/deploy_test.go
index 1bb548f1cb..5b31a2269e 100644
--- a/src/pkg/packager/filters/deploy_test.go
+++ b/src/pkg/packager/filters/deploy_test.go
@@ -10,8 +10,8 @@ import (
 	"testing"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/types"
 	"github.com/stretchr/testify/require"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 func componentFromQuery(t *testing.T, q string) types.ZarfComponent {
diff --git a/src/pkg/packager/filters/diff.go b/src/pkg/packager/filters/diff.go
index fe722e9741..bbba9ab789 100644
--- a/src/pkg/packager/filters/diff.go
+++ b/src/pkg/packager/filters/diff.go
@@ -6,10 +6,10 @@ package filters
 import (
 	"fmt"
 
-	"github.com/defenseunicorns/zarf/src/internal/packager/git"
-	"github.com/defenseunicorns/zarf/src/pkg/transform"
-	"github.com/defenseunicorns/zarf/src/types"
 	"github.com/go-git/go-git/v5/plumbing"
+	"github.com/zarf-dev/zarf/src/internal/packager/git"
+	"github.com/zarf-dev/zarf/src/pkg/transform"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 // ByDifferentialData filters any images and repos already present in the reference package components.
diff --git a/src/pkg/packager/filters/diff_test.go b/src/pkg/packager/filters/diff_test.go
index 8ee64fab84..0b279b8f08 100644
--- a/src/pkg/packager/filters/diff_test.go
+++ b/src/pkg/packager/filters/diff_test.go
@@ -6,8 +6,8 @@ package filters
 import (
 	"testing"
 
-	"github.com/defenseunicorns/zarf/src/types"
 	"github.com/stretchr/testify/require"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 func TestCopyFilter(t *testing.T) {
diff --git a/src/pkg/packager/filters/empty.go b/src/pkg/packager/filters/empty.go
index 860799fb7b..af4eb09663 100644
--- a/src/pkg/packager/filters/empty.go
+++ b/src/pkg/packager/filters/empty.go
@@ -4,7 +4,7 @@
 // Package filters contains core implementations of the ComponentFilterStrategy interface.
 package filters
 
-import "github.com/defenseunicorns/zarf/src/types"
+import "github.com/zarf-dev/zarf/src/types"
 
 // Empty returns a filter that does nothing.
 func Empty() ComponentFilterStrategy {
diff --git a/src/pkg/packager/filters/empty_test.go b/src/pkg/packager/filters/empty_test.go
index 8096219ad5..8d55fd70ad 100644
--- a/src/pkg/packager/filters/empty_test.go
+++ b/src/pkg/packager/filters/empty_test.go
@@ -7,8 +7,8 @@ package filters
 import (
 	"testing"
 
-	"github.com/defenseunicorns/zarf/src/types"
 	"github.com/stretchr/testify/require"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 func TestEmptyFilter_Apply(t *testing.T) {
diff --git a/src/pkg/packager/filters/os.go b/src/pkg/packager/filters/os.go
index b031f35bbc..845c0cb400 100644
--- a/src/pkg/packager/filters/os.go
+++ b/src/pkg/packager/filters/os.go
@@ -7,7 +7,7 @@ package filters
 import (
 	"errors"
 
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 // ByLocalOS creates a new filter that filters components based on local (runtime) OS.
diff --git a/src/pkg/packager/filters/os_test.go b/src/pkg/packager/filters/os_test.go
index 7d54beecd3..4dcc4b5279 100644
--- a/src/pkg/packager/filters/os_test.go
+++ b/src/pkg/packager/filters/os_test.go
@@ -7,8 +7,8 @@ package filters
 import (
 	"testing"
 
-	"github.com/defenseunicorns/zarf/src/types"
 	"github.com/stretchr/testify/require"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 func TestLocalOSFilter(t *testing.T) {
diff --git a/src/pkg/packager/filters/select.go b/src/pkg/packager/filters/select.go
index 9116efe453..35694f580f 100644
--- a/src/pkg/packager/filters/select.go
+++ b/src/pkg/packager/filters/select.go
@@ -6,7 +6,7 @@ package filters
 
 import (
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 // BySelectState creates a new simple included filter.
diff --git a/src/pkg/packager/filters/select_test.go b/src/pkg/packager/filters/select_test.go
index 9d87fbf014..b4d4ac9289 100644
--- a/src/pkg/packager/filters/select_test.go
+++ b/src/pkg/packager/filters/select_test.go
@@ -7,8 +7,8 @@ package filters
 import (
 	"testing"
 
-	"github.com/defenseunicorns/zarf/src/types"
 	"github.com/stretchr/testify/require"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 func Test_selectStateFilter_Apply(t *testing.T) {
diff --git a/src/pkg/packager/filters/strat.go b/src/pkg/packager/filters/strat.go
index 497778b2df..1411ae3c5f 100644
--- a/src/pkg/packager/filters/strat.go
+++ b/src/pkg/packager/filters/strat.go
@@ -7,7 +7,7 @@ package filters
 import (
 	"fmt"
 
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 // ComponentFilterStrategy is a strategy interface for filtering components.
diff --git a/src/pkg/packager/filters/strat_test.go b/src/pkg/packager/filters/strat_test.go
index 5f5391153c..12f7dad86e 100644
--- a/src/pkg/packager/filters/strat_test.go
+++ b/src/pkg/packager/filters/strat_test.go
@@ -7,8 +7,8 @@ package filters
 import (
 	"testing"
 
-	"github.com/defenseunicorns/zarf/src/types"
 	"github.com/stretchr/testify/require"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 func TestCombine(t *testing.T) {
diff --git a/src/pkg/packager/generate.go b/src/pkg/packager/generate.go
index d03e80c88d..905859bc53 100644
--- a/src/pkg/packager/generate.go
+++ b/src/pkg/packager/generate.go
@@ -11,11 +11,11 @@ import (
 	"strings"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/pkg/layout"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/types"
 	goyaml "github.com/goccy/go-yaml"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/pkg/layout"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 // Generate generates a Zarf package definition.
diff --git a/src/pkg/packager/inspect.go b/src/pkg/packager/inspect.go
index d68ae5f5de..bfa29d860b 100644
--- a/src/pkg/packager/inspect.go
+++ b/src/pkg/packager/inspect.go
@@ -10,8 +10,8 @@ import (
 	"os"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/internal/packager/sbom"
-	"github.com/defenseunicorns/zarf/src/pkg/utils"
+	"github.com/zarf-dev/zarf/src/internal/packager/sbom"
+	"github.com/zarf-dev/zarf/src/pkg/utils"
 )
 
 // Inspect list the contents of a package.
diff --git a/src/pkg/packager/interactive.go b/src/pkg/packager/interactive.go
index 8c67fd55fe..3a09595eab 100644
--- a/src/pkg/packager/interactive.go
+++ b/src/pkg/packager/interactive.go
@@ -11,11 +11,11 @@ import (
 
 	"github.com/AlecAivazis/survey/v2"
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/pkg/layout"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/utils"
 	"github.com/pterm/pterm"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/pkg/layout"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/utils"
 )
 
 func (p *Packager) confirmAction(stage string, warnings []string, sbomViewFiles []string) (confirm bool) {
diff --git a/src/pkg/packager/lint/findings.go b/src/pkg/packager/lint/findings.go
index 5b184146ed..8b48bdea78 100644
--- a/src/pkg/packager/lint/findings.go
+++ b/src/pkg/packager/lint/findings.go
@@ -6,7 +6,7 @@ package lint
 
 import (
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 // GroupFindingsByPath groups findings by their package path
diff --git a/src/pkg/packager/lint/findings_test.go b/src/pkg/packager/lint/findings_test.go
index 99f0b7a652..522135eb96 100644
--- a/src/pkg/packager/lint/findings_test.go
+++ b/src/pkg/packager/lint/findings_test.go
@@ -7,8 +7,8 @@ package lint
 import (
 	"testing"
 
-	"github.com/defenseunicorns/zarf/src/types"
 	"github.com/stretchr/testify/require"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 func TestGroupFindingsByPath(t *testing.T) {
diff --git a/src/pkg/packager/lint/lint.go b/src/pkg/packager/lint/lint.go
index 27a823deff..34ab432fe0 100644
--- a/src/pkg/packager/lint/lint.go
+++ b/src/pkg/packager/lint/lint.go
@@ -12,15 +12,15 @@ import (
 	"strings"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/config/lang"
-	"github.com/defenseunicorns/zarf/src/pkg/layout"
-	"github.com/defenseunicorns/zarf/src/pkg/packager/composer"
-	"github.com/defenseunicorns/zarf/src/pkg/packager/creator"
-	"github.com/defenseunicorns/zarf/src/pkg/transform"
-	"github.com/defenseunicorns/zarf/src/pkg/utils"
-	"github.com/defenseunicorns/zarf/src/types"
 	"github.com/xeipuuv/gojsonschema"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/config/lang"
+	"github.com/zarf-dev/zarf/src/pkg/layout"
+	"github.com/zarf-dev/zarf/src/pkg/packager/composer"
+	"github.com/zarf-dev/zarf/src/pkg/packager/creator"
+	"github.com/zarf-dev/zarf/src/pkg/transform"
+	"github.com/zarf-dev/zarf/src/pkg/utils"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 // ZarfSchema is exported so main.go can embed the schema file
diff --git a/src/pkg/packager/lint/lint_test.go b/src/pkg/packager/lint/lint_test.go
index 67af529a8d..213c0938d2 100644
--- a/src/pkg/packager/lint/lint_test.go
+++ b/src/pkg/packager/lint/lint_test.go
@@ -11,10 +11,10 @@ import (
 	"os"
 	"testing"
 
-	"github.com/defenseunicorns/zarf/src/pkg/variables"
-	"github.com/defenseunicorns/zarf/src/types"
 	goyaml "github.com/goccy/go-yaml"
 	"github.com/stretchr/testify/require"
+	"github.com/zarf-dev/zarf/src/pkg/variables"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 func TestZarfSchema(t *testing.T) {
diff --git a/src/pkg/packager/mirror.go b/src/pkg/packager/mirror.go
index 27ffaf9c18..9cafe38f58 100644
--- a/src/pkg/packager/mirror.go
+++ b/src/pkg/packager/mirror.go
@@ -10,10 +10,10 @@ import (
 	"runtime"
 	"strings"
 
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/packager/filters"
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/packager/filters"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 // Mirror pulls resources from a package (images, git repositories, etc) and pushes them to remotes in the air gap without deploying them
diff --git a/src/pkg/packager/prepare.go b/src/pkg/packager/prepare.go
index 9a4f7a1280..c71038b2f8 100644
--- a/src/pkg/packager/prepare.go
+++ b/src/pkg/packager/prepare.go
@@ -16,16 +16,16 @@ import (
 	"github.com/goccy/go-yaml"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/config/lang"
-	"github.com/defenseunicorns/zarf/src/internal/packager/helm"
-	"github.com/defenseunicorns/zarf/src/internal/packager/images"
-	"github.com/defenseunicorns/zarf/src/internal/packager/kustomize"
-	"github.com/defenseunicorns/zarf/src/pkg/layout"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/packager/creator"
-	"github.com/defenseunicorns/zarf/src/pkg/utils"
-	"github.com/defenseunicorns/zarf/src/types"
 	"github.com/google/go-containerregistry/pkg/crane"
+	"github.com/zarf-dev/zarf/src/config/lang"
+	"github.com/zarf-dev/zarf/src/internal/packager/helm"
+	"github.com/zarf-dev/zarf/src/internal/packager/images"
+	"github.com/zarf-dev/zarf/src/internal/packager/kustomize"
+	"github.com/zarf-dev/zarf/src/pkg/layout"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/packager/creator"
+	"github.com/zarf-dev/zarf/src/pkg/utils"
+	"github.com/zarf-dev/zarf/src/types"
 	v1 "k8s.io/api/apps/v1"
 	batchv1 "k8s.io/api/batch/v1"
 	corev1 "k8s.io/api/core/v1"
diff --git a/src/pkg/packager/publish.go b/src/pkg/packager/publish.go
index 6f5e90843c..bf664f2739 100644
--- a/src/pkg/packager/publish.go
+++ b/src/pkg/packager/publish.go
@@ -12,16 +12,16 @@ import (
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
 	"github.com/defenseunicorns/pkg/oci"
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/pkg/layout"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/packager/creator"
-	"github.com/defenseunicorns/zarf/src/pkg/packager/filters"
-	"github.com/defenseunicorns/zarf/src/pkg/packager/sources"
-	"github.com/defenseunicorns/zarf/src/pkg/utils"
-	"github.com/defenseunicorns/zarf/src/pkg/zoci"
-	"github.com/defenseunicorns/zarf/src/types"
 	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/pkg/layout"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/packager/creator"
+	"github.com/zarf-dev/zarf/src/pkg/packager/filters"
+	"github.com/zarf-dev/zarf/src/pkg/packager/sources"
+	"github.com/zarf-dev/zarf/src/pkg/utils"
+	"github.com/zarf-dev/zarf/src/pkg/zoci"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 // Publish publishes the package to a registry
diff --git a/src/pkg/packager/remove.go b/src/pkg/packager/remove.go
index be34b6dda7..dbfbf7d690 100644
--- a/src/pkg/packager/remove.go
+++ b/src/pkg/packager/remove.go
@@ -18,14 +18,14 @@ import (
 	kerrors "k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/internal/packager/helm"
-	"github.com/defenseunicorns/zarf/src/pkg/cluster"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/packager/actions"
-	"github.com/defenseunicorns/zarf/src/pkg/packager/filters"
-	"github.com/defenseunicorns/zarf/src/pkg/packager/sources"
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/internal/packager/helm"
+	"github.com/zarf-dev/zarf/src/pkg/cluster"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/packager/actions"
+	"github.com/zarf-dev/zarf/src/pkg/packager/filters"
+	"github.com/zarf-dev/zarf/src/pkg/packager/sources"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 // Remove removes a package that was already deployed onto a cluster, uninstalling all installed helm charts.
diff --git a/src/pkg/packager/sources/cluster.go b/src/pkg/packager/sources/cluster.go
index 5936c5d6f0..bd671120e8 100644
--- a/src/pkg/packager/sources/cluster.go
+++ b/src/pkg/packager/sources/cluster.go
@@ -9,11 +9,11 @@ import (
 	"fmt"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/pkg/cluster"
-	"github.com/defenseunicorns/zarf/src/pkg/layout"
-	"github.com/defenseunicorns/zarf/src/pkg/packager/filters"
-	"github.com/defenseunicorns/zarf/src/pkg/utils"
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/pkg/cluster"
+	"github.com/zarf-dev/zarf/src/pkg/layout"
+	"github.com/zarf-dev/zarf/src/pkg/packager/filters"
+	"github.com/zarf-dev/zarf/src/pkg/utils"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 var (
diff --git a/src/pkg/packager/sources/new.go b/src/pkg/packager/sources/new.go
index c9f1f46a14..9018632085 100644
--- a/src/pkg/packager/sources/new.go
+++ b/src/pkg/packager/sources/new.go
@@ -12,12 +12,12 @@ import (
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
 	"github.com/defenseunicorns/pkg/oci"
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/pkg/layout"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/packager/filters"
-	"github.com/defenseunicorns/zarf/src/pkg/zoci"
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/pkg/layout"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/packager/filters"
+	"github.com/zarf-dev/zarf/src/pkg/zoci"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 // PackageSource is an interface for package sources.
diff --git a/src/pkg/packager/sources/new_test.go b/src/pkg/packager/sources/new_test.go
index 9c7629ba42..a1a495b3ca 100644
--- a/src/pkg/packager/sources/new_test.go
+++ b/src/pkg/packager/sources/new_test.go
@@ -17,9 +17,9 @@ import (
 
 	"github.com/stretchr/testify/require"
 
-	"github.com/defenseunicorns/zarf/src/pkg/layout"
-	"github.com/defenseunicorns/zarf/src/pkg/packager/filters"
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/pkg/layout"
+	"github.com/zarf-dev/zarf/src/pkg/packager/filters"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 func TestNewPackageSource(t *testing.T) {
@@ -51,13 +51,13 @@ func TestNewPackageSource(t *testing.T) {
 		},
 		{
 			name:             "https",
-			src:              "https://github.com/defenseunicorns/zarf/releases/download/v1.0.0/zarf-init-amd64-v1.0.0.tar.zst",
+			src:              "https://github.com/zarf-dev/zarf/releases/download/v1.0.0/zarf-init-amd64-v1.0.0.tar.zst",
 			expectedIdentify: "https",
 			expectedType:     &URLSource{},
 		},
 		{
 			name:             "http",
-			src:              "http://github.com/defenseunicorns/zarf/releases/download/v1.0.0/zarf-init-amd64-v1.0.0.tar.zst",
+			src:              "http://github.com/zarf-dev/zarf/releases/download/v1.0.0/zarf-init-amd64-v1.0.0.tar.zst",
 			expectedIdentify: "http",
 			expectedType:     &URLSource{},
 		},
diff --git a/src/pkg/packager/sources/oci.go b/src/pkg/packager/sources/oci.go
index 84ba85ebaf..99a98137fc 100644
--- a/src/pkg/packager/sources/oci.go
+++ b/src/pkg/packager/sources/oci.go
@@ -12,14 +12,14 @@ import (
 	"path/filepath"
 	"strings"
 
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/pkg/layout"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/packager/filters"
-	"github.com/defenseunicorns/zarf/src/pkg/utils"
-	"github.com/defenseunicorns/zarf/src/pkg/zoci"
-	"github.com/defenseunicorns/zarf/src/types"
 	"github.com/mholt/archiver/v3"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/pkg/layout"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/packager/filters"
+	"github.com/zarf-dev/zarf/src/pkg/utils"
+	"github.com/zarf-dev/zarf/src/pkg/zoci"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 var (
diff --git a/src/pkg/packager/sources/split.go b/src/pkg/packager/sources/split.go
index 1594a51c20..473aa0008a 100644
--- a/src/pkg/packager/sources/split.go
+++ b/src/pkg/packager/sources/split.go
@@ -15,10 +15,10 @@ import (
 	"strings"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/pkg/layout"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/packager/filters"
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/pkg/layout"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/packager/filters"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 var (
diff --git a/src/pkg/packager/sources/tarball.go b/src/pkg/packager/sources/tarball.go
index 663a4bd31c..b99253c0a5 100644
--- a/src/pkg/packager/sources/tarball.go
+++ b/src/pkg/packager/sources/tarball.go
@@ -14,12 +14,12 @@ import (
 	"path/filepath"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/pkg/layout"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/packager/filters"
-	"github.com/defenseunicorns/zarf/src/pkg/zoci"
-	"github.com/defenseunicorns/zarf/src/types"
 	"github.com/mholt/archiver/v3"
+	"github.com/zarf-dev/zarf/src/pkg/layout"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/packager/filters"
+	"github.com/zarf-dev/zarf/src/pkg/zoci"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 var (
diff --git a/src/pkg/packager/sources/url.go b/src/pkg/packager/sources/url.go
index 9fa3cfb8e0..02fc785d81 100644
--- a/src/pkg/packager/sources/url.go
+++ b/src/pkg/packager/sources/url.go
@@ -12,11 +12,11 @@ import (
 	"strings"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/pkg/layout"
-	"github.com/defenseunicorns/zarf/src/pkg/packager/filters"
-	"github.com/defenseunicorns/zarf/src/pkg/utils"
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/pkg/layout"
+	"github.com/zarf-dev/zarf/src/pkg/packager/filters"
+	"github.com/zarf-dev/zarf/src/pkg/utils"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 var (
diff --git a/src/pkg/packager/sources/utils.go b/src/pkg/packager/sources/utils.go
index f880e11d0e..bb2e3227d9 100644
--- a/src/pkg/packager/sources/utils.go
+++ b/src/pkg/packager/sources/utils.go
@@ -12,12 +12,12 @@ import (
 	"strings"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/pkg/layout"
-	"github.com/defenseunicorns/zarf/src/pkg/zoci"
-	"github.com/defenseunicorns/zarf/src/types"
 	goyaml "github.com/goccy/go-yaml"
 	"github.com/mholt/archiver/v3"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/pkg/layout"
+	"github.com/zarf-dev/zarf/src/pkg/zoci"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 // GetValidPackageExtensions returns the valid package extensions.
diff --git a/src/pkg/packager/sources/validate.go b/src/pkg/packager/sources/validate.go
index 1d8a4f6255..427d05708a 100644
--- a/src/pkg/packager/sources/validate.go
+++ b/src/pkg/packager/sources/validate.go
@@ -14,10 +14,10 @@ import (
 	"strings"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/pkg/layout"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/pkg/utils"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/pkg/layout"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/utils"
 )
 
 var (
diff --git a/src/pkg/pki/pki.go b/src/pkg/pki/pki.go
index 6923042393..0eaf5ea82b 100644
--- a/src/pkg/pki/pki.go
+++ b/src/pkg/pki/pki.go
@@ -16,7 +16,7 @@ import (
 	"time"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 // Based off of https://github.com/dmcgowan/quicktls/blob/master/main.go
diff --git a/src/pkg/transform/git_test.go b/src/pkg/transform/git_test.go
index 70145275aa..19c5778966 100644
--- a/src/pkg/transform/git_test.go
+++ b/src/pkg/transform/git_test.go
@@ -13,9 +13,9 @@ import (
 var gitURLs = []string{
 	// Normal git repos and references for pushing/pulling
 	"https://repo1.dso.mil/platform-one/big-bang/apps/security-tools/twistlock.git",
-	"https://github.com/defenseunicorns/zarf.git",
+	"https://github.com/zarf-dev/zarf.git",
 	"https://ghcr.io/stefanprodan/podinfo_fasd-123.git",
-	"git://k3d-cluster.localhost/defenseunicorns/zarf-agent",
+	"git://k3d-cluster.localhost/zarf-dev/zarf-agent",
 	"http://localhost:5000/some-cool-repo",
 	"ssh://ghcr.io/stefanprodan/podinfo@6.0.0",
 	"https://stefanprodan/podinfo.git@adf0fasd10.1.223124123123-asdf",
@@ -23,19 +23,19 @@ var gitURLs = []string{
 	"file:///srv/git/stefanprodan/podinfo@adf0fasd10.1.223124123123-asdf",
 	"https://me0515@dev.azure.com/me0515/zarf-public-test/_git/zarf-public-test",
 	"https://me0515@dev.azure.com/me0515/zarf-public-test/_git/zarf-public-test@524980951ff16e19dc25232e9aea8fd693989ba6",
-	"https://github.com/defenseunicorns/zarf.helm.git",
-	"https://github.com/defenseunicorns/zarf.git@refs/tags/v0.16.0",
+	"https://github.com/zarf-dev/zarf.helm.git",
+	"https://github.com/zarf-dev/zarf.git@refs/tags/v0.16.0",
 	"https://github.com/DoD-Platform-One/big-bang.git@refs/heads/release-1.54.x",
 	"https://github.com/prometheus-community/helm-charts.git@kube-prometheus-stack-47.3.0",
 	"https://github.com/prometheus-community/",
 	"https://github.com/",
 
 	// Smart Git Protocol URLs for proxying (https://www.git-scm.com/docs/http-protocol)
-	"https://github.com/defenseunicorns/zarf.helm.git/info/refs",
-	"https://github.com/defenseunicorns/zarf.helm.git/info/refs?service=git-upload-pack",
-	"https://github.com/defenseunicorns/zarf.helm.git/info/refs?service=git-receive-pack",
-	"https://github.com/defenseunicorns/zarf.helm.git/git-upload-pack",
-	"https://github.com/defenseunicorns/zarf.helm.git/git-receive-pack",
+	"https://github.com/zarf-dev/zarf.helm.git/info/refs",
+	"https://github.com/zarf-dev/zarf.helm.git/info/refs?service=git-upload-pack",
+	"https://github.com/zarf-dev/zarf.helm.git/info/refs?service=git-receive-pack",
+	"https://github.com/zarf-dev/zarf.helm.git/git-upload-pack",
+	"https://github.com/zarf-dev/zarf.helm.git/git-receive-pack",
 }
 
 var badGitURLs = []string{
@@ -48,11 +48,11 @@ func TestMutateGitURLsInText(t *testing.T) {
 	originalText := `
 	# Here we handle invalid URLs (see below comment)
 	# We transform https://*/*.git URLs
-	https://github.com/defenseunicorns/zarf.git
+	https://github.com/zarf-dev/zarf.git
 	# Even URLs with things on either side
-	stuff https://github.com/defenseunicorns/zarf.git andthings
+	stuff https://github.com/zarf-dev/zarf.git andthings
 	# Including ssh://*/*.git URLs
-	ssh://git@github.com/defenseunicorns/zarf.git
+	ssh://git@github.com/zarf-dev/zarf.git
 	# Or non .git URLs
 	https://www.defenseunicorns.com/
 	`
@@ -60,11 +60,11 @@ func TestMutateGitURLsInText(t *testing.T) {
 	expectedText := `
 	# Here we handle invalid URLs (see below comment)
 	# We transform https://*/*.git URLs
-	https://gitlab.com/repo-owner/zarf-1211668992.git
+	https://gitlab.com/repo-owner/zarf-4156197301.git
 	# Even URLs with things on either side
-	stuff https://gitlab.com/repo-owner/zarf-1211668992.git andthings
+	stuff https://gitlab.com/repo-owner/zarf-4156197301.git andthings
 	# Including ssh://*/*.git URLs
-	https://gitlab.com/repo-owner/zarf-2566185087.git
+	https://gitlab.com/repo-owner/zarf-1231196790.git
 	# Or non .git URLs
 	https://www.defenseunicorns.com/
 	`
@@ -77,9 +77,9 @@ func TestGitURLSplitRef(t *testing.T) {
 	var expectedResult = [][]string{
 		// Normal git repos and references for pushing/pulling
 		{"https://repo1.dso.mil/platform-one/big-bang/apps/security-tools/twistlock.git", ""},
-		{"https://github.com/defenseunicorns/zarf.git", ""},
+		{"https://github.com/zarf-dev/zarf.git", ""},
 		{"https://ghcr.io/stefanprodan/podinfo_fasd-123.git", ""},
-		{"git://k3d-cluster.localhost/defenseunicorns/zarf-agent", ""},
+		{"git://k3d-cluster.localhost/zarf-dev/zarf-agent", ""},
 		{"http://localhost:5000/some-cool-repo", ""},
 		{"ssh://ghcr.io/stefanprodan/podinfo", "6.0.0"},
 		{"https://stefanprodan/podinfo.git", "adf0fasd10.1.223124123123-asdf"},
@@ -87,19 +87,19 @@ func TestGitURLSplitRef(t *testing.T) {
 		{"file:///srv/git/stefanprodan/podinfo", "adf0fasd10.1.223124123123-asdf"},
 		{"https://me0515@dev.azure.com/me0515/zarf-public-test/_git/zarf-public-test", ""},
 		{"https://me0515@dev.azure.com/me0515/zarf-public-test/_git/zarf-public-test", "524980951ff16e19dc25232e9aea8fd693989ba6"},
-		{"https://github.com/defenseunicorns/zarf.helm.git", ""},
-		{"https://github.com/defenseunicorns/zarf.git", "refs/tags/v0.16.0"},
+		{"https://github.com/zarf-dev/zarf.helm.git", ""},
+		{"https://github.com/zarf-dev/zarf.git", "refs/tags/v0.16.0"},
 		{"https://github.com/DoD-Platform-One/big-bang.git", "refs/heads/release-1.54.x"},
 		{"https://github.com/prometheus-community/helm-charts.git", "kube-prometheus-stack-47.3.0"},
 		{"https://github.com/prometheus-community", ""},
 		{"https://github.com/", ""},
 
 		// Smart Git Protocol URLs for proxying (https://www.git-scm.com/docs/http-protocol)
-		{"https://github.com/defenseunicorns/zarf.helm.git", ""},
-		{"https://github.com/defenseunicorns/zarf.helm.git", ""},
-		{"https://github.com/defenseunicorns/zarf.helm.git", ""},
-		{"https://github.com/defenseunicorns/zarf.helm.git", ""},
-		{"https://github.com/defenseunicorns/zarf.helm.git", ""},
+		{"https://github.com/zarf-dev/zarf.helm.git", ""},
+		{"https://github.com/zarf-dev/zarf.helm.git", ""},
+		{"https://github.com/zarf-dev/zarf.helm.git", ""},
+		{"https://github.com/zarf-dev/zarf.helm.git", ""},
+		{"https://github.com/zarf-dev/zarf.helm.git", ""},
 	}
 
 	for idx, url := range gitURLs {
@@ -119,9 +119,9 @@ func TestGitURLtoFolderName(t *testing.T) {
 	var expectedResult = []string{
 		// Normal git repos and references for pushing/pulling
 		"twistlock-1590638614",
-		"zarf-3863619701",
+		"zarf-3457133088",
 		"podinfo_fasd-123-1478387306",
-		"zarf-agent-802453811",
+		"zarf-agent-927663661",
 		"some-cool-repo-1916670310",
 		"podinfo-1350532569",
 		"podinfo-1853010387",
@@ -129,19 +129,19 @@ func TestGitURLtoFolderName(t *testing.T) {
 		"podinfo-122075437",
 		"zarf-public-test-612413317",
 		"zarf-public-test-634307705",
-		"zarf.helm-2570741950",
-		"zarf-2175050463",
+		"zarf.helm-93697844",
+		"zarf-2360044954",
 		"big-bang-2705706079",
 		"helm-charts-1319967699",
 		"prometheus-community-3453166319",
 		"-1276058275",
 
 		// Smart Git Protocol URLs for proxying (https://www.git-scm.com/docs/http-protocol)
-		"zarf.helm-2570741950",
-		"zarf.helm-2570741950",
-		"zarf.helm-2570741950",
-		"zarf.helm-2570741950",
-		"zarf.helm-2570741950",
+		"zarf.helm-93697844",
+		"zarf.helm-93697844",
+		"zarf.helm-93697844",
+		"zarf.helm-93697844",
+		"zarf.helm-93697844",
 	}
 
 	for idx, url := range gitURLs {
@@ -160,9 +160,9 @@ func TestGitURLtoRepoName(t *testing.T) {
 	var expectedResult = []string{
 		// Normal git repos and references for pushing/pulling
 		"twistlock-97328248",
-		"zarf-1211668992",
+		"zarf-4156197301",
 		"podinfo_fasd-123-84577122",
-		"zarf-agent-3633494462",
+		"zarf-agent-1776579160",
 		"some-cool-repo-926913879",
 		"podinfo-2985051089",
 		"podinfo-2197246515",
@@ -170,19 +170,19 @@ func TestGitURLtoRepoName(t *testing.T) {
 		"podinfo-1175499642",
 		"zarf-public-test-2170732467",
 		"zarf-public-test-2170732467",
-		"zarf.helm-842267124",
-		"zarf-1211668992",
+		"zarf.helm-693435256",
+		"zarf-4156197301",
 		"big-bang-2366614037",
 		"helm-charts-3648076006",
 		"prometheus-community-2749132599",
 		"-98306241",
 
 		// Smart Git Protocol URLs for proxying (https://www.git-scm.com/docs/http-protocol)
-		"zarf.helm-842267124",
-		"zarf.helm-842267124",
-		"zarf.helm-842267124",
-		"zarf.helm-842267124",
-		"zarf.helm-842267124",
+		"zarf.helm-693435256",
+		"zarf.helm-693435256",
+		"zarf.helm-693435256",
+		"zarf.helm-693435256",
+		"zarf.helm-693435256",
 	}
 
 	for idx, url := range gitURLs {
@@ -201,9 +201,9 @@ func TestGitURL(t *testing.T) {
 	var expectedResult = []string{
 		// Normal git repos and references for pushing/pulling
 		"https://gitlab.com/repo-owner/twistlock-97328248.git",
-		"https://gitlab.com/repo-owner/zarf-1211668992.git",
+		"https://gitlab.com/repo-owner/zarf-4156197301.git",
 		"https://gitlab.com/repo-owner/podinfo_fasd-123-84577122.git",
-		"https://gitlab.com/repo-owner/zarf-agent-3633494462",
+		"https://gitlab.com/repo-owner/zarf-agent-1776579160",
 		"https://gitlab.com/repo-owner/some-cool-repo-926913879",
 		"https://gitlab.com/repo-owner/podinfo-2985051089",
 		"https://gitlab.com/repo-owner/podinfo-2197246515.git",
@@ -211,19 +211,19 @@ func TestGitURL(t *testing.T) {
 		"https://gitlab.com/repo-owner/podinfo-1175499642",
 		"https://gitlab.com/repo-owner/zarf-public-test-2170732467",
 		"https://gitlab.com/repo-owner/zarf-public-test-2170732467",
-		"https://gitlab.com/repo-owner/zarf.helm-842267124.git",
-		"https://gitlab.com/repo-owner/zarf-1211668992.git",
+		"https://gitlab.com/repo-owner/zarf.helm-693435256.git",
+		"https://gitlab.com/repo-owner/zarf-4156197301.git",
 		"https://gitlab.com/repo-owner/big-bang-2366614037.git",
 		"https://gitlab.com/repo-owner/helm-charts-3648076006.git",
 		"https://gitlab.com/repo-owner/prometheus-community-2749132599",
 		"https://gitlab.com/repo-owner/-98306241",
 
 		// Smart Git Protocol URLs for proxying (https://www.git-scm.com/docs/http-protocol)
-		"https://gitlab.com/repo-owner/zarf.helm-842267124.git/info/refs",
-		"https://gitlab.com/repo-owner/zarf.helm-842267124.git/info/refs?service=git-upload-pack",
-		"https://gitlab.com/repo-owner/zarf.helm-842267124.git/info/refs?service=git-receive-pack",
-		"https://gitlab.com/repo-owner/zarf.helm-842267124.git/git-upload-pack",
-		"https://gitlab.com/repo-owner/zarf.helm-842267124.git/git-receive-pack",
+		"https://gitlab.com/repo-owner/zarf.helm-693435256.git/info/refs",
+		"https://gitlab.com/repo-owner/zarf.helm-693435256.git/info/refs?service=git-upload-pack",
+		"https://gitlab.com/repo-owner/zarf.helm-693435256.git/info/refs?service=git-receive-pack",
+		"https://gitlab.com/repo-owner/zarf.helm-693435256.git/git-upload-pack",
+		"https://gitlab.com/repo-owner/zarf.helm-693435256.git/git-receive-pack",
 	}
 
 	for idx, url := range gitURLs {
diff --git a/src/pkg/transform/image_test.go b/src/pkg/transform/image_test.go
index cc61154efa..13fd300c25 100644
--- a/src/pkg/transform/image_test.go
+++ b/src/pkg/transform/image_test.go
@@ -13,11 +13,11 @@ import (
 var imageRefs = []string{
 	"nginx",
 	"nginx:1.23.3",
-	"defenseunicorns/zarf-agent:v0.22.1",
-	"defenseunicorns/zarf-agent@sha256:84605f731c6a18194794c51e70021c671ab064654b751aa57e905bce55be13de",
+	"zarf-dev/zarf-agent:v0.22.1",
+	"zarf-dev/zarf-agent@sha256:84605f731c6a18194794c51e70021c671ab064654b751aa57e905bce55be13de",
 	"busybox:latest@sha256:3fbc632167424a6d997e74f52b878d7cc478225cffac6bc977eedfe51c7f4e79",
 	"ghcr.io/stefanprodan/podinfo:6.3.3",
-	"registry1.dso.mil/ironbank/opensource/defenseunicorns/zarf/zarf-agent:v0.25.0",
+	"registry1.dso.mil/ironbank/opensource/zarf-dev/zarf/zarf-agent:v0.25.0",
 	"gitlab.com/project/gitea/gitea:1.19.3-rootless-zarf-3431384023",
 	"oci://10.43.130.183:5000/stefanprodan/manifests/podinfo",
 }
@@ -33,11 +33,11 @@ func TestImageTransformHost(t *testing.T) {
 		// Normal git repos and references for pushing/pulling
 		"gitlab.com/project/library/nginx:latest-zarf-3793515731",
 		"gitlab.com/project/library/nginx:1.23.3-zarf-3793515731",
-		"gitlab.com/project/defenseunicorns/zarf-agent:v0.22.1-zarf-4283503412",
-		"gitlab.com/project/defenseunicorns/zarf-agent@sha256:84605f731c6a18194794c51e70021c671ab064654b751aa57e905bce55be13de",
+		"gitlab.com/project/zarf-dev/zarf-agent:v0.22.1-zarf-2183797434",
+		"gitlab.com/project/zarf-dev/zarf-agent@sha256:84605f731c6a18194794c51e70021c671ab064654b751aa57e905bce55be13de",
 		"gitlab.com/project/library/busybox@sha256:3fbc632167424a6d997e74f52b878d7cc478225cffac6bc977eedfe51c7f4e79",
 		"gitlab.com/project/stefanprodan/podinfo:6.3.3-zarf-2985051089",
-		"gitlab.com/project/ironbank/opensource/defenseunicorns/zarf/zarf-agent:v0.25.0-zarf-2003217571",
+		"gitlab.com/project/ironbank/opensource/zarf-dev/zarf/zarf-agent:v0.25.0-zarf-1211467612",
 		"gitlab.com/project/gitea/gitea:1.19.3-rootless-zarf-3431384023",
 		"gitlab.com/project/stefanprodan/manifests/podinfo:latest-zarf-531355090",
 	}
@@ -58,11 +58,11 @@ func TestImageTransformHostWithoutChecksum(t *testing.T) {
 	var expectedResult = []string{
 		"gitlab.com/project/library/nginx:latest",
 		"gitlab.com/project/library/nginx:1.23.3",
-		"gitlab.com/project/defenseunicorns/zarf-agent:v0.22.1",
-		"gitlab.com/project/defenseunicorns/zarf-agent@sha256:84605f731c6a18194794c51e70021c671ab064654b751aa57e905bce55be13de",
+		"gitlab.com/project/zarf-dev/zarf-agent:v0.22.1",
+		"gitlab.com/project/zarf-dev/zarf-agent@sha256:84605f731c6a18194794c51e70021c671ab064654b751aa57e905bce55be13de",
 		"gitlab.com/project/library/busybox@sha256:3fbc632167424a6d997e74f52b878d7cc478225cffac6bc977eedfe51c7f4e79",
 		"gitlab.com/project/stefanprodan/podinfo:6.3.3",
-		"gitlab.com/project/ironbank/opensource/defenseunicorns/zarf/zarf-agent:v0.25.0",
+		"gitlab.com/project/ironbank/opensource/zarf-dev/zarf/zarf-agent:v0.25.0",
 		"gitlab.com/project/gitea/gitea:1.19.3-rootless-zarf-3431384023",
 		"gitlab.com/project/stefanprodan/manifests/podinfo:latest",
 	}
@@ -83,11 +83,11 @@ func TestParseImageRef(t *testing.T) {
 	var expectedResult = [][]string{
 		{"docker.io/", "library/nginx", "latest", ""},
 		{"docker.io/", "library/nginx", "1.23.3", ""},
-		{"docker.io/", "defenseunicorns/zarf-agent", "v0.22.1", ""},
-		{"docker.io/", "defenseunicorns/zarf-agent", "", "sha256:84605f731c6a18194794c51e70021c671ab064654b751aa57e905bce55be13de"},
+		{"docker.io/", "zarf-dev/zarf-agent", "v0.22.1", ""},
+		{"docker.io/", "zarf-dev/zarf-agent", "", "sha256:84605f731c6a18194794c51e70021c671ab064654b751aa57e905bce55be13de"},
 		{"docker.io/", "library/busybox", "latest", "sha256:3fbc632167424a6d997e74f52b878d7cc478225cffac6bc977eedfe51c7f4e79"},
 		{"ghcr.io/", "stefanprodan/podinfo", "6.3.3", ""},
-		{"registry1.dso.mil/", "ironbank/opensource/defenseunicorns/zarf/zarf-agent", "v0.25.0", ""},
+		{"registry1.dso.mil/", "ironbank/opensource/zarf-dev/zarf/zarf-agent", "v0.25.0", ""},
 		{"gitlab.com/", "project/gitea/gitea", "1.19.3-rootless-zarf-3431384023", ""},
 		{"10.43.130.183:5000/", "stefanprodan/manifests/podinfo", "latest", ""},
 	}
diff --git a/src/pkg/utils/auth.go b/src/pkg/utils/auth.go
index 69a313cc13..c66b29b548 100644
--- a/src/pkg/utils/auth.go
+++ b/src/pkg/utils/auth.go
@@ -12,8 +12,8 @@ import (
 	"path/filepath"
 	"strings"
 
-	"github.com/defenseunicorns/zarf/src/pkg/message"
 	"github.com/go-git/go-git/v5/plumbing/transport/http"
+	"github.com/zarf-dev/zarf/src/pkg/message"
 )
 
 // Credential represents authentication for a given host.
diff --git a/src/pkg/utils/auth_test.go b/src/pkg/utils/auth_test.go
index 6260e7af0d..3493cdf919 100644
--- a/src/pkg/utils/auth_test.go
+++ b/src/pkg/utils/auth_test.go
@@ -7,9 +7,9 @@ package utils
 import (
 	"testing"
 
-	mocks "github.com/defenseunicorns/zarf/src/test/mocks"
 	"github.com/go-git/go-git/v5/plumbing/transport/http"
 	"github.com/stretchr/testify/require"
+	mocks "github.com/zarf-dev/zarf/src/test/mocks"
 )
 
 func TestCredentialParser(t *testing.T) {
diff --git a/src/pkg/utils/bytes.go b/src/pkg/utils/bytes.go
index 4ff6c06d59..032cc65334 100644
--- a/src/pkg/utils/bytes.go
+++ b/src/pkg/utils/bytes.go
@@ -13,7 +13,7 @@ import (
 	"time"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/message"
 )
 
 // RoundUp rounds a float64 to the given number of decimal places.
diff --git a/src/pkg/utils/cosign.go b/src/pkg/utils/cosign.go
index fc66d92ba9..ae8e553cda 100644
--- a/src/pkg/utils/cosign.go
+++ b/src/pkg/utils/cosign.go
@@ -12,13 +12,13 @@ import (
 	"strings"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/config/lang"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
 	"github.com/google/go-containerregistry/pkg/authn"
 	"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"
 
 	"github.com/sigstore/cosign/v2/cmd/cosign/cli/fulcio"
 	"github.com/sigstore/cosign/v2/cmd/cosign/cli/options"
diff --git a/src/pkg/utils/image.go b/src/pkg/utils/image.go
index a6490375dc..828fea84ad 100644
--- a/src/pkg/utils/image.go
+++ b/src/pkg/utils/image.go
@@ -11,10 +11,10 @@ import (
 	"path/filepath"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/pkg/transform"
 	v1 "github.com/google/go-containerregistry/pkg/v1"
 	"github.com/google/go-containerregistry/pkg/v1/layout"
 	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+	"github.com/zarf-dev/zarf/src/pkg/transform"
 )
 
 // LoadOCIImage returns a v1.Image with the image ref specified from a location provided, or an error if the image cannot be found.
diff --git a/src/pkg/utils/io.go b/src/pkg/utils/io.go
index 16c1abf377..06885d623a 100755
--- a/src/pkg/utils/io.go
+++ b/src/pkg/utils/io.go
@@ -10,8 +10,8 @@ import (
 	"path/filepath"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/pkg/message"
 )
 
 const (
diff --git a/src/pkg/utils/network.go b/src/pkg/utils/network.go
index 8a4a93821f..e17c086161 100644
--- a/src/pkg/utils/network.go
+++ b/src/pkg/utils/network.go
@@ -15,8 +15,8 @@ import (
 	"strings"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/config/lang"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/config/lang"
+	"github.com/zarf-dev/zarf/src/pkg/message"
 )
 
 func parseChecksum(src string) (string, string, error) {
diff --git a/src/pkg/utils/network_test.go b/src/pkg/utils/network_test.go
index c2f059d7fe..d2357f907d 100644
--- a/src/pkg/utils/network_test.go
+++ b/src/pkg/utils/network_test.go
@@ -21,7 +21,7 @@ import (
 func TestParseChecksum(t *testing.T) {
 	t.Parallel()
 
-	adr := "https://raw.githubusercontent.com/defenseunicorns/zarf/main/.adr-dir"
+	adr := "https://raw.githubusercontent.com/zarf-dev/zarf/main/.adr-dir"
 	sum := "930f4d5a191812e57b39bd60fca789ace07ec5acd36d63e1047604c8bdf998a3"
 
 	tests := []struct {
diff --git a/src/pkg/utils/wait.go b/src/pkg/utils/wait.go
index 4ccc3d2481..fd2d7f1422 100644
--- a/src/pkg/utils/wait.go
+++ b/src/pkg/utils/wait.go
@@ -14,9 +14,9 @@ import (
 	"strings"
 	"time"
 
-	"github.com/defenseunicorns/zarf/src/pkg/utils/exec"
+	"github.com/zarf-dev/zarf/src/pkg/utils/exec"
 
-	"github.com/defenseunicorns/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/pkg/message"
 )
 
 // isJSONPathWaitType checks if the condition is a JSONPath or condition.
diff --git a/src/pkg/utils/wait_test.go b/src/pkg/utils/wait_test.go
index 1c66400ae1..30ca050a1e 100644
--- a/src/pkg/utils/wait_test.go
+++ b/src/pkg/utils/wait_test.go
@@ -7,9 +7,9 @@ package utils
 import (
 	"testing"
 
-	"github.com/defenseunicorns/zarf/src/pkg/message"
 	"github.com/stretchr/testify/require"
 	"github.com/stretchr/testify/suite"
+	"github.com/zarf-dev/zarf/src/pkg/message"
 )
 
 type TestIsJSONPathWaitTypeSuite struct {
diff --git a/src/pkg/utils/yaml.go b/src/pkg/utils/yaml.go
index bc49d46502..e61083bc51 100644
--- a/src/pkg/utils/yaml.go
+++ b/src/pkg/utils/yaml.go
@@ -15,13 +15,13 @@ import (
 	"regexp"
 	"strings"
 
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
 	"github.com/fatih/color"
 	goyaml "github.com/goccy/go-yaml"
 	"github.com/goccy/go-yaml/lexer"
 	"github.com/goccy/go-yaml/printer"
 	"github.com/pterm/pterm"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/pkg/message"
 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
 	"k8s.io/apimachinery/pkg/runtime"
 	kubeyaml "k8s.io/apimachinery/pkg/util/yaml"
diff --git a/src/pkg/variables/types.go b/src/pkg/variables/types.go
index f6f51a6917..3fb8d18d80 100644
--- a/src/pkg/variables/types.go
+++ b/src/pkg/variables/types.go
@@ -8,7 +8,7 @@ import (
 	"fmt"
 	"regexp"
 
-	"github.com/defenseunicorns/zarf/src/config/lang"
+	"github.com/zarf-dev/zarf/src/config/lang"
 )
 
 // VariableType represents a type of a Zarf package variable
diff --git a/src/pkg/zoci/common.go b/src/pkg/zoci/common.go
index 8a19d58cc7..41cf415d1b 100644
--- a/src/pkg/zoci/common.go
+++ b/src/pkg/zoci/common.go
@@ -8,9 +8,9 @@ import (
 	"log/slog"
 
 	"github.com/defenseunicorns/pkg/oci"
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
 	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/pkg/message"
 )
 
 const (
diff --git a/src/pkg/zoci/copier.go b/src/pkg/zoci/copier.go
index d6ed8dffb4..74c8636a74 100644
--- a/src/pkg/zoci/copier.go
+++ b/src/pkg/zoci/copier.go
@@ -10,8 +10,8 @@ import (
 	"fmt"
 
 	"github.com/defenseunicorns/pkg/oci"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
 	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+	"github.com/zarf-dev/zarf/src/pkg/message"
 	"oras.land/oras-go/v2/content"
 )
 
diff --git a/src/pkg/zoci/fetch.go b/src/pkg/zoci/fetch.go
index 33f155059f..3a2d04bb9f 100644
--- a/src/pkg/zoci/fetch.go
+++ b/src/pkg/zoci/fetch.go
@@ -8,9 +8,9 @@ import (
 	"context"
 
 	"github.com/defenseunicorns/pkg/oci"
-	"github.com/defenseunicorns/zarf/src/pkg/layout"
-	"github.com/defenseunicorns/zarf/src/types"
 	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+	"github.com/zarf-dev/zarf/src/pkg/layout"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 // FetchZarfYAML fetches the zarf.yaml file from the remote repository.
diff --git a/src/pkg/zoci/pull.go b/src/pkg/zoci/pull.go
index bd259259e1..c74e66588d 100644
--- a/src/pkg/zoci/pull.go
+++ b/src/pkg/zoci/pull.go
@@ -11,11 +11,11 @@ import (
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
 	"github.com/defenseunicorns/pkg/oci"
-	"github.com/defenseunicorns/zarf/src/pkg/layout"
-	"github.com/defenseunicorns/zarf/src/pkg/transform"
-	"github.com/defenseunicorns/zarf/src/pkg/utils"
-	"github.com/defenseunicorns/zarf/src/types"
 	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+	"github.com/zarf-dev/zarf/src/pkg/layout"
+	"github.com/zarf-dev/zarf/src/pkg/transform"
+	"github.com/zarf-dev/zarf/src/pkg/utils"
+	"github.com/zarf-dev/zarf/src/types"
 	"oras.land/oras-go/v2/content/file"
 )
 
diff --git a/src/pkg/zoci/push.go b/src/pkg/zoci/push.go
index 19ee37a761..63a80b425f 100644
--- a/src/pkg/zoci/push.go
+++ b/src/pkg/zoci/push.go
@@ -10,10 +10,10 @@ import (
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
 	"github.com/defenseunicorns/pkg/oci"
-	"github.com/defenseunicorns/zarf/src/pkg/layout"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/types"
 	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+	"github.com/zarf-dev/zarf/src/pkg/layout"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/types"
 	"oras.land/oras-go/v2"
 	"oras.land/oras-go/v2/content/file"
 )
diff --git a/src/pkg/zoci/utils.go b/src/pkg/zoci/utils.go
index bcd5da45d4..e9ac1f57e3 100644
--- a/src/pkg/zoci/utils.go
+++ b/src/pkg/zoci/utils.go
@@ -10,7 +10,7 @@ import (
 	"strings"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/types"
+	"github.com/zarf-dev/zarf/src/types"
 	"oras.land/oras-go/v2/registry"
 )
 
diff --git a/src/test/common.go b/src/test/common.go
index 70492f014c..0339fe0f48 100644
--- a/src/test/common.go
+++ b/src/test/common.go
@@ -17,8 +17,8 @@ import (
 	"slices"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/pkg/utils/exec"
 	"github.com/stretchr/testify/require"
+	"github.com/zarf-dev/zarf/src/pkg/utils/exec"
 )
 
 // ZarfE2ETest Struct holding common fields most of the tests will utilize.
diff --git a/src/test/e2e/05_tarball_test.go b/src/test/e2e/05_tarball_test.go
index e4ebfde06d..ab91e06e4d 100644
--- a/src/test/e2e/05_tarball_test.go
+++ b/src/test/e2e/05_tarball_test.go
@@ -12,10 +12,10 @@ import (
 	"testing"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/pkg/layout"
-	"github.com/defenseunicorns/zarf/src/pkg/utils"
-	"github.com/defenseunicorns/zarf/src/types"
 	"github.com/stretchr/testify/require"
+	"github.com/zarf-dev/zarf/src/pkg/layout"
+	"github.com/zarf-dev/zarf/src/pkg/utils"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 func TestMultiPartPackage(t *testing.T) {
diff --git a/src/test/e2e/07_create_git_test.go b/src/test/e2e/07_create_git_test.go
index 6c1e3a38c6..af475a3593 100644
--- a/src/test/e2e/07_create_git_test.go
+++ b/src/test/e2e/07_create_git_test.go
@@ -9,8 +9,8 @@ import (
 	"path/filepath"
 	"testing"
 
-	"github.com/defenseunicorns/zarf/src/pkg/utils/exec"
 	"github.com/stretchr/testify/require"
+	"github.com/zarf-dev/zarf/src/pkg/utils/exec"
 )
 
 func TestCreateGit(t *testing.T) {
diff --git a/src/test/e2e/08_create_differential_test.go b/src/test/e2e/08_create_differential_test.go
index ff0a1a698c..d692d1b9cc 100644
--- a/src/test/e2e/08_create_differential_test.go
+++ b/src/test/e2e/08_create_differential_test.go
@@ -9,12 +9,12 @@ import (
 	"path/filepath"
 	"testing"
 
-	"github.com/defenseunicorns/zarf/src/config/lang"
-	"github.com/defenseunicorns/zarf/src/pkg/layout"
-	"github.com/defenseunicorns/zarf/src/pkg/utils"
-	"github.com/defenseunicorns/zarf/src/types"
 	"github.com/mholt/archiver/v3"
 	"github.com/stretchr/testify/require"
+	"github.com/zarf-dev/zarf/src/config/lang"
+	"github.com/zarf-dev/zarf/src/pkg/layout"
+	"github.com/zarf-dev/zarf/src/pkg/utils"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 // TestCreateDifferential creates several differential packages and ensures the reference package images and repos are not included in the new package.
@@ -63,7 +63,7 @@ func TestCreateDifferential(t *testing.T) {
 	expectedGitRepos := []string{
 		"https://github.com/stefanprodan/podinfo.git",
 		"https://github.com/kelseyhightower/nocode.git",
-		"https://github.com/defenseunicorns/zarf.git@refs/tags/v0.26.0",
+		"https://github.com/zarf-dev/zarf.git@refs/tags/v0.26.0",
 	}
 	require.Len(t, actualGitRepos, 4, "zarf.yaml from the differential package does not contain the correct number of repos")
 	for _, expectedRepo := range expectedGitRepos {
diff --git a/src/test/e2e/12_lint_test.go b/src/test/e2e/12_lint_test.go
index dc31217601..a577bb397f 100644
--- a/src/test/e2e/12_lint_test.go
+++ b/src/test/e2e/12_lint_test.go
@@ -9,8 +9,8 @@ import (
 	"path/filepath"
 	"testing"
 
-	"github.com/defenseunicorns/zarf/src/config/lang"
 	"github.com/stretchr/testify/require"
+	"github.com/zarf-dev/zarf/src/config/lang"
 )
 
 func TestLint(t *testing.T) {
diff --git a/src/test/e2e/13_zarf_package_generate_test.go b/src/test/e2e/13_zarf_package_generate_test.go
index ad613ba96a..305141739c 100644
--- a/src/test/e2e/13_zarf_package_generate_test.go
+++ b/src/test/e2e/13_zarf_package_generate_test.go
@@ -8,10 +8,10 @@ import (
 	"path/filepath"
 	"testing"
 
-	"github.com/defenseunicorns/zarf/src/pkg/layout"
-	"github.com/defenseunicorns/zarf/src/pkg/utils"
-	"github.com/defenseunicorns/zarf/src/types"
 	"github.com/stretchr/testify/require"
+	"github.com/zarf-dev/zarf/src/pkg/layout"
+	"github.com/zarf-dev/zarf/src/pkg/utils"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 func TestZarfDevGenerate(t *testing.T) {
diff --git a/src/test/e2e/20_zarf_init_test.go b/src/test/e2e/20_zarf_init_test.go
index f54fc54f85..572cedea0f 100644
--- a/src/test/e2e/20_zarf_init_test.go
+++ b/src/test/e2e/20_zarf_init_test.go
@@ -12,8 +12,8 @@ import (
 
 	"encoding/json"
 
-	"github.com/defenseunicorns/zarf/src/types"
 	"github.com/stretchr/testify/require"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 func TestZarfInit(t *testing.T) {
diff --git a/src/test/e2e/21_connect_creds_test.go b/src/test/e2e/21_connect_creds_test.go
index 8a2a1f65ba..b96d6c579b 100644
--- a/src/test/e2e/21_connect_creds_test.go
+++ b/src/test/e2e/21_connect_creds_test.go
@@ -13,8 +13,8 @@ import (
 	"strings"
 	"testing"
 
-	"github.com/defenseunicorns/zarf/src/pkg/cluster"
 	"github.com/stretchr/testify/require"
+	"github.com/zarf-dev/zarf/src/pkg/cluster"
 )
 
 type RegistryResponse struct {
diff --git a/src/test/e2e/22_git_and_gitops_test.go b/src/test/e2e/22_git_and_gitops_test.go
index 572702dbe4..559bb79e3f 100644
--- a/src/test/e2e/22_git_and_gitops_test.go
+++ b/src/test/e2e/22_git_and_gitops_test.go
@@ -13,10 +13,10 @@ import (
 	"path/filepath"
 	"testing"
 
-	"github.com/defenseunicorns/zarf/src/internal/packager/git"
-	"github.com/defenseunicorns/zarf/src/pkg/cluster"
-	"github.com/defenseunicorns/zarf/src/types"
 	"github.com/stretchr/testify/require"
+	"github.com/zarf-dev/zarf/src/internal/packager/git"
+	"github.com/zarf-dev/zarf/src/pkg/cluster"
+	"github.com/zarf-dev/zarf/src/types"
 )
 
 func TestGit(t *testing.T) {
diff --git a/src/test/e2e/23_data_injection_test.go b/src/test/e2e/23_data_injection_test.go
index 9e4bbef7c3..08f913fc41 100644
--- a/src/test/e2e/23_data_injection_test.go
+++ b/src/test/e2e/23_data_injection_test.go
@@ -12,9 +12,9 @@ import (
 	"testing"
 	"time"
 
-	"github.com/defenseunicorns/zarf/src/pkg/cluster"
-	"github.com/defenseunicorns/zarf/src/pkg/utils/exec"
 	"github.com/stretchr/testify/require"
+	"github.com/zarf-dev/zarf/src/pkg/cluster"
+	"github.com/zarf-dev/zarf/src/pkg/utils/exec"
 )
 
 func TestDataInjection(t *testing.T) {
diff --git a/src/test/e2e/25_helm_test.go b/src/test/e2e/25_helm_test.go
index 280ba3d7ec..071732da10 100644
--- a/src/test/e2e/25_helm_test.go
+++ b/src/test/e2e/25_helm_test.go
@@ -132,7 +132,7 @@ func testHelmUninstallRollback(t *testing.T) {
 	// Ensure this leaves behind a dos-games chart.
 	// We do not want to uninstall charts that had failed installs/upgrades
 	// to prevent unintentional deletion and/or data loss in production environments.
-	// https://github.com/defenseunicorns/zarf/issues/2455
+	// https://github.com/zarf-dev/zarf/issues/2455
 	helmOut, err := exec.Command("helm", "list", "-n", "dos-games").Output()
 	require.NoError(t, err)
 	require.Contains(t, string(helmOut), "zarf-f53a99d4a4dd9a3575bedf59cd42d48d751ae866")
diff --git a/src/test/e2e/26_simple_packages_test.go b/src/test/e2e/26_simple_packages_test.go
index 97a67423e3..05a95d97d2 100644
--- a/src/test/e2e/26_simple_packages_test.go
+++ b/src/test/e2e/26_simple_packages_test.go
@@ -11,8 +11,8 @@ import (
 	"path/filepath"
 	"testing"
 
-	"github.com/defenseunicorns/zarf/src/pkg/cluster"
 	"github.com/stretchr/testify/require"
+	"github.com/zarf-dev/zarf/src/pkg/cluster"
 )
 
 func TestDosGames(t *testing.T) {
diff --git a/src/test/e2e/27_deploy_regression_test.go b/src/test/e2e/27_deploy_regression_test.go
index fec8d55433..49808addff 100644
--- a/src/test/e2e/27_deploy_regression_test.go
+++ b/src/test/e2e/27_deploy_regression_test.go
@@ -9,8 +9,8 @@ import (
 	"fmt"
 	"testing"
 
-	"github.com/defenseunicorns/zarf/src/pkg/utils/exec"
 	"github.com/stretchr/testify/require"
+	"github.com/zarf-dev/zarf/src/pkg/utils/exec"
 )
 
 func TestGHCRDeploy(t *testing.T) {
diff --git a/src/test/e2e/28_wait_test.go b/src/test/e2e/28_wait_test.go
index 0de68f243e..e1b22b4f28 100644
--- a/src/test/e2e/28_wait_test.go
+++ b/src/test/e2e/28_wait_test.go
@@ -10,8 +10,8 @@ import (
 
 	"testing"
 
-	"github.com/defenseunicorns/zarf/src/test"
 	"github.com/stretchr/testify/require"
+	"github.com/zarf-dev/zarf/src/test"
 )
 
 type zarfCommandResult struct {
diff --git a/src/test/e2e/50_oci_publish_deploy_test.go b/src/test/e2e/50_oci_publish_deploy_test.go
index f3d5d89428..81e5e39f54 100644
--- a/src/test/e2e/50_oci_publish_deploy_test.go
+++ b/src/test/e2e/50_oci_publish_deploy_test.go
@@ -13,9 +13,9 @@ import (
 	"time"
 
 	"github.com/defenseunicorns/pkg/oci"
-	"github.com/defenseunicorns/zarf/src/pkg/zoci"
 	"github.com/stretchr/testify/require"
 	"github.com/stretchr/testify/suite"
+	"github.com/zarf-dev/zarf/src/pkg/zoci"
 	"oras.land/oras-go/v2/registry"
 	"oras.land/oras-go/v2/registry/remote"
 )
diff --git a/src/test/e2e/51_oci_compose_test.go b/src/test/e2e/51_oci_compose_test.go
index 124dbb953a..b38db002a6 100644
--- a/src/test/e2e/51_oci_compose_test.go
+++ b/src/test/e2e/51_oci_compose_test.go
@@ -13,12 +13,12 @@ import (
 	"testing"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/pkg/layout"
-	"github.com/defenseunicorns/zarf/src/pkg/transform"
-	"github.com/defenseunicorns/zarf/src/pkg/utils"
-	"github.com/defenseunicorns/zarf/src/types"
 	"github.com/stretchr/testify/require"
 	"github.com/stretchr/testify/suite"
+	"github.com/zarf-dev/zarf/src/pkg/layout"
+	"github.com/zarf-dev/zarf/src/pkg/transform"
+	"github.com/zarf-dev/zarf/src/pkg/utils"
+	"github.com/zarf-dev/zarf/src/types"
 	corev1 "k8s.io/api/core/v1"
 	"oras.land/oras-go/v2/registry"
 )
diff --git a/src/test/e2e/99_yolo_test.go b/src/test/e2e/99_yolo_test.go
index 01671b8600..93a9b9ed60 100644
--- a/src/test/e2e/99_yolo_test.go
+++ b/src/test/e2e/99_yolo_test.go
@@ -10,8 +10,8 @@ import (
 	"net/http"
 	"testing"
 
-	"github.com/defenseunicorns/zarf/src/pkg/cluster"
 	"github.com/stretchr/testify/require"
+	"github.com/zarf-dev/zarf/src/pkg/cluster"
 )
 
 func TestYOLOMode(t *testing.T) {
diff --git a/src/test/e2e/main_test.go b/src/test/e2e/main_test.go
index 6c9c283a55..9fe02d40df 100644
--- a/src/test/e2e/main_test.go
+++ b/src/test/e2e/main_test.go
@@ -10,9 +10,9 @@ import (
 	"path/filepath"
 	"testing"
 
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/pkg/message"
-	"github.com/defenseunicorns/zarf/src/test"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/pkg/message"
+	"github.com/zarf-dev/zarf/src/test"
 )
 
 var (
diff --git a/src/test/external/common.go b/src/test/external/common.go
index 2e9cd8bb68..36e8405a25 100644
--- a/src/test/external/common.go
+++ b/src/test/external/common.go
@@ -12,10 +12,10 @@ import (
 	"testing"
 	"time"
 
-	"github.com/defenseunicorns/zarf/src/pkg/utils/exec"
-	"github.com/defenseunicorns/zarf/src/test"
 	"github.com/otiai10/copy"
 	"github.com/stretchr/testify/require"
+	"github.com/zarf-dev/zarf/src/pkg/utils/exec"
+	"github.com/zarf-dev/zarf/src/test"
 )
 
 var zarfBinPath = path.Join("../../../build", test.GetCLIName())
diff --git a/src/test/external/ext_in_cluster_test.go b/src/test/external/ext_in_cluster_test.go
index 655cb7c59a..97a52fda0a 100644
--- a/src/test/external/ext_in_cluster_test.go
+++ b/src/test/external/ext_in_cluster_test.go
@@ -15,10 +15,10 @@ import (
 	"time"
 
 	pkgkubernetes "github.com/defenseunicorns/pkg/kubernetes"
-	"github.com/defenseunicorns/zarf/src/pkg/cluster"
-	"github.com/defenseunicorns/zarf/src/pkg/utils/exec"
 	"github.com/stretchr/testify/require"
 	"github.com/stretchr/testify/suite"
+	"github.com/zarf-dev/zarf/src/pkg/cluster"
+	"github.com/zarf-dev/zarf/src/pkg/utils/exec"
 	"k8s.io/apimachinery/pkg/runtime/schema"
 	"sigs.k8s.io/cli-utils/pkg/object"
 )
diff --git a/src/test/external/ext_out_cluster_test.go b/src/test/external/ext_out_cluster_test.go
index b32960c318..dfcc9da580 100644
--- a/src/test/external/ext_out_cluster_test.go
+++ b/src/test/external/ext_out_cluster_test.go
@@ -16,10 +16,10 @@ import (
 	"testing"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/pkg/utils"
-	"github.com/defenseunicorns/zarf/src/pkg/utils/exec"
 	"github.com/stretchr/testify/require"
 	"github.com/stretchr/testify/suite"
+	"github.com/zarf-dev/zarf/src/pkg/utils"
+	"github.com/zarf-dev/zarf/src/pkg/utils/exec"
 	"helm.sh/helm/v3/pkg/repo"
 )
 
diff --git a/src/test/nightly/ecr_publish_test.go b/src/test/nightly/ecr_publish_test.go
index 8d696660c8..7716ebf270 100644
--- a/src/test/nightly/ecr_publish_test.go
+++ b/src/test/nightly/ecr_publish_test.go
@@ -11,9 +11,9 @@ import (
 	"path/filepath"
 	"testing"
 
-	"github.com/defenseunicorns/zarf/src/config"
-	"github.com/defenseunicorns/zarf/src/test"
 	"github.com/stretchr/testify/require"
+	"github.com/zarf-dev/zarf/src/config"
+	"github.com/zarf-dev/zarf/src/test"
 )
 
 var (
diff --git a/src/test/packages/08-differential-package/zarf.yaml b/src/test/packages/08-differential-package/zarf.yaml
index c1e5d4ab71..5f5fae02c0 100644
--- a/src/test/packages/08-differential-package/zarf.yaml
+++ b/src/test/packages/08-differential-package/zarf.yaml
@@ -11,8 +11,8 @@ components:
       - ghcr.io/stefanprodan/podinfo:6.0.0
       - ghcr.io/zarf-dev/zarf/agent:###ZARF_PKG_TMPL_PACKAGE_VERSION###
     repos:
-      - https://github.com/defenseunicorns/zarf.git@c74e2e9626da0400e0a41e78319b3054c53a5d4e
-      - https://github.com/defenseunicorns/zarf.git@refs/tags/###ZARF_PKG_TMPL_PACKAGE_VERSION###
+      - https://github.com/zarf-dev/zarf.git@c74e2e9626da0400e0a41e78319b3054c53a5d4e
+      - https://github.com/zarf-dev/zarf.git@refs/tags/###ZARF_PKG_TMPL_PACKAGE_VERSION###
 
   - name: generalized-assets
     required: true
@@ -22,4 +22,4 @@ components:
       # Do a full Git Repo Mirror
       - https://github.com/stefanprodan/podinfo.git
       - https://github.com/kelseyhightower/nocode.git
-      - https://github.com/defenseunicorns/zarf.git@refs/heads/main
+      - https://github.com/zarf-dev/zarf.git@refs/heads/main
diff --git a/src/test/packages/51-import-everything/zarf.yaml b/src/test/packages/51-import-everything/zarf.yaml
index b69ef73086..2f29435f1e 100644
--- a/src/test/packages/51-import-everything/zarf.yaml
+++ b/src/test/packages/51-import-everything/zarf.yaml
@@ -39,7 +39,7 @@ components:
       - source: ../09-composable-packages/files/coffee-ipsum.txt
         target: ../09-composable-packages/coffee-ipsum.txt
         # Import of a file from a URL
-      - source: https://raw.githubusercontent.com/defenseunicorns/zarf/main/README.md
+      - source: https://raw.githubusercontent.com/zarf-dev/zarf/main/README.md
         target: files/zarf-readme.md
     actions:
       onDeploy:
diff --git a/src/test/upgrade/previously_built_test.go b/src/test/upgrade/previously_built_test.go
index 179bad0432..a7c42e87a1 100644
--- a/src/test/upgrade/previously_built_test.go
+++ b/src/test/upgrade/previously_built_test.go
@@ -9,9 +9,9 @@ import (
 	"path"
 	"testing"
 
-	"github.com/defenseunicorns/zarf/src/pkg/utils/exec"
-	test "github.com/defenseunicorns/zarf/src/test"
 	"github.com/stretchr/testify/require"
+	"github.com/zarf-dev/zarf/src/pkg/utils/exec"
+	test "github.com/zarf-dev/zarf/src/test"
 )
 
 func kubectl(args ...string) (string, string, error) {
diff --git a/src/types/component.go b/src/types/component.go
index 958d60e74d..4ccf392970 100644
--- a/src/types/component.go
+++ b/src/types/component.go
@@ -5,10 +5,10 @@
 package types
 
 import (
-	"github.com/defenseunicorns/zarf/src/pkg/utils/exec"
-	"github.com/defenseunicorns/zarf/src/pkg/variables"
-	"github.com/defenseunicorns/zarf/src/types/extensions"
 	"github.com/invopop/jsonschema"
+	"github.com/zarf-dev/zarf/src/pkg/utils/exec"
+	"github.com/zarf-dev/zarf/src/pkg/variables"
+	"github.com/zarf-dev/zarf/src/types/extensions"
 )
 
 // ZarfComponent is the primary functional grouping of assets to deploy by Zarf.
diff --git a/src/types/k8s.go b/src/types/k8s.go
index 2c2c6b3527..a8f61856ce 100644
--- a/src/types/k8s.go
+++ b/src/types/k8s.go
@@ -9,7 +9,7 @@ import (
 	"time"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/config/lang"
+	"github.com/zarf-dev/zarf/src/config/lang"
 )
 
 // WebhookStatus defines the status of a Component Webhook operating on a Zarf package secret.
diff --git a/src/types/package.go b/src/types/package.go
index cff00da592..c78f1fe461 100644
--- a/src/types/package.go
+++ b/src/types/package.go
@@ -4,7 +4,7 @@
 // Package types contains all the types used by Zarf.
 package types
 
-import "github.com/defenseunicorns/zarf/src/pkg/variables"
+import "github.com/zarf-dev/zarf/src/pkg/variables"
 
 // ZarfPackageKind is an enum of the different kinds of Zarf packages.
 type ZarfPackageKind string
diff --git a/src/types/validate.go b/src/types/validate.go
index 131c556e39..4d39d36b23 100644
--- a/src/types/validate.go
+++ b/src/types/validate.go
@@ -12,7 +12,7 @@ import (
 	"slices"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/config/lang"
+	"github.com/zarf-dev/zarf/src/config/lang"
 )
 
 const (
diff --git a/src/types/validate_test.go b/src/types/validate_test.go
index 64af534f58..f283302675 100644
--- a/src/types/validate_test.go
+++ b/src/types/validate_test.go
@@ -11,9 +11,9 @@ import (
 	"testing"
 
 	"github.com/defenseunicorns/pkg/helpers/v2"
-	"github.com/defenseunicorns/zarf/src/config/lang"
-	"github.com/defenseunicorns/zarf/src/pkg/variables"
 	"github.com/stretchr/testify/require"
+	"github.com/zarf-dev/zarf/src/config/lang"
+	"github.com/zarf-dev/zarf/src/pkg/variables"
 )
 
 func TestZarfPackageValidate(t *testing.T) {
diff --git a/zarf.schema.json b/zarf.schema.json
index 3004a424b1..8658787b3b 100644
--- a/zarf.schema.json
+++ b/zarf.schema.json
@@ -1,6 +1,6 @@
 {
   "$schema": "https://json-schema.org/draft/2020-12/schema",
-  "$id": "https://github.com/defenseunicorns/zarf/src/types/zarf-package",
+  "$id": "https://github.com/zarf-dev/zarf/src/types/zarf-package",
   "$defs": {
     "BigBang": {
       "properties": {

From 290d0662ec77a02af51a90001b1bc14d2acbf295 Mon Sep 17 00:00:00 2001
From: schristoff <28318173+schristoff@users.noreply.github.com>
Date: Sun, 21 Jul 2024 16:04:50 -0400
Subject: [PATCH 10/68] chore: move context.TODO to context.Background()
 (#2742)

Signed-off-by: schristoff-du <167717759+schristoff-du@users.noreply.github.com>
Co-authored-by: schristoff-du <167717759+schristoff-du@users.noreply.github.com>
---
 src/cmd/dev.go                     |  4 ++--
 src/extensions/bigbang/bigbang.go  | 11 ++++++-----
 src/internal/packager/git/clone.go | 10 +++++-----
 src/internal/packager/git/pull.go  |  9 +++++----
 src/internal/packager/helm/repo.go | 13 +++++++------
 src/pkg/packager/creator/normal.go | 14 +++++++-------
 src/pkg/packager/generate.go       |  5 +++--
 src/pkg/packager/prepare.go        |  6 +++---
 8 files changed, 38 insertions(+), 34 deletions(-)

diff --git a/src/cmd/dev.go b/src/cmd/dev.go
index c31e0d5fe8..b10f2dde51 100644
--- a/src/cmd/dev.go
+++ b/src/cmd/dev.go
@@ -71,7 +71,7 @@ var devGenerateCmd = &cobra.Command{
 	Args:    cobra.ExactArgs(1),
 	Short:   lang.CmdDevGenerateShort,
 	Example: lang.CmdDevGenerateExample,
-	RunE: func(_ *cobra.Command, args []string) error {
+	RunE: func(cmd *cobra.Command, args []string) error {
 		pkgConfig.GenerateOpts.Name = args[0]
 
 		pkgConfig.CreateOpts.BaseDir = "."
@@ -83,7 +83,7 @@ var devGenerateCmd = &cobra.Command{
 		}
 		defer pkgClient.ClearTempPaths()
 
-		err = pkgClient.Generate()
+		err = pkgClient.Generate(cmd.Context())
 		if err != nil {
 			return err
 		}
diff --git a/src/extensions/bigbang/bigbang.go b/src/extensions/bigbang/bigbang.go
index b97c8f6e25..e312f382f9 100644
--- a/src/extensions/bigbang/bigbang.go
+++ b/src/extensions/bigbang/bigbang.go
@@ -5,6 +5,7 @@
 package bigbang
 
 import (
+	"context"
 	"fmt"
 	"os"
 	"path"
@@ -42,7 +43,7 @@ var tenMins = metav1.Duration{
 
 // Run mutates a component that should deploy Big Bang to a set of manifests
 // that contain the flux deployment of Big Bang
-func Run(YOLO bool, tmpPaths *layout.ComponentPaths, c types.ZarfComponent) (types.ZarfComponent, error) {
+func Run(ctx context.Context, YOLO bool, tmpPaths *layout.ComponentPaths, c types.ZarfComponent) (types.ZarfComponent, error) {
 	cfg := c.Extensions.BigBang
 	manifests := []types.ZarfManifest{}
 
@@ -99,7 +100,7 @@ func Run(YOLO bool, tmpPaths *layout.ComponentPaths, c types.ZarfComponent) (typ
 	)
 
 	// Download the chart from Git and save it to a temporary directory.
-	err = helmCfg.PackageChartFromGit(c.DeprecatedCosignKeyPath)
+	err = helmCfg.PackageChartFromGit(ctx, c.DeprecatedCosignKeyPath)
 	if err != nil {
 		return c, fmt.Errorf("unable to download Big Bang Chart: %w", err)
 	}
@@ -220,7 +221,7 @@ func Run(YOLO bool, tmpPaths *layout.ComponentPaths, c types.ZarfComponent) (typ
 			gitRepo := gitRepos[hr.NamespacedSource]
 			values := hrValues[namespacedName]
 
-			images, err := findImagesforBBChartRepo(gitRepo, values)
+			images, err := findImagesforBBChartRepo(ctx, gitRepo, values)
 			if err != nil {
 				return c, fmt.Errorf("unable to find images for chart repo: %w", err)
 			}
@@ -523,7 +524,7 @@ func addBigBangManifests(YOLO bool, manifestDir string, cfg *extensions.BigBang)
 }
 
 // findImagesforBBChartRepo finds and returns the images for the Big Bang chart repo
-func findImagesforBBChartRepo(repo string, values chartutil.Values) (images []string, err error) {
+func findImagesforBBChartRepo(ctx context.Context, repo string, values chartutil.Values) (images []string, err error) {
 	matches := strings.Split(repo, "@")
 	if len(matches) < 2 {
 		return images, fmt.Errorf("cannot convert git repo %s to helm chart without a version tag", repo)
@@ -532,7 +533,7 @@ func findImagesforBBChartRepo(repo string, values chartutil.Values) (images []st
 	spinner := message.NewProgressSpinner("Discovering images in %s", repo)
 	defer spinner.Stop()
 
-	gitPath, err := helm.DownloadChartFromGitToTemp(repo, spinner)
+	gitPath, err := helm.DownloadChartFromGitToTemp(ctx, repo, spinner)
 	if err != nil {
 		return images, err
 	}
diff --git a/src/internal/packager/git/clone.go b/src/internal/packager/git/clone.go
index 6e70077511..bd38cbcdd4 100644
--- a/src/internal/packager/git/clone.go
+++ b/src/internal/packager/git/clone.go
@@ -18,7 +18,7 @@ import (
 )
 
 // clone performs a `git clone` of a given repo.
-func (g *Git) clone(gitURL string, ref plumbing.ReferenceName, shallow bool) error {
+func (g *Git) clone(ctx context.Context, gitURL string, ref plumbing.ReferenceName, shallow bool) error {
 	cloneOptions := &git.CloneOptions{
 		URL:        gitURL,
 		Progress:   g.Spinner,
@@ -47,7 +47,7 @@ func (g *Git) clone(gitURL string, ref plumbing.ReferenceName, shallow bool) err
 	repo, err := git.PlainClone(g.GitPath, false, cloneOptions)
 	if err != nil {
 		message.Notef("Falling back to host 'git', failed to clone the repo %q with Zarf: %s", gitURL, err.Error())
-		return g.gitCloneFallback(gitURL, ref, shallow)
+		return g.gitCloneFallback(ctx, gitURL, ref, shallow)
 	}
 
 	// If we're cloning the whole repo, we need to also fetch the other branches besides the default.
@@ -72,7 +72,7 @@ func (g *Git) clone(gitURL string, ref plumbing.ReferenceName, shallow bool) err
 }
 
 // gitCloneFallback is a fallback if go-git fails to clone a repo.
-func (g *Git) gitCloneFallback(gitURL string, ref plumbing.ReferenceName, shallow bool) error {
+func (g *Git) gitCloneFallback(ctx context.Context, gitURL string, ref plumbing.ReferenceName, shallow bool) error {
 	// If we can't clone with go-git, fallback to the host clone
 	// Only support "all tags" due to the azure clone url format including a username
 	cloneArgs := []string{"clone", "--origin", onlineRemoteName, gitURL, g.GitPath}
@@ -96,7 +96,7 @@ func (g *Git) gitCloneFallback(gitURL string, ref plumbing.ReferenceName, shallo
 
 	message.Command("git %s", strings.Join(cloneArgs, " "))
 
-	_, _, err := exec.CmdWithContext(context.TODO(), cloneExecConfig, "git", cloneArgs...)
+	_, _, err := exec.CmdWithContext(ctx, cloneExecConfig, "git", cloneArgs...)
 	if err != nil {
 		return err
 	}
@@ -113,7 +113,7 @@ func (g *Git) gitCloneFallback(gitURL string, ref plumbing.ReferenceName, shallo
 
 		message.Command("git %s", strings.Join(fetchArgs, " "))
 
-		_, _, err := exec.CmdWithContext(context.TODO(), fetchExecConfig, "git", fetchArgs...)
+		_, _, err := exec.CmdWithContext(ctx, fetchExecConfig, "git", fetchArgs...)
 		if err != nil {
 			return err
 		}
diff --git a/src/internal/packager/git/pull.go b/src/internal/packager/git/pull.go
index bd2472c08c..5d9e6f1006 100644
--- a/src/internal/packager/git/pull.go
+++ b/src/internal/packager/git/pull.go
@@ -5,6 +5,7 @@
 package git
 
 import (
+	"context"
 	"fmt"
 	"path"
 	"strings"
@@ -16,7 +17,7 @@ import (
 )
 
 // DownloadRepoToTemp clones or updates a repo into a temp folder to perform ephemeral actions (i.e. process chart repos).
-func (g *Git) DownloadRepoToTemp(gitURL string) error {
+func (g *Git) DownloadRepoToTemp(ctx context.Context, gitURL string) error {
 	g.Spinner.Updatef("g.DownloadRepoToTemp(%s)", gitURL)
 
 	path, err := utils.MakeTempDir(config.CommonOptions.TempDirectory)
@@ -26,7 +27,7 @@ func (g *Git) DownloadRepoToTemp(gitURL string) error {
 
 	// If downloading to temp, set this as a shallow clone to only pull the exact
 	// gitURL w/ ref that was specified since we will throw away git history anyway
-	if err = g.Pull(gitURL, path, true); err != nil {
+	if err = g.Pull(ctx, gitURL, path, true); err != nil {
 		return fmt.Errorf("unable to pull the git repo at %s: %w", gitURL, err)
 	}
 
@@ -34,7 +35,7 @@ func (g *Git) DownloadRepoToTemp(gitURL string) error {
 }
 
 // Pull clones or updates a git repository into the target folder.
-func (g *Git) Pull(gitURL, targetFolder string, shallow bool) error {
+func (g *Git) Pull(ctx context.Context, gitURL, targetFolder string, shallow bool) error {
 	g.Spinner.Updatef("Processing git repo %s", gitURL)
 
 	// Split the remote url and the zarf reference
@@ -59,7 +60,7 @@ func (g *Git) Pull(gitURL, targetFolder string, shallow bool) error {
 	g.GitPath = path.Join(targetFolder, repoFolder)
 
 	// Clone the git repository.
-	err = g.clone(gitURLNoRef, ref, shallow)
+	err = g.clone(ctx, gitURLNoRef, ref, shallow)
 	if err != nil {
 		return fmt.Errorf("not a valid git repo or unable to clone (%s): %w", gitURL, err)
 	}
diff --git a/src/internal/packager/helm/repo.go b/src/internal/packager/helm/repo.go
index c3ea9c646f..148a4176a4 100644
--- a/src/internal/packager/helm/repo.go
+++ b/src/internal/packager/helm/repo.go
@@ -5,6 +5,7 @@
 package helm
 
 import (
+	"context"
 	"fmt"
 	"os"
 	"path/filepath"
@@ -32,7 +33,7 @@ import (
 )
 
 // PackageChart creates a chart archive from a path to a chart on the host os and builds chart dependencies
-func (h *Helm) PackageChart(cosignKeyPath string) error {
+func (h *Helm) PackageChart(ctx context.Context, cosignKeyPath string) error {
 	if len(h.chart.URL) > 0 {
 		url, refPlain, err := transform.GitURLSplitRef(h.chart.URL)
 		// check if the chart is a git url with a ref (if an error is returned url will be empty)
@@ -47,7 +48,7 @@ func (h *Helm) PackageChart(cosignKeyPath string) error {
 				h.chart.URL = fmt.Sprintf("%s@%s", h.chart.URL, h.chart.Version)
 			}
 
-			err = h.PackageChartFromGit(cosignKeyPath)
+			err = h.PackageChartFromGit(ctx, cosignKeyPath)
 			if err != nil {
 				return fmt.Errorf("unable to pull the chart %q from git: %w", h.chart.Name, err)
 			}
@@ -113,12 +114,12 @@ func (h *Helm) PackageChartFromLocalFiles(cosignKeyPath string) error {
 }
 
 // PackageChartFromGit is a special implementation of chart archiving that supports the https://p1.dso.mil/#/products/big-bang/ model.
-func (h *Helm) PackageChartFromGit(cosignKeyPath string) error {
+func (h *Helm) PackageChartFromGit(ctx context.Context, cosignKeyPath string) error {
 	spinner := message.NewProgressSpinner("Processing helm chart %s", h.chart.Name)
 	defer spinner.Stop()
 
 	// Retrieve the repo containing the chart
-	gitPath, err := DownloadChartFromGitToTemp(h.chart.URL, spinner)
+	gitPath, err := DownloadChartFromGitToTemp(ctx, h.chart.URL, spinner)
 	if err != nil {
 		return err
 	}
@@ -232,12 +233,12 @@ func (h *Helm) DownloadPublishedChart(cosignKeyPath string) error {
 }
 
 // DownloadChartFromGitToTemp downloads a chart from git into a temp directory
-func DownloadChartFromGitToTemp(url string, spinner *message.Spinner) (string, error) {
+func DownloadChartFromGitToTemp(ctx context.Context, url string, spinner *message.Spinner) (string, error) {
 	// Create the Git configuration and download the repo
 	gitCfg := git.NewWithSpinner(types.GitServerInfo{}, spinner)
 
 	// Download the git repo to a temporary directory
-	err := gitCfg.DownloadRepoToTemp(url)
+	err := gitCfg.DownloadRepoToTemp(ctx, url)
 	if err != nil {
 		return "", fmt.Errorf("unable to download the git repo %s: %w", url, err)
 	}
diff --git a/src/pkg/packager/creator/normal.go b/src/pkg/packager/creator/normal.go
index b8135a8c2f..3b34b7e846 100644
--- a/src/pkg/packager/creator/normal.go
+++ b/src/pkg/packager/creator/normal.go
@@ -86,7 +86,7 @@ func (pc *PackageCreator) LoadPackageDefinition(ctx context.Context, src *layout
 	warnings = append(warnings, templateWarnings...)
 
 	// After templates are filled process any create extensions
-	pkg.Components, err = pc.processExtensions(pkg.Components, src, pkg.Metadata.YOLO)
+	pkg.Components, err = pc.processExtensions(ctx, pkg.Components, src, pkg.Metadata.YOLO)
 	if err != nil {
 		return types.ZarfPackage{}, nil, err
 	}
@@ -142,7 +142,7 @@ func (pc *PackageCreator) Assemble(ctx context.Context, dst *layout.PackagePaths
 			}
 		}
 
-		if err := pc.addComponent(component, dst); err != nil {
+		if err := pc.addComponent(ctx, component, dst); err != nil {
 			onFailure()
 			return fmt.Errorf("unable to add component %q: %w", component.Name, err)
 		}
@@ -327,7 +327,7 @@ func (pc *PackageCreator) Output(ctx context.Context, dst *layout.PackagePaths,
 	return nil
 }
 
-func (pc *PackageCreator) processExtensions(components []types.ZarfComponent, layout *layout.PackagePaths, isYOLO bool) (processedComponents []types.ZarfComponent, err error) {
+func (pc *PackageCreator) processExtensions(ctx context.Context, components []types.ZarfComponent, layout *layout.PackagePaths, isYOLO bool) (processedComponents []types.ZarfComponent, err error) {
 	// Create component paths and process extensions for each component.
 	for _, c := range components {
 		componentPaths, err := layout.Components.Create(c)
@@ -337,7 +337,7 @@ func (pc *PackageCreator) processExtensions(components []types.ZarfComponent, la
 
 		// Big Bang
 		if c.Extensions.BigBang != nil {
-			if c, err = bigbang.Run(isYOLO, componentPaths, c); err != nil {
+			if c, err = bigbang.Run(ctx, isYOLO, componentPaths, c); err != nil {
 				return nil, fmt.Errorf("unable to process bigbang extension: %w", err)
 			}
 		}
@@ -348,7 +348,7 @@ func (pc *PackageCreator) processExtensions(components []types.ZarfComponent, la
 	return processedComponents, nil
 }
 
-func (pc *PackageCreator) addComponent(component types.ZarfComponent, dst *layout.PackagePaths) error {
+func (pc *PackageCreator) addComponent(ctx context.Context, component types.ZarfComponent, dst *layout.PackagePaths) error {
 	message.HeaderInfof("📦 %s COMPONENT", strings.ToUpper(component.Name))
 
 	componentPaths, err := dst.Components.Create(component)
@@ -364,7 +364,7 @@ func (pc *PackageCreator) addComponent(component types.ZarfComponent, dst *layou
 	// If any helm charts are defined, process them.
 	for _, chart := range component.Charts {
 		helmCfg := helm.New(chart, componentPaths.Charts, componentPaths.Values)
-		if err := helmCfg.PackageChart(componentPaths.Charts); err != nil {
+		if err := helmCfg.PackageChart(ctx, componentPaths.Charts); err != nil {
 			return err
 		}
 	}
@@ -514,7 +514,7 @@ func (pc *PackageCreator) addComponent(component types.ZarfComponent, dst *layou
 		for _, url := range component.Repos {
 			// Pull all the references if there is no `@` in the string.
 			gitCfg := git.NewWithSpinner(types.GitServerInfo{}, spinner)
-			if err := gitCfg.Pull(url, componentPaths.Repos, false); err != nil {
+			if err := gitCfg.Pull(ctx, url, componentPaths.Repos, false); err != nil {
 				return fmt.Errorf("unable to pull git repo %s: %w", url, err)
 			}
 		}
diff --git a/src/pkg/packager/generate.go b/src/pkg/packager/generate.go
index 905859bc53..d1fc593033 100644
--- a/src/pkg/packager/generate.go
+++ b/src/pkg/packager/generate.go
@@ -5,6 +5,7 @@
 package packager
 
 import (
+	"context"
 	"fmt"
 	"os"
 	"path/filepath"
@@ -19,7 +20,7 @@ import (
 )
 
 // Generate generates a Zarf package definition.
-func (p *Packager) Generate() (err error) {
+func (p *Packager) Generate(ctx context.Context) (err error) {
 	generatedZarfYAMLPath := filepath.Join(p.cfg.GenerateOpts.Output, layout.ZarfYAML)
 	spinner := message.NewProgressSpinner("Generating package for %q at %s", p.cfg.GenerateOpts.Name, generatedZarfYAMLPath)
 
@@ -61,7 +62,7 @@ func (p *Packager) Generate() (err error) {
 		},
 	}
 
-	images, err := p.findImages()
+	images, err := p.findImages(ctx)
 	if err != nil {
 		// purposefully not returning error here, as we can still generate the package without images
 		message.Warnf("Unable to find images: %s", err.Error())
diff --git a/src/pkg/packager/prepare.go b/src/pkg/packager/prepare.go
index c71038b2f8..340ac1c85a 100644
--- a/src/pkg/packager/prepare.go
+++ b/src/pkg/packager/prepare.go
@@ -70,10 +70,10 @@ func (p *Packager) FindImages(ctx context.Context) (map[string][]string, error)
 		message.Warn(warning)
 	}
 
-	return p.findImages()
+	return p.findImages(ctx)
 }
 
-func (p *Packager) findImages() (imgMap map[string][]string, err error) {
+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
@@ -172,7 +172,7 @@ func (p *Packager) findImages() (imgMap map[string][]string, err error) {
 				helm.WithVariableConfig(p.variableConfig),
 			)
 
-			err = helmCfg.PackageChart(component.DeprecatedCosignKeyPath)
+			err = helmCfg.PackageChart(ctx, component.DeprecatedCosignKeyPath)
 			if err != nil {
 				return nil, fmt.Errorf("unable to package the chart %s: %w", chart.Name, err)
 			}

From 1d8a86b094a8bd3eeacbd21b10a68f9975aa5db1 Mon Sep 17 00:00:00 2001
From: Kenny Paul <44849153+KennyPaul@users.noreply.github.com>
Date: Sun, 21 Jul 2024 15:48:36 -0700
Subject: [PATCH 11/68] docs: charter update (#2731)

Signed-off-by: Kenny Paul 
Co-authored-by: schristoff <28318173+schristoff@users.noreply.github.com>
---
 CHARTER.pdf | Bin 0 -> 396835 bytes
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 CHARTER.pdf

diff --git a/CHARTER.pdf b/CHARTER.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..6834ea3fb555a6cf01a4ade5bd4ae63e267c342b
GIT binary patch
literal 396835
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 literal 0 HcmV?d00001 From b0c6d569354c910fbc792edc51ee11cd7f25cc03 Mon Sep 17 00:00:00 2001 From: schristoff <28318173+schristoff@users.noreply.github.com> Date: Mon, 22 Jul 2024 11:24:15 -0600 Subject: [PATCH 12/68] chore: update CODEOWNERS to protect TSC files (#2744) Signed-off-by: schristoff-du <167717759+schristoff-du@users.noreply.github.com> Co-authored-by: schristoff-du <167717759+schristoff-du@users.noreply.github.com> --- CODEOWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/CODEOWNERS b/CODEOWNERS index 976d425740..1f66adaee1 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -3,3 +3,4 @@ /CODEOWNERS @zarf-dev/tsc /cosign.pub @zarf-dev/tsc /LICENSE @zarf-dev/tsc +/CHARTER.pdf @zarf-dev/tsc From 612bd8e6254b2c7c802ec8704801d42340e33926 Mon Sep 17 00:00:00 2001 From: Philip Laine Date: Mon, 22 Jul 2024 21:06:54 +0200 Subject: [PATCH 13/68] fix: replace debug logs with returning errors (#2719) Signed-off-by: Philip Laine --- src/cmd/destroy.go | 2 +- src/internal/agent/http/proxy.go | 4 +- src/internal/packager/git/clone.go | 5 +- src/internal/packager/helm/post-render.go | 6 +- src/pkg/packager/common.go | 5 +- src/pkg/packager/deprecated/common.go | 13 ++-- src/pkg/packager/deprecated/common_test.go | 3 +- src/pkg/utils/auth.go | 73 ++++++++++------------ src/pkg/utils/auth_test.go | 34 +++++----- src/test/mocks/read_closer_mock.go | 24 ------- 10 files changed, 81 insertions(+), 88 deletions(-) delete mode 100644 src/test/mocks/read_closer_mock.go diff --git a/src/cmd/destroy.go b/src/cmd/destroy.go index a6c45519b0..1e3d1bb646 100644 --- a/src/cmd/destroy.go +++ b/src/cmd/destroy.go @@ -68,7 +68,7 @@ var destroyCmd = &cobra.Command{ // Don't remove scripts we can't execute so the user can try to manually run continue } else if err != nil { - message.Debugf("Received error when trying to execute the script (%s): %#v", script, err) + return fmt.Errorf("received an error when executing the script %s: %w", script, err) } // Try to remove the script, but ignore any errors diff --git a/src/internal/agent/http/proxy.go b/src/internal/agent/http/proxy.go index 8a9d939507..719ef17281 100644 --- a/src/internal/agent/http/proxy.go +++ b/src/internal/agent/http/proxy.go @@ -112,7 +112,9 @@ func proxyResponseTransform(resp *http.Response) error { message.Debugf("Before Resp Location %#v", resp.Header.Get("Location")) locationURL, err := url.Parse(resp.Header.Get("Location")) - message.Debugf("%#v", err) + if err != nil { + return err + } locationURL.Path = transform.NoTransform + locationURL.Path locationURL.Host = resp.Request.Header.Get("X-Forwarded-Host") diff --git a/src/internal/packager/git/clone.go b/src/internal/packager/git/clone.go index bd38cbcdd4..2f607670e7 100644 --- a/src/internal/packager/git/clone.go +++ b/src/internal/packager/git/clone.go @@ -38,7 +38,10 @@ func (g *Git) clone(ctx context.Context, gitURL string, ref plumbing.ReferenceNa } // Setup git credentials if we have them, ignore if we don't. - gitCred := utils.FindAuthForHost(gitURL) + gitCred, err := utils.FindAuthForHost(gitURL) + if err != nil { + return err + } if gitCred != nil { cloneOptions.Auth = &gitCred.Auth } diff --git a/src/internal/packager/helm/post-render.go b/src/internal/packager/helm/post-render.go index 5f45b437a0..8d6c157427 100644 --- a/src/internal/packager/helm/post-render.go +++ b/src/internal/packager/helm/post-render.go @@ -285,6 +285,10 @@ func (r *renderer) editHelmResources(ctx context.Context, resources []releaseuti return err } resource, err := dc.Resource(mapping.Resource).Namespace(deployedNamespace).Get(ctx, rawData.GetName(), metav1.GetOptions{}) + // Ignore resources that are yet to be created + if kerrors.IsNotFound(err) { + return nil + } if err != nil { return err } @@ -308,7 +312,7 @@ func (r *renderer) editHelmResources(ctx context.Context, resources []releaseuti return nil }() if err != nil { - message.Debugf("Unable to adopt resource %s: %s", rawData.GetName(), err.Error()) + return fmt.Errorf("unable to adopt the resource %s: %w", rawData.GetName(), err) } } // Finally place this back onto the output buffer diff --git a/src/pkg/packager/common.go b/src/pkg/packager/common.go index 3b7f59f968..d790275d12 100644 --- a/src/pkg/packager/common.go +++ b/src/pkg/packager/common.go @@ -192,7 +192,10 @@ func (p *Packager) attemptClusterChecks(ctx context.Context) (err error) { // Check for any breaking changes between the initialized Zarf version and this CLI if existingInitPackage, _ := p.cluster.GetDeployedPackage(ctx, "init"); existingInitPackage != nil { // Use the build version instead of the metadata since this will support older Zarf versions - deprecated.PrintBreakingChanges(os.Stderr, existingInitPackage.Data.Build.Version, config.CLIVersion) + err := deprecated.PrintBreakingChanges(os.Stderr, existingInitPackage.Data.Build.Version, config.CLIVersion) + if err != nil { + return err + } } spinner.Success() diff --git a/src/pkg/packager/deprecated/common.go b/src/pkg/packager/deprecated/common.go index f97e07bce0..e0dd708c27 100644 --- a/src/pkg/packager/deprecated/common.go +++ b/src/pkg/packager/deprecated/common.go @@ -5,6 +5,7 @@ package deprecated import ( + "errors" "fmt" "io" "strings" @@ -78,11 +79,14 @@ func MigrateComponent(build types.ZarfBuildData, component types.ZarfComponent) } // PrintBreakingChanges prints the breaking changes between the provided version and the current CLIVersion. -func PrintBreakingChanges(w io.Writer, deployedZarfVersion, cliVersion string) { +func PrintBreakingChanges(w io.Writer, deployedZarfVersion, cliVersion string) error { deployedSemver, err := semver.NewVersion(deployedZarfVersion) + // Dev versions of Zarf are not semver. + if errors.Is(err, semver.ErrInvalidSemVer) { + return nil + } if err != nil { - message.Debugf("Unable to check for breaking changes between Zarf versions") - return + return fmt.Errorf("unable to check for breaking changes between Zarf versions: %w", err) } // List of breaking changes to warn the user of. @@ -103,7 +107,7 @@ func PrintBreakingChanges(w io.Writer, deployedZarfVersion, cliVersion string) { } if len(applicableBreakingChanges) == 0 { - return + return nil } // Print header information @@ -123,4 +127,5 @@ func PrintBreakingChanges(w io.Writer, deployedZarfVersion, cliVersion string) { } message.HorizontalRule() + return nil } diff --git a/src/pkg/packager/deprecated/common_test.go b/src/pkg/packager/deprecated/common_test.go index b789f0c2ce..ed562593ad 100644 --- a/src/pkg/packager/deprecated/common_test.go +++ b/src/pkg/packager/deprecated/common_test.go @@ -48,7 +48,8 @@ func TestPrintBreakingChanges(t *testing.T) { t.Parallel() var output bytes.Buffer message.InitializePTerm(&output) - PrintBreakingChanges(&output, tt.deployedVersion, tt.cliVersion) + err := PrintBreakingChanges(&output, tt.deployedVersion, tt.cliVersion) + require.NoError(t, err) for _, bc := range tt.breakingChanges { require.Contains(t, output.String(), bc.String()) } diff --git a/src/pkg/utils/auth.go b/src/pkg/utils/auth.go index c66b29b548..0bc5cf501a 100644 --- a/src/pkg/utils/auth.go +++ b/src/pkg/utils/auth.go @@ -6,14 +6,13 @@ package utils import ( "bufio" - "io" + "errors" "net/url" "os" "path/filepath" "strings" "github.com/go-git/go-git/v5/plumbing/transport/http" - "github.com/zarf-dev/zarf/src/pkg/message" ) // Credential represents authentication for a given host. @@ -23,47 +22,47 @@ type Credential struct { } // FindAuthForHost finds the authentication scheme for a given host using .git-credentials then .netrc. -func FindAuthForHost(baseURL string) *Credential { +func FindAuthForHost(baseURL string) (*Credential, error) { homePath, _ := os.UserHomeDir() // Read the ~/.git-credentials file credentialsPath := filepath.Join(homePath, ".git-credentials") - // Dogsled the error since we are ok if this file doesn't exist (error message debugged on close) - credentialsFile, _ := os.Open(credentialsPath) - gitCreds := credentialParser(credentialsFile) + gitCreds, err := credentialParser(credentialsPath) + if err != nil { + return nil, err + } // Read the ~/.netrc file netrcPath := filepath.Join(homePath, ".netrc") - // Dogsled the error since we are ok if this file doesn't exist (error message debugged on close) - netrcFile, _ := os.Open(netrcPath) - netrcCreds := netrcParser(netrcFile) + netrcCreds, err := netrcParser(netrcPath) + if err != nil { + return nil, err + } // Combine the creds together (.netrc second because it could have a default) creds := append(gitCreds, netrcCreds...) - - // Look for a match for the given host path in the creds file for _, cred := range creds { // An empty credPath means that we have reached the default from the .netrc hasPath := strings.Contains(baseURL, cred.Path) || cred.Path == "" if hasPath { - return &cred + return &cred, nil } } - - return nil + return nil, nil } // credentialParser parses a user's .git-credentials file to find git creds for hosts. -func credentialParser(file io.ReadCloser) []Credential { - var credentials []Credential - - defer func(file io.ReadCloser) { - err := file.Close() - if err != nil { - message.Debugf("Unable to load an existing git credentials file: %s", err.Error()) - } - }(file) +func credentialParser(path string) ([]Credential, error) { + file, err := os.Open(path) + if errors.Is(err, os.ErrNotExist) { + return nil, nil + } + if err != nil { + return nil, err + } + defer file.Close() + var credentials []Credential scanner := bufio.NewScanner(file) for scanner.Scan() { gitURL, err := url.Parse(scanner.Text()) @@ -80,27 +79,25 @@ func credentialParser(file io.ReadCloser) []Credential { } credentials = append(credentials, credential) } - - return credentials + return credentials, nil } // netrcParser parses a user's .netrc file using the method curl did pre 7.84.0: https://daniel.haxx.se/blog/2022/05/31/netrc-pains/. -func netrcParser(file io.ReadCloser) []Credential { - var credentials []Credential - - defer func(file io.ReadCloser) { - err := file.Close() - if err != nil { - message.Debugf("Unable to load an existing netrc file: %s", err.Error()) - } - }(file) +func netrcParser(path string) ([]Credential, error) { + file, err := os.Open(path) + if errors.Is(err, os.ErrNotExist) { + return nil, nil + } + if err != nil { + return nil, err + } + defer file.Close() + var credentials []Credential scanner := bufio.NewScanner(file) - activeMacro := false activeCommand := "" var activeMachine map[string]string - for scanner.Scan() { line := scanner.Text() @@ -154,13 +151,11 @@ func netrcParser(file io.ReadCloser) []Credential { } } } - // Append the last machine (if exists) at the end of the file if activeMachine != nil { credentials = appendNetrcMachine(activeMachine, credentials) } - - return credentials + return credentials, nil } func appendNetrcMachine(machine map[string]string, credentials []Credential) []Credential { diff --git a/src/pkg/utils/auth_test.go b/src/pkg/utils/auth_test.go index 3493cdf919..bad85c2c4a 100644 --- a/src/pkg/utils/auth_test.go +++ b/src/pkg/utils/auth_test.go @@ -5,23 +5,25 @@ package utils import ( + "os" + "path/filepath" "testing" "github.com/go-git/go-git/v5/plumbing/transport/http" "github.com/stretchr/testify/require" - mocks "github.com/zarf-dev/zarf/src/test/mocks" ) func TestCredentialParser(t *testing.T) { - credentialsFile := &mocks.MockReadCloser{ - MockData: []byte( - `https://wayne:password@github.com/ + t.Parallel() + + data := `https://wayne:password@github.com/ bad line https://wayne:p%40ss%20word%2520@zarf.dev -http://google.com`, - ), - } +http://google.com` + path := filepath.Join(t.TempDir(), "file") + err := os.WriteFile(path, []byte(data), 0o644) + require.NoError(t, err) expectedCreds := []Credential{ { @@ -47,15 +49,15 @@ http://google.com`, }, } - gitCredentials := credentialParser(credentialsFile) + gitCredentials, err := credentialParser(path) + require.NoError(t, err) require.Equal(t, expectedCreds, gitCredentials) } func TestNetRCParser(t *testing.T) { + t.Parallel() - netrcFile := &mocks.MockReadCloser{ - MockData: []byte( - `# top of file comment + data := `# top of file comment machine github.com login wayne password password @@ -70,9 +72,10 @@ machine google.com #comment password fun and login info! default login anonymous - password password`, - ), - } + password password` + path := filepath.Join(t.TempDir(), "file") + err := os.WriteFile(path, []byte(data), 0o644) + require.NoError(t, err) expectedCreds := []Credential{ { @@ -105,6 +108,7 @@ default }, } - netrcCredentials := netrcParser(netrcFile) + netrcCredentials, err := netrcParser(path) + require.NoError(t, err) require.Equal(t, expectedCreds, netrcCredentials) } diff --git a/src/test/mocks/read_closer_mock.go b/src/test/mocks/read_closer_mock.go deleted file mode 100644 index 494215f41e..0000000000 --- a/src/test/mocks/read_closer_mock.go +++ /dev/null @@ -1,24 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2021-Present The Zarf Authors - -// Package mocks contains all the mocks used in Zarf tests. -package mocks - -// MockReadCloser is a mock for the go ReadCloser object. -type ( - MockReadCloser struct { - MockData []byte - MockReadErr error - MockCloseErr error - } -) - -// Read copies a tests expected data and returns an expectedError. -func (mrc *MockReadCloser) Read(buf []byte) (n int, err error) { - numBytes := copy(buf, mrc.MockData) - mrc.MockData = mrc.MockData[numBytes:len(mrc.MockData)] - return numBytes, mrc.MockReadErr -} - -// Close simply returns the expected close err from a test. -func (mrc *MockReadCloser) Close() error { return mrc.MockCloseErr } From 1c3e426b4e8aa4de2d7a0c28d191075e85de6ecd Mon Sep 17 00:00:00 2001 From: Philip Laine Date: Mon, 22 Jul 2024 21:17:57 +0200 Subject: [PATCH 14/68] fix: data injection to return errors (#2720) Signed-off-by: Philip Laine --- src/pkg/cluster/data.go | 182 +++++++++++++++++++------------------ src/pkg/packager/deploy.go | 21 +++-- 2 files changed, 103 insertions(+), 100 deletions(-) diff --git a/src/pkg/cluster/data.go b/src/pkg/cluster/data.go index 7b19257040..cd46dbb28b 100644 --- a/src/pkg/cluster/data.go +++ b/src/pkg/cluster/data.go @@ -13,7 +13,6 @@ import ( "sort" "strconv" "strings" - "sync" "time" corev1 "k8s.io/api/core/v1" @@ -32,12 +31,10 @@ import ( // HandleDataInjection waits for the target pod(s) to come up and inject the data into them // todo: this currently requires kubectl but we should have enough k8s work to make this native now. -func (c *Cluster) HandleDataInjection(ctx context.Context, wg *sync.WaitGroup, data types.ZarfDataInjection, componentPath *layout.ComponentPaths, dataIdx int) { - defer wg.Done() +func (c *Cluster) HandleDataInjection(ctx context.Context, data types.ZarfDataInjection, componentPath *layout.ComponentPaths, dataIdx int) error { injectionCompletionMarker := filepath.Join(componentPath.DataInjections, config.GetDataInjectionMarker()) if err := os.WriteFile(injectionCompletionMarker, []byte("🦄"), helpers.ReadWriteUser); err != nil { - message.WarnErrf(err, "Unable to create the data injection completion marker") - return + return fmt.Errorf("unable to create the data injection completion marker: %w", err) } tarCompressFlag := "" @@ -59,103 +56,110 @@ func (c *Cluster) HandleDataInjection(ctx context.Context, wg *sync.WaitGroup, d shell, shellArgs := exec.GetOSShell(exec.Shell{Windows: "cmd"}) if _, _, err := exec.Cmd(shell, append(shellArgs, "tar --version")...); err != nil { - message.WarnErr(err, "Unable to execute tar on this system. Please ensure it is installed and on your $PATH.") - return + return fmt.Errorf("unable to execute tar, ensure it is installed in the $PATH: %w", err) } -iterator: - // The eternal loop because some data injections can take a very long time for { - 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)) + 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) { - message.Warnf("Unable to find the data injection source path %s", source) - return + // 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 := waitForPodsAndContainers(ctx, c.Clientset, target, podFilterByInitContainer) - if len(pods) < 1 { - continue - } + target := podLookup{ + Namespace: data.Target.Namespace, + Selector: data.Target.Selector, + Container: data.Target.Container, + } - // Inject into all the pods - for _, pod := range pods { - // Try to use the embedded kubectl if we can - zarfCommand, err := utils.GetFinalExecutableCommand() - kubectlBinPath := "kubectl" + // Wait until the pod we are injecting data into becomes available + pods, err := waitForPodsAndContainers(ctx, c.Clientset, target, podFilterByInitContainer) 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) + return err + } + if len(pods) < 1 { + continue } - kubectlCmd := fmt.Sprintf("%s exec -i -n %s %s -c %s ", kubectlBinPath, data.Target.Namespace, pod.Name, data.Target.Container) - // 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 { - message.Warnf("Unable to create the data injection target directory %s in pod %s", data.Target.Path, pod.Name) - continue iterator - } + // 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, - ) - - // Do the actual data injection - if err := exec.CmdWithPrint(shell, append(shellArgs, cpPodCmd)...); err != nil { - message.Warnf("Error copying data into the pod %#v: %#v\n", pod.Name, err) - continue iterator - } + // 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) + } + + 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 { - message.Warnf("Error saving the zarf sync completion file after injection into pod %#v\n", pod.Name) - continue iterator + // 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) + } + + // 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 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, - } + // 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, + } - // 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 - _ = waitForPodsAndContainers(ctx, c.Clientset, podOnlyTarget, podFilterByInitContainer) + // 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 + } - // Cleanup now to reduce disk pressure - _ = os.RemoveAll(source) + // Cleanup now to reduce disk pressure + err = os.RemoveAll(source) + if err != nil { + return err + } - // Return to stop the loop - return + // Return to stop the loop + return nil + } } } @@ -173,7 +177,7 @@ type podFilter func(pod corev1.Pod) bool // It will wait up to 90 seconds for the pods to be found and will return a list of matching pod names // 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 { +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() @@ -183,16 +187,14 @@ func waitForPodsAndContainers(ctx context.Context, clientset kubernetes.Interfac for { select { case <-waitCtx.Done(): - message.Debug("Pod lookup failed: %v", ctx.Err()) - return nil + return nil, ctx.Err() case <-timer.C: listOpts := metav1.ListOptions{ LabelSelector: target.Selector, } podList, err := clientset.CoreV1().Pods(target.Namespace).List(ctx, listOpts) if err != nil { - message.Debug("Unable to find matching pods: %w", err) - return nil + return nil, err } message.Debug("Found %d pods for target %#v", len(podList.Items), target) @@ -245,7 +247,7 @@ func waitForPodsAndContainers(ctx context.Context, clientset kubernetes.Interfac } } if len(readyPods) > 0 { - return readyPods + return readyPods, nil } timer.Reset(3 * time.Second) } diff --git a/src/pkg/packager/deploy.go b/src/pkg/packager/deploy.go index 35f31514fd..5c174a684f 100644 --- a/src/pkg/packager/deploy.go +++ b/src/pkg/packager/deploy.go @@ -14,9 +14,10 @@ import ( "runtime" "strconv" "strings" - "sync" "time" + "golang.org/x/sync/errgroup" + corev1 "k8s.io/api/core/v1" kerrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -293,7 +294,6 @@ func (p *Packager) deployComponent(ctx context.Context, component types.ZarfComp hasCharts := len(component.Charts) > 0 hasManifests := len(component.Manifests) > 0 hasRepos := len(component.Repos) > 0 - hasDataInjections := len(component.DataInjections) > 0 hasFiles := len(component.Files) > 0 onDeploy := component.Actions.OnDeploy @@ -344,14 +344,11 @@ func (p *Packager) deployComponent(ctx context.Context, component types.ZarfComp } } - if hasDataInjections { - waitGroup := sync.WaitGroup{} - defer waitGroup.Wait() - - for idx, data := range component.DataInjections { - waitGroup.Add(1) - go p.cluster.HandleDataInjection(ctx, &waitGroup, data, componentPath, idx) - } + g, gCtx := errgroup.WithContext(ctx) + for idx, data := range component.DataInjections { + g.Go(func() error { + return p.cluster.HandleDataInjection(gCtx, data, componentPath, idx) + }) } if hasCharts || hasManifests { @@ -364,6 +361,10 @@ func (p *Packager) deployComponent(ctx context.Context, component types.ZarfComp return charts, fmt.Errorf("unable to run component after action: %w", err) } + err = g.Wait() + if err != nil { + return nil, err + } return charts, nil } From 0d3d0c3e89bbc222103fe9c110176eaa108c331b Mon Sep 17 00:00:00 2001 From: Austin Abro <37223396+AustinAbro321@users.noreply.github.com> Date: Mon, 22 Jul 2024 16:34:23 -0400 Subject: [PATCH 15/68] feat: revert "feat: remove .metadata.image from schema (#2606)" (#2618) --- src/types/package.go | 1 + zarf.schema.json | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/src/types/package.go b/src/types/package.go index c78f1fe461..17419dd6e3 100644 --- a/src/types/package.go +++ b/src/types/package.go @@ -47,6 +47,7 @@ type ZarfMetadata struct { Description string `json:"description,omitempty" jsonschema:"description=Additional information about this package"` Version string `json:"version,omitempty" jsonschema:"description=Generic string set by a package author to track the package version (Note: ZarfInitConfigs will always be versioned to the CLIVersion they were created with)"` URL string `json:"url,omitempty" jsonschema:"description=Link to package information when online"` + Image string `json:"image,omitempty" jsonschema:"description=An image URL to embed in this package (Reserved for future use in Zarf UI)"` Uncompressed bool `json:"uncompressed,omitempty" jsonschema:"description=Disable compression of this package"` Architecture string `json:"architecture,omitempty" jsonschema:"description=The target cluster architecture for this package,example=arm64,example=amd64"` YOLO bool `json:"yolo,omitempty" jsonschema:"description=Yaml OnLy Online (YOLO): True enables deploying a Zarf package without first running zarf init against the cluster. This is ideal for connected environments where you want to use existing VCS and container registries."` diff --git a/zarf.schema.json b/zarf.schema.json index 8658787b3b..b5c7a971d4 100644 --- a/zarf.schema.json +++ b/zarf.schema.json @@ -1023,6 +1023,10 @@ "type": "string", "description": "Link to package information when online" }, + "image": { + "type": "string", + "description": "An image URL to embed in this package (Reserved for future use in Zarf UI)" + }, "uncompressed": { "type": "boolean", "description": "Disable compression of this package" From 05ef439336f0d02771d51f0c388ef994acf201e1 Mon Sep 17 00:00:00 2001 From: Austin Abro <37223396+AustinAbro321@users.noreply.github.com> Date: Mon, 22 Jul 2024 16:50:14 -0400 Subject: [PATCH 16/68] chore: updating permissions of eks & ecr nightly tests (#2745) Signed-off-by: Austin Abro --- .github/workflows/nightly-ecr.yml | 5 +++-- .github/workflows/nightly-eks.yml | 8 ++++---- packages/distros/eks/eks.yaml | 17 +++++++++++++++++ src/test/nightly/ecr_publish_test.go | 4 ++-- 4 files changed, 26 insertions(+), 8 deletions(-) diff --git a/.github/workflows/nightly-ecr.yml b/.github/workflows/nightly-ecr.yml index 655d3c4dd1..f922e89dba 100644 --- a/.github/workflows/nightly-ecr.yml +++ b/.github/workflows/nightly-ecr.yml @@ -2,7 +2,6 @@ name: Test ECR Publishing on: schedule: - cron: '0 7 * * * ' ## Every day at 0700 UTC - workflow_dispatch: ## Give us the ability to run this manually @@ -28,11 +27,13 @@ jobs: - name: Build the Zarf binary run: make build-cli-linux-amd - - name: Configure AWS Credentials + - name: Auth with AWS uses: aws-actions/configure-aws-credentials@010d0da01d0b5a38af31e9c3470dbfdabdecca3a # v4.0.1 with: role-to-assume: ${{ secrets.AWS_NIGHTLY_ROLE }} + role-session-name: ${{ github.job || github.event.client_payload.pull_request.head.sha || github.sha }} aws-region: us-east-1 + role-duration-seconds: 3600 # NOTE: The aws cli will need to be explicitly installed on self-hosted runners - name: Login to the ECR Registry diff --git a/.github/workflows/nightly-eks.yml b/.github/workflows/nightly-eks.yml index c4bee3432f..1fe4f4ad7c 100644 --- a/.github/workflows/nightly-eks.yml +++ b/.github/workflows/nightly-eks.yml @@ -2,7 +2,6 @@ name: Test EKS Cluster on: schedule: - cron: '0 7 * * *' ## Every day at 0700 UTC - workflow_dispatch: ## Give us the ability to run this manually inputs: cluster_name: @@ -36,12 +35,13 @@ jobs: - name: Build binary and zarf packages uses: ./.github/actions/packages - - name: Configure AWS Credentials + - name: Auth with AWS uses: aws-actions/configure-aws-credentials@010d0da01d0b5a38af31e9c3470dbfdabdecca3a # v4.0.1 with: role-to-assume: ${{ secrets.AWS_NIGHTLY_ROLE }} + role-session-name: ${{ github.job || github.event.client_payload.pull_request.head.sha || github.sha }} aws-region: us-east-1 - role-duration-seconds: 14400 + role-duration-seconds: 3600 - name: Build the eks package run: ./build/zarf package create packages/distros/eks -o build --confirm @@ -55,7 +55,7 @@ jobs: --confirm - name: Run tests - run: make test-e2e ARCH=amd64 + run: make test-e2e-with-cluster ARCH=amd64 - name: Teardown the cluster if: always() diff --git a/packages/distros/eks/eks.yaml b/packages/distros/eks/eks.yaml index 50ae84a197..530da71f8c 100644 --- a/packages/distros/eks/eks.yaml +++ b/packages/distros/eks/eks.yaml @@ -5,15 +5,28 @@ metadata: name: ###ZARF_VAR_EKS_CLUSTER_NAME### region: ###ZARF_VAR_EKS_CLUSTER_REGION### version: "###ZARF_VAR_EKS_CLUSTER_VERSION###" + tags: + PermissionsBoundary: "zarf_dev_base_policy" iam: withOIDC: true + serviceRolePermissionsBoundary: "arn:aws:iam::173911864621:policy/zarf_dev_base_policy" addons: - name: aws-ebs-csi-driver version: "###ZARF_VAR_EBS_DRIVER_VERSION###" attachPolicyARNs: - arn:aws:iam::aws:policy/service-role/AmazonEBSCSIDriverPolicy + permissionsBoundary: "arn:aws:iam::173911864621:policy/zarf_dev_base_policy" + tags: + PermissionsBoundary: "zarf_dev_base_policy" + + - name: vpc-cni + attachPolicyARNs: + - arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy + permissionsBoundary: "arn:aws:iam::173911864621:policy/zarf_dev_base_policy" + tags: + PermissionsBoundary: "zarf_dev_base_policy" managedNodeGroups: - instanceType: ###ZARF_VAR_EKS_INSTANCE_TYPE### @@ -21,3 +34,7 @@ managedNodeGroups: minSize: 3 maxSize: 6 spot: true + tags: + PermissionsBoundary: "zarf_dev_base_policy" + iam: + instanceRolePermissionsBoundary: "arn:aws:iam::173911864621:policy/zarf_dev_base_policy" diff --git a/src/test/nightly/ecr_publish_test.go b/src/test/nightly/ecr_publish_test.go index 7716ebf270..2d872c16e1 100644 --- a/src/test/nightly/ecr_publish_test.go +++ b/src/test/nightly/ecr_publish_test.go @@ -45,8 +45,8 @@ func TestECRPublishing(t *testing.T) { testPackageVersion := "0.0.1" testPackageFileName := fmt.Sprintf("zarf-package-%s-%s-%s.tar.zst", testPackageName, e2e.Arch, testPackageVersion) testPackageLocation := filepath.Join(tmpDir, testPackageFileName) - registryURL := "oci://public.ecr.aws/t8y5r5z5/zarf-nightly" - upstreamPackageURL := fmt.Sprintf("%s/%s:%s-%s", registryURL, testPackageName, testPackageVersion, e2e.Arch) + registryURL := "oci://public.ecr.aws/z6q5p6f7/zarf-nightly" + upstreamPackageURL := fmt.Sprintf("%s/%s:%s", registryURL, testPackageName, testPackageVersion) keyFlag := fmt.Sprintf("--key=%s", "./src/test/packages/zarf-test.pub") // Build the package with our test signature From c77f4461ec611147b44871f3bd227bf6c05b7c83 Mon Sep 17 00:00:00 2001 From: Philip Laine Date: Tue, 23 Jul 2024 18:15:09 +0200 Subject: [PATCH 17/68] refactor: move setup CLI to only run once in root command (#2722) Signed-off-by: Philip Laine --- src/cmd/common/setup.go | 50 ++++++++++++++++---------------------- src/cmd/root.go | 41 ++++++++++++++++++++++++------- src/cmd/tools/common.go | 15 ++---------- src/cmd/version.go | 7 ++---- src/config/config.go | 6 ----- src/config/lang/english.go | 2 -- src/pkg/message/message.go | 8 ++++-- src/pkg/utils/yaml.go | 6 ++--- 8 files changed, 66 insertions(+), 69 deletions(-) diff --git a/src/cmd/common/setup.go b/src/cmd/common/setup.go index 703d9355bf..ac47d0c95d 100644 --- a/src/cmd/common/setup.go +++ b/src/cmd/common/setup.go @@ -5,43 +5,38 @@ package common import ( + "errors" "fmt" "io" "os" "time" "github.com/pterm/pterm" - "github.com/zarf-dev/zarf/src/config" - "github.com/zarf-dev/zarf/src/config/lang" + "github.com/zarf-dev/zarf/src/pkg/message" ) -// LogLevelCLI holds the log level as input from a command -var LogLevelCLI string - -// SetupCLI sets up the CLI logging, interrupt functions, and more -func SetupCLI() { - match := map[string]message.LogLevel{ - "warn": message.WarnLevel, - "info": message.InfoLevel, - "debug": message.DebugLevel, - "trace": message.TraceLevel, - } - - if config.NoColor { +// SetupCLI sets up the CLI logging +func SetupCLI(logLevel string, skipLogFile, noColor bool) error { + if noColor { message.DisableColor() } printViperConfigUsed() - // No log level set, so use the default - if LogLevelCLI != "" { - if lvl, ok := match[LogLevelCLI]; ok { - message.SetLogLevel(lvl) - message.Debug("Log level set to " + LogLevelCLI) - } else { - message.Warn(lang.RootCmdErrInvalidLogLevel) + if logLevel != "" { + match := map[string]message.LogLevel{ + "warn": message.WarnLevel, + "info": message.InfoLevel, + "debug": message.DebugLevel, + "trace": message.TraceLevel, } + lvl, ok := match[logLevel] + if !ok { + return errors.New("invalid log level, valid options are warn, info, debug, and trace") + } + message.SetLogLevel(lvl) + message.Debug("Log level set to " + logLevel) } // Disable progress bars for CI envs @@ -50,21 +45,18 @@ func SetupCLI() { message.NoProgress = true } - if !config.SkipLogFile { + if !skipLogFile { ts := time.Now().Format("2006-01-02-15-04-05") - f, err := os.CreateTemp("", fmt.Sprintf("zarf-%s-*.log", ts)) if err != nil { - message.WarnErr(err, "Error creating a log file in a temporary directory") - return + return fmt.Errorf("could not create a log file in a the temporary directory: %w", err) } logFile, err := message.UseLogFile(f) if err != nil { - message.WarnErr(err, "Error saving a log file to a temporary directory") - return + return fmt.Errorf("could not save a log file to the temporary directory: %w", err) } - pterm.SetDefaultOutput(io.MultiWriter(os.Stderr, logFile)) message.Notef("Saving log file to %s", f.Name()) } + return nil } diff --git a/src/cmd/root.go b/src/cmd/root.go index 086a1cab6c..876efdf20e 100644 --- a/src/cmd/root.go +++ b/src/cmd/root.go @@ -26,20 +26,43 @@ import ( var ( // Default global config for the packager pkgConfig = types.PackagerConfig{} + // LogLevelCLI holds the log level as input from a command + LogLevelCLI string + // SkipLogFile is a flag to skip logging to a file + SkipLogFile bool + // NoColor is a flag to disable colors in output + NoColor bool ) var rootCmd = &cobra.Command{ Use: "zarf COMMAND", - PersistentPreRun: func(cmd *cobra.Command, _ []string) { - // Skip for vendor-only commands + PersistentPreRunE: func(cmd *cobra.Command, _ []string) error { + // Skip for vendor only commands if common.CheckVendorOnlyFromPath(cmd) { - return + return nil } - // Don't log the help command + + skipLogFile := SkipLogFile + + // Dont write tool commands to file. + comps := strings.Split(cmd.CommandPath(), " ") + if len(comps) > 1 && comps[1] == "tools" { + skipLogFile = true + } + if len(comps) > 1 && comps[1] == "version" { + skipLogFile = true + } + + // Dont write help command to file. if cmd.Parent() == nil { - config.SkipLogFile = true + skipLogFile = true + } + + err := common.SetupCLI(LogLevelCLI, skipLogFile, NoColor) + if err != nil { + return err } - common.SetupCLI() + return nil }, Short: lang.RootCmdShort, Long: lang.RootCmdLong, @@ -89,11 +112,11 @@ func init() { v := common.InitViper() - rootCmd.PersistentFlags().StringVarP(&common.LogLevelCLI, "log-level", "l", v.GetString(common.VLogLevel), lang.RootCmdFlagLogLevel) + rootCmd.PersistentFlags().StringVarP(&LogLevelCLI, "log-level", "l", v.GetString(common.VLogLevel), lang.RootCmdFlagLogLevel) rootCmd.PersistentFlags().StringVarP(&config.CLIArch, "architecture", "a", v.GetString(common.VArchitecture), lang.RootCmdFlagArch) - rootCmd.PersistentFlags().BoolVar(&config.SkipLogFile, "no-log-file", v.GetBool(common.VNoLogFile), lang.RootCmdFlagSkipLogFile) + rootCmd.PersistentFlags().BoolVar(&SkipLogFile, "no-log-file", v.GetBool(common.VNoLogFile), lang.RootCmdFlagSkipLogFile) rootCmd.PersistentFlags().BoolVar(&message.NoProgress, "no-progress", v.GetBool(common.VNoProgress), lang.RootCmdFlagNoProgress) - rootCmd.PersistentFlags().BoolVar(&config.NoColor, "no-color", v.GetBool(common.VNoColor), lang.RootCmdFlagNoColor) + rootCmd.PersistentFlags().BoolVar(&NoColor, "no-color", v.GetBool(common.VNoColor), lang.RootCmdFlagNoColor) rootCmd.PersistentFlags().StringVar(&config.CommonOptions.CachePath, "zarf-cache", v.GetString(common.VZarfCache), lang.RootCmdFlagCachePath) rootCmd.PersistentFlags().StringVar(&config.CommonOptions.TempDirectory, "tmpdir", v.GetString(common.VTmpDir), lang.RootCmdFlagTempDir) rootCmd.PersistentFlags().BoolVar(&config.CommonOptions.Insecure, "insecure", v.GetBool(common.VInsecure), lang.RootCmdFlagInsecure) diff --git a/src/cmd/tools/common.go b/src/cmd/tools/common.go index 7f8f375be0..0aef6e95c5 100644 --- a/src/cmd/tools/common.go +++ b/src/cmd/tools/common.go @@ -8,25 +8,14 @@ import ( "fmt" "github.com/spf13/cobra" - "github.com/zarf-dev/zarf/src/cmd/common" - "github.com/zarf-dev/zarf/src/config" + "github.com/zarf-dev/zarf/src/config/lang" ) var toolsCmd = &cobra.Command{ Use: "tools", Aliases: []string{"t"}, - PersistentPreRun: func(cmd *cobra.Command, _ []string) { - config.SkipLogFile = true - - // Skip for vendor-only commands - if common.CheckVendorOnlyFromPath(cmd) { - return - } - - common.SetupCLI() - }, - Short: lang.CmdToolsShort, + Short: lang.CmdToolsShort, } // Include adds the tools command to the root command. diff --git a/src/cmd/version.go b/src/cmd/version.go index 26299c7db5..a08af2aaab 100644 --- a/src/cmd/version.go +++ b/src/cmd/version.go @@ -24,11 +24,8 @@ var outputFormat string var versionCmd = &cobra.Command{ Use: "version", Aliases: []string{"v"}, - PersistentPreRun: func(_ *cobra.Command, _ []string) { - config.SkipLogFile = true - }, - Short: lang.CmdVersionShort, - Long: lang.CmdVersionLong, + Short: lang.CmdVersionShort, + Long: lang.CmdVersionLong, RunE: func(_ *cobra.Command, _ []string) error { if outputFormat == "" { fmt.Println(config.CLIVersion) diff --git a/src/config/config.go b/src/config/config.go index 4f55f48e61..dc60ea2fd8 100644 --- a/src/config/config.go +++ b/src/config/config.go @@ -60,12 +60,6 @@ var ( // ZarfSeedPort is the NodePort Zarf uses for the 'seed registry' ZarfSeedPort string - // SkipLogFile is a flag to skip logging to a file - SkipLogFile bool - - // NoColor is a flag to disable colors in output - NoColor bool - CosignPublicKey string // Timestamp of when the CLI was started diff --git a/src/config/lang/english.go b/src/config/lang/english.go index df39428f48..9b90c23b22 100644 --- a/src/config/lang/english.go +++ b/src/config/lang/english.go @@ -58,8 +58,6 @@ const ( RootCmdDeprecatedDeploy = "Deprecated: Please use \"zarf package deploy %s\" to deploy this package. This warning will be removed in Zarf v1.0.0." RootCmdDeprecatedCreate = "Deprecated: Please use \"zarf package create\" to create this package. This warning will be removed in Zarf v1.0.0." - RootCmdErrInvalidLogLevel = "Invalid log level. Valid options are: warn, info, debug, trace." - // zarf connect CmdConnectShort = "Accesses services or pods deployed in the cluster" CmdConnectLong = "Uses a k8s port-forward to connect to resources within the cluster referenced by your kube-context.\n" + diff --git a/src/pkg/message/message.go b/src/pkg/message/message.go index f9d7d48c3c..e271cbf9d4 100644 --- a/src/pkg/message/message.go +++ b/src/pkg/message/message.go @@ -14,7 +14,6 @@ import ( "github.com/defenseunicorns/pkg/helpers/v2" "github.com/fatih/color" "github.com/pterm/pterm" - "github.com/zarf-dev/zarf/src/config" ) // LogLevel is the level of logging to display. @@ -99,6 +98,11 @@ func DisableColor() { pterm.DisableColor() } +// ColorEnabled returns true if color printing is enabled. +func ColorEnabled() bool { + return pterm.PrintColor +} + // ZarfCommand prints a zarf terminal command. func ZarfCommand(format string, a ...any) { Command("zarf "+format, a...) @@ -276,7 +280,7 @@ func Table(header []string, data [][]string) { // preventing future characters from taking on the given color // returns string as normal if color is disabled func ColorWrap(str string, attr color.Attribute) string { - if config.NoColor || str == "" { + if !ColorEnabled() || str == "" { return str } return fmt.Sprintf("\x1b[%dm%s\x1b[0m", attr, str) diff --git a/src/pkg/utils/yaml.go b/src/pkg/utils/yaml.go index e61083bc51..5f86202970 100644 --- a/src/pkg/utils/yaml.go +++ b/src/pkg/utils/yaml.go @@ -20,12 +20,12 @@ import ( "github.com/goccy/go-yaml/lexer" "github.com/goccy/go-yaml/printer" "github.com/pterm/pterm" - "github.com/zarf-dev/zarf/src/config" - "github.com/zarf-dev/zarf/src/pkg/message" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" kubeyaml "k8s.io/apimachinery/pkg/util/yaml" k8syaml "sigs.k8s.io/yaml" + + "github.com/zarf-dev/zarf/src/pkg/message" ) const yamlEscape = "\x1b" @@ -93,7 +93,7 @@ func ColorPrintYAML(data any, hints map[string]string, spaceRootLists bool) { outputYAML = strings.Replace(outputYAML, key, value, 1) } - if config.NoColor { + if !message.ColorEnabled() { // If no color is specified strip any color codes from the output - https://regex101.com/r/YFyIwC/2 ansiRegex := regexp.MustCompile(`\x1b\[(.*?)m`) outputYAML = ansiRegex.ReplaceAllString(outputYAML, "") From 5c74276d5c4fd1f6bf00f93347c469a0d90522e4 Mon Sep 17 00:00:00 2001 From: schristoff <28318173+schristoff@users.noreply.github.com> Date: Wed, 24 Jul 2024 17:00:00 -0600 Subject: [PATCH 18/68] chore: move context.TODO to context.Background() (3) (#2747) Signed-off-by: schristoff-du <167717759+schristoff-du@users.noreply.github.com> Co-authored-by: schristoff-du <167717759+schristoff-du@users.noreply.github.com> --- src/extensions/bigbang/bigbang.go | 2 +- src/internal/packager/helm/chart.go | 13 +++++++------ src/internal/packager/helm/post-render.go | 4 ++-- src/internal/packager/helm/zarf.go | 4 ++-- src/pkg/packager/deploy.go | 8 ++++---- src/pkg/packager/prepare.go | 2 +- 6 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/extensions/bigbang/bigbang.go b/src/extensions/bigbang/bigbang.go index e312f382f9..ebe068f003 100644 --- a/src/extensions/bigbang/bigbang.go +++ b/src/extensions/bigbang/bigbang.go @@ -107,7 +107,7 @@ func Run(ctx context.Context, YOLO bool, tmpPaths *layout.ComponentPaths, c type // Template the chart so we can see what GitRepositories are being referenced in the // manifests created with the provided Helm. - template, _, err := helmCfg.TemplateChart() + template, _, err := helmCfg.TemplateChart(ctx) if err != nil { return c, fmt.Errorf("unable to template Big Bang Chart: %w", err) } diff --git a/src/internal/packager/helm/chart.go b/src/internal/packager/helm/chart.go index f9ac5eefe0..0bd483df7f 100644 --- a/src/internal/packager/helm/chart.go +++ b/src/internal/packager/helm/chart.go @@ -5,6 +5,7 @@ package helm import ( + "context" "errors" "fmt" "time" @@ -30,7 +31,7 @@ import ( ) // InstallOrUpgradeChart performs a helm install of the given chart. -func (h *Helm) InstallOrUpgradeChart() (types.ConnectStrings, string, error) { +func (h *Helm) InstallOrUpgradeChart(ctx context.Context) (types.ConnectStrings, string, error) { fromMessage := h.chart.URL if fromMessage == "" { fromMessage = "Zarf-generated helm chart" @@ -52,7 +53,7 @@ func (h *Helm) InstallOrUpgradeChart() (types.ConnectStrings, string, error) { return nil, "", fmt.Errorf("unable to initialize the K8s client: %w", err) } - postRender, err := h.newRenderer() + postRender, err := h.newRenderer(ctx) if err != nil { return nil, "", fmt.Errorf("unable to create helm renderer: %w", err) } @@ -126,7 +127,7 @@ func (h *Helm) InstallOrUpgradeChart() (types.ConnectStrings, string, error) { } // TemplateChart generates a helm template from a given chart. -func (h *Helm) TemplateChart() (manifest string, chartValues chartutil.Values, err error) { +func (h *Helm) TemplateChart(ctx context.Context) (manifest string, chartValues chartutil.Values, err error) { message.Debugf("helm.TemplateChart()") spinner := message.NewProgressSpinner("Templating helm chart %s", h.chart.Name) defer spinner.Stop() @@ -170,7 +171,7 @@ func (h *Helm) TemplateChart() (manifest string, chartValues chartutil.Values, e return "", nil, fmt.Errorf("unable to load chart data: %w", err) } - client.PostRenderer, err = h.newRenderer() + client.PostRenderer, err = h.newRenderer(ctx) if err != nil { return "", nil, fmt.Errorf("unable to create helm renderer: %w", err) } @@ -204,7 +205,7 @@ func (h *Helm) RemoveChart(namespace string, name string, spinner *message.Spinn // UpdateReleaseValues updates values for a given chart release // (note: this only works on single-deep charts, charts with dependencies (like loki-stack) will not work) -func (h *Helm) UpdateReleaseValues(updatedValues map[string]interface{}) error { +func (h *Helm) UpdateReleaseValues(ctx context.Context, updatedValues map[string]interface{}) error { spinner := message.NewProgressSpinner("Updating values for helm release %s", h.chart.ReleaseName) defer spinner.Stop() @@ -213,7 +214,7 @@ func (h *Helm) UpdateReleaseValues(updatedValues map[string]interface{}) error { return fmt.Errorf("unable to initialize the K8s client: %w", err) } - postRender, err := h.newRenderer() + postRender, err := h.newRenderer(ctx) if err != nil { return fmt.Errorf("unable to create helm renderer: %w", err) } diff --git a/src/internal/packager/helm/post-render.go b/src/internal/packager/helm/post-render.go index 8d6c157427..9a514fc6a6 100644 --- a/src/internal/packager/helm/post-render.go +++ b/src/internal/packager/helm/post-render.go @@ -37,7 +37,7 @@ type renderer struct { namespaces map[string]*corev1.Namespace } -func (h *Helm) newRenderer() (*renderer, error) { +func (h *Helm) newRenderer(ctx context.Context) (*renderer, error) { message.Debugf("helm.NewRenderer()") rend := &renderer{ @@ -49,7 +49,7 @@ func (h *Helm) newRenderer() (*renderer, error) { return rend, nil } - namespace, err := h.cluster.Clientset.CoreV1().Namespaces().Get(context.TODO(), h.chart.Namespace, metav1.GetOptions{}) + namespace, err := h.cluster.Clientset.CoreV1().Namespaces().Get(ctx, h.chart.Namespace, metav1.GetOptions{}) if err != nil && !kerrors.IsNotFound(err) { return nil, fmt.Errorf("unable to check for existing namespace %q in cluster: %w", h.chart.Namespace, err) } diff --git a/src/internal/packager/helm/zarf.go b/src/internal/packager/helm/zarf.go index 0381ef4b52..8706fe2711 100644 --- a/src/internal/packager/helm/zarf.go +++ b/src/internal/packager/helm/zarf.go @@ -45,7 +45,7 @@ func (h *Helm) UpdateZarfRegistryValues(ctx context.Context) error { Namespace: "zarf", ReleaseName: "zarf-docker-registry", } - err = h.UpdateReleaseValues(registryValues) + err = h.UpdateReleaseValues(ctx, registryValues) if err != nil { return fmt.Errorf("error updating the release values: %w", err) } @@ -119,7 +119,7 @@ func (h *Helm) UpdateZarfAgentValues(ctx context.Context) error { } h.variableConfig.SetApplicationTemplates(applicationTemplates) - err = h.UpdateReleaseValues(map[string]interface{}{}) + err = h.UpdateReleaseValues(ctx, map[string]interface{}{}) if err != nil { return fmt.Errorf("error updating the release values: %w", err) } diff --git a/src/pkg/packager/deploy.go b/src/pkg/packager/deploy.go index 5c174a684f..73aec8f006 100644 --- a/src/pkg/packager/deploy.go +++ b/src/pkg/packager/deploy.go @@ -352,7 +352,7 @@ func (p *Packager) deployComponent(ctx context.Context, component types.ZarfComp } if hasCharts || hasManifests { - if charts, err = p.installChartAndManifests(componentPath, component); err != nil { + if charts, err = p.installChartAndManifests(ctx, componentPath, component); err != nil { return charts, err } } @@ -610,7 +610,7 @@ func (p *Packager) generateValuesOverrides(chart types.ZarfChart, componentName } // Install all Helm charts and raw k8s manifests into the k8s cluster. -func (p *Packager) installChartAndManifests(componentPaths *layout.ComponentPaths, component types.ZarfComponent) (installedCharts []types.InstalledChart, err error) { +func (p *Packager) installChartAndManifests(ctx context.Context, componentPaths *layout.ComponentPaths, component types.ZarfComponent) (installedCharts []types.InstalledChart, err error) { for _, chart := range component.Charts { // Do not wait for the chart to be ready if data injections are present. if len(component.DataInjections) > 0 { @@ -646,7 +646,7 @@ func (p *Packager) installChartAndManifests(componentPaths *layout.ComponentPath p.cfg.PkgOpts.Retries), ) - addedConnectStrings, installedChartName, err := helmCfg.InstallOrUpgradeChart() + addedConnectStrings, installedChartName, err := helmCfg.InstallOrUpgradeChart(ctx) if err != nil { return installedCharts, err } @@ -699,7 +699,7 @@ func (p *Packager) installChartAndManifests(componentPaths *layout.ComponentPath } // Install the chart. - addedConnectStrings, installedChartName, err := helmCfg.InstallOrUpgradeChart() + addedConnectStrings, installedChartName, err := helmCfg.InstallOrUpgradeChart(ctx) if err != nil { return installedCharts, err } diff --git a/src/pkg/packager/prepare.go b/src/pkg/packager/prepare.go index 340ac1c85a..2b888c3966 100644 --- a/src/pkg/packager/prepare.go +++ b/src/pkg/packager/prepare.go @@ -185,7 +185,7 @@ func (p *Packager) findImages(ctx context.Context) (imgMap map[string][]string, } // Generate helm templates for this chart - chartTemplate, chartValues, err := helmCfg.TemplateChart() + 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) From 437e63ce6ac54b2c71ca4d837647646230c1500a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 24 Jul 2024 18:13:34 -0600 Subject: [PATCH 19/68] fix(deps): update github.com/anchore/clio digest to ac88e09 (#2527) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- go.mod | 12 ++++++------ go.sum | 24 ++++++++++++------------ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/go.mod b/go.mod index 9bf35fbbba..d69363783f 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/AlecAivazis/survey/v2 v2.3.7 github.com/Masterminds/semver/v3 v3.2.1 github.com/agnivade/levenshtein v1.1.1 - github.com/anchore/clio v0.0.0-20240408173007-3c4abf89e72f + github.com/anchore/clio v0.0.0-20240705045624-ac88e09ad9d0 github.com/anchore/stereoscope v0.0.1 github.com/anchore/syft v0.100.0 github.com/defenseunicorns/pkg/helpers/v2 v2.0.1 @@ -40,14 +40,14 @@ require ( github.com/sigstore/sigstore/pkg/signature/kms/azure v1.8.1 github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.8.1 github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.8.1 - github.com/spf13/cobra v1.8.0 + github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.18.2 github.com/stretchr/testify v1.9.0 github.com/xeipuuv/gojsonschema v1.2.0 golang.org/x/crypto v0.24.0 golang.org/x/sync v0.7.0 - golang.org/x/term v0.21.0 + golang.org/x/term v0.22.0 helm.sh/helm/v3 v3.14.2 k8s.io/api v0.30.0 k8s.io/apimachinery v0.30.0 @@ -132,7 +132,7 @@ require ( github.com/alibabacloud-go/tea-xml v1.1.3 // indirect github.com/aliyun/credentials-go v1.3.1 // indirect github.com/anchore/bubbly v0.0.0-20231115134915-def0aba654a9 // indirect - github.com/anchore/fangs v0.0.0-20231201140849-5075d28d6d8b // indirect + github.com/anchore/fangs v0.0.0-20240508143433-f016b099950f // indirect github.com/anchore/go-logger v0.0.0-20230725134548-c21dafa1ec5a // indirect github.com/anchore/go-macholibre v0.0.0-20220308212642-53e6d0aaf6fb // indirect github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092 // indirect @@ -199,7 +199,7 @@ require ( github.com/containerd/ttrpc v1.2.2 // indirect github.com/containerd/typeurl/v2 v2.1.1 // indirect github.com/coreos/go-oidc/v3 v3.9.0 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect github.com/cyberphone/json-canonicalization v0.0.0-20231011164504-785e29786b46 // indirect github.com/cyphar/filepath-securejoin v0.2.4 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect @@ -483,7 +483,7 @@ require ( golang.org/x/mod v0.17.0 // indirect golang.org/x/net v0.26.0 // indirect golang.org/x/oauth2 v0.21.0 // indirect - golang.org/x/sys v0.21.0 // indirect + golang.org/x/sys v0.22.0 // indirect golang.org/x/text v0.16.0 // indirect golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect diff --git a/go.sum b/go.sum index 27f7af4f00..a0be8e7f61 100644 --- a/go.sum +++ b/go.sum @@ -372,10 +372,10 @@ github.com/aliyun/credentials-go v1.3.1 h1:uq/0v7kWrxmoLGpqjx7vtQ/s03f0zR//0br/x github.com/aliyun/credentials-go v1.3.1/go.mod h1:8jKYhQuDawt8x2+fusqa1Y6mPxemTsBEN04dgcAcYz0= github.com/anchore/bubbly v0.0.0-20231115134915-def0aba654a9 h1:p0ZIe0htYOX284Y4axJaGBvXHU0VCCzLN5Wf5XbKStU= github.com/anchore/bubbly v0.0.0-20231115134915-def0aba654a9/go.mod h1:3ZsFB9tzW3vl4gEiUeuSOMDnwroWxIxJelOOHUp8dSw= -github.com/anchore/clio v0.0.0-20240408173007-3c4abf89e72f h1:2xJPf4KWzxFDwZK/yax+h8QHP2Gnn4fgXUCCeizhbyU= -github.com/anchore/clio v0.0.0-20240408173007-3c4abf89e72f/go.mod h1:1k7cwq2CeVH9dgAl0X/JBBfJ4y/E8h2R9KqByDkrCA4= -github.com/anchore/fangs v0.0.0-20231201140849-5075d28d6d8b h1:L/djgY7ZbZ/38+wUtdkk398W3PIBJLkt1N8nU/7e47A= -github.com/anchore/fangs v0.0.0-20231201140849-5075d28d6d8b/go.mod h1:TLcE0RE5+8oIx2/NPWem/dq1DeaMoC+fPEH7hoSzPLo= +github.com/anchore/clio v0.0.0-20240705045624-ac88e09ad9d0 h1:rtO6Bcc5KX1i6Ndj4pFcFUkE5PaiKv0J4hKSlmbEIXQ= +github.com/anchore/clio v0.0.0-20240705045624-ac88e09ad9d0/go.mod h1:U3M+opzBUkSBUIRUXsQj6ZgrX9i7Nn0YLn4CjmhKMNI= +github.com/anchore/fangs v0.0.0-20240508143433-f016b099950f h1:NOhzafCyNYFi88qxkBFjMzQo4dRa1vDhBzx+0Uovx8Q= +github.com/anchore/fangs v0.0.0-20240508143433-f016b099950f/go.mod h1:sVpRS2yNCw6tLVpvA1QSDVWTJVpCuAm8JNZgn4Sjz/k= github.com/anchore/go-logger v0.0.0-20230725134548-c21dafa1ec5a h1:nJ2G8zWKASyVClGVgG7sfM5mwoZlZ2zYpIzN2OhjWkw= github.com/anchore/go-logger v0.0.0-20230725134548-c21dafa1ec5a/go.mod h1:ubLFmlsv8/DFUQrZwY5syT5/8Er3ugSr4rDFwHsE3hg= github.com/anchore/go-macholibre v0.0.0-20220308212642-53e6d0aaf6fb h1:iDMnx6LIjtjZ46C0akqveX83WFzhpTD3eqOthawb5vU= @@ -578,8 +578,8 @@ github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8 github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM= -github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0= github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= @@ -1584,8 +1584,8 @@ github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v1.3.0/go.mod h1:BrRVncBjOJa/eUcVVm9CE+oC6as8k+VYr4NY7WCi9V4= -github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= -github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= @@ -2067,8 +2067,8 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= -golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -2082,8 +2082,8 @@ golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= -golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA= -golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= +golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= +golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= From b96446752706a9ffa4f02b0fcec6f657141f384d Mon Sep 17 00:00:00 2001 From: Philip Laine Date: Thu, 25 Jul 2024 10:21:45 +0200 Subject: [PATCH 20/68] refactor: add error handling to view SBOM files (#2752) Signed-off-by: Philip Laine --- src/internal/packager/sbom/tools.go | 43 ++++++++++++++++------------- src/pkg/packager/creator/normal.go | 5 +++- src/pkg/packager/inspect.go | 5 +++- 3 files changed, 32 insertions(+), 21 deletions(-) diff --git a/src/internal/packager/sbom/tools.go b/src/internal/packager/sbom/tools.go index 60aa998958..972b709906 100644 --- a/src/internal/packager/sbom/tools.go +++ b/src/internal/packager/sbom/tools.go @@ -14,26 +14,31 @@ import ( ) // ViewSBOMFiles opens a browser to view the SBOM files and pauses for user input. -func ViewSBOMFiles(directory string) { - sbomViewFiles, _ := filepath.Glob(filepath.Join(directory, "sbom-viewer-*")) - - if len(sbomViewFiles) > 0 { - link := sbomViewFiles[0] - msg := fmt.Sprintf("This package has %d images with software bill-of-materials (SBOM) included. If your browser did not open automatically you can copy and paste this file location into your browser address bar to view them: %s\n\n", len(sbomViewFiles), link) - message.Note(msg) - - if err := exec.LaunchURL(link); err != nil { - message.Debug(err) - } +func ViewSBOMFiles(directory string) error { + sbomViewFiles, err := filepath.Glob(filepath.Join(directory, "sbom-viewer-*")) + if err != nil { + return err + } - // Use survey.Input to hang until user input - var value string - prompt := &survey.Input{ - Message: "Hit the 'enter' key when you are done viewing the SBOM files", - Default: "", - } - _ = survey.AskOne(prompt, &value) - } else { + if len(sbomViewFiles) == 0 { message.Note("There were no images with software bill-of-materials (SBOM) included.") + return nil + } + + link := sbomViewFiles[0] + msg := fmt.Sprintf("This package has %d images with software bill-of-materials (SBOM) included. If your browser did not open automatically you can copy and paste this file location into your browser address bar to view them: %s\n\n", len(sbomViewFiles), link) + message.Note(msg) + if err := exec.LaunchURL(link); err != nil { + return err + } + var value string + prompt := &survey.Input{ + Message: "Hit the 'enter' key when you are done viewing the SBOM files", + Default: "", + } + err = survey.AskOne(prompt, &value) + if err != nil { + return err } + return nil } diff --git a/src/pkg/packager/creator/normal.go b/src/pkg/packager/creator/normal.go index 3b34b7e846..52baa708e4 100644 --- a/src/pkg/packager/creator/normal.go +++ b/src/pkg/packager/creator/normal.go @@ -321,7 +321,10 @@ func (pc *PackageCreator) Output(ctx context.Context, dst *layout.PackagePaths, } if pc.createOpts.ViewSBOM { - sbom.ViewSBOMFiles(sbomDir) + err := sbom.ViewSBOMFiles(sbomDir) + if err != nil { + return err + } } } return nil diff --git a/src/pkg/packager/inspect.go b/src/pkg/packager/inspect.go index bfa29d860b..88b1de88d8 100644 --- a/src/pkg/packager/inspect.go +++ b/src/pkg/packager/inspect.go @@ -47,7 +47,10 @@ func (p *Packager) Inspect(ctx context.Context) (err error) { } if p.cfg.InspectOpts.ViewSBOM { - sbom.ViewSBOMFiles(sbomDir) + err := sbom.ViewSBOMFiles(sbomDir) + if err != nil { + return err + } } return nil From 5058a673bef1496195afd9e193a64030df6f28ba Mon Sep 17 00:00:00 2001 From: Austin Abro <37223396+AustinAbro321@users.noreply.github.com> Date: Thu, 25 Jul 2024 04:44:50 -0400 Subject: [PATCH 21/68] feat: annotate image mutation (#2755) Signed-off-by: Austin Abro Signed-off-by: Philip Laine Co-authored-by: Philip Laine --- src/internal/agent/hooks/pods.go | 16 ++++++++++++++++ src/internal/agent/hooks/pods_test.go | 22 +++++++++++++++++++--- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/src/internal/agent/hooks/pods.go b/src/internal/agent/hooks/pods.go index 1eaccb5fbb..60362785a5 100644 --- a/src/internal/agent/hooks/pods.go +++ b/src/internal/agent/hooks/pods.go @@ -20,6 +20,8 @@ import ( corev1 "k8s.io/api/core/v1" ) +const annotationPrefix = "zarf.dev" + // NewPodMutationHook creates a new instance of pods mutation hook. func NewPodMutationHook(ctx context.Context, cluster *cluster.Cluster) operations.Hook { return operations.Hook{ @@ -40,6 +42,10 @@ func parsePod(object []byte) (*corev1.Pod, error) { return &pod, nil } +func getImageAnnotationKey(containerName string) string { + return fmt.Sprintf("%s/original-image-%s", annotationPrefix, containerName) +} + func mutatePod(ctx context.Context, r *v1.AdmissionRequest, cluster *cluster.Cluster) (*operations.Result, error) { pod, err := parsePod(r.Object.Raw) if err != nil { @@ -66,6 +72,11 @@ func mutatePod(ctx context.Context, r *v1.AdmissionRequest, cluster *cluster.Clu zarfSecret := []corev1.LocalObjectReference{{Name: config.ZarfImagePullSecretName}} patches = append(patches, operations.ReplacePatchOperation("/spec/imagePullSecrets", zarfSecret)) + updatedAnnotations := pod.Annotations + if updatedAnnotations == nil { + updatedAnnotations = make(map[string]string) + } + // update the image host for each init container for idx, container := range pod.Spec.InitContainers { path := fmt.Sprintf("/spec/initContainers/%d/image", idx) @@ -74,6 +85,7 @@ func mutatePod(ctx context.Context, r *v1.AdmissionRequest, cluster *cluster.Clu message.Warnf(lang.AgentErrImageSwap, container.Image) continue // Continue, because we might as well attempt to mutate the other containers for this pod } + updatedAnnotations[getImageAnnotationKey(container.Name)] = container.Image patches = append(patches, operations.ReplacePatchOperation(path, replacement)) } @@ -85,6 +97,7 @@ func mutatePod(ctx context.Context, r *v1.AdmissionRequest, cluster *cluster.Clu message.Warnf(lang.AgentErrImageSwap, container.Image) continue // Continue, because we might as well attempt to mutate the other containers for this pod } + updatedAnnotations[getImageAnnotationKey(container.Name)] = container.Image patches = append(patches, operations.ReplacePatchOperation(path, replacement)) } @@ -96,11 +109,14 @@ func mutatePod(ctx context.Context, r *v1.AdmissionRequest, cluster *cluster.Clu message.Warnf(lang.AgentErrImageSwap, container.Image) continue // Continue, because we might as well attempt to mutate the other containers for this pod } + updatedAnnotations[getImageAnnotationKey(container.Name)] = container.Image patches = append(patches, operations.ReplacePatchOperation(path, replacement)) } patches = append(patches, getLabelPatch(pod.Labels)) + patches = append(patches, operations.ReplacePatchOperation("/metadata/annotations", updatedAnnotations)) + return &operations.Result{ Allowed: true, PatchOps: patches, diff --git a/src/internal/agent/hooks/pods_test.go b/src/internal/agent/hooks/pods_test.go index dafa786f8c..60bd09d0f5 100644 --- a/src/internal/agent/hooks/pods_test.go +++ b/src/internal/agent/hooks/pods_test.go @@ -50,11 +50,12 @@ func TestPodMutationWebhook(t *testing.T) { Annotations: map[string]string{"should-be": "mutated"}, }, Spec: corev1.PodSpec{ - Containers: []corev1.Container{{Image: "nginx"}}, - InitContainers: []corev1.Container{{Image: "busybox"}}, + Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}, + InitContainers: []corev1.Container{{Name: "different", Image: "busybox"}}, EphemeralContainers: []corev1.EphemeralContainer{ { EphemeralContainerCommon: corev1.EphemeralContainerCommon{ + Name: "alpine", Image: "alpine", }, }, @@ -85,6 +86,15 @@ func TestPodMutationWebhook(t *testing.T) { "should-be": "mutated", }, ), + operations.ReplacePatchOperation( + "/metadata/annotations", + map[string]string{ + "zarf.dev/original-image-nginx": "nginx", + "zarf.dev/original-image-alpine": "alpine", + "zarf.dev/original-image-different": "busybox", + "should-be": "mutated", + }, + ), }, code: http.StatusOK, }, @@ -108,7 +118,7 @@ func TestPodMutationWebhook(t *testing.T) { Labels: nil, }, Spec: corev1.PodSpec{ - Containers: []corev1.Container{{Image: "nginx"}}, + Containers: []corev1.Container{{Name: "nginx", Image: "nginx"}}, }, }), patch: []operations.PatchOperation{ @@ -124,6 +134,12 @@ func TestPodMutationWebhook(t *testing.T) { "/metadata/labels", map[string]string{"zarf-agent": "patched"}, ), + operations.ReplacePatchOperation( + "/metadata/annotations", + map[string]string{ + "zarf.dev/original-image-nginx": "nginx", + }, + ), }, code: http.StatusOK, }, From 049fe2e110f16b050e1ebf6eb239e831b3275ee4 Mon Sep 17 00:00:00 2001 From: schristoff <28318173+schristoff@users.noreply.github.com> Date: Thu, 25 Jul 2024 02:50:59 -0600 Subject: [PATCH 22/68] chore: move context.TODO to context.Background() (2) (#2746) Signed-off-by: schristoff-du <167717759+schristoff-du@users.noreply.github.com> Co-authored-by: schristoff-du <167717759+schristoff-du@users.noreply.github.com> --- src/pkg/utils/exec/exec.go | 8 ++++ src/test/common.go | 11 ++--- src/test/e2e/00_use_cli_test.go | 44 ++++++++--------- src/test/e2e/01_component_choice_test.go | 6 +-- src/test/e2e/02_component_actions_test.go | 20 ++++---- src/test/e2e/03_deprecations_test.go | 14 +++--- src/test/e2e/04_create_templating_test.go | 10 ++-- src/test/e2e/05_tarball_test.go | 12 ++--- src/test/e2e/06_create_sbom_test.go | 10 ++-- src/test/e2e/07_create_git_test.go | 2 +- src/test/e2e/08_create_differential_test.go | 6 +-- src/test/e2e/09_component_compose_test.go | 6 +-- src/test/e2e/10_component_flavor_test.go | 8 ++-- src/test/e2e/11_oci_pull_inspect_test.go | 10 ++-- src/test/e2e/12_lint_test.go | 4 +- src/test/e2e/13_find_images_test.go | 16 +++---- src/test/e2e/13_zarf_package_generate_test.go | 2 +- src/test/e2e/14_create_sha_index_test.go | 2 +- src/test/e2e/20_zarf_init_test.go | 48 +++++++++---------- src/test/e2e/21_connect_creds_test.go | 14 +++--- src/test/e2e/22_git_and_gitops_test.go | 30 ++++++------ src/test/e2e/23_data_injection_test.go | 8 ++-- src/test/e2e/24_variables_test.go | 16 +++---- src/test/e2e/25_helm_test.go | 46 +++++++++--------- src/test/e2e/26_simple_packages_test.go | 16 +++---- src/test/e2e/27_deploy_regression_test.go | 9 ++-- src/test/e2e/28_wait_test.go | 12 ++--- src/test/e2e/29_config_file_test.go | 18 +++---- .../e2e/30_component_action_cluster_test.go | 8 ++-- .../e2e/31_checksum_and_signature_test.go | 12 ++--- src/test/e2e/32_component_webhooks_test.go | 16 +++---- src/test/e2e/33_manifest_with_symlink_test.go | 4 +- src/test/e2e/34_custom_init_package_test.go | 10 ++-- src/test/e2e/35_custom_retries_test.go | 6 +-- src/test/e2e/50_oci_publish_deploy_test.go | 22 ++++----- src/test/e2e/51_oci_compose_test.go | 26 +++++----- src/test/e2e/99_appliance_remove_test.go | 10 ++-- src/test/e2e/99_yolo_test.go | 10 ++-- src/test/external/common.go | 3 +- src/test/external/ext_in_cluster_test.go | 2 +- src/test/nightly/ecr_publish_test.go | 12 ++--- src/test/upgrade/previously_built_test.go | 37 +++++++------- 42 files changed, 295 insertions(+), 291 deletions(-) diff --git a/src/pkg/utils/exec/exec.go b/src/pkg/utils/exec/exec.go index 40b4023d50..a3957edd31 100644 --- a/src/pkg/utils/exec/exec.go +++ b/src/pkg/utils/exec/exec.go @@ -15,6 +15,7 @@ import ( "runtime" "strings" "sync" + "testing" ) // Config is a struct for configuring the Cmd function. @@ -50,6 +51,13 @@ func CmdWithPrint(command string, args ...string) error { return err } +// CmdWithTesting takes a *testing.T and generates a context the cancels on cleanup +func CmdWithTesting(t *testing.T, config Config, command string, args ...string) (string, string, error) { + ctx, cancel := context.WithCancel(context.Background()) + t.Cleanup(cancel) + return CmdWithContext(ctx, config, command, args...) +} + // CmdWithContext executes a given command with given config. func CmdWithContext(ctx context.Context, config Config, command string, args ...string) (string, string, error) { if command == "" { diff --git a/src/test/common.go b/src/test/common.go index 0339fe0f48..c75e71ec7c 100644 --- a/src/test/common.go +++ b/src/test/common.go @@ -6,7 +6,6 @@ package test import ( "bufio" - "context" "fmt" "os" "regexp" @@ -53,7 +52,7 @@ func GetCLIName() string { } // Zarf executes a Zarf command. -func (e2e *ZarfE2ETest) Zarf(args ...string) (string, string, error) { +func (e2e *ZarfE2ETest) Zarf(t *testing.T, args ...string) (string, string, error) { if !slices.Contains(args, "--tmpdir") && !slices.Contains(args, "tools") { tmpdir, err := os.MkdirTemp("", "zarf-") if err != nil { @@ -76,14 +75,14 @@ func (e2e *ZarfE2ETest) Zarf(args ...string) (string, string, error) { args = append(args, "--zarf-cache", cacheDir) defer os.RemoveAll(cacheDir) } - return exec.CmdWithContext(context.TODO(), exec.PrintCfg(), e2e.ZarfBinPath, args...) + return exec.CmdWithTesting(t, exec.PrintCfg(), e2e.ZarfBinPath, args...) } // Kubectl executes `zarf tools kubectl ...` -func (e2e *ZarfE2ETest) Kubectl(args ...string) (string, string, error) { +func (e2e *ZarfE2ETest) Kubectl(t *testing.T, args ...string) (string, string, error) { tk := []string{"tools", "kubectl"} args = append(tk, args...) - return e2e.Zarf(args...) + return e2e.Zarf(t, args...) } // CleanFiles removes files and directories that have been created during the test. @@ -132,7 +131,7 @@ func (e2e *ZarfE2ETest) TeardownRegistry(t *testing.T, port int) { // GetZarfVersion returns the current build/zarf version func (e2e *ZarfE2ETest) GetZarfVersion(t *testing.T) string { // Get the version of the CLI - stdOut, stdErr, err := e2e.Zarf("version") + stdOut, stdErr, err := e2e.Zarf(t, "version") require.NoError(t, err, stdOut, stdErr) return strings.Trim(stdOut, "\n") } diff --git a/src/test/e2e/00_use_cli_test.go b/src/test/e2e/00_use_cli_test.go index 93c5778c0c..ff8a07106b 100644 --- a/src/test/e2e/00_use_cli_test.go +++ b/src/test/e2e/00_use_cli_test.go @@ -35,7 +35,7 @@ func TestUseCLI(t *testing.T) { err := os.WriteFile(shasumTestFilePath, []byte("random test data 🦄\n"), helpers.ReadWriteUser) require.NoError(t, err) - stdOut, stdErr, err := e2e.Zarf("prepare", "sha256sum", shasumTestFilePath) + stdOut, stdErr, err := e2e.Zarf(t, "prepare", "sha256sum", shasumTestFilePath) require.NoError(t, err, stdOut, stdErr) require.Equal(t, expectedShasum, stdOut, "The expected SHASUM should equal the actual SHASUM") }) @@ -45,7 +45,7 @@ func TestUseCLI(t *testing.T) { // Test `zarf prepare sha256sum` for a remote asset expectedShasum := "c3cdea0573ba5a058ec090b5d2683bf398e8b1614c37ec81136ed03b78167617\n" - stdOut, stdErr, err := e2e.Zarf("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-public.s3-us-gov-west-1.amazonaws.com/pipelines/zarf-prepare-shasum-remote-test-file.txt") require.NoError(t, err, stdOut, stdErr) require.Contains(t, stdOut, expectedShasum, "The expected SHASUM should equal the actual SHASUM") }) @@ -53,19 +53,19 @@ func TestUseCLI(t *testing.T) { t.Run("zarf version", func(t *testing.T) { t.Parallel() // Test `zarf version` - version, _, err := e2e.Zarf("version") + version, _, err := e2e.Zarf(t, "version") require.NoError(t, err) require.NotEmpty(t, version, "Zarf version should not be an empty string") version = strings.Trim(version, "\n") // test `zarf version --output=json` - stdOut, _, err := e2e.Zarf("version", "--output=json") + stdOut, _, err := e2e.Zarf(t, "version", "--output=json") require.NoError(t, err) jsonVersion := fmt.Sprintf(",\"version\":\"%s\"}", version) require.Contains(t, stdOut, jsonVersion, "Zarf version should be the same in all formats") // test `zarf version --output=yaml` - stdOut, _, err = e2e.Zarf("version", "--output=yaml") + stdOut, _, err = e2e.Zarf(t, "version", "--output=yaml") require.NoError(t, err) yamlVersion := fmt.Sprintf("version: %s", version) require.Contains(t, stdOut, yamlVersion, "Zarf version should be the same in all formats") @@ -75,23 +75,23 @@ func TestUseCLI(t *testing.T) { t.Parallel() // Test for expected failure when given a bad component input path := fmt.Sprintf("build/zarf-package-component-actions-%s.tar.zst", e2e.Arch) - _, _, err := e2e.Zarf("package", "deploy", path, "--components=on-create,foo,git-server", "--confirm") + _, _, err := e2e.Zarf(t, "package", "deploy", path, "--components=on-create,foo,git-server", "--confirm") require.Error(t, err) }) t.Run("zarf deploy should return a warning when no components are deployed", func(t *testing.T) { t.Parallel() - _, _, err := e2e.Zarf("package", "create", "src/test/packages/00-no-components", "-o=build", "--confirm") + _, _, err := e2e.Zarf(t, "package", "create", "src/test/packages/00-no-components", "-o=build", "--confirm") require.NoError(t, err) path := fmt.Sprintf("build/zarf-package-no-components-%s.tar.zst", e2e.Arch) // Test that excluding all components with a leading dash results in a warning - _, stdErr, err := e2e.Zarf("package", "deploy", path, "--components=-deselect-me", "--confirm") + _, stdErr, err := e2e.Zarf(t, "package", "deploy", path, "--components=-deselect-me", "--confirm") require.NoError(t, err) require.Contains(t, stdErr, "No components were selected for deployment") // Test that excluding still works even if a wildcard is given - _, stdErr, err = e2e.Zarf("package", "deploy", path, "--components=*,-deselect-me", "--confirm") + _, stdErr, err = e2e.Zarf(t, "package", "deploy", path, "--components=*,-deselect-me", "--confirm") require.NoError(t, err) require.NotContains(t, stdErr, "DESELECT-ME COMPONENT") }) @@ -99,13 +99,13 @@ func TestUseCLI(t *testing.T) { t.Run("changing log level", func(t *testing.T) { t.Parallel() // Test that changing the log level actually applies the requested level - _, stdErr, _ := e2e.Zarf("internal", "crc32", "zarf", "--log-level=debug") + _, stdErr, _ := e2e.Zarf(t, "internal", "crc32", "zarf", "--log-level=debug") expectedOutString := "Log level set to debug" require.Contains(t, stdErr, expectedOutString, "The log level should be changed to 'debug'") }) t.Run("zarf package to test bad remote images", func(t *testing.T) { - _, stdErr, err := e2e.Zarf("package", "create", "src/test/packages/00-remote-pull-fail", "--confirm") + _, stdErr, err := e2e.Zarf(t, "package", "create", "src/test/packages/00-remote-pull-fail", "--confirm") // expecting zarf to have an error and output to stderr require.Error(t, err) // Make sure we print the get request error (only look for GET since the actual error changes based on login status) @@ -116,11 +116,11 @@ func TestUseCLI(t *testing.T) { t.Run("zarf package to test archive path", func(t *testing.T) { t.Parallel() - stdOut, stdErr, err := e2e.Zarf("package", "create", "packages/distros/eks", "--confirm") + stdOut, stdErr, err := e2e.Zarf(t, "package", "create", "packages/distros/eks", "--confirm") require.NoError(t, err, stdOut, stdErr) path := fmt.Sprintf("zarf-package-distro-eks-%s-0.0.3.tar.zst", e2e.Arch) - stdOut, stdErr, err = e2e.Zarf("package", "deploy", path, "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "deploy", path, "--confirm") require.NoError(t, err, stdOut, stdErr) require.FileExists(t, "binaries/eksctl_Darwin_x86_64") @@ -134,7 +134,7 @@ func TestUseCLI(t *testing.T) { t.Parallel() tmpdir := t.TempDir() cacheDir := filepath.Join(t.TempDir(), ".cache-location") - stdOut, stdErr, err := e2e.Zarf("package", "create", "examples/dos-games", "--zarf-cache", cacheDir, "--tmpdir", tmpdir, "--log-level=debug", "-o=build", "--confirm") + stdOut, stdErr, err := e2e.Zarf(t, "package", "create", "examples/dos-games", "--zarf-cache", cacheDir, "--tmpdir", tmpdir, "--log-level=debug", "-o=build", "--confirm") require.Contains(t, stdErr, tmpdir, "The other tmp path should show as being created") require.NoError(t, err, stdOut, stdErr) @@ -147,7 +147,7 @@ func TestUseCLI(t *testing.T) { t.Parallel() path := fmt.Sprintf("build/zarf-package-component-actions-%s.tar.zst", e2e.Arch) tmpdir := t.TempDir() - stdOut, stdErr, err := e2e.Zarf("package", "inspect", path, "--tmpdir", tmpdir, "--log-level=debug") + stdOut, stdErr, err := e2e.Zarf(t, "package", "inspect", path, "--tmpdir", tmpdir, "--log-level=debug") require.Contains(t, stdErr, tmpdir, "The other tmp path should show as being created") require.NoError(t, err, stdOut, stdErr) }) @@ -164,7 +164,7 @@ func TestUseCLI(t *testing.T) { e2e.CleanFiles(firstFile, secondFile) }) path := fmt.Sprintf("build/zarf-package-component-choice-%s.tar.zst", e2e.Arch) - stdOut, stdErr, err := e2e.Zarf("package", "deploy", path, "--tmpdir", tmpdir, "--log-level=debug", "--confirm") + stdOut, stdErr, err := e2e.Zarf(t, "package", "deploy", path, "--tmpdir", tmpdir, "--log-level=debug", "--confirm") require.Contains(t, stdErr, tmpdir, "The other tmp path should show as being created") require.NoError(t, err, stdOut, stdErr) }) @@ -174,7 +174,7 @@ func TestUseCLI(t *testing.T) { tmpdir := t.TempDir() // Test removal of cache cachePath := filepath.Join(tmpdir, ".cache-location") - stdOut, stdErr, err := e2e.Zarf("tools", "clear-cache", "--zarf-cache", cachePath) + stdOut, stdErr, err := e2e.Zarf(t, "tools", "clear-cache", "--zarf-cache", cachePath) require.NoError(t, err, stdOut, stdErr) // Check that ReadDir returns no such file or directory for the cachePath _, err = os.ReadDir(cachePath) @@ -196,7 +196,7 @@ func TestUseCLI(t *testing.T) { t.Cleanup(func() { e2e.CleanFiles(tlsCA, tlsCert, tlsKey) }) - stdOut, stdErr, err := e2e.Zarf("tools", "gen-pki", "github.com", "--sub-alt-name", "google.com") + stdOut, stdErr, err := e2e.Zarf(t, "tools", "gen-pki", "github.com", "--sub-alt-name", "google.com") require.NoError(t, err, stdOut, stdErr) require.Contains(t, stdErr, "Successfully created a chain of trust for github.com") @@ -225,16 +225,16 @@ func TestUseCLI(t *testing.T) { require.NoError(t, err) // Test that yq can eval properly - _, stdErr, err := e2e.Zarf("tools", "yq", "eval", "-i", `.items[1].name = "renamed-item"`, file) + _, stdErr, err := e2e.Zarf(t, "tools", "yq", "eval", "-i", `.items[1].name = "renamed-item"`, file) require.NoError(t, err, stdErr) - stdOut, _, err := e2e.Zarf("tools", "yq", ".items[1].name", file) + stdOut, _, err := e2e.Zarf(t, "tools", "yq", ".items[1].name", file) require.NoError(t, err) require.Contains(t, stdOut, "renamed-item") // Test that yq ea can be used properly - _, _, err = e2e.Zarf("tools", "yq", "eval-all", "-i", `. as $doc ireduce ({}; .items += $doc.items)`, file, otherFile) + _, _, err = e2e.Zarf(t, "tools", "yq", "eval-all", "-i", `. as $doc ireduce ({}; .items += $doc.items)`, file, otherFile) require.NoError(t, err) - stdOut, _, err = e2e.Zarf("tools", "yq", "e", ".items | length", file) + stdOut, _, err = e2e.Zarf(t, "tools", "yq", "e", ".items | length", file) require.NoError(t, err) require.Equal(t, "4\n", stdOut) }) diff --git a/src/test/e2e/01_component_choice_test.go b/src/test/e2e/01_component_choice_test.go index 8930094f24..8668586956 100644 --- a/src/test/e2e/01_component_choice_test.go +++ b/src/test/e2e/01_component_choice_test.go @@ -26,11 +26,11 @@ func TestComponentChoice(t *testing.T) { // Try to deploy both and expect failure due to only one component allowed at a time // We currently don't have a pattern to actually test the interactive prompt, so just testing automation for now - stdOut, stdErr, err := e2e.Zarf("package", "deploy", path, "--components=first-choice,second-choice", "--confirm") + stdOut, stdErr, err := e2e.Zarf(t, "package", "deploy", path, "--components=first-choice,second-choice", "--confirm") require.Error(t, err, stdOut, stdErr) // Deploy a single choice and expect success - stdOut, stdErr, err = e2e.Zarf("package", "deploy", path, "--components=first-choice", "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "deploy", path, "--components=first-choice", "--confirm") require.NoError(t, err, stdOut, stdErr) require.Contains(t, stdErr, "Component first-choice is using group which has been deprecated", "output should show a warning for group being deprecated.") @@ -40,7 +40,7 @@ func TestComponentChoice(t *testing.T) { require.NoFileExists(t, secondFile) // Deploy using default choice - stdOut, stdErr, err = e2e.Zarf("package", "deploy", path, "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "deploy", path, "--confirm") require.NoError(t, err, stdOut, stdErr) // Verify the file was created diff --git a/src/test/e2e/02_component_actions_test.go b/src/test/e2e/02_component_actions_test.go index b709c0c267..94f9d997db 100644 --- a/src/test/e2e/02_component_actions_test.go +++ b/src/test/e2e/02_component_actions_test.go @@ -31,7 +31,7 @@ func TestComponentActions(t *testing.T) { /* Create */ // Try creating the package to test the onCreate actions. - stdOut, stdErr, err := e2e.Zarf("package", "create", "examples/component-actions", "--confirm") + stdOut, stdErr, err := e2e.Zarf(t, "package", "create", "examples/component-actions", "--confirm") require.NoError(t, err, stdOut, stdErr) require.Contains(t, stdErr, "Completed \"Create a test file\"") require.Contains(t, stdErr, "Completed \"touch test-create-after.txt\"") @@ -54,7 +54,7 @@ func TestComponentActions(t *testing.T) { t.Parallel() // Deploy the simple script that should pass. - stdOut, stdErr, err = e2e.Zarf("package", "deploy", path, "--components=on-deploy-and-remove", "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "deploy", path, "--components=on-deploy-and-remove", "--confirm") require.NoError(t, err, stdOut, stdErr) // Check that the deploy artifacts were created. @@ -63,7 +63,7 @@ func TestComponentActions(t *testing.T) { } // Remove the simple script that should pass. - stdOut, stdErr, err = e2e.Zarf("package", "remove", path, "--components=on-deploy-and-remove", "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "remove", path, "--components=on-deploy-and-remove", "--confirm") require.NoError(t, err, stdOut, stdErr) // Check that the deploy artifacts were removed. @@ -75,7 +75,7 @@ func TestComponentActions(t *testing.T) { t.Run("action on-deploy-with-timeout", func(t *testing.T) { t.Parallel() // Deploy the simple action that should fail the timeout. - stdOut, stdErr, err = e2e.Zarf("package", "deploy", path, "--components=on-deploy-with-timeout", "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "deploy", path, "--components=on-deploy-with-timeout", "--confirm") require.Error(t, err, stdOut, stdErr) require.Contains(t, stdErr, "after 1 second") require.Contains(t, stdErr, "😭😭😭 this action failed because it took too long to run 😭😭😭") @@ -85,7 +85,7 @@ func TestComponentActions(t *testing.T) { t.Parallel() // Test using a Zarf Variable within the action - stdOut, stdErr, err = e2e.Zarf("package", "deploy", path, "--components=on-deploy-with-variable", "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "deploy", path, "--components=on-deploy-with-variable", "--confirm") require.NoError(t, err, stdOut, stdErr) require.Contains(t, stdErr, "the dog says ruff") @@ -94,7 +94,7 @@ func TestComponentActions(t *testing.T) { t.Run("action on-deploy-with-dynamic-variable", func(t *testing.T) { t.Parallel() // Test using dynamic and multiple-variables - stdOut, stdErr, err = e2e.Zarf("package", "deploy", path, "--components=on-deploy-with-dynamic-variable,on-deploy-with-multiple-variables", "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "deploy", path, "--components=on-deploy-with-dynamic-variable,on-deploy-with-multiple-variables", "--confirm") require.NoError(t, err, stdOut, stdErr) require.Contains(t, stdErr, "the cat says meow") require.Contains(t, stdErr, "the dog says ruff") @@ -108,7 +108,7 @@ func TestComponentActions(t *testing.T) { deployWithEnvVarArtifact := "test-filename-from-env.txt" // Test using environment variables - stdOut, stdErr, err = e2e.Zarf("package", "deploy", path, "--components=on-deploy-with-env-var", "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "deploy", path, "--components=on-deploy-with-env-var", "--confirm") require.NoError(t, err, stdOut, stdErr) require.FileExists(t, deployWithEnvVarArtifact) @@ -121,7 +121,7 @@ func TestComponentActions(t *testing.T) { deployTemplatedArtifact := "test-templated.txt" // Test using a templated file but without dynamic variables - stdOut, stdErr, err = e2e.Zarf("package", "deploy", path, "--components=on-deploy-with-template-use-of-variable", "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "deploy", path, "--components=on-deploy-with-template-use-of-variable", "--confirm") require.NoError(t, err, stdOut, stdErr) outTemplated, err := os.ReadFile(deployTemplatedArtifact) require.NoError(t, err) @@ -133,7 +133,7 @@ func TestComponentActions(t *testing.T) { e2e.CleanFiles(deployTemplatedArtifact) // Test using a templated file with dynamic variables - stdOut, stdErr, err = e2e.Zarf("package", "deploy", path, "--components=on-deploy-with-template-use-of-variable,on-deploy-with-dynamic-variable,on-deploy-with-multiple-variables", "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "deploy", path, "--components=on-deploy-with-template-use-of-variable,on-deploy-with-dynamic-variable,on-deploy-with-multiple-variables", "--confirm") require.NoError(t, err, stdOut, stdErr) outTemplated, err = os.ReadFile(deployTemplatedArtifact) require.NoError(t, err) @@ -147,7 +147,7 @@ func TestComponentActions(t *testing.T) { t.Run("action on-deploy-immediate-failure", func(t *testing.T) { t.Parallel() - stdOut, stdErr, err = e2e.Zarf("package", "deploy", path, "--components=on-deploy-immediate-failure", "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "deploy", path, "--components=on-deploy-immediate-failure", "--confirm") require.Error(t, err, stdOut, stdErr) require.Contains(t, stdErr, "failed to deploy package") // regression test to ensure that failed commands are not erroneously flagged as a timeout diff --git a/src/test/e2e/03_deprecations_test.go b/src/test/e2e/03_deprecations_test.go index 9d1c96b0c9..0414a3915e 100644 --- a/src/test/e2e/03_deprecations_test.go +++ b/src/test/e2e/03_deprecations_test.go @@ -30,7 +30,7 @@ func TestDeprecatedComponentScripts(t *testing.T) { // 1. Try creating the package to test the create scripts testPackagePath := fmt.Sprintf("%s/zarf-package-deprecated-component-scripts-%s.tar.zst", testPackageDirPath, e2e.Arch) outputFlag := fmt.Sprintf("-o=%s", testPackageDirPath) - stdOut, stdErr, err := e2e.Zarf("package", "create", testPackageDirPath, outputFlag, "--confirm") + stdOut, stdErr, err := e2e.Zarf(t, "package", "create", testPackageDirPath, outputFlag, "--confirm") defer e2e.CleanFiles(testPackagePath) require.NoError(t, err, stdOut, stdErr) require.Contains(t, stdErr, "Component '1-test-deprecated-prepare-scripts' is using scripts") @@ -46,7 +46,7 @@ func TestDeprecatedComponentScripts(t *testing.T) { } // 2. Deploy the simple script that should pass - stdOut, stdErr, err = e2e.Zarf("package", "deploy", testPackagePath, "--confirm", "--components=2-test-deprecated-deploy-scripts") + stdOut, stdErr, err = e2e.Zarf(t, "package", "deploy", testPackagePath, "--confirm", "--components=2-test-deprecated-deploy-scripts") require.NoError(t, err, stdOut, stdErr) // Check that the deploy artifacts were created @@ -55,7 +55,7 @@ func TestDeprecatedComponentScripts(t *testing.T) { } // 3. Deploy the simple script that should fail the timeout - stdOut, stdErr, err = e2e.Zarf("package", "deploy", testPackagePath, "--confirm", "--components=3-test-deprecated-timeout-scripts") + stdOut, stdErr, err = e2e.Zarf(t, "package", "deploy", testPackagePath, "--confirm", "--components=3-test-deprecated-timeout-scripts") require.Error(t, err, stdOut, stdErr) } @@ -79,24 +79,24 @@ func TestDeprecatedSetAndPackageVariables(t *testing.T) { outputFlag := fmt.Sprintf("-o=%s", testPackageDirPath) // Check that the command still errors out - stdOut, stdErr, err := e2e.Zarf("package", "create", testPackageDirPath, outputFlag, "--confirm") + stdOut, stdErr, err := e2e.Zarf(t, "package", "create", testPackageDirPath, outputFlag, "--confirm") require.Error(t, err, stdOut, stdErr) require.Contains(t, stdErr, "template \"ECHO\" must be '--set'") // Check that the command displays a warning on create - stdOut, stdErr, err = e2e.Zarf("package", "create", testPackageDirPath, outputFlag, "--confirm", "--set", "ECHO=Zarf-The-Axolotl") + stdOut, stdErr, err = e2e.Zarf(t, "package", "create", testPackageDirPath, outputFlag, "--confirm", "--set", "ECHO=Zarf-The-Axolotl") defer e2e.CleanFiles(testPackagePath) require.NoError(t, err, stdOut, stdErr) require.Contains(t, stdErr, "Component '1-test-deprecated-set-variable' is using setVariable") require.Contains(t, stdErr, "deprecated syntax ###ZARF_PKG_VAR_ECHO###") // 1. Deploy the setVariable action that should pass and output the variable - stdOut, stdErr, err = e2e.Zarf("package", "deploy", testPackagePath, "--confirm", "--components=1-test-deprecated-set-variable") + stdOut, stdErr, err = e2e.Zarf(t, "package", "deploy", testPackagePath, "--confirm", "--components=1-test-deprecated-set-variable") require.NoError(t, err, stdOut, stdErr) require.Contains(t, stdErr, "Hello from Hello Kitteh") // 2. Deploy the setVariable action that should pass and output the variable - stdOut, stdErr, err = e2e.Zarf("package", "deploy", testPackagePath, "--confirm", "--components=2-test-deprecated-pkg-var") + stdOut, stdErr, err = e2e.Zarf(t, "package", "deploy", testPackagePath, "--confirm", "--components=2-test-deprecated-pkg-var") require.NoError(t, err, stdOut, stdErr) require.Contains(t, stdErr, "Zarf-The-Axolotl") } diff --git a/src/test/e2e/04_create_templating_test.go b/src/test/e2e/04_create_templating_test.go index a77ba1abd6..d69839547b 100644 --- a/src/test/e2e/04_create_templating_test.go +++ b/src/test/e2e/04_create_templating_test.go @@ -24,15 +24,15 @@ func TestCreateTemplating(t *testing.T) { pkgName := fmt.Sprintf("zarf-package-variables-%s.tar.zst", e2e.Arch) // Test that not specifying a package variable results in an error - _, stdErr, _ := e2e.Zarf("package", "create", "examples/variables", "--confirm") + _, stdErr, _ := e2e.Zarf(t, "package", "create", "examples/variables", "--confirm") expectedOutString := "variable 'NGINX_VERSION' must be '--set' when using the '--confirm' flag" require.Contains(t, stdErr, "", expectedOutString) // Test a simple package variable example with `--set` (will fail to pull an image if this is not set correctly) - stdOut, stdErr, err := e2e.Zarf("package", "create", "examples/variables", "--set", "NGINX_VERSION=1.23.3", "--confirm") + stdOut, stdErr, err := e2e.Zarf(t, "package", "create", "examples/variables", "--set", "NGINX_VERSION=1.23.3", "--confirm") require.NoError(t, err, stdOut, stdErr) - stdOut, stdErr, err = e2e.Zarf("t", "archiver", "decompress", pkgName, decompressPath, "--unarchive-all") + stdOut, stdErr, err = e2e.Zarf(t, "t", "archiver", "decompress", pkgName, decompressPath, "--unarchive-all") require.NoError(t, err, stdOut, stdErr) // Check that the constant in the zarf.yaml is replaced correctly @@ -41,14 +41,14 @@ func TestCreateTemplating(t *testing.T) { require.Contains(t, string(builtConfig), "name: NGINX_VERSION\n value: 1.23.3") // Test that files and file folders template and handle SBOMs correctly - stdOut, stdErr, err = e2e.Zarf("package", "create", "src/test/packages/04-file-folders-templating-sbom/", "--sbom-out", sbomPath, "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "create", "src/test/packages/04-file-folders-templating-sbom/", "--sbom-out", sbomPath, "--confirm") require.NoError(t, err, stdOut, stdErr) require.Contains(t, stdErr, "Creating SBOMs for 0 images and 2 components with files.") fileFoldersPkgName := fmt.Sprintf("zarf-package-file-folders-templating-sbom-%s.tar.zst", e2e.Arch) // Deploy the package and look for the variables in the output - stdOut, stdErr, err = e2e.Zarf("package", "deploy", fileFoldersPkgName, "--set", "DOGGO=doggy", "--set", "KITTEH=meowza", "--set", "PANDA=pandemonium", "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "deploy", fileFoldersPkgName, "--set", "DOGGO=doggy", "--set", "KITTEH=meowza", "--set", "PANDA=pandemonium", "--confirm") require.NoError(t, err, stdOut, stdErr) require.Contains(t, stdErr, "A doggy barks!") require.Contains(t, stdErr, " - meowza") diff --git a/src/test/e2e/05_tarball_test.go b/src/test/e2e/05_tarball_test.go index ab91e06e4d..cac1a07582 100644 --- a/src/test/e2e/05_tarball_test.go +++ b/src/test/e2e/05_tarball_test.go @@ -30,7 +30,7 @@ func TestMultiPartPackage(t *testing.T) { e2e.CleanFiles(deployPath, outputFile) // Create the package with a max size of 20MB - stdOut, stdErr, err := e2e.Zarf("package", "create", createPath, "--max-package-size=20", "--confirm") + stdOut, stdErr, err := e2e.Zarf(t, "package", "create", createPath, "--max-package-size=20", "--confirm") require.NoError(t, err, stdOut, stdErr) parts, err := filepath.Glob("zarf-package-multi-part-*") @@ -53,7 +53,7 @@ func TestMultiPartPackage(t *testing.T) { require.Equal(t, 3, pkgData.Count) fmt.Printf("%#v", pkgData) - stdOut, stdErr, err = e2e.Zarf("package", "deploy", deployPath, "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "deploy", deployPath, "--confirm") require.NoError(t, err, stdOut, stdErr) // Verify the package was deployed @@ -87,10 +87,10 @@ func TestReproducibleTarballs(t *testing.T) { unpack2 = filepath.Join(tmp, "unpack2") ) - stdOut, stdErr, err := e2e.Zarf("package", "create", createPath, "--confirm", "--output", tmp) + stdOut, stdErr, err := e2e.Zarf(t, "package", "create", createPath, "--confirm", "--output", tmp) require.NoError(t, err, stdOut, stdErr) - stdOut, stdErr, err = e2e.Zarf("tools", "archiver", "decompress", tb, unpack1) + stdOut, stdErr, err = e2e.Zarf(t, "tools", "archiver", "decompress", tb, unpack1) require.NoError(t, err, stdOut, stdErr) var pkg1 types.ZarfPackage @@ -99,10 +99,10 @@ func TestReproducibleTarballs(t *testing.T) { e2e.CleanFiles(unpack1, tb) - stdOut, stdErr, err = e2e.Zarf("package", "create", createPath, "--confirm", "--output", tmp) + stdOut, stdErr, err = e2e.Zarf(t, "package", "create", createPath, "--confirm", "--output", tmp) require.NoError(t, err, stdOut, stdErr) - stdOut, stdErr, err = e2e.Zarf("tools", "archiver", "decompress", tb, unpack2) + stdOut, stdErr, err = e2e.Zarf(t, "tools", "archiver", "decompress", tb, unpack2) require.NoError(t, err, stdOut, stdErr) var pkg2 types.ZarfPackage diff --git a/src/test/e2e/06_create_sbom_test.go b/src/test/e2e/06_create_sbom_test.go index d040ba2e05..75b1b309ff 100644 --- a/src/test/e2e/06_create_sbom_test.go +++ b/src/test/e2e/06_create_sbom_test.go @@ -20,7 +20,7 @@ func TestCreateSBOM(t *testing.T) { pkgName := fmt.Sprintf("zarf-package-dos-games-%s-1.0.0.tar.zst", e2e.Arch) - stdOut, stdErr, err := e2e.Zarf("package", "create", "examples/dos-games", "--sbom-out", sbomPath, "--confirm") + stdOut, stdErr, err := e2e.Zarf(t, "package", "create", "examples/dos-games", "--sbom-out", sbomPath, "--confirm") require.NoError(t, err, stdOut, stdErr) require.Contains(t, stdErr, "Creating SBOMs for 1 images and 0 components with files.") // Test that the game package generates the SBOMs we expect (images only) @@ -31,7 +31,7 @@ func TestCreateSBOM(t *testing.T) { // Clean the SBOM path so it is force to be recreated e2e.CleanFiles(sbomPath) - stdOut, stdErr, err = e2e.Zarf("package", "inspect", pkgName, "--sbom-out", sbomPath) + stdOut, stdErr, err = e2e.Zarf(t, "package", "inspect", pkgName, "--sbom-out", sbomPath) require.NoError(t, err, stdOut, stdErr) // Test that the game package generates the SBOMs we expect (images only) _, err = os.ReadFile(filepath.Join(sbomPath, "dos-games", "sbom-viewer-docker.io_defenseunicorns_zarf-game_multi-tile-dark.html")) @@ -41,17 +41,17 @@ func TestCreateSBOM(t *testing.T) { _, err = os.ReadFile(filepath.Join(sbomPath, "dos-games", "docker.io_defenseunicorns_zarf-game_multi-tile-dark.json")) require.NoError(t, err) - stdOut, _, err = e2e.Zarf("package", "inspect", pkgName, "--list-images") + stdOut, _, err = e2e.Zarf(t, "package", "inspect", pkgName, "--list-images") require.NoError(t, err) require.Equal(t, "- defenseunicorns/zarf-game:multi-tile-dark\n", stdOut) // Pull the current zarf binary version to find the corresponding init package - version, stdErr, err := e2e.Zarf("version") + version, stdErr, err := e2e.Zarf(t, "version") require.NoError(t, err, version, stdErr) initName := fmt.Sprintf("build/zarf-init-%s-%s.tar.zst", e2e.Arch, strings.TrimSpace(version)) - stdOut, stdErr, err = e2e.Zarf("package", "inspect", initName, "--sbom-out", sbomPath) + stdOut, stdErr, err = e2e.Zarf(t, "package", "inspect", initName, "--sbom-out", sbomPath) require.NoError(t, err, stdOut, stdErr) // Test that we preserve the filepath _, err = os.ReadFile(filepath.Join(sbomPath, "dos-games", "sbom-viewer-docker.io_defenseunicorns_zarf-game_multi-tile-dark.html")) diff --git a/src/test/e2e/07_create_git_test.go b/src/test/e2e/07_create_git_test.go index af475a3593..7a08043c1f 100644 --- a/src/test/e2e/07_create_git_test.go +++ b/src/test/e2e/07_create_git_test.go @@ -21,7 +21,7 @@ func TestCreateGit(t *testing.T) { // Extract the test package. path := fmt.Sprintf("build/zarf-package-git-data-%s-0.0.1.tar.zst", e2e.Arch) - stdOut, stdErr, err := e2e.Zarf("tools", "archiver", "decompress", path, extractDir, "--unarchive-all") + stdOut, stdErr, err := e2e.Zarf(t, "tools", "archiver", "decompress", path, extractDir, "--unarchive-all") require.NoError(t, err, stdOut, stdErr) defer e2e.CleanFiles(extractDir) diff --git a/src/test/e2e/08_create_differential_test.go b/src/test/e2e/08_create_differential_test.go index d692d1b9cc..97aaf40de2 100644 --- a/src/test/e2e/08_create_differential_test.go +++ b/src/test/e2e/08_create_differential_test.go @@ -28,17 +28,17 @@ func TestCreateDifferential(t *testing.T) { differentialFlag := fmt.Sprintf("--differential=%s", packageName) // Build the package a first time - stdOut, stdErr, err := e2e.Zarf("package", "create", packagePath, "--set=PACKAGE_VERSION=v0.25.0", "--confirm") + stdOut, stdErr, err := e2e.Zarf(t, "package", "create", packagePath, "--set=PACKAGE_VERSION=v0.25.0", "--confirm") require.NoError(t, err, stdOut, stdErr) defer e2e.CleanFiles(packageName) // Build the differential package without changing the version - _, stdErr, err = e2e.Zarf("package", "create", packagePath, "--set=PACKAGE_VERSION=v0.25.0", differentialFlag, "--confirm") + _, stdErr, err = e2e.Zarf(t, "package", "create", packagePath, "--set=PACKAGE_VERSION=v0.25.0", differentialFlag, "--confirm") require.Error(t, err, "zarf package create should have errored when a differential package was being created without updating the package version number") require.Contains(t, e2e.StripMessageFormatting(stdErr), lang.PkgCreateErrDifferentialSameVersion) // Build the differential package - stdOut, stdErr, err = e2e.Zarf("package", "create", packagePath, "--set=PACKAGE_VERSION=v0.26.0", differentialFlag, "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "create", packagePath, "--set=PACKAGE_VERSION=v0.26.0", differentialFlag, "--confirm") require.NoError(t, err, stdOut, stdErr) defer e2e.CleanFiles(differentialPackageName) diff --git a/src/test/e2e/09_component_compose_test.go b/src/test/e2e/09_component_compose_test.go index 176b96207e..37a905456a 100644 --- a/src/test/e2e/09_component_compose_test.go +++ b/src/test/e2e/09_component_compose_test.go @@ -45,7 +45,7 @@ func (suite *CompositionSuite) TearDownSuite() { func (suite *CompositionSuite) Test_0_ComposabilityExample() { suite.T().Log("E2E: Package Compose Example") - _, stdErr, err := e2e.Zarf("package", "create", composeExample, "-o", "build", "--no-color", "--confirm") + _, stdErr, err := e2e.Zarf(suite.T(), "package", "create", composeExample, "-o", "build", "--no-color", "--confirm") suite.NoError(err) // Ensure that common names merge @@ -71,7 +71,7 @@ func (suite *CompositionSuite) Test_0_ComposabilityExample() { func (suite *CompositionSuite) Test_1_FullComposability() { suite.T().Log("E2E: Full Package Compose") - _, stdErr, err := e2e.Zarf("package", "create", composeTest, "-o", "build", "--no-color", "--confirm") + _, stdErr, err := e2e.Zarf(suite.T(), "package", "create", composeTest, "-o", "build", "--no-color", "--confirm") suite.NoError(err) // Ensure that names merge and that composition is added appropriately @@ -183,7 +183,7 @@ func (suite *CompositionSuite) Test_1_FullComposability() { func (suite *CompositionSuite) Test_2_ComposabilityBadLocalOS() { suite.T().Log("E2E: Package Compose Example") - _, stdErr, err := e2e.Zarf("package", "create", composeTestBadLocalOS, "-o", "build", "--no-color", "--confirm") + _, 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") } diff --git a/src/test/e2e/10_component_flavor_test.go b/src/test/e2e/10_component_flavor_test.go index 3ae8cfc234..a1f748bd22 100644 --- a/src/test/e2e/10_component_flavor_test.go +++ b/src/test/e2e/10_component_flavor_test.go @@ -46,7 +46,7 @@ func (suite *FlavorSuite) TearDownSuite() { func (suite *FlavorSuite) Test_0_FlavorExample() { suite.T().Log("E2E: Package Flavor Example") - _, stdErr, err := e2e.Zarf("package", "create", flavorExample, "-o", "build", "--flavor", "oracle-cookie-crunch", "--no-color", "--confirm") + _, stdErr, err := e2e.Zarf(suite.T(), "package", "create", flavorExample, "-o", "build", "--flavor", "oracle-cookie-crunch", "--no-color", "--confirm") suite.NoError(err) // Ensure that the oracle image is included @@ -64,7 +64,7 @@ func (suite *FlavorSuite) Test_0_FlavorExample() { func (suite *FlavorSuite) Test_1_FlavorArchFiltering() { suite.T().Log("E2E: Package Flavor + Arch Filtering") - _, stdErr, err := e2e.Zarf("package", "create", flavorTest, "-o", "build", "--flavor", "vanilla", "-a", "amd64", "--no-color", "--confirm") + _, stdErr, err := e2e.Zarf(suite.T(), "package", "create", flavorTest, "-o", "build", "--flavor", "vanilla", "-a", "amd64", "--no-color", "--confirm") suite.NoError(err) // Ensure that the initial filter was applied @@ -82,7 +82,7 @@ func (suite *FlavorSuite) Test_1_FlavorArchFiltering() { suite.NotContains(stdErr, `chocolate-amd`) suite.NotContains(stdErr, `chocolate-arm`) - _, stdErr, err = e2e.Zarf("package", "create", flavorTest, "-o", "build", "--flavor", "chocolate", "-a", "amd64", "--no-color", "--confirm") + _, stdErr, err = e2e.Zarf(suite.T(), "package", "create", flavorTest, "-o", "build", "--flavor", "chocolate", "-a", "amd64", "--no-color", "--confirm") suite.NoError(err) // Ensure that the initial filter was applied @@ -100,7 +100,7 @@ func (suite *FlavorSuite) Test_1_FlavorArchFiltering() { suite.NotContains(stdErr, `vanilla-amd`) suite.NotContains(stdErr, `chocolate-arm`) - _, stdErr, err = e2e.Zarf("package", "create", flavorTest, "-o", "build", "--flavor", "chocolate", "-a", "arm64", "--no-color", "--confirm") + _, stdErr, err = e2e.Zarf(suite.T(), "package", "create", flavorTest, "-o", "build", "--flavor", "chocolate", "-a", "arm64", "--no-color", "--confirm") suite.NoError(err) // Ensure that the initial filter was applied diff --git a/src/test/e2e/11_oci_pull_inspect_test.go b/src/test/e2e/11_oci_pull_inspect_test.go index 98e5e4ff52..a992a50f55 100644 --- a/src/test/e2e/11_oci_pull_inspect_test.go +++ b/src/test/e2e/11_oci_pull_inspect_test.go @@ -45,7 +45,7 @@ func (suite *PullInspectTestSuite) Test_0_Pull() { ref := fmt.Sprintf("oci://ghcr.io/zarf-dev/packages/dos-games:1.0.0-%s", e2e.Arch) // Pull the package via OCI. - stdOut, stdErr, err := e2e.Zarf("package", "pull", ref) + stdOut, stdErr, err := e2e.Zarf(suite.T(), "package", "pull", ref) suite.NoError(err, stdOut, stdErr) suite.Contains(stdErr, fmt.Sprintf("Pulling %q", ref)) suite.Contains(stdErr, "Validating full package checksums") @@ -55,13 +55,13 @@ func (suite *PullInspectTestSuite) Test_0_Pull() { // Verify the package was pulled correctly. suite.FileExists(out) - stdOut, stdErr, err = e2e.Zarf("package", "inspect", out, "--key", "https://zarf.dev/cosign.pub", "--sbom-out", sbomTmp) + stdOut, stdErr, err = e2e.Zarf(suite.T(), "package", "inspect", out, "--key", "https://zarf.dev/cosign.pub", "--sbom-out", sbomTmp) suite.NoError(err, stdOut, stdErr) suite.Contains(stdErr, "Validating SBOM checksums") suite.Contains(stdErr, "Package signature validated!") // Test pull w/ bad ref. - stdOut, stdErr, err = e2e.Zarf("package", "pull", "oci://"+badPullInspectRef.String(), "--insecure") + stdOut, stdErr, err = e2e.Zarf(suite.T(), "package", "pull", "oci://"+badPullInspectRef.String(), "--insecure") suite.Error(err, stdOut, stdErr) } @@ -69,13 +69,13 @@ func (suite *PullInspectTestSuite) Test_1_Remote_Inspect() { suite.T().Log("E2E: Package Inspect oci://") // Test inspect w/ bad ref. - _, stdErr, err := e2e.Zarf("package", "inspect", "oci://"+badPullInspectRef.String(), "--insecure") + _, stdErr, err := e2e.Zarf(suite.T(), "package", "inspect", "oci://"+badPullInspectRef.String(), "--insecure") suite.Error(err, stdErr) // Test inspect on a public package. // NOTE: This also makes sure that Zarf does not attempt auth when inspecting a public package. ref := fmt.Sprintf("oci://ghcr.io/zarf-dev/packages/dos-games:1.0.0-%s", e2e.Arch) - _, stdErr, err = e2e.Zarf("package", "inspect", ref) + _, stdErr, err = e2e.Zarf(suite.T(), "package", "inspect", ref) suite.NoError(err, stdErr) } diff --git a/src/test/e2e/12_lint_test.go b/src/test/e2e/12_lint_test.go index a577bb397f..6b7239a17a 100644 --- a/src/test/e2e/12_lint_test.go +++ b/src/test/e2e/12_lint_test.go @@ -20,7 +20,7 @@ func TestLint(t *testing.T) { t.Log("E2E: Test lint on schema success") // This runs lint on the zarf.yaml in the base directory of the repo - _, _, err := e2e.Zarf("dev", "lint") + _, _, err := e2e.Zarf(t, "dev", "lint") require.NoError(t, err, "Expect no error here because the yaml file is following schema") }) @@ -30,7 +30,7 @@ func TestLint(t *testing.T) { testPackagePath := filepath.Join("src", "test", "packages", "12-lint") configPath := filepath.Join(testPackagePath, "zarf-config.toml") os.Setenv("ZARF_CONFIG", configPath) - _, stderr, err := e2e.Zarf("dev", "lint", testPackagePath, "-f", "good-flavor") + _, stderr, err := e2e.Zarf(t, "dev", "lint", testPackagePath, "-f", "good-flavor") os.Unsetenv("ZARF_CONFIG") require.Error(t, err, "Require an exit code since there was warnings / errors") strippedStderr := e2e.StripMessageFormatting(stderr) diff --git a/src/test/e2e/13_find_images_test.go b/src/test/e2e/13_find_images_test.go index 27e7bbe715..a161ed15f6 100644 --- a/src/test/e2e/13_find_images_test.go +++ b/src/test/e2e/13_find_images_test.go @@ -18,11 +18,11 @@ func TestFindImages(t *testing.T) { t.Run("zarf prepare find-images", func(t *testing.T) { t.Parallel() // Test `zarf prepare find-images` for a remote asset - stdOut, stdErr, err := e2e.Zarf("prepare", "find-images", "examples/helm-charts") + stdOut, stdErr, err := e2e.Zarf(t, "prepare", "find-images", "examples/helm-charts") require.NoError(t, err, stdOut, stdErr) require.Contains(t, stdOut, "ghcr.io/stefanprodan/podinfo:6.4.0", "The chart image should be found by Zarf") // Test `zarf prepare find-images` with a chart that uses helm annotations - stdOut, stdErr, err = e2e.Zarf("prepare", "find-images", "src/test/packages/00-helm-annotations") + stdOut, stdErr, err = e2e.Zarf(t, "prepare", "find-images", "src/test/packages/00-helm-annotations") require.NoError(t, err, stdOut, stdErr) require.Contains(t, stdOut, "registry1.dso.mil/ironbank/opensource/istio/pilot:1.17.2", "The pilot image should be found by Zarf") }) @@ -34,13 +34,13 @@ func TestFindImages(t *testing.T) { // Test `zarf prepare find-images` on a chart that has a `kubeVersion` declaration greater than the Helm default (v1.20.0) // This should pass because we build Zarf specifying the kubeVersion value from the kubernetes client-go library instead - stdOut, stdErr, err := e2e.Zarf("prepare", "find-images", "src/test/packages/00-kube-version-override") + stdOut, stdErr, err := e2e.Zarf(t, "prepare", "find-images", "src/test/packages/00-kube-version-override") require.NoError(t, err, stdOut, stdErr) require.Contains(t, stdOut, controllerImageWithTag, "The chart image should be found by Zarf") require.Contains(t, stdOut, controlImageWithSignature, "The image signature should be found by Zarf") // Test `zarf prepare find-images` with `--kube-version` specified and less than than the declared minimum (v1.21.0) - stdOut, stdErr, err = e2e.Zarf("prepare", "find-images", "--kube-version=v1.20.0", "src/test/packages/00-kube-version-override") + 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") @@ -51,14 +51,14 @@ func TestFindImages(t *testing.T) { registry := "coolregistry.gov" agentTag := "test" - stdOut, _, err := e2e.Zarf("prepare", "find-images", ".", "--registry-url", registry, "--create-set", fmt.Sprintf("agent_image_tag=%s", agentTag)) + stdOut, _, err := e2e.Zarf(t, "prepare", "find-images", ".", "--registry-url", registry, "--create-set", fmt.Sprintf("agent_image_tag=%s", agentTag)) require.NoError(t, err) internalRegistryImage := fmt.Sprintf("%s/%s:%s", registry, "zarf-dev/zarf/agent", agentTag) require.Contains(t, stdOut, internalRegistryImage, "registry image should be found with registry url") require.Contains(t, stdOut, "busybox:latest", "Busybox image should be found as long as helm chart doesn't error") path := filepath.Join("src", "test", "packages", "00-find-images-with-vars") - stdOut, _, err = e2e.Zarf("prepare", "find-images", path, "--deploy-set", "BUSYBOX_IMAGE=busybox:earliest") + stdOut, _, err = e2e.Zarf(t, "prepare", "find-images", path, "--deploy-set", "BUSYBOX_IMAGE=busybox:earliest") require.NoError(t, err) require.Contains(t, stdOut, "nginx:latest", "Manifests aren't interpreting vars") require.Contains(t, stdOut, "busybox:earliest", "Values files aren't interpreting vars") @@ -69,7 +69,7 @@ func TestFindImages(t *testing.T) { testPackagePath := filepath.Join("examples", "wordpress") sets := []string{"WORDPRESS_USERNAME=zarf", "WORDPRESS_PASSWORD=fake", "WORDPRESS_EMAIL=hello@defenseunicorns.com", "WORDPRESS_FIRST_NAME=zarf", "WORDPRESS_LAST_NAME=zarf", "WORDPRESS_BLOG_NAME=blog"} deploysSet := strings.Join(sets, ",") - stdOut, _, err := e2e.Zarf("dev", "find-images", testPackagePath, "--why", "docker.io/bitnami/apache-exporter:0.13.3-debian-11-r2", "--deploy-set", deploysSet) + stdOut, _, err := e2e.Zarf(t, "dev", "find-images", testPackagePath, "--why", "docker.io/bitnami/apache-exporter:0.13.3-debian-11-r2", "--deploy-set", deploysSet) require.NoError(t, err) require.Contains(t, stdOut, "component: wordpress") require.Contains(t, stdOut, "chart: wordpress") @@ -80,7 +80,7 @@ func TestFindImages(t *testing.T) { t.Parallel() testPackagePath := filepath.Join("examples", "manifests") - stdOut, _, err := e2e.Zarf("dev", "find-images", testPackagePath, "--why", "httpd:alpine3.18") + stdOut, _, err := e2e.Zarf(t, "dev", "find-images", testPackagePath, "--why", "httpd:alpine3.18") require.NoError(t, err) require.Contains(t, stdOut, "component: httpd-local") require.Contains(t, stdOut, "manifest: simple-httpd-deployment") diff --git a/src/test/e2e/13_zarf_package_generate_test.go b/src/test/e2e/13_zarf_package_generate_test.go index 305141739c..9d73747210 100644 --- a/src/test/e2e/13_zarf_package_generate_test.go +++ b/src/test/e2e/13_zarf_package_generate_test.go @@ -24,7 +24,7 @@ func TestZarfDevGenerate(t *testing.T) { version := "6.4.0" gitPath := "charts/podinfo" - stdOut, stdErr, err := e2e.Zarf("dev", "generate", "podinfo", "--url", url, "--version", version, "--gitPath", gitPath, "--output-directory", tmpDir) + stdOut, stdErr, err := e2e.Zarf(t, "dev", "generate", "podinfo", "--url", url, "--version", version, "--gitPath", gitPath, "--output-directory", tmpDir) require.NoError(t, err, stdOut, stdErr) zarfPackage := types.ZarfPackage{} diff --git a/src/test/e2e/14_create_sha_index_test.go b/src/test/e2e/14_create_sha_index_test.go index 59993c5874..eb2849975a 100644 --- a/src/test/e2e/14_create_sha_index_test.go +++ b/src/test/e2e/14_create_sha_index_test.go @@ -32,7 +32,7 @@ func TestCreateIndexShaErrors(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - _, stderr, err := e2e.Zarf("package", "create", tc.packagePath, "--confirm") + _, stderr, err := e2e.Zarf(t, "package", "create", tc.packagePath, "--confirm") require.Error(t, err) require.Contains(t, stderr, tc.expectedImageInStderr) }) diff --git a/src/test/e2e/20_zarf_init_test.go b/src/test/e2e/20_zarf_init_test.go index 572cedea0f..6f788ef3b1 100644 --- a/src/test/e2e/20_zarf_init_test.go +++ b/src/test/e2e/20_zarf_init_test.go @@ -37,25 +37,25 @@ func TestZarfInit(t *testing.T) { if runtime.GOOS == "linux" { // Build init package with different arch than the cluster arch. - stdOut, stdErr, err := e2e.Zarf("package", "create", "src/test/packages/20-mismatched-arch-init", "--architecture", mismatchedArch, "--confirm") + stdOut, stdErr, err := e2e.Zarf(t, "package", "create", "src/test/packages/20-mismatched-arch-init", "--architecture", mismatchedArch, "--confirm") require.NoError(t, err, stdOut, stdErr) // Check that `zarf init` returns an error because of the mismatched architectures. // We need to use the --architecture flag here to force zarf to find the package. - _, stdErr, err = e2e.Zarf("init", "--architecture", mismatchedArch, "--components=k3s", "--confirm") + _, stdErr, err = e2e.Zarf(t, "init", "--architecture", mismatchedArch, "--components=k3s", "--confirm") require.Error(t, err, stdErr) require.Contains(t, stdErr, expectedErrorMessage) } if !e2e.ApplianceMode { // throw a pending pod into the cluster to ensure we can properly ignore them when selecting images - _, _, err := e2e.Kubectl("apply", "-f", "https://raw.githubusercontent.com/kubernetes/website/main/content/en/examples/pods/pod-with-node-affinity.yaml") + _, _, err := e2e.Kubectl(t, "apply", "-f", "https://raw.githubusercontent.com/kubernetes/website/main/content/en/examples/pods/pod-with-node-affinity.yaml") require.NoError(t, err) } // Check for any old secrets to ensure that they don't get saved in the init log oldState := types.ZarfState{} - base64State, _, err := e2e.Kubectl("get", "secret", "zarf-state", "-n", "zarf", "-o", "jsonpath={.data.state}") + base64State, _, err := e2e.Kubectl(t, "get", "secret", "zarf-state", "-n", "zarf", "-o", "jsonpath={.data.state}") if err == nil { oldStateJSON, err := base64.StdEncoding.DecodeString(base64State) require.NoError(t, err) @@ -64,7 +64,7 @@ func TestZarfInit(t *testing.T) { } // run `zarf init` - _, initStdErr, err := e2e.Zarf("init", "--components="+initComponents, "--nodeport", "31337", "-l", "trace", "--confirm") + _, initStdErr, err := e2e.Zarf(t, "init", "--components="+initComponents, "--nodeport", "31337", "-l", "trace", "--confirm") require.NoError(t, err) require.Contains(t, initStdErr, "an inventory of all software contained in this package") require.NotContains(t, initStdErr, "This package does NOT contain an SBOM. If you require an SBOM, please contact the creator of this package to request a version that includes an SBOM.") @@ -73,7 +73,7 @@ func TestZarfInit(t *testing.T) { // Verify that any state secrets were not included in the log state := types.ZarfState{} - base64State, _, err = e2e.Kubectl("get", "secret", "zarf-state", "-n", "zarf", "-o", "jsonpath={.data.state}") + base64State, _, err = e2e.Kubectl(t, "get", "secret", "zarf-state", "-n", "zarf", "-o", "jsonpath={.data.state}") require.NoError(t, err) stateJSON, err := base64.StdEncoding.DecodeString(base64State) require.NoError(t, err) @@ -83,18 +83,18 @@ func TestZarfInit(t *testing.T) { if e2e.ApplianceMode { // make sure that we upgraded `k3s` correctly and are running the correct version - this should match that found in `packages/distros/k3s` - kubeletVersion, _, err := e2e.Kubectl("get", "nodes", "-o", "jsonpath={.items[0].status.nodeInfo.kubeletVersion}") + kubeletVersion, _, err := e2e.Kubectl(t, "get", "nodes", "-o", "jsonpath={.items[0].status.nodeInfo.kubeletVersion}") require.NoError(t, err) require.Contains(t, kubeletVersion, "v1.28.4+k3s2") } // Check that the registry is running on the correct NodePort - stdOut, _, err := e2e.Kubectl("get", "service", "-n", "zarf", "zarf-docker-registry", "-o=jsonpath='{.spec.ports[*].nodePort}'") + stdOut, _, err := e2e.Kubectl(t, "get", "service", "-n", "zarf", "zarf-docker-registry", "-o=jsonpath='{.spec.ports[*].nodePort}'") require.NoError(t, err) require.Contains(t, stdOut, "31337") // Check that the registry is running with the correct scale down policy - stdOut, _, err = e2e.Kubectl("get", "hpa", "-n", "zarf", "zarf-docker-registry", "-o=jsonpath='{.spec.behavior.scaleDown.selectPolicy}'") + stdOut, _, err = e2e.Kubectl(t, "get", "hpa", "-n", "zarf", "zarf-docker-registry", "-o=jsonpath='{.spec.behavior.scaleDown.selectPolicy}'") require.NoError(t, err) require.Contains(t, stdOut, "Min") @@ -104,8 +104,8 @@ func TestZarfInit(t *testing.T) { verifyZarfServiceLabels(t) // Special sizing-hacking for reducing resources where Kind + CI eats a lot of free cycles (ignore errors) - _, _, _ = e2e.Kubectl("scale", "deploy", "-n", "kube-system", "coredns", "--replicas=1") - _, _, _ = e2e.Kubectl("scale", "deploy", "-n", "zarf", "agent-hook", "--replicas=1") + _, _, _ = e2e.Kubectl(t, "scale", "deploy", "-n", "kube-system", "coredns", "--replicas=1") + _, _, _ = e2e.Kubectl(t, "scale", "deploy", "-n", "zarf", "agent-hook", "--replicas=1") } func checkLogForSensitiveState(t *testing.T, logText string, zarfState types.ZarfState) { @@ -129,7 +129,7 @@ func verifyZarfNamespaceLabels(t *testing.T) { t.Helper() expectedLabels := `'{"app.kubernetes.io/managed-by":"zarf","kubernetes.io/metadata.name":"zarf"}'` - actualLabels, _, err := e2e.Kubectl("get", "ns", "zarf", "-o=jsonpath='{.metadata.labels}'") + actualLabels, _, err := e2e.Kubectl(t, "get", "ns", "zarf", "-o=jsonpath='{.metadata.labels}'") require.NoError(t, err) require.Equal(t, expectedLabels, actualLabels) } @@ -139,19 +139,19 @@ func verifyZarfSecretLabels(t *testing.T) { // zarf state expectedLabels := `'{"app.kubernetes.io/managed-by":"zarf"}'` - actualLabels, _, err := e2e.Kubectl("get", "-n=zarf", "secret", "zarf-state", "-o=jsonpath='{.metadata.labels}'") + actualLabels, _, err := e2e.Kubectl(t, "get", "-n=zarf", "secret", "zarf-state", "-o=jsonpath='{.metadata.labels}'") require.NoError(t, err) require.Equal(t, expectedLabels, actualLabels) // init package secret expectedLabels = `'{"app.kubernetes.io/managed-by":"zarf","package-deploy-info":"init"}'` - actualLabels, _, err = e2e.Kubectl("get", "-n=zarf", "secret", "zarf-package-init", "-o=jsonpath='{.metadata.labels}'") + actualLabels, _, err = e2e.Kubectl(t, "get", "-n=zarf", "secret", "zarf-package-init", "-o=jsonpath='{.metadata.labels}'") require.NoError(t, err) require.Equal(t, expectedLabels, actualLabels) // registry expectedLabels = `'{"app.kubernetes.io/managed-by":"zarf"}'` - actualLabels, _, err = e2e.Kubectl("get", "-n=zarf", "secret", "private-registry", "-o=jsonpath='{.metadata.labels}'") + actualLabels, _, err = e2e.Kubectl(t, "get", "-n=zarf", "secret", "private-registry", "-o=jsonpath='{.metadata.labels}'") require.NoError(t, err) require.Equal(t, expectedLabels, actualLabels) @@ -160,13 +160,13 @@ func verifyZarfSecretLabels(t *testing.T) { // this secret does not have the managed by zarf label // because it is deployed as a helm chart rather than generated in Go code. expectedLabels = `'{"app.kubernetes.io/managed-by":"Helm"}'` - actualLabels, _, err = e2e.Kubectl("get", "-n=zarf", "secret", "agent-hook-tls", "-o=jsonpath='{.metadata.labels}'") + actualLabels, _, err = e2e.Kubectl(t, "get", "-n=zarf", "secret", "agent-hook-tls", "-o=jsonpath='{.metadata.labels}'") require.NoError(t, err) require.Equal(t, expectedLabels, actualLabels) // git server expectedLabels = `'{"app.kubernetes.io/managed-by":"zarf"}'` - actualLabels, _, err = e2e.Kubectl("get", "-n=zarf", "secret", "private-git-server", "-o=jsonpath='{.metadata.labels}'") + actualLabels, _, err = e2e.Kubectl(t, "get", "-n=zarf", "secret", "private-git-server", "-o=jsonpath='{.metadata.labels}'") require.NoError(t, err) require.Equal(t, expectedLabels, actualLabels) } @@ -175,24 +175,24 @@ func verifyZarfPodLabels(t *testing.T) { t.Helper() // registry - podHash, _, err := e2e.Kubectl("get", "-n=zarf", "--selector=app=docker-registry", "pods", `-o=jsonpath="{.items[0].metadata.labels['pod-template-hash']}"`) + podHash, _, err := e2e.Kubectl(t, "get", "-n=zarf", "--selector=app=docker-registry", "pods", `-o=jsonpath="{.items[0].metadata.labels['pod-template-hash']}"`) require.NoError(t, err) expectedLabels := fmt.Sprintf(`'{"app":"docker-registry","pod-template-hash":%s,"release":"zarf-docker-registry","zarf.dev/agent":"ignore"}'`, podHash) - actualLabels, _, err := e2e.Kubectl("get", "-n=zarf", "--selector=app=docker-registry", "pods", "-o=jsonpath='{.items[0].metadata.labels}'") + actualLabels, _, err := e2e.Kubectl(t, "get", "-n=zarf", "--selector=app=docker-registry", "pods", "-o=jsonpath='{.items[0].metadata.labels}'") require.NoError(t, err) require.Equal(t, expectedLabels, actualLabels) // agent - podHash, _, err = e2e.Kubectl("get", "-n=zarf", "--selector=app=agent-hook", "pods", `-o=jsonpath="{.items[0].metadata.labels['pod-template-hash']}"`) + podHash, _, err = e2e.Kubectl(t, "get", "-n=zarf", "--selector=app=agent-hook", "pods", `-o=jsonpath="{.items[0].metadata.labels['pod-template-hash']}"`) require.NoError(t, err) expectedLabels = fmt.Sprintf(`'{"app":"agent-hook","pod-template-hash":%s,"zarf.dev/agent":"ignore"}'`, podHash) - actualLabels, _, err = e2e.Kubectl("get", "-n=zarf", "--selector=app=agent-hook", "pods", "-o=jsonpath='{.items[0].metadata.labels}'") + actualLabels, _, err = e2e.Kubectl(t, "get", "-n=zarf", "--selector=app=agent-hook", "pods", "-o=jsonpath='{.items[0].metadata.labels}'") require.NoError(t, err) require.Equal(t, expectedLabels, actualLabels) // git server patchedLabel := `"zarf-agent":"patched"` - actualLabels, _, err = e2e.Kubectl("get", "-n=zarf", "--selector=app.kubernetes.io/instance=zarf-gitea ", "pods", "-o=jsonpath='{.items[0].metadata.labels}'") + actualLabels, _, err = e2e.Kubectl(t, "get", "-n=zarf", "--selector=app.kubernetes.io/instance=zarf-gitea ", "pods", "-o=jsonpath='{.items[0].metadata.labels}'") require.NoError(t, err) require.Contains(t, actualLabels, patchedLabel) } @@ -202,13 +202,13 @@ func verifyZarfServiceLabels(t *testing.T) { // registry expectedLabels := `'{"app.kubernetes.io/managed-by":"Helm","zarf.dev/connect-name":"registry"}'` - actualLabels, _, err := e2e.Kubectl("get", "-n=zarf", "service", "zarf-connect-registry", "-o=jsonpath='{.metadata.labels}'") + actualLabels, _, err := e2e.Kubectl(t, "get", "-n=zarf", "service", "zarf-connect-registry", "-o=jsonpath='{.metadata.labels}'") require.NoError(t, err) require.Equal(t, expectedLabels, actualLabels) // git server expectedLabels = `'{"app.kubernetes.io/managed-by":"Helm","zarf.dev/connect-name":"git"}'` - actualLabels, _, err = e2e.Kubectl("get", "-n=zarf", "service", "zarf-connect-git", "-o=jsonpath='{.metadata.labels}'") + actualLabels, _, err = e2e.Kubectl(t, "get", "-n=zarf", "service", "zarf-connect-git", "-o=jsonpath='{.metadata.labels}'") require.NoError(t, err) require.Equal(t, expectedLabels, actualLabels) } diff --git a/src/test/e2e/21_connect_creds_test.go b/src/test/e2e/21_connect_creds_test.go index b96d6c579b..e794de3f3e 100644 --- a/src/test/e2e/21_connect_creds_test.go +++ b/src/test/e2e/21_connect_creds_test.go @@ -24,17 +24,17 @@ type RegistryResponse struct { func TestConnectAndCreds(t *testing.T) { t.Log("E2E: Connect") - prevAgentSecretData, _, err := e2e.Kubectl("get", "secret", "agent-hook-tls", "-n", "zarf", "-o", "jsonpath={.data}") + prevAgentSecretData, _, err := e2e.Kubectl(t, "get", "secret", "agent-hook-tls", "-n", "zarf", "-o", "jsonpath={.data}") require.NoError(t, err) ctx := context.Background() connectToZarfServices(ctx, t) - stdOut, stdErr, err := e2e.Zarf("tools", "update-creds", "--confirm") + stdOut, stdErr, err := e2e.Zarf(t, "tools", "update-creds", "--confirm") require.NoError(t, err, stdOut, stdErr) - newAgentSecretData, _, err := e2e.Kubectl("get", "secret", "agent-hook-tls", "-n", "zarf", "-o", "jsonpath={.data}") + 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") @@ -81,7 +81,7 @@ func TestMetrics(t *testing.T) { func connectToZarfServices(ctx context.Context, t *testing.T) { // Make the Registry contains the images we expect - stdOut, stdErr, err := e2e.Zarf("tools", "registry", "catalog") + stdOut, stdErr, err := e2e.Zarf(t, "tools", "registry", "catalog") require.NoError(t, err, stdOut, stdErr) registryList := strings.Split(strings.Trim(stdOut, "\n "), "\n") @@ -93,13 +93,13 @@ func connectToZarfServices(ctx context.Context, t *testing.T) { require.Contains(t, stdOut, "library/registry") // Get the git credentials - stdOut, stdErr, err = e2e.Zarf("tools", "get-creds", "git") + stdOut, stdErr, err = e2e.Zarf(t, "tools", "get-creds", "git") require.NoError(t, err, stdOut, stdErr) gitPushPassword := strings.TrimSpace(stdOut) - stdOut, stdErr, err = e2e.Zarf("tools", "get-creds", "git-readonly") + stdOut, stdErr, err = e2e.Zarf(t, "tools", "get-creds", "git-readonly") require.NoError(t, err, stdOut, stdErr) gitPullPassword := strings.TrimSpace(stdOut) - stdOut, stdErr, err = e2e.Zarf("tools", "get-creds", "artifact") + stdOut, stdErr, err = e2e.Zarf(t, "tools", "get-creds", "artifact") require.NoError(t, err, stdOut, stdErr) gitArtifactToken := strings.TrimSpace(stdOut) diff --git a/src/test/e2e/22_git_and_gitops_test.go b/src/test/e2e/22_git_and_gitops_test.go index 559bb79e3f..363d5be1df 100644 --- a/src/test/e2e/22_git_and_gitops_test.go +++ b/src/test/e2e/22_git_and_gitops_test.go @@ -23,14 +23,14 @@ func TestGit(t *testing.T) { t.Log("E2E: Git") buildPath := filepath.Join("src", "test", "packages", "22-git-data") - stdOut, stdErr, err := e2e.Zarf("package", "create", buildPath, "-o=build", "--confirm") + stdOut, stdErr, err := e2e.Zarf(t, "package", "create", buildPath, "-o=build", "--confirm") require.NoError(t, err, stdOut, stdErr) path := fmt.Sprintf("build/zarf-package-git-data-test-%s-1.0.0.tar.zst", e2e.Arch) defer e2e.CleanFiles(path) // Deploy the git data example (with component globbing to test that as well) - stdOut, stdErr, err = e2e.Zarf("package", "deploy", path, "--components=full-repo,specific-*", "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "deploy", path, "--components=full-repo,specific-*", "--confirm") require.NoError(t, err, stdOut, stdErr) c, err := cluster.NewCluster() @@ -135,54 +135,54 @@ func waitFluxPodInfoDeployment(t *testing.T) { require.NoError(t, err) // Deploy the flux example and verify that it works path := fmt.Sprintf("build/zarf-package-podinfo-flux-%s.tar.zst", e2e.Arch) - stdOut, stdErr, err := e2e.Zarf("package", "deploy", path, "--confirm") + stdOut, stdErr, err := e2e.Zarf(t, "package", "deploy", path, "--confirm") require.NoError(t, err, stdOut, stdErr) // Tests the URL mutation for GitRepository CRD for Flux. - stdOut, stdErr, err = e2e.Kubectl("get", "gitrepositories", "podinfo", "-n", "flux-system", "-o", "jsonpath={.spec.url}") + stdOut, stdErr, err = e2e.Kubectl(t, "get", "gitrepositories", "podinfo", "-n", "flux-system", "-o", "jsonpath={.spec.url}") require.NoError(t, err, stdOut, stdErr) expectedMutatedRepoURL := fmt.Sprintf("%s/%s/podinfo-1646971829.git", types.ZarfInClusterGitServiceURL, types.ZarfGitPushUser) require.Equal(t, expectedMutatedRepoURL, stdOut) // Tests the URL mutation for HelmRepository CRD for Flux. - stdOut, stdErr, err = e2e.Kubectl("get", "helmrepositories", "podinfo", "-n", "flux-system", "-o", "jsonpath={.spec.url}") + stdOut, stdErr, err = e2e.Kubectl(t, "get", "helmrepositories", "podinfo", "-n", "flux-system", "-o", "jsonpath={.spec.url}") require.NoError(t, err, stdOut, stdErr) expectedMutatedRepoURL = fmt.Sprintf("oci://%s/stefanprodan/charts", registryAddress) require.Equal(t, expectedMutatedRepoURL, stdOut) - stdOut, stdErr, err = e2e.Kubectl("get", "helmrelease", "podinfo", "-n", "flux-system", "-o", "jsonpath={.spec.chart.spec.version}") + stdOut, stdErr, err = e2e.Kubectl(t, "get", "helmrelease", "podinfo", "-n", "flux-system", "-o", "jsonpath={.spec.chart.spec.version}") require.NoError(t, err, stdOut, stdErr) expectedMutatedRepoTag := "6.4.0" require.Equal(t, expectedMutatedRepoTag, stdOut) // Tests the URL mutation for OCIRepository CRD for Flux. - stdOut, stdErr, err = e2e.Kubectl("get", "ocirepositories", "podinfo", "-n", "flux-system", "-o", "jsonpath={.spec.url}") + stdOut, stdErr, err = e2e.Kubectl(t, "get", "ocirepositories", "podinfo", "-n", "flux-system", "-o", "jsonpath={.spec.url}") require.NoError(t, err, stdOut, stdErr) expectedMutatedRepoURL = fmt.Sprintf("oci://%s/stefanprodan/manifests/podinfo", registryAddress) require.Equal(t, expectedMutatedRepoURL, stdOut) - stdOut, stdErr, err = e2e.Kubectl("get", "ocirepositories", "podinfo", "-n", "flux-system", "-o", "jsonpath={.spec.ref.tag}") + stdOut, stdErr, err = e2e.Kubectl(t, "get", "ocirepositories", "podinfo", "-n", "flux-system", "-o", "jsonpath={.spec.ref.tag}") require.NoError(t, err, stdOut, stdErr) expectedMutatedRepoTag = "6.4.0-zarf-2823281104" require.Equal(t, expectedMutatedRepoTag, stdOut) // Remove the flux example when deployment completes - stdOut, stdErr, err = e2e.Zarf("package", "remove", "podinfo-flux", "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "remove", "podinfo-flux", "--confirm") require.NoError(t, err, stdOut, stdErr) // Prune the flux images to reduce disk pressure - stdOut, stdErr, err = e2e.Zarf("tools", "registry", "prune", "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "tools", "registry", "prune", "--confirm") require.NoError(t, err, stdOut, stdErr) } func waitArgoDeployment(t *testing.T) { // Deploy the argocd example and verify that it works path := fmt.Sprintf("build/zarf-package-argocd-%s.tar.zst", e2e.Arch) - stdOut, stdErr, err := e2e.Zarf("package", "deploy", path, "--components=argocd-apps", "--confirm") + stdOut, stdErr, err := e2e.Zarf(t, "package", "deploy", path, "--components=argocd-apps", "--confirm") require.NoError(t, err, stdOut, stdErr) expectedMutatedRepoURL := fmt.Sprintf("%s/%s/podinfo-1646971829.git", types.ZarfInClusterGitServiceURL, types.ZarfGitPushUser) // Tests the mutation of the private repository Secret for ArgoCD. - stdOut, stdErr, err = e2e.Kubectl("get", "secret", "argocd-repo-github-podinfo", "-n", "argocd", "-o", "jsonpath={.data.url}") + stdOut, stdErr, err = e2e.Kubectl(t, "get", "secret", "argocd-repo-github-podinfo", "-n", "argocd", "-o", "jsonpath={.data.url}") require.NoError(t, err, stdOut, stdErr) expectedMutatedPrivateRepoURLSecret, err := base64.StdEncoding.DecodeString(stdOut) @@ -190,15 +190,15 @@ func waitArgoDeployment(t *testing.T) { require.Equal(t, expectedMutatedRepoURL, string(expectedMutatedPrivateRepoURLSecret)) // Tests the mutation of the repoURL for Application CRD source(s) for ArgoCD. - stdOut, stdErr, err = e2e.Kubectl("get", "application", "apps", "-n", "argocd", "-o", "jsonpath={.spec.sources[0].repoURL}") + stdOut, stdErr, err = e2e.Kubectl(t, "get", "application", "apps", "-n", "argocd", "-o", "jsonpath={.spec.sources[0].repoURL}") require.NoError(t, err, stdOut, stdErr) require.Equal(t, expectedMutatedRepoURL, stdOut) // Remove the argocd example when deployment completes - stdOut, stdErr, err = e2e.Zarf("package", "remove", "argocd", "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "remove", "argocd", "--confirm") require.NoError(t, err, stdOut, stdErr) // Prune the ArgoCD images to reduce disk pressure - stdOut, stdErr, err = e2e.Zarf("tools", "registry", "prune", "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "tools", "registry", "prune", "--confirm") require.NoError(t, err, stdOut, stdErr) } diff --git a/src/test/e2e/23_data_injection_test.go b/src/test/e2e/23_data_injection_test.go index 08f913fc41..c7400b240e 100644 --- a/src/test/e2e/23_data_injection_test.go +++ b/src/test/e2e/23_data_injection_test.go @@ -33,9 +33,9 @@ func TestDataInjection(t *testing.T) { } // Verify the file and injection marker were created - runningKiwixPod, _, err := e2e.Kubectl("--namespace=kiwix", "get", "pods", "--selector=app=kiwix-serve", "--field-selector=status.phase=Running", "--output=jsonpath={.items[0].metadata.name}") + runningKiwixPod, _, err := e2e.Kubectl(t, "--namespace=kiwix", "get", "pods", "--selector=app=kiwix-serve", "--field-selector=status.phase=Running", "--output=jsonpath={.items[0].metadata.name}") require.NoError(t, err) - stdOut, stdErr, err := e2e.Kubectl("--namespace=kiwix", "logs", runningKiwixPod, "--tail=5", "-c=kiwix-serve") + stdOut, stdErr, err := e2e.Kubectl(t, "--namespace=kiwix", "logs", runningKiwixPod, "--tail=5", "-c=kiwix-serve") require.NoError(t, err, stdOut, stdErr) require.Contains(t, stdOut, "devops.stackexchange.com_en_all_2023-05.zim") require.Contains(t, stdOut, ".zarf-injection-") @@ -53,11 +53,11 @@ func TestDataInjection(t *testing.T) { require.Equal(t, 200, resp.StatusCode) // Remove the data injection example - stdOut, stdErr, err = e2e.Zarf("package", "remove", path, "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "remove", path, "--confirm") require.NoError(t, err, stdOut, stdErr) // Ensure that the `requirements.txt` file is discovered correctly - stdOut, stdErr, err = e2e.Zarf("package", "inspect", path, "--sbom-out", sbomPath) + stdOut, stdErr, err = e2e.Zarf(t, "package", "inspect", path, "--sbom-out", sbomPath) require.NoError(t, err, stdOut, stdErr) require.FileExists(t, filepath.Join(sbomPath, "kiwix", "compare.html"), "A compare.html file should have been made") diff --git a/src/test/e2e/24_variables_test.go b/src/test/e2e/24_variables_test.go index 765c8902bf..f5b06116d0 100644 --- a/src/test/e2e/24_variables_test.go +++ b/src/test/e2e/24_variables_test.go @@ -27,34 +27,34 @@ func TestVariables(t *testing.T) { e2e.CleanFiles(tfPath, evilPath) // Test that specifying an invalid setVariable value results in an error - stdOut, stdErr, err := e2e.Zarf("package", "create", evilSrc, "--set", "NUMB3R5=K1TT3H", "--confirm") + stdOut, stdErr, err := e2e.Zarf(t, "package", "create", evilSrc, "--set", "NUMB3R5=K1TT3H", "--confirm") require.NoError(t, err, stdOut, stdErr) expectedOutString := "\"K1TT3H\"" require.Contains(t, stdErr, "", expectedOutString) - stdOut, stdErr, err = e2e.Zarf("package", "deploy", evilPath, "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "deploy", evilPath, "--confirm") require.Error(t, err, stdOut, stdErr) expectedOutString = "variable \"HELLO_KITTEH\" does not match pattern " require.Contains(t, stdErr, "", expectedOutString) // Test that specifying an invalid constant value results in an error - stdOut, stdErr, err = e2e.Zarf("package", "create", src, "--set", "NGINX_VERSION=", "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "create", src, "--set", "NGINX_VERSION=", "--confirm") require.Error(t, err, stdOut, stdErr) expectedOutString = "constant \"NGINX_VERSION\" does not match pattern " require.Contains(t, stdErr, "", expectedOutString) // Test that not specifying a prompted variable results in an error - _, stdErr, _ = e2e.Zarf("package", "deploy", path, "--confirm") + _, stdErr, _ = e2e.Zarf(t, "package", "deploy", path, "--confirm") expectedOutString = "variable 'SITE_NAME' must be '--set' when using the '--confirm' flag" require.Contains(t, stdErr, "", expectedOutString) // Test that specifying an invalid variable value results in an error - stdOut, stdErr, err = e2e.Zarf("package", "deploy", path, "--set", "SITE_NAME=#INVALID", "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "deploy", path, "--set", "SITE_NAME=#INVALID", "--confirm") require.Error(t, err, stdOut, stdErr) expectedOutString = "variable \"SITE_NAME\" does not match pattern " require.Contains(t, stdErr, "", expectedOutString) // Deploy nginx - stdOut, stdErr, err = e2e.Zarf("package", "deploy", path, "--confirm", "--set", "SITE_NAME=Lula Web", "--set", "AWS_REGION=unicorn-land", "-l", "trace") + stdOut, stdErr, err = e2e.Zarf(t, "package", "deploy", path, "--confirm", "--set", "SITE_NAME=Lula Web", "--set", "AWS_REGION=unicorn-land", "-l", "trace") require.NoError(t, err, stdOut, stdErr) // Verify that the variables were shown to the user in the formats we expect require.Contains(t, stdErr, "currently set to 'Defense Unicorns' (default)") @@ -73,7 +73,7 @@ func TestVariables(t *testing.T) { require.Contains(t, string(outputTF), "unicorn-land") // Verify the configmap was properly templated - kubectlOut, _, _ := e2e.Kubectl("-n", "nginx", "get", "configmap", "nginx-configmap", "-o", "jsonpath='{.data.index\\.html}' ") + kubectlOut, _, _ := e2e.Kubectl(t, "-n", "nginx", "get", "configmap", "nginx-configmap", "-o", "jsonpath='{.data.index\\.html}' ") // OPTIONAL_FOOTER should remain unset because it was not set during deploy require.Contains(t, string(kubectlOut), "

\n \n ") // STYLE should take the default value @@ -88,7 +88,7 @@ func TestVariables(t *testing.T) { require.Contains(t, string(kubectlOut), "63af41aebec53e3679948b254073c3c0d603d47ab01b03ab14abd7d98234e101") // Remove the variables example - stdOut, stdErr, err = e2e.Zarf("package", "remove", path, "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "remove", path, "--confirm") require.NoError(t, err, stdOut, stdErr) e2e.CleanFiles(tfPath, evilPath) diff --git a/src/test/e2e/25_helm_test.go b/src/test/e2e/25_helm_test.go index 071732da10..322d3c89dd 100644 --- a/src/test/e2e/25_helm_test.go +++ b/src/test/e2e/25_helm_test.go @@ -36,52 +36,52 @@ func testHelmChartsExample(t *testing.T) { // Create a package that has a tarball as a local chart localTgzChartPath := filepath.Join("src", "test", "packages", "25-local-tgz-chart") - stdOut, stdErr, err := e2e.Zarf("package", "create", localTgzChartPath, "--tmpdir", tmpdir, "--confirm") + stdOut, stdErr, err := e2e.Zarf(t, "package", "create", localTgzChartPath, "--tmpdir", tmpdir, "--confirm") require.NoError(t, err, stdOut, stdErr) defer e2e.CleanFiles(fmt.Sprintf("zarf-package-helm-charts-local-tgz-%s-0.0.1.tar.zst", e2e.Arch)) // Create a package that needs dependencies evilChartDepsPath := filepath.Join("src", "test", "packages", "25-evil-chart-deps") - stdOut, stdErr, err = e2e.Zarf("package", "create", evilChartDepsPath, "--tmpdir", tmpdir, "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "create", evilChartDepsPath, "--tmpdir", tmpdir, "--confirm") require.Error(t, err, stdOut, stdErr) require.Contains(t, e2e.StripMessageFormatting(stdErr), "could not download https://charts.jetstack.io/charts/cert-manager-v1.11.1.tgz") require.FileExists(t, filepath.Join(evilChartDepsPath, "good-chart", "charts", "gitlab-runner-0.55.0.tgz")) // Create a package with a chart name that doesn't exist in a repo evilChartLookupPath := filepath.Join("src", "test", "packages", "25-evil-chart-lookup") - stdOut, stdErr, err = e2e.Zarf("package", "create", evilChartLookupPath, "--tmpdir", tmpdir, "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "create", evilChartLookupPath, "--tmpdir", tmpdir, "--confirm") require.Error(t, err, stdOut, stdErr) require.Contains(t, e2e.StripMessageFormatting(stdErr), "chart \"asdf\" version \"6.4.0\" not found") require.Contains(t, e2e.StripMessageFormatting(stdErr), "Available charts and versions from \"https://stefanprodan.github.io/podinfo\":") // Create a test package (with a registry override (host+subpath to host+subpath) to test that as well) - stdOut, stdErr, err = e2e.Zarf("package", "create", "examples/helm-charts", "-o", "build", "--registry-override", "ghcr.io/stefanprodan=docker.io/stefanprodan", "--tmpdir", tmpdir, "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "create", "examples/helm-charts", "-o", "build", "--registry-override", "ghcr.io/stefanprodan=docker.io/stefanprodan", "--tmpdir", tmpdir, "--confirm") require.NoError(t, err, stdOut, stdErr) // Create a test package (with a registry override (host to host+subpath) to test that as well) // expect to fail as ghcr.io is overridden and the expected final image doesn't exist but the override works well based on the error message in the output - stdOut, stdErr, err = e2e.Zarf("package", "create", "examples/helm-charts", "-o", "build", "--registry-override", "ghcr.io=localhost:555/noway", "--tmpdir", tmpdir, "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "create", "examples/helm-charts", "-o", "build", "--registry-override", "ghcr.io=localhost:555/noway", "--tmpdir", tmpdir, "--confirm") require.Error(t, err, stdOut, stdErr) require.Contains(t, string(stdErr), "localhost:555/noway") // Create a test package (with a registry override (host+subpath to host) to test that as well) // works same as the above failing test - stdOut, stdErr, err = e2e.Zarf("package", "create", "examples/helm-charts", "-o", "build", "--registry-override", "ghcr.io/stefanprodan=localhost:555", "--tmpdir", tmpdir, "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "create", "examples/helm-charts", "-o", "build", "--registry-override", "ghcr.io/stefanprodan=localhost:555", "--tmpdir", tmpdir, "--confirm") require.Error(t, err, stdOut, stdErr) require.Contains(t, string(stdErr), "localhost:555") // Create the package (with a registry override (host to host) to test that as well) - stdOut, stdErr, err = e2e.Zarf("package", "create", "examples/helm-charts", "-o", "build", "--registry-override", "ghcr.io=docker.io", "--tmpdir", tmpdir, "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "create", "examples/helm-charts", "-o", "build", "--registry-override", "ghcr.io=docker.io", "--tmpdir", tmpdir, "--confirm") require.NoError(t, err, stdOut, stdErr) // Deploy the example package. - stdOut, stdErr, err = e2e.Zarf("package", "deploy", helmChartsPkg, "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "deploy", helmChartsPkg, "--confirm") require.NoError(t, err, stdOut, stdErr) require.Contains(t, string(stdErr), "registryOverrides", "registry overrides was not saved to build data") require.Contains(t, string(stdErr), "docker.io", "docker.io not found in registry overrides") // Remove the example package. - stdOut, stdErr, err = e2e.Zarf("package", "remove", "helm-charts", "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "remove", "helm-charts", "--confirm") require.NoError(t, err, stdOut, stdErr) } @@ -90,13 +90,13 @@ func testHelmEscaping(t *testing.T) { t.Log("E2E: Helm chart escaping") // Create the package. - stdOut, stdErr, err := e2e.Zarf("package", "create", "src/test/packages/25-evil-templates/", "--confirm") + stdOut, stdErr, err := e2e.Zarf(t, "package", "create", "src/test/packages/25-evil-templates/", "--confirm") require.NoError(t, err, stdOut, stdErr) path := fmt.Sprintf("zarf-package-evil-templates-%s.tar.zst", e2e.Arch) // Deploy the package. - stdOut, stdErr, err = e2e.Zarf("package", "deploy", path, "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "deploy", path, "--confirm") require.NoError(t, err, stdOut, stdErr) // Verify the configmap was deployed, escaped, and contains all of its data @@ -108,7 +108,7 @@ func testHelmEscaping(t *testing.T) { require.Contains(t, string(kubectlOut), `TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIG`) // Remove the package. - stdOut, stdErr, err = e2e.Zarf("package", "remove", "evil-templates", "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "remove", "evil-templates", "--confirm") require.NoError(t, err, stdOut, stdErr) } @@ -119,11 +119,11 @@ func testHelmUninstallRollback(t *testing.T) { evilPath := fmt.Sprintf("zarf-package-dos-games-%s.tar.zst", e2e.Arch) // Create the evil package (with the bad service). - stdOut, stdErr, err := e2e.Zarf("package", "create", "src/test/packages/25-evil-dos-games/", "--skip-sbom", "--confirm") + stdOut, stdErr, err := e2e.Zarf(t, "package", "create", "src/test/packages/25-evil-dos-games/", "--skip-sbom", "--confirm") require.NoError(t, err, stdOut, stdErr) // Deploy the evil package. - stdOut, stdErr, err = e2e.Zarf("package", "deploy", evilPath, "--timeout", "10s", "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "deploy", evilPath, "--timeout", "10s", "--confirm") require.Error(t, err, stdOut, stdErr) // This package contains SBOMable things but was created with --skip-sbom @@ -138,7 +138,7 @@ func testHelmUninstallRollback(t *testing.T) { require.Contains(t, string(helmOut), "zarf-f53a99d4a4dd9a3575bedf59cd42d48d751ae866") // Deploy the good package. - stdOut, stdErr, err = e2e.Zarf("package", "deploy", goodPath, "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "deploy", goodPath, "--confirm") require.NoError(t, err, stdOut, stdErr) // Ensure this upgrades/fixes the dos-games chart. @@ -147,7 +147,7 @@ func testHelmUninstallRollback(t *testing.T) { require.Contains(t, string(helmOut), "zarf-f53a99d4a4dd9a3575bedf59cd42d48d751ae866") // Deploy the evil package. - stdOut, stdErr, err = e2e.Zarf("package", "deploy", evilPath, "--timeout", "10s", "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "deploy", evilPath, "--timeout", "10s", "--confirm") require.Error(t, err, stdOut, stdErr) // Ensure that we rollback properly @@ -156,7 +156,7 @@ func testHelmUninstallRollback(t *testing.T) { require.Contains(t, string(helmOut), "Rollback to 4") // Deploy the evil package (again to ensure we check full history) - stdOut, stdErr, err = e2e.Zarf("package", "deploy", evilPath, "--timeout", "10s", "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "deploy", evilPath, "--timeout", "10s", "--confirm") require.Error(t, err, stdOut, stdErr) // Ensure that we rollback properly @@ -165,7 +165,7 @@ func testHelmUninstallRollback(t *testing.T) { require.Contains(t, string(helmOut), "Rollback to 8") // Remove the package. - stdOut, stdErr, err = e2e.Zarf("package", "remove", "dos-games", "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "remove", "dos-games", "--confirm") require.NoError(t, err, stdOut, stdErr) } @@ -176,11 +176,11 @@ func testHelmAdoption(t *testing.T) { deploymentManifest := "src/test/packages/25-manifest-adoption/deployment.yaml" // Deploy dos-games manually into the cluster without Zarf - kubectlOut, _, _ := e2e.Kubectl("apply", "-f", deploymentManifest) + kubectlOut, _, _ := e2e.Kubectl(t, "apply", "-f", deploymentManifest) require.Contains(t, string(kubectlOut), "deployment.apps/game created") // Deploy dos-games into the cluster with Zarf - stdOut, stdErr, err := e2e.Zarf("package", "deploy", packagePath, "--confirm", "--adopt-existing-resources") + stdOut, stdErr, err := e2e.Zarf(t, "package", "deploy", packagePath, "--confirm", "--adopt-existing-resources") require.NoError(t, err, stdOut, stdErr) // Ensure that this does create a dos-games chart @@ -188,14 +188,14 @@ func testHelmAdoption(t *testing.T) { require.NoError(t, err) require.Contains(t, string(helmOut), "zarf-f53a99d4a4dd9a3575bedf59cd42d48d751ae866") - existingLabel, _, err := e2e.Kubectl("get", "ns", "dos-games", "-o=jsonpath={.metadata.labels.keep-this}") + existingLabel, _, err := e2e.Kubectl(t, "get", "ns", "dos-games", "-o=jsonpath={.metadata.labels.keep-this}") require.Equal(t, "label", existingLabel) require.NoError(t, err) - existingAnnotation, _, err := e2e.Kubectl("get", "ns", "dos-games", "-o=jsonpath={.metadata.annotations.keep-this}") + existingAnnotation, _, err := e2e.Kubectl(t, "get", "ns", "dos-games", "-o=jsonpath={.metadata.annotations.keep-this}") require.Equal(t, "annotation", existingAnnotation) require.NoError(t, err) // Remove the package. - stdOut, stdErr, err = e2e.Zarf("package", "remove", "dos-games", "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "remove", "dos-games", "--confirm") require.NoError(t, err, stdOut, stdErr) } diff --git a/src/test/e2e/26_simple_packages_test.go b/src/test/e2e/26_simple_packages_test.go index 05a95d97d2..6e4c20bd8a 100644 --- a/src/test/e2e/26_simple_packages_test.go +++ b/src/test/e2e/26_simple_packages_test.go @@ -21,7 +21,7 @@ func TestDosGames(t *testing.T) { path := filepath.Join("build", fmt.Sprintf("zarf-package-dos-games-%s-1.0.0.tar.zst", e2e.Arch)) // Deploy the game - stdOut, stdErr, err := e2e.Zarf("package", "deploy", path, "--confirm") + stdOut, stdErr, err := e2e.Zarf(t, "package", "deploy", path, "--confirm") require.NoError(t, err, stdOut, stdErr) c, err := cluster.NewCluster() @@ -35,18 +35,18 @@ func TestDosGames(t *testing.T) { require.NoError(t, err, resp) require.Equal(t, 200, resp.StatusCode) - stdOut, stdErr, err = e2e.Zarf("package", "remove", "dos-games", "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "remove", "dos-games", "--confirm") require.NoError(t, err, stdOut, stdErr) testCreate := filepath.Join("src", "test", "packages", "26-image-dos-games") testDeploy := filepath.Join("build", fmt.Sprintf("zarf-package-dos-games-images-%s.tar.zst", e2e.Arch)) // Create the game image test package - stdOut, stdErr, err = e2e.Zarf("package", "create", testCreate, "-o", "build", "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "create", testCreate, "-o", "build", "--confirm") require.NoError(t, err, stdOut, stdErr) // Deploy the game image test package - stdOut, stdErr, err = e2e.Zarf("package", "deploy", testDeploy, "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "deploy", testDeploy, "--confirm") require.NoError(t, err, stdOut, stdErr) } @@ -56,11 +56,11 @@ func TestManifests(t *testing.T) { path := filepath.Join("build", fmt.Sprintf("zarf-package-manifests-%s-0.0.1.tar.zst", e2e.Arch)) // Deploy the package - stdOut, stdErr, err := e2e.Zarf("package", "deploy", path, "--confirm") + stdOut, stdErr, err := e2e.Zarf(t, "package", "deploy", path, "--confirm") require.NoError(t, err, stdOut, stdErr) // Remove the package - stdOut, stdErr, err = e2e.Zarf("package", "remove", "manifests", "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "remove", "manifests", "--confirm") require.NoError(t, err, stdOut, stdErr) } @@ -71,10 +71,10 @@ func TestAgentIgnore(t *testing.T) { testDeploy := filepath.Join("build", fmt.Sprintf("zarf-package-agent-ignore-namespace-%s.tar.zst", e2e.Arch)) // Create the agent ignore test package - stdOut, stdErr, err := e2e.Zarf("package", "create", testCreate, "-o", "build", "--confirm") + stdOut, stdErr, err := e2e.Zarf(t, "package", "create", testCreate, "-o", "build", "--confirm") require.NoError(t, err, stdOut, stdErr) // Deploy the agent ignore test package - stdOut, stdErr, err = e2e.Zarf("package", "deploy", testDeploy, "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "deploy", testDeploy, "--confirm") require.NoError(t, err, stdOut, stdErr) } diff --git a/src/test/e2e/27_deploy_regression_test.go b/src/test/e2e/27_deploy_regression_test.go index 49808addff..f16c3d243a 100644 --- a/src/test/e2e/27_deploy_regression_test.go +++ b/src/test/e2e/27_deploy_regression_test.go @@ -5,7 +5,6 @@ package test import ( - "context" "fmt" "testing" @@ -26,10 +25,10 @@ func TestGHCRDeploy(t *testing.T) { } // Test with command from https://docs.zarf.dev/getting-started/install/ - stdOut, stdErr, err := e2e.Zarf("package", "deploy", fmt.Sprintf("oci://🦄/dos-games:1.0.0-%s@sha256:%s", e2e.Arch, sha), "--key=https://zarf.dev/cosign.pub", "--confirm") + 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("package", "remove", "dos-games", "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "remove", "dos-games", "--confirm") require.NoError(t, err, stdOut, stdErr) } @@ -39,9 +38,9 @@ func TestCosignDeploy(t *testing.T) { // 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.CmdWithContext(context.TODO(), exec.PrintCfg(), "sh", "-c", command) + stdOut, stdErr, err := exec.CmdWithTesting(t, exec.PrintCfg(), "sh", "-c", command) require.NoError(t, err, stdOut, stdErr) - stdOut, stdErr, err = e2e.Zarf("package", "remove", "dos-games", "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "remove", "dos-games", "--confirm") require.NoError(t, err, stdOut, stdErr) } diff --git a/src/test/e2e/28_wait_test.go b/src/test/e2e/28_wait_test.go index e1b22b4f28..e150d163fd 100644 --- a/src/test/e2e/28_wait_test.go +++ b/src/test/e2e/28_wait_test.go @@ -20,22 +20,22 @@ type zarfCommandResult struct { err error } -func zarfCommandWStruct(e2e test.ZarfE2ETest, path string) (result zarfCommandResult) { - result.stdOut, result.stdErr, result.err = e2e.Zarf("package", "deploy", path, "--confirm") +func zarfCommandWStruct(t *testing.T, e2e test.ZarfE2ETest, path string) (result zarfCommandResult) { + result.stdOut, result.stdErr, result.err = e2e.Zarf(t, "package", "deploy", path, "--confirm") return result } func TestNoWait(t *testing.T) { t.Log("E2E: Helm Wait") - stdOut, stdErr, err := e2e.Zarf("package", "create", "src/test/packages/28-helm-no-wait", "-o=build", "--confirm") + stdOut, stdErr, err := e2e.Zarf(t, "package", "create", "src/test/packages/28-helm-no-wait", "-o=build", "--confirm") require.NoError(t, err, stdOut, stdErr) path := fmt.Sprintf("build/zarf-package-helm-no-wait-%s.tar.zst", e2e.Arch) zarfChannel := make(chan zarfCommandResult, 1) go func() { - zarfChannel <- zarfCommandWStruct(e2e, path) + zarfChannel <- zarfCommandWStruct(t, e2e, path) }() stdOut = "" @@ -50,10 +50,10 @@ func TestNoWait(t *testing.T) { case <-time.After(30 * time.Second): t.Error("Timeout waiting for zarf deploy (it tried to wait)") t.Log("Removing hanging namespace...") - _, _, _ = e2e.Kubectl("delete", "namespace", "no-wait", "--force=true", "--wait=false", "--grace-period=0") + _, _, _ = e2e.Kubectl(t, "delete", "namespace", "no-wait", "--force=true", "--wait=false", "--grace-period=0") } require.NoError(t, err, stdOut, stdErr) - stdOut, stdErr, err = e2e.Zarf("package", "remove", "helm-no-wait", "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "remove", "helm-no-wait", "--confirm") require.NoError(t, err, stdOut, stdErr) } diff --git a/src/test/e2e/29_config_file_test.go b/src/test/e2e/29_config_file_test.go index 40c66b4204..e947621518 100644 --- a/src/test/e2e/29_config_file_test.go +++ b/src/test/e2e/29_config_file_test.go @@ -31,7 +31,7 @@ func TestConfigFile(t *testing.T) { configFileDefaultTests(t) - stdOut, stdErr, err := e2e.Zarf("package", "remove", path, "--confirm") + stdOut, stdErr, err := e2e.Zarf(t, "package", "remove", path, "--confirm") require.NoError(t, err, stdOut, stdErr) e2e.CleanFiles(path) @@ -40,12 +40,12 @@ func TestConfigFile(t *testing.T) { func configFileTests(t *testing.T, dir, path string) { t.Helper() - _, stdErr, err := e2e.Zarf("package", "create", dir, "--confirm") + _, stdErr, err := e2e.Zarf(t, "package", "create", dir, "--confirm") require.NoError(t, err) require.Contains(t, string(stdErr), "This is a zebra and they have stripes") require.Contains(t, string(stdErr), "This is a leopard and they have spots") - _, stdErr, err = e2e.Zarf("package", "deploy", path, "--confirm") + _, stdErr, err = e2e.Zarf(t, "package", "deploy", path, "--confirm") require.NoError(t, err) require.Contains(t, string(stdErr), "📦 LION COMPONENT") require.NotContains(t, string(stdErr), "📦 LEOPARD COMPONENT") @@ -55,7 +55,7 @@ func configFileTests(t *testing.T, dir, path string) { require.NotContains(t, string(stdErr), "This package does NOT contain an SBOM.") // Verify the configmap was properly templated - kubectlOut, _, err := e2e.Kubectl("-n", "zarf", "get", "configmap", "simple-configmap", "-o", "jsonpath={.data.templateme\\.properties}") + kubectlOut, _, err := e2e.Kubectl(t, "-n", "zarf", "get", "configmap", "simple-configmap", "-o", "jsonpath={.data.templateme\\.properties}") require.NoError(t, err) require.Contains(t, string(kubectlOut), "scorpion=iridescent") require.Contains(t, string(kubectlOut), "camel_spider=matte") @@ -89,7 +89,7 @@ b42JLSKqwpvVjQDiFZPI/0wZTo3WkWm9Rd7CAACheb8S70K1r/JIzsmIcnj0v4xs sfd+R35UE+m8MExbDP4lKFParmvi2/UZfb3VFNMmMPTV6AEIBl6N4PmhHMZOsIRs H4RxbE+FpmsMAUCpdrzvFkc= -----END PRIVATE KEY-----` - kubectlOut, _, err = e2e.Kubectl("-n", "zarf", "get", "configmap", "simple-configmap", "-o", "jsonpath={.data.tls-key}") + kubectlOut, _, err = e2e.Kubectl(t, "-n", "zarf", "get", "configmap", "simple-configmap", "-o", "jsonpath={.data.tls-key}") require.NoError(t, err) require.Equal(t, tlsKey, kubectlOut) } @@ -142,25 +142,25 @@ func configFileDefaultTests(t *testing.T) { defer os.Unsetenv("ZARF_CONFIG") // Test global flags - stdOut, _, _ := e2e.Zarf("--help") + stdOut, _, _ := e2e.Zarf(t, "--help") for _, test := range globalFlags { require.Contains(t, string(stdOut), test) } // Test init flags - stdOut, _, _ = e2e.Zarf("init", "--help") + stdOut, _, _ = e2e.Zarf(t, "init", "--help") for _, test := range initFlags { require.Contains(t, string(stdOut), test) } // Test package create flags - stdOut, _, _ = e2e.Zarf("package", "create", "--help") + stdOut, _, _ = e2e.Zarf(t, "package", "create", "--help") for _, test := range packageCreateFlags { require.Contains(t, string(stdOut), test) } // Test package deploy flags - stdOut, _, _ = e2e.Zarf("package", "deploy", "--help") + stdOut, _, _ = e2e.Zarf(t, "package", "deploy", "--help") for _, test := range packageDeployFlags { require.Contains(t, string(stdOut), test) } diff --git a/src/test/e2e/30_component_action_cluster_test.go b/src/test/e2e/30_component_action_cluster_test.go index 5d6658152f..6763a042dc 100644 --- a/src/test/e2e/30_component_action_cluster_test.go +++ b/src/test/e2e/30_component_action_cluster_test.go @@ -17,10 +17,10 @@ func TestComponentActionRemove(t *testing.T) { packagePath := filepath.Join("build", fmt.Sprintf("zarf-package-component-actions-%s.tar.zst", e2e.Arch)) - stdOut, stdErr, err := e2e.Zarf("package", "deploy", packagePath, "--confirm", "--components=on-remove") + stdOut, stdErr, err := e2e.Zarf(t, "package", "deploy", packagePath, "--confirm", "--components=on-remove") require.NoError(t, err, stdOut, stdErr) - stdOut, stdErr, err = e2e.Zarf("package", "remove", packagePath, "--confirm", "--components=on-remove") + stdOut, stdErr, err = e2e.Zarf(t, "package", "remove", packagePath, "--confirm", "--components=on-remove") require.NoError(t, err, stdOut, stdErr) require.Contains(t, stdErr, "NAME") require.Contains(t, stdErr, "DATA") @@ -34,10 +34,10 @@ func TestComponentActionEdgeCases(t *testing.T) { sourcePath := filepath.Join("src", "test", "packages", "31-component-actions-edgecases") packagePath := fmt.Sprintf("zarf-package-component-actions-edgecases-%s.tar.zst", e2e.Arch) - stdOut, stdErr, err := e2e.Zarf("package", "create", sourcePath, "--confirm") + stdOut, stdErr, err := e2e.Zarf(t, "package", "create", sourcePath, "--confirm") require.NoError(t, err, stdOut, stdErr) defer e2e.CleanFiles(packagePath) - stdOut, stdErr, err = e2e.Zarf("package", "deploy", packagePath, "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "deploy", packagePath, "--confirm") require.NoError(t, err, stdOut, stdErr) } diff --git a/src/test/e2e/31_checksum_and_signature_test.go b/src/test/e2e/31_checksum_and_signature_test.go index 2b3856779f..e8aed4c1cb 100644 --- a/src/test/e2e/31_checksum_and_signature_test.go +++ b/src/test/e2e/31_checksum_and_signature_test.go @@ -19,32 +19,32 @@ func TestChecksumAndSignature(t *testing.T) { privateKeyFlag := "--signing-key=src/test/packages/zarf-test.prv-key" publicKeyFlag := "--key=src/test/packages/zarf-test.pub" - stdOut, stdErr, err := e2e.Zarf("package", "create", testPackageDirPath, privateKeyFlag, "--confirm") + stdOut, stdErr, err := e2e.Zarf(t, "package", "create", testPackageDirPath, privateKeyFlag, "--confirm") require.NoError(t, err, stdOut, stdErr) defer e2e.CleanFiles(pkgName) /* Test operations during package inspect */ // Test that we can inspect the yaml of the package without the private key - stdOut, stdErr, err = e2e.Zarf("package", "inspect", pkgName) + stdOut, stdErr, err = e2e.Zarf(t, "package", "inspect", pkgName) require.NoError(t, err, stdOut, stdErr) // Test that we don't get an error when we remember to provide the public key - stdOut, stdErr, err = e2e.Zarf("package", "inspect", pkgName, publicKeyFlag) + stdOut, stdErr, err = e2e.Zarf(t, "package", "inspect", pkgName, publicKeyFlag) require.NoError(t, err, stdOut, stdErr) require.Contains(t, stdErr, "Verified OK") /* Test operations during package deploy */ // Test that we get an error when trying to deploy a package without providing the public key - stdOut, stdErr, err = e2e.Zarf("package", "deploy", pkgName, "--confirm") + 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") // Test that we don't get an error when we remember to provide the public key - stdOut, stdErr, err = e2e.Zarf("package", "deploy", pkgName, publicKeyFlag, "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "deploy", pkgName, publicKeyFlag, "--confirm") require.NoError(t, err, stdOut, stdErr) require.Contains(t, stdErr, "Zarf deployment complete") // Remove the package - stdOut, stdErr, err = e2e.Zarf("package", "remove", pkgName, publicKeyFlag, "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "remove", pkgName, publicKeyFlag, "--confirm") require.NoError(t, err, stdOut, stdErr) } diff --git a/src/test/e2e/32_component_webhooks_test.go b/src/test/e2e/32_component_webhooks_test.go index d409e62521..7d6d761835 100644 --- a/src/test/e2e/32_component_webhooks_test.go +++ b/src/test/e2e/32_component_webhooks_test.go @@ -16,32 +16,32 @@ func TestComponentWebhooks(t *testing.T) { // Deploy example Pepr webhook. webhookPath := fmt.Sprintf("build/zarf-package-component-webhooks-%s-0.0.1.tar.zst", e2e.Arch) - stdOut, stdErr, err := e2e.Zarf("package", "deploy", webhookPath, "--confirm") + stdOut, stdErr, err := e2e.Zarf(t, "package", "deploy", webhookPath, "--confirm") require.NoError(t, err, stdOut, stdErr) - stdOut, stdErr, err = e2e.Zarf("tools", "wait-for", "deployment", "pepr-cb5693ef-d13c-5fe1-b5ad-c870fd911b3b", "available", "-n=pepr-system") + stdOut, stdErr, err = e2e.Zarf(t, "tools", "wait-for", "deployment", "pepr-cb5693ef-d13c-5fe1-b5ad-c870fd911b3b", "available", "-n=pepr-system") require.NoError(t, err, stdOut, stdErr) 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) - stdOut, stdErr, err = e2e.Zarf("package", "deploy", gamesPath, "--confirm") + 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\"") // Ensure package deployments with the '--skip-webhooks' flag do not wait on webhooks to complete. - stdOut, stdErr, err = e2e.Zarf("package", "deploy", gamesPath, "--skip-webhooks", "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "deploy", gamesPath, "--skip-webhooks", "--confirm") require.NoError(t, err, stdOut, stdErr) require.NotContains(t, stdErr, "Waiting for webhook \"test-webhook\" to complete for component \"baseline\"") // Remove the Pepr webhook package. - stdOut, stdErr, err = e2e.Zarf("package", "remove", "component-webhooks", "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "remove", "component-webhooks", "--confirm") require.NoError(t, err, stdOut, stdErr) - stdOut, stdErr, err = e2e.Kubectl("delete", "namespace", "pepr-system") + stdOut, stdErr, err = e2e.Kubectl(t, "delete", "namespace", "pepr-system") require.NoError(t, err, stdOut, stdErr) // Remove the dos-games package. - stdOut, stdErr, err = e2e.Zarf("package", "remove", "dos-games", "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "remove", "dos-games", "--confirm") require.NoError(t, err, stdOut, stdErr) - stdOut, stdErr, err = e2e.Kubectl("delete", "namespace", "dos-games") + stdOut, stdErr, err = e2e.Kubectl(t, "delete", "namespace", "dos-games") require.NoError(t, err, stdOut, stdErr) } diff --git a/src/test/e2e/33_manifest_with_symlink_test.go b/src/test/e2e/33_manifest_with_symlink_test.go index 4664189636..9748154dc7 100644 --- a/src/test/e2e/33_manifest_with_symlink_test.go +++ b/src/test/e2e/33_manifest_with_symlink_test.go @@ -17,14 +17,14 @@ func TestManifestWithSymlink(t *testing.T) { // Build the package, should succeed, even though there is a symlink in the package. buildPath := filepath.Join("src", "test", "packages", "34-manifest-with-symlink") - stdOut, stdErr, err := e2e.Zarf("package", "create", buildPath, "-o=build", "--confirm") + stdOut, stdErr, err := e2e.Zarf(t, "package", "create", buildPath, "-o=build", "--confirm") require.NoError(t, err, stdOut, stdErr) path := fmt.Sprintf("build/zarf-package-manifest-with-symlink-%s-0.0.1.tar.zst", e2e.Arch) require.FileExists(t, path) defer e2e.CleanFiles(path) - stdOut, stdErr, err = e2e.Zarf("package", "deploy", path, "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "deploy", path, "--confirm") defer e2e.CleanFiles("temp/manifests") require.NoError(t, err, stdOut, stdErr) require.FileExists(t, "temp/manifests/resources/img", "Symlink does not exist in the package as expected.") diff --git a/src/test/e2e/34_custom_init_package_test.go b/src/test/e2e/34_custom_init_package_test.go index 6229255aca..c61cf91e2d 100644 --- a/src/test/e2e/34_custom_init_package_test.go +++ b/src/test/e2e/34_custom_init_package_test.go @@ -20,28 +20,28 @@ func TestCustomInit(t *testing.T) { privateKeyFlag := "--signing-key=src/test/packages/zarf-test.prv-key" publicKeyFlag := "--key=src/test/packages/zarf-test.pub" - stdOut, stdErr, err := e2e.Zarf("package", "create", buildPath, privateKeyFlag, "--confirm") + stdOut, stdErr, err := e2e.Zarf(t, "package", "create", buildPath, privateKeyFlag, "--confirm") require.NoError(t, err, stdOut, stdErr) defer e2e.CleanFiles(pkgName) /* Test operations during package inspect */ // Test that we can inspect the yaml of the package without the private key - stdOut, stdErr, err = e2e.Zarf("package", "inspect", pkgName) + stdOut, stdErr, err = e2e.Zarf(t, "package", "inspect", pkgName) require.NoError(t, err, stdOut, stdErr) // Test that we don't get an error when we remember to provide the public key - stdOut, stdErr, err = e2e.Zarf("package", "inspect", pkgName, publicKeyFlag) + stdOut, stdErr, err = e2e.Zarf(t, "package", "inspect", pkgName, publicKeyFlag) require.NoError(t, err, stdOut, stdErr) require.Contains(t, stdErr, "Verified OK") /* Test operations during package deploy */ // Test that we get an error when trying to deploy a package without providing the public key - stdOut, stdErr, err = e2e.Zarf("init", "--confirm") + 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") /* Test operations during package deploy */ // Test that we can deploy the package with the public key - stdOut, stdErr, err = e2e.Zarf("init", "--confirm", publicKeyFlag) + stdOut, stdErr, err = e2e.Zarf(t, "init", "--confirm", publicKeyFlag) require.NoError(t, err, stdOut, stdErr) } diff --git a/src/test/e2e/35_custom_retries_test.go b/src/test/e2e/35_custom_retries_test.go index 92d7e2fffe..e6a87ff5e1 100644 --- a/src/test/e2e/35_custom_retries_test.go +++ b/src/test/e2e/35_custom_retries_test.go @@ -21,14 +21,14 @@ func TestRetries(t *testing.T) { buildPath := filepath.Join("src", "test", "packages", "25-evil-dos-games") pkgName := fmt.Sprintf("zarf-package-dos-games-%s.tar.zst", e2e.Arch) - stdOut, stdErr, err := e2e.Zarf("package", "create", buildPath, "--tmpdir", tmpDir, "--output", tmpDir, "--confirm") + stdOut, stdErr, err := e2e.Zarf(t, "package", "create", buildPath, "--tmpdir", tmpDir, "--output", tmpDir, "--confirm") require.NoError(t, err, stdOut, stdErr) - stdOut, stdErr, err = e2e.Zarf("package", "deploy", path.Join(tmpDir, pkgName), "--retries", "2", "--timeout", "3s", "--tmpdir", tmpDir, "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "deploy", path.Join(tmpDir, pkgName), "--retries", "2", "--timeout", "3s", "--tmpdir", tmpDir, "--confirm") require.Error(t, err, stdOut, stdErr) require.Contains(t, stdErr, "Retrying in 5s") require.Contains(t, e2e.StripMessageFormatting(stdErr), "unable to install chart after 2 attempts") - _, _, err = e2e.Zarf("package", "remove", "dos-games", "--confirm") + _, _, err = e2e.Zarf(t, "package", "remove", "dos-games", "--confirm") require.NoError(t, err) } diff --git a/src/test/e2e/50_oci_publish_deploy_test.go b/src/test/e2e/50_oci_publish_deploy_test.go index 81e5e39f54..f72fbb28b5 100644 --- a/src/test/e2e/50_oci_publish_deploy_test.go +++ b/src/test/e2e/50_oci_publish_deploy_test.go @@ -54,35 +54,35 @@ func (suite *PublishDeploySuiteTestSuite) Test_0_Publish() { // Publish package. example := filepath.Join(suite.PackagesDir, fmt.Sprintf("zarf-package-helm-charts-%s-0.0.1.tar.zst", e2e.Arch)) ref := suite.Reference.String() - stdOut, stdErr, err := e2e.Zarf("package", "publish", example, "oci://"+ref, "--insecure") + stdOut, stdErr, err := e2e.Zarf(suite.T(), "package", "publish", example, "oci://"+ref, "--insecure") suite.NoError(err, stdOut, stdErr) suite.Contains(stdErr, "Published "+ref) // Pull the package via OCI. - stdOut, stdErr, err = e2e.Zarf("package", "pull", "oci://"+ref+"/helm-charts:0.0.1", "--insecure") + stdOut, stdErr, err = e2e.Zarf(suite.T(), "package", "pull", "oci://"+ref+"/helm-charts:0.0.1", "--insecure") suite.NoError(err, stdOut, stdErr) // Publish w/ package missing `metadata.version` field. example = filepath.Join(suite.PackagesDir, fmt.Sprintf("zarf-package-component-actions-%s.tar.zst", e2e.Arch)) - _, stdErr, err = e2e.Zarf("package", "publish", example, "oci://"+ref, "--insecure") + _, stdErr, err = e2e.Zarf(suite.T(), "package", "publish", example, "oci://"+ref, "--insecure") suite.Error(err, stdErr) // Inline publish package. dir := filepath.Join("examples", "helm-charts") - stdOut, stdErr, err = e2e.Zarf("package", "create", dir, "-o", "oci://"+ref, "--insecure", "--oci-concurrency=5", "--confirm") + stdOut, stdErr, err = e2e.Zarf(suite.T(), "package", "create", dir, "-o", "oci://"+ref, "--insecure", "--oci-concurrency=5", "--confirm") suite.NoError(err, stdOut, stdErr) // Inline publish flavor. dir = filepath.Join("examples", "package-flavors") - stdOut, stdErr, err = e2e.Zarf("package", "create", dir, "-o", "oci://"+ref, "--flavor", "oracle-cookie-crunch", "--insecure", "--confirm") + stdOut, stdErr, err = e2e.Zarf(suite.T(), "package", "create", dir, "-o", "oci://"+ref, "--flavor", "oracle-cookie-crunch", "--insecure", "--confirm") suite.NoError(err, stdOut, stdErr) // Inspect published flavor. - stdOut, stdErr, err = e2e.Zarf("package", "inspect", "oci://"+ref+"/package-flavors:1.0.0-oracle-cookie-crunch", "--insecure") + stdOut, stdErr, err = e2e.Zarf(suite.T(), "package", "inspect", "oci://"+ref+"/package-flavors:1.0.0-oracle-cookie-crunch", "--insecure") suite.NoError(err, stdOut, stdErr) // Inspect the published package. - stdOut, stdErr, err = e2e.Zarf("package", "inspect", "oci://"+ref+"/helm-charts:0.0.1", "--insecure") + stdOut, stdErr, err = e2e.Zarf(suite.T(), "package", "inspect", "oci://"+ref+"/helm-charts:0.0.1", "--insecure") suite.NoError(err, stdOut, stdErr) } @@ -95,15 +95,15 @@ func (suite *PublishDeploySuiteTestSuite) Test_1_Deploy() { ref := suite.Reference.String() // Deploy the package via OCI. - stdOut, stdErr, err := e2e.Zarf("package", "deploy", "oci://"+ref, "--insecure", "--confirm") + stdOut, stdErr, err := e2e.Zarf(suite.T(), "package", "deploy", "oci://"+ref, "--insecure", "--confirm") suite.NoError(err, stdOut, stdErr) // Remove the package via OCI. - stdOut, stdErr, err = e2e.Zarf("package", "remove", "oci://"+ref, "--insecure", "--confirm") + stdOut, stdErr, err = e2e.Zarf(suite.T(), "package", "remove", "oci://"+ref, "--insecure", "--confirm") suite.NoError(err, stdOut, stdErr) // Test deploy w/ bad ref. - _, stdErr, err = e2e.Zarf("package", "deploy", "oci://"+badDeployRef.String(), "--insecure", "--confirm") + _, stdErr, err = e2e.Zarf(suite.T(), "package", "deploy", "oci://"+badDeployRef.String(), "--insecure", "--confirm") suite.Error(err, stdErr) } @@ -116,7 +116,7 @@ func (suite *PublishDeploySuiteTestSuite) Test_2_Pull_And_Deploy() { suite.FileExists(local) // Deploy the local package. - stdOut, stdErr, err := e2e.Zarf("package", "deploy", local, "--confirm") + stdOut, stdErr, err := e2e.Zarf(suite.T(), "package", "deploy", local, "--confirm") suite.NoError(err, stdOut, stdErr) } diff --git a/src/test/e2e/51_oci_compose_test.go b/src/test/e2e/51_oci_compose_test.go index b38db002a6..0d98d13c8b 100644 --- a/src/test/e2e/51_oci_compose_test.go +++ b/src/test/e2e/51_oci_compose_test.go @@ -63,50 +63,50 @@ func (suite *SkeletonSuite) Test_0_Publish_Skeletons() { ref := suite.Reference.String() helmCharts := filepath.Join("examples", "helm-charts") - _, stdErr, err := e2e.Zarf("package", "publish", helmCharts, "oci://"+ref, "--insecure") + _, stdErr, err := e2e.Zarf(suite.T(), "package", "publish", helmCharts, "oci://"+ref, "--insecure") suite.NoError(err) suite.Contains(stdErr, "Published "+ref) bigBang := filepath.Join("src", "test", "packages", "51-import-everything", "big-bang-min") - _, stdErr, err = e2e.Zarf("package", "publish", bigBang, "oci://"+ref, "--insecure") + _, stdErr, err = e2e.Zarf(suite.T(), "package", "publish", bigBang, "oci://"+ref, "--insecure") suite.NoError(err) suite.Contains(stdErr, "Published "+ref) composable := filepath.Join("src", "test", "packages", "09-composable-packages") - _, stdErr, err = e2e.Zarf("package", "publish", composable, "oci://"+ref, "--insecure") + _, stdErr, err = e2e.Zarf(suite.T(), "package", "publish", composable, "oci://"+ref, "--insecure") suite.NoError(err) suite.Contains(stdErr, "Published "+ref) - _, stdErr, err = e2e.Zarf("package", "publish", importEverything, "oci://"+ref, "--insecure") + _, stdErr, err = e2e.Zarf(suite.T(), "package", "publish", importEverything, "oci://"+ref, "--insecure") suite.NoError(err) suite.Contains(stdErr, "Published "+ref) - _, _, err = e2e.Zarf("package", "inspect", "oci://"+ref+"/import-everything:0.0.1", "--insecure", "-a", "skeleton") + _, _, err = e2e.Zarf(suite.T(), "package", "inspect", "oci://"+ref+"/import-everything:0.0.1", "--insecure", "-a", "skeleton") suite.NoError(err) - _, _, err = e2e.Zarf("package", "pull", "oci://"+ref+"/import-everything:0.0.1", "-o", "build", "--insecure", "-a", "skeleton") + _, _, err = e2e.Zarf(suite.T(), "package", "pull", "oci://"+ref+"/import-everything:0.0.1", "-o", "build", "--insecure", "-a", "skeleton") suite.NoError(err) - _, _, err = e2e.Zarf("package", "pull", "oci://"+ref+"/helm-charts:0.0.1", "-o", "build", "--insecure", "-a", "skeleton") + _, _, err = e2e.Zarf(suite.T(), "package", "pull", "oci://"+ref+"/helm-charts:0.0.1", "-o", "build", "--insecure", "-a", "skeleton") suite.NoError(err) - _, _, err = e2e.Zarf("package", "pull", "oci://"+ref+"/big-bang-min:2.10.0", "-o", "build", "--insecure", "-a", "skeleton") + _, _, err = e2e.Zarf(suite.T(), "package", "pull", "oci://"+ref+"/big-bang-min:2.10.0", "-o", "build", "--insecure", "-a", "skeleton") suite.NoError(err) - _, _, err = e2e.Zarf("package", "pull", "oci://"+ref+"/test-compose-package:0.0.1", "-o", "build", "--insecure", "-a", "skeleton") + _, _, err = e2e.Zarf(suite.T(), "package", "pull", "oci://"+ref+"/test-compose-package:0.0.1", "-o", "build", "--insecure", "-a", "skeleton") suite.NoError(err) } func (suite *SkeletonSuite) Test_1_Compose_Everything_Inception() { suite.T().Log("E2E: Skeleton Package Compose oci://") - _, _, err := e2e.Zarf("package", "create", importEverything, "-o", "build", "--insecure", "--confirm") + _, _, err := e2e.Zarf(suite.T(), "package", "create", importEverything, "-o", "build", "--insecure", "--confirm") suite.NoError(err) - _, _, err = e2e.Zarf("package", "create", importception, "-o", "build", "--insecure", "--confirm") + _, _, err = e2e.Zarf(suite.T(), "package", "create", importception, "-o", "build", "--insecure", "--confirm") suite.NoError(err) - _, stdErr, err := e2e.Zarf("package", "inspect", importEverythingPath) + _, stdErr, err := e2e.Zarf(suite.T(), "package", "inspect", importEverythingPath) suite.NoError(err) targets := []string{ @@ -140,7 +140,7 @@ func (suite *SkeletonSuite) Test_2_FilePaths() { unpacked := strings.TrimSuffix(pkgTar, ".tar.zst") defer os.RemoveAll(unpacked) defer os.RemoveAll(pkgTar) - _, _, err := e2e.Zarf("tools", "archiver", "decompress", pkgTar, unpacked, "--unarchive-all") + _, _, err := e2e.Zarf(suite.T(), "tools", "archiver", "decompress", pkgTar, unpacked, "--unarchive-all") suite.NoError(err) suite.DirExists(unpacked) diff --git a/src/test/e2e/99_appliance_remove_test.go b/src/test/e2e/99_appliance_remove_test.go index 321f353228..1cd25d41e4 100644 --- a/src/test/e2e/99_appliance_remove_test.go +++ b/src/test/e2e/99_appliance_remove_test.go @@ -24,23 +24,23 @@ func TestApplianceRemove(t *testing.T) { path := fmt.Sprintf("build/zarf-init-%s-%s.tar.zst", e2e.Arch, initPackageVersion) // Package remove the cluster to test Zarf cleaning up after itself - stdOut, stdErr, err := e2e.Zarf("package", "remove", path, "--confirm") + stdOut, stdErr, err := e2e.Zarf(t, "package", "remove", path, "--confirm") require.NoError(t, err, stdOut, stdErr) // Check that the cluster is now gone - _, _, err = e2e.Kubectl("get", "nodes") + _, _, err = e2e.Kubectl(t, "get", "nodes") require.Error(t, err) // TODO (@WSTARR) - This needs to be refactored to use the remove logic instead of reaching into a magic directory // Re-init the cluster so that we can test if the destroy scripts run - stdOut, stdErr, err = e2e.Zarf("init", "--components=k3s", "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "init", "--components=k3s", "--confirm") require.NoError(t, err, stdOut, stdErr) // Destroy the cluster to test Zarf cleaning up after itself - stdOut, stdErr, err = e2e.Zarf("destroy", "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "destroy", "--confirm") require.NoError(t, err, stdOut, stdErr) // Check that the cluster gone again - _, _, err = e2e.Kubectl("get", "nodes") + _, _, err = e2e.Kubectl(t, "get", "nodes") require.Error(t, err) } diff --git a/src/test/e2e/99_yolo_test.go b/src/test/e2e/99_yolo_test.go index 93a9b9ed60..03281df1a7 100644 --- a/src/test/e2e/99_yolo_test.go +++ b/src/test/e2e/99_yolo_test.go @@ -23,13 +23,13 @@ func TestYOLOMode(t *testing.T) { } // Destroy the cluster to test Zarf cleaning up after itself - stdOut, stdErr, err := e2e.Zarf("destroy", "--confirm", "--remove-components") + stdOut, stdErr, err := e2e.Zarf(t, "destroy", "--confirm", "--remove-components") require.NoError(t, err, stdOut, stdErr) path := fmt.Sprintf("build/zarf-package-yolo-%s.tar.zst", e2e.Arch) // Deploy the YOLO package - stdOut, stdErr, err = e2e.Zarf("package", "deploy", path, "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "deploy", path, "--confirm") require.NoError(t, err, stdOut, stdErr) c, err := cluster.NewCluster() @@ -43,7 +43,7 @@ func TestYOLOMode(t *testing.T) { require.NoError(t, err, resp) require.Equal(t, 200, resp.StatusCode) - stdOut, stdErr, err = e2e.Zarf("package", "remove", "yolo", "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "remove", "yolo", "--confirm") require.NoError(t, err, stdOut, stdErr) } @@ -53,9 +53,9 @@ func TestDevDeploy(t *testing.T) { return } - stdOut, stdErr, err := e2e.Zarf("dev", "deploy", "examples/dos-games") + stdOut, stdErr, err := e2e.Zarf(t, "dev", "deploy", "examples/dos-games") require.NoError(t, err, stdOut, stdErr) - stdOut, stdErr, err = e2e.Zarf("package", "remove", "dos-games", "--confirm") + stdOut, stdErr, err = e2e.Zarf(t, "package", "remove", "dos-games", "--confirm") require.NoError(t, err, stdOut, stdErr) } diff --git a/src/test/external/common.go b/src/test/external/common.go index 36e8405a25..0209ddadb2 100644 --- a/src/test/external/common.go +++ b/src/test/external/common.go @@ -5,7 +5,6 @@ package external import ( - "context" "path" "path/filepath" "strings" @@ -47,7 +46,7 @@ func verifyWaitSuccess(t *testing.T, timeoutMinutes time.Duration, cmd string, a // after delay, try running default: // Check information from the given command - stdOut, _, err := exec.CmdWithContext(context.TODO(), exec.PrintCfg(), cmd, args...) + stdOut, _, err := exec.CmdWithTesting(t, exec.PrintCfg(), cmd, args...) // Log error if err != nil { t.Log(string(stdOut), err) diff --git a/src/test/external/ext_in_cluster_test.go b/src/test/external/ext_in_cluster_test.go index 97a52fda0a..bddc84fbf6 100644 --- a/src/test/external/ext_in_cluster_test.go +++ b/src/test/external/ext_in_cluster_test.go @@ -187,7 +187,7 @@ func (suite *ExtInClusterTestSuite) Test_1_Deploy() { err = pkgkubernetes.WaitForReady(waitCtx, c.Watcher, objs) suite.NoError(err) - _, _, err = exec.CmdWithContext(context.TODO(), exec.PrintCfg(), zarfBinPath, "destroy", "--confirm") + _, _, err = exec.CmdWithTesting(suite.T(), exec.PrintCfg(), zarfBinPath, "destroy", "--confirm") suite.NoError(err, "unable to teardown zarf") } diff --git a/src/test/nightly/ecr_publish_test.go b/src/test/nightly/ecr_publish_test.go index 2d872c16e1..ea58faa677 100644 --- a/src/test/nightly/ecr_publish_test.go +++ b/src/test/nightly/ecr_publish_test.go @@ -50,33 +50,33 @@ func TestECRPublishing(t *testing.T) { keyFlag := fmt.Sprintf("--key=%s", "./src/test/packages/zarf-test.pub") // Build the package with our test signature - stdOut, stdErr, err := e2e.Zarf("package", "create", "examples/helm-charts", "--signing-key=./src/test/packages/zarf-test.prv-key", "--confirm", fmt.Sprintf("-o=%s", tmpDir)) + stdOut, stdErr, err := e2e.Zarf(t, "package", "create", "examples/helm-charts", "--signing-key=./src/test/packages/zarf-test.prv-key", "--confirm", fmt.Sprintf("-o=%s", tmpDir)) require.NoError(t, err, stdOut, stdErr) require.FileExists(t, testPackageLocation) // Validate that we can publish the package to ECR without an issue - stdOut, stdErr, err = e2e.Zarf("package", "publish", testPackageLocation, registryURL, keyFlag) + stdOut, stdErr, err = e2e.Zarf(t, "package", "publish", testPackageLocation, registryURL, keyFlag) require.NoError(t, err, stdOut, stdErr) // Ensure we get a warning when trying to inspect the online published package - stdOut, stdErr, err = e2e.Zarf("package", "inspect", upstreamPackageURL, keyFlag, "--sbom-out", tmpDir) + stdOut, stdErr, err = e2e.Zarf(t, "package", "inspect", upstreamPackageURL, keyFlag, "--sbom-out", tmpDir) require.NoError(t, err, stdOut, stdErr) require.Contains(t, stdErr, "Validating SBOM checksums") require.Contains(t, stdErr, "Package signature validated!") // Validate that we can pull the package down from ECR - stdOut, stdErr, err = e2e.Zarf("package", "pull", upstreamPackageURL) + stdOut, stdErr, err = e2e.Zarf(t, "package", "pull", upstreamPackageURL) require.NoError(t, err, stdOut, stdErr) defer e2e.CleanFiles(testPackageFileName) // Ensure we get a warning when trying to inspect the package without providing the public key - stdOut, stdErr, err = e2e.Zarf("package", "inspect", testPackageFileName) + stdOut, stdErr, err = e2e.Zarf(t, "package", "inspect", testPackageFileName) require.NoError(t, err, stdOut, stdErr) require.NotContains(t, stdErr, "Validating SBOM checksums") require.Contains(t, stdErr, "The package was signed but no public key was provided, skipping signature validation") // Validate that we get no warnings when inspecting the package while providing the public key - stdOut, stdErr, err = e2e.Zarf("package", "inspect", testPackageFileName, keyFlag) + stdOut, stdErr, err = e2e.Zarf(t, "package", "inspect", testPackageFileName, keyFlag) require.NoError(t, err, stdOut, stdErr) require.NotContains(t, stdErr, "Validating SBOM checksums") require.Contains(t, stdErr, "Package signature validated!") diff --git a/src/test/upgrade/previously_built_test.go b/src/test/upgrade/previously_built_test.go index a7c42e87a1..0b59761d6d 100644 --- a/src/test/upgrade/previously_built_test.go +++ b/src/test/upgrade/previously_built_test.go @@ -5,7 +5,6 @@ package upgrade import ( - "context" "path" "testing" @@ -14,15 +13,15 @@ import ( test "github.com/zarf-dev/zarf/src/test" ) -func kubectl(args ...string) (string, string, error) { +func kubectl(t *testing.T, args ...string) (string, string, error) { tk := []string{"tools", "kubectl"} args = append(tk, args...) - return zarf(args...) + return zarf(t, args...) } -func zarf(args ...string) (string, string, error) { +func zarf(t *testing.T, args ...string) (string, string, error) { zarfBinPath := path.Join("../../../build", test.GetCLIName()) - return exec.CmdWithContext(context.TODO(), exec.PrintCfg(), zarfBinPath, args...) + return exec.CmdWithTesting(t, exec.PrintCfg(), zarfBinPath, args...) } func TestPreviouslyBuiltZarfPackage(t *testing.T) { @@ -30,18 +29,18 @@ func TestPreviouslyBuiltZarfPackage(t *testing.T) { t.Log("Upgrade: Previously Built Zarf Package") // For the upgrade test, podinfo-upgrade should already be in the cluster (version 6.3.3) (see .github/workflows/test-upgrade.yml) - kubectlOut, _, _ := kubectl("-n=podinfo-upgrade", "rollout", "status", "deployment/podinfo-upgrade") + kubectlOut, _, _ := kubectl(t, "-n=podinfo-upgrade", "rollout", "status", "deployment/podinfo-upgrade") require.Contains(t, kubectlOut, "successfully rolled out") - kubectlOut, _, _ = kubectl("-n=podinfo-upgrade", "get", "deployment", "podinfo-upgrade", "-o=jsonpath={.metadata.labels}}") + kubectlOut, _, _ = kubectl(t, "-n=podinfo-upgrade", "get", "deployment", "podinfo-upgrade", "-o=jsonpath={.metadata.labels}}") require.Contains(t, kubectlOut, "6.3.3") // Verify that the private-registry secret and private-git-server secret in the podinfo-upgrade namespace are the same after re-init // This tests that `zarf tools update-creds` successfully updated the other namespace - zarfRegistrySecret, _, _ := kubectl("-n=zarf", "get", "secret", "private-registry", "-o", "jsonpath={.data}") - podinfoRegistrySecret, _, _ := kubectl("-n=podinfo-upgrade", "get", "secret", "private-registry", "-o", "jsonpath={.data}") + zarfRegistrySecret, _, _ := kubectl(t, "-n=zarf", "get", "secret", "private-registry", "-o", "jsonpath={.data}") + podinfoRegistrySecret, _, _ := kubectl(t, "-n=podinfo-upgrade", "get", "secret", "private-registry", "-o", "jsonpath={.data}") require.Equal(t, zarfRegistrySecret, podinfoRegistrySecret, "the zarf registry secret and podinfo-upgrade registry secret did not match") - zarfGitServerSecret, _, _ := kubectl("-n=zarf", "get", "secret", "private-git-server", "-o", "jsonpath={.data}") - podinfoGitServerSecret, _, _ := kubectl("-n=podinfo-upgrade", "get", "secret", "private-git-server", "-o", "jsonpath={.data}") + zarfGitServerSecret, _, _ := kubectl(t, "-n=zarf", "get", "secret", "private-git-server", "-o", "jsonpath={.data}") + podinfoGitServerSecret, _, _ := kubectl(t, "-n=podinfo-upgrade", "get", "secret", "private-git-server", "-o", "jsonpath={.data}") require.Equal(t, zarfGitServerSecret, podinfoGitServerSecret, "the zarf git server secret and podinfo-upgrade git server secret did not match") // We also expect a 6.3.4 package to have been previously built @@ -49,7 +48,7 @@ func TestPreviouslyBuiltZarfPackage(t *testing.T) { // Deploy the package. zarfDeployArgs := []string{"package", "deploy", previouslyBuiltPackage, "--confirm"} - stdOut, stdErr, err := zarf(zarfDeployArgs...) + stdOut, stdErr, err := zarf(t, zarfDeployArgs...) require.NoError(t, err, stdOut, stdErr) // [DEPRECATIONS] We expect any deprecated things to work from the old package @@ -57,18 +56,18 @@ func TestPreviouslyBuiltZarfPackage(t *testing.T) { require.Contains(t, stdErr, "-----BEGIN PUBLIC KEY-----") // Verify that podinfo-upgrade successfully deploys in the cluster (version 6.3.4) - kubectlOut, _, _ = kubectl("-n=podinfo-upgrade", "rollout", "status", "deployment/podinfo-upgrade") + kubectlOut, _, _ = kubectl(t, "-n=podinfo-upgrade", "rollout", "status", "deployment/podinfo-upgrade") require.Contains(t, kubectlOut, "successfully rolled out") - kubectlOut, _, _ = kubectl("-n=podinfo-upgrade", "get", "deployment", "podinfo-upgrade", "-o=jsonpath={.metadata.labels}}") + kubectlOut, _, _ = kubectl(t, "-n=podinfo-upgrade", "get", "deployment", "podinfo-upgrade", "-o=jsonpath={.metadata.labels}}") require.Contains(t, kubectlOut, "6.3.4") // We also want to build a new package. - stdOut, stdErr, err = zarf("package", "create", "../../../src/test/upgrade", "--set", "PODINFO_VERSION=6.3.5", "--confirm") + stdOut, stdErr, err = zarf(t, "package", "create", "../../../src/test/upgrade", "--set", "PODINFO_VERSION=6.3.5", "--confirm") require.NoError(t, err, stdOut, stdErr) newlyBuiltPackage := "zarf-package-test-upgrade-package-amd64-6.3.5.tar.zst" // Deploy the package. - stdOut, stdErr, err = zarf("package", "deploy", newlyBuiltPackage, "--confirm") + stdOut, stdErr, err = zarf(t, "package", "deploy", newlyBuiltPackage, "--confirm") require.NoError(t, err, stdOut, stdErr) // [DEPRECATIONS] We expect any deprecated things to work from the new package @@ -76,12 +75,12 @@ func TestPreviouslyBuiltZarfPackage(t *testing.T) { require.Contains(t, stdErr, "-----BEGIN PUBLIC KEY-----") // Verify that podinfo-upgrade successfully deploys in the cluster (version 6.3.5) - kubectlOut, _, _ = kubectl("-n=podinfo-upgrade", "rollout", "status", "deployment/podinfo-upgrade") + kubectlOut, _, _ = kubectl(t, "-n=podinfo-upgrade", "rollout", "status", "deployment/podinfo-upgrade") require.Contains(t, kubectlOut, "successfully rolled out") - kubectlOut, _, _ = kubectl("-n=podinfo-upgrade", "get", "deployment", "podinfo-upgrade", "-o=jsonpath={.metadata.labels}}") + kubectlOut, _, _ = kubectl(t, "-n=podinfo-upgrade", "get", "deployment", "podinfo-upgrade", "-o=jsonpath={.metadata.labels}}") require.Contains(t, kubectlOut, "6.3.5") // Remove the package. - stdOut, stdErr, err = zarf("package", "remove", "test-upgrade-package", "--confirm") + stdOut, stdErr, err = zarf(t, "package", "remove", "test-upgrade-package", "--confirm") require.NoError(t, err, stdOut, stdErr) } From 1c8e55f265ed8bb57cf1ee7008956725be42451f Mon Sep 17 00:00:00 2001 From: Xander Grzywinski Date: Thu, 25 Jul 2024 01:53:12 -0700 Subject: [PATCH 23/68] docs: update repo name across docs (#2735) Signed-off-by: Xander Grzywinski Co-authored-by: Austin Abro <37223396+AustinAbro321@users.noreply.github.com> --- site/public/tutorials/package_create_wordpress.html | 2 +- site/src/content/docs/ref/deploy.mdx | 2 +- site/src/content/docs/ref/deployment-ui.mdx | 2 +- site/src/content/docs/roadmap.mdx | 2 +- site/src/content/docs/tutorials/3-deploy-a-retro-arcade.mdx | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/site/public/tutorials/package_create_wordpress.html b/site/public/tutorials/package_create_wordpress.html index abb216bb08..940bd94cc9 100644 --- a/site/public/tutorials/package_create_wordpress.html +++ b/site/public/tutorials/package_create_wordpress.html @@ -91,7 +91,7 @@ sensitive: true - name: WORDPRESS_EMAIL description: The email that is used for the WordPress admin account - default: hello@defenseunicorns.com + default: hello@zarf-dev.com prompt: true - name: WORDPRESS_FIRST_NAME description: The first name that is used for the WordPress admin account diff --git a/site/src/content/docs/ref/deploy.mdx b/site/src/content/docs/ref/deploy.mdx index 28e61f7114..dbb5dc1679 100644 --- a/site/src/content/docs/ref/deploy.mdx +++ b/site/src/content/docs/ref/deploy.mdx @@ -117,7 +117,7 @@ $ zarf connect [service name] :::note -You can also specify a package locally, or via oci such as `zarf package deploy oci://defenseunicorns/dos-games:1.0.0-$(uname -m) --key=https://zarf.dev/cosign.pub` +You can also specify a package locally, or via oci such as `zarf package deploy oci://defenseunicorns/dos-games:1.0.0 --key=https://zarf.dev/cosign.pub` ::: diff --git a/site/src/content/docs/ref/deployment-ui.mdx b/site/src/content/docs/ref/deployment-ui.mdx index c560a4fc92..b21f028a51 100644 --- a/site/src/content/docs/ref/deployment-ui.mdx +++ b/site/src/content/docs/ref/deployment-ui.mdx @@ -24,7 +24,7 @@ The Zarf Deployment Web UI can easily be downloaded from the [Zarf UI Github Pro Follow these steps to get started using the Web UI -1. Step one: [Download the Zarf UI](https://github.com/defenseunicorns/zarf-ui/releases/latest) version that matches your system (i.e. `zarf-ui_v0.1.0-Darwin_arm64`) +1. Step one: [Download the Zarf UI](https://github.com/zarf-dev/zarf-ui/releases/latest) version that matches your system (i.e. `zarf-ui_v0.1.0-Darwin_arm64`) 2. Step two: (if applicable) Mark the file as executable with `chmod +x zarf-ui_v0.1.0-Darwin_arm64` 3. Step three: Run the binary with `./zarf-ui_v0.1.0-Darwin_arm64` or by double clicking the file in your file browser diff --git a/site/src/content/docs/roadmap.mdx b/site/src/content/docs/roadmap.mdx index 43a80e41ad..f0a9244752 100644 --- a/site/src/content/docs/roadmap.mdx +++ b/site/src/content/docs/roadmap.mdx @@ -4,7 +4,7 @@ title: Roadmap ## Issue Tracking -The issue board for Zarf is hosted on a [GitHub Project Board](https://github.com/orgs/defenseunicorns/projects/1) that tracks the issues the Zarf team is working along with future work we are prioritizing. +The issue board for Zarf is hosted on a [GitHub Project Board](https://github.com/orgs/zarf-dev/projects/1) that tracks the issues the Zarf team is working along with future work we are prioritizing. If you would like to add bug reports or feature requests, please [add an issue](https://github.com/zarf-dev/zarf/issues) to the GitHub repository under the appropriate template. If you have a more general question about a feature, feel free to ask the team in the [Zarf Kubernetes Slack Channel](https://kubernetes.slack.com/archives/C03B6BJAUJ3). diff --git a/site/src/content/docs/tutorials/3-deploy-a-retro-arcade.mdx b/site/src/content/docs/tutorials/3-deploy-a-retro-arcade.mdx index abfcd55b42..ebb499ffbb 100644 --- a/site/src/content/docs/tutorials/3-deploy-a-retro-arcade.mdx +++ b/site/src/content/docs/tutorials/3-deploy-a-retro-arcade.mdx @@ -22,7 +22,7 @@ Before beginning this tutorial you will need the following: ## Deploying the Arcade -1. The `dos-games` package is easily deployable via `oci://` by running `zarf package deploy oci://defenseunicorns/dos-games:1.0.0-$(uname -m) --key=https://zarf.dev/cosign.pub`. +1. The `dos-games` package is easily deployable via `oci://` by running `zarf package deploy oci://defenseunicorns/dos-games:1.0.0 --key=https://zarf.dev/cosign.pub`. :::tip From 5f91e88d4036e05de4dd822d882a3775f94fa48a Mon Sep 17 00:00:00 2001 From: Philip Laine Date: Thu, 25 Jul 2024 15:38:54 +0200 Subject: [PATCH 24/68] fix: add whitespace linter and fix all warnings (#2764) Signed-off-by: Philip Laine --- .golangci.yaml | 1 + src/cmd/tools/yq.go | 1 - src/extensions/bigbang/flux.go | 1 - src/internal/agent/hooks/flux-gitrepo.go | 1 - src/internal/agent/hooks/flux-helmrepo.go | 1 - src/internal/agent/hooks/flux-ocirepo.go | 1 - src/internal/packager/git/gitea.go | 1 - src/internal/packager/helm/post-render.go | 2 -- src/internal/packager/helm/repo.go | 1 - src/pkg/cluster/zarf.go | 1 - src/pkg/interactive/prompt.go | 1 - src/pkg/message/credentials.go | 1 - src/pkg/packager/actions/actions.go | 1 - src/pkg/packager/common.go | 1 - src/pkg/packager/composer/oci.go | 1 - src/pkg/packager/creator/skeleton.go | 1 - src/pkg/packager/deploy.go | 2 -- src/pkg/packager/filters/deploy_test.go | 1 - src/pkg/packager/filters/os_test.go | 1 - src/pkg/packager/prepare.go | 2 -- src/pkg/utils/bytes.go | 1 - src/pkg/utils/image.go | 1 - src/pkg/utils/wait.go | 3 --- src/pkg/zoci/copier.go | 1 - src/test/e2e/02_component_actions_test.go | 2 -- src/test/e2e/12_lint_test.go | 2 -- src/test/e2e/13_find_images_test.go | 2 -- src/test/e2e/14_create_sha_index_test.go | 1 - src/test/e2e/50_oci_publish_deploy_test.go | 1 - src/test/e2e/51_oci_compose_test.go | 3 --- src/test/external/ext_out_cluster_test.go | 1 - src/types/validate.go | 1 - 32 files changed, 1 insertion(+), 41 deletions(-) diff --git a/.golangci.yaml b/.golangci.yaml index ab7cc77904..37d811f119 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -14,6 +14,7 @@ linters: - goimports - nolintlint - testifylint + - whitespace linters-settings: govet: enable-all: true diff --git a/src/cmd/tools/yq.go b/src/cmd/tools/yq.go index 85d72ab767..41839f568b 100644 --- a/src/cmd/tools/yq.go +++ b/src/cmd/tools/yq.go @@ -10,7 +10,6 @@ import ( ) func init() { - yqCmd := yq.New() yqCmd.Example = lang.CmdToolsYqExample yqCmd.Use = "yq" diff --git a/src/extensions/bigbang/flux.go b/src/extensions/bigbang/flux.go index d67097f26c..91680970e9 100644 --- a/src/extensions/bigbang/flux.go +++ b/src/extensions/bigbang/flux.go @@ -120,7 +120,6 @@ func readFluxImages(localPath string) (images []string, err error) { for _, container := range pod.Containers { images = append(images, container.Image) } - } } diff --git a/src/internal/agent/hooks/flux-gitrepo.go b/src/internal/agent/hooks/flux-gitrepo.go index 079ee6a8e0..38a5aedadb 100644 --- a/src/internal/agent/hooks/flux-gitrepo.go +++ b/src/internal/agent/hooks/flux-gitrepo.go @@ -38,7 +38,6 @@ func NewGitRepositoryMutationHook(ctx context.Context, cluster *cluster.Cluster) // mutateGitRepoCreate mutates the git repository url to point to the repository URL defined in the ZarfState. func mutateGitRepo(ctx context.Context, r *v1.AdmissionRequest, cluster *cluster.Cluster) (result *operations.Result, err error) { - var ( patches []operations.PatchOperation isPatched bool diff --git a/src/internal/agent/hooks/flux-helmrepo.go b/src/internal/agent/hooks/flux-helmrepo.go index 90aab22f7a..c053bb669b 100644 --- a/src/internal/agent/hooks/flux-helmrepo.go +++ b/src/internal/agent/hooks/flux-helmrepo.go @@ -36,7 +36,6 @@ func NewHelmRepositoryMutationHook(ctx context.Context, cluster *cluster.Cluster // mutateHelmRepo mutates the repository url to point to the repository URL defined in the ZarfState. func mutateHelmRepo(ctx context.Context, r *v1.AdmissionRequest, cluster *cluster.Cluster) (*operations.Result, error) { - src := &flux.HelmRepository{} if err := json.Unmarshal(r.Object.Raw, &src); err != nil { return nil, fmt.Errorf(lang.ErrUnmarshal, err) diff --git a/src/internal/agent/hooks/flux-ocirepo.go b/src/internal/agent/hooks/flux-ocirepo.go index 045b315e3a..021a0a619d 100644 --- a/src/internal/agent/hooks/flux-ocirepo.go +++ b/src/internal/agent/hooks/flux-ocirepo.go @@ -35,7 +35,6 @@ func NewOCIRepositoryMutationHook(ctx context.Context, cluster *cluster.Cluster) // mutateOCIRepo mutates the oci repository url to point to the repository URL defined in the ZarfState. func mutateOCIRepo(ctx context.Context, r *v1.AdmissionRequest, cluster *cluster.Cluster) (*operations.Result, error) { - src := &flux.OCIRepository{} if err := json.Unmarshal(r.Object.Raw, &src); err != nil { return nil, fmt.Errorf(lang.ErrUnmarshal, err) diff --git a/src/internal/packager/git/gitea.go b/src/internal/packager/git/gitea.go index a6c2f4b48a..4bfbcf60ab 100644 --- a/src/internal/packager/git/gitea.go +++ b/src/internal/packager/git/gitea.go @@ -103,7 +103,6 @@ func (g *Git) CreateReadOnlyUser(ctx context.Context) error { // UpdateZarfGiteaUsers updates Zarf gitea users func (g *Git) UpdateZarfGiteaUsers(ctx context.Context, oldState *types.ZarfState) error { - //Update git read only user password err := g.UpdateGitUser(ctx, oldState.GitServer.PushPassword, g.Server.PullUsername, g.Server.PullPassword) if err != nil { diff --git a/src/internal/packager/helm/post-render.go b/src/internal/packager/helm/post-render.go index 9a514fc6a6..60d8fde0e3 100644 --- a/src/internal/packager/helm/post-render.go +++ b/src/internal/packager/helm/post-render.go @@ -125,7 +125,6 @@ func (r *renderer) adoptAndUpdateNamespaces(ctx context.Context) error { return err } for name, namespace := range r.namespaces { - // Check to see if this namespace already exists var existingNamespace bool for _, serverNamespace := range namespaceList.Items { @@ -205,7 +204,6 @@ func (r *renderer) adoptAndUpdateNamespaces(ctx context.Context) error { if err != nil { message.WarnErrf(err, "Problem creating git server secret for the %s namespace", name) } - } } return nil diff --git a/src/internal/packager/helm/repo.go b/src/internal/packager/helm/repo.go index 148a4176a4..1e47b6e6bf 100644 --- a/src/internal/packager/helm/repo.go +++ b/src/internal/packager/helm/repo.go @@ -58,7 +58,6 @@ func (h *Helm) PackageChart(ctx context.Context, cosignKeyPath string) error { return fmt.Errorf("unable to download the published chart %q: %w", h.chart.Name, err) } } - } else { err := h.PackageChartFromLocalFiles(cosignKeyPath) if err != nil { diff --git a/src/pkg/cluster/zarf.go b/src/pkg/cluster/zarf.go index 7320e4610b..71d6f73c9e 100644 --- a/src/pkg/cluster/zarf.go +++ b/src/pkg/cluster/zarf.go @@ -105,7 +105,6 @@ func (c *Cluster) StripZarfLabelsAndSecretsFromNamespaces(ctx context.Context) { // PackageSecretNeedsWait checks if a package component has a running webhook that needs to be waited on. func (c *Cluster) PackageSecretNeedsWait(deployedPackage *types.DeployedPackage, component types.ZarfComponent, skipWebhooks bool) (needsWait bool, waitSeconds int, hookName string) { - // Skip checking webhook status when '--skip-webhooks' flag is provided and for YOLO packages if skipWebhooks || deployedPackage == nil || deployedPackage.Data.Metadata.YOLO { return false, 0, "" diff --git a/src/pkg/interactive/prompt.go b/src/pkg/interactive/prompt.go index 759f520948..c22b05e449 100644 --- a/src/pkg/interactive/prompt.go +++ b/src/pkg/interactive/prompt.go @@ -24,7 +24,6 @@ func PromptSigPassword() ([]byte, error) { // PromptVariable prompts the user for a value for a variable func PromptVariable(variable variables.InteractiveVariable) (value string, err error) { - if variable.Description != "" { message.Question(variable.Description) } diff --git a/src/pkg/message/credentials.go b/src/pkg/message/credentials.go index 74b127a1c6..34134e6484 100644 --- a/src/pkg/message/credentials.go +++ b/src/pkg/message/credentials.go @@ -91,7 +91,6 @@ func PrintCredentialUpdates(oldState *types.ZarfState, newState *types.ZarfState } for _, service := range services { - HorizontalRule() switch service { diff --git a/src/pkg/packager/actions/actions.go b/src/pkg/packager/actions/actions.go index c92457675c..541c73b0fe 100644 --- a/src/pkg/packager/actions/actions.go +++ b/src/pkg/packager/actions/actions.go @@ -97,7 +97,6 @@ func runAction(defaultCfg types.ZarfComponentActionDefaults, action types.ZarfCo // Keep trying until the max retries is reached. retryCmd: for remaining := actionDefaults.MaxRetries + 1; remaining > 0; remaining-- { - // Perform the action run. tryCmd := func(ctx context.Context) error { // Try running the command and continue the retry loop if it fails. diff --git a/src/pkg/packager/common.go b/src/pkg/packager/common.go index d790275d12..a5b77ff9d1 100644 --- a/src/pkg/packager/common.go +++ b/src/pkg/packager/common.go @@ -170,7 +170,6 @@ func (p *Packager) hasImages() bool { // attemptClusterChecks attempts to connect to the cluster and check for useful metadata and config mismatches. // NOTE: attemptClusterChecks should only return an error if there is a problem significant enough to halt a deployment, otherwise it should return nil and print a warning message. func (p *Packager) attemptClusterChecks(ctx context.Context) (err error) { - spinner := message.NewProgressSpinner("Gathering additional cluster information (if available)") defer spinner.Stop() diff --git a/src/pkg/packager/composer/oci.go b/src/pkg/packager/composer/oci.go index 129013d487..2541e45f32 100644 --- a/src/pkg/packager/composer/oci.go +++ b/src/pkg/packager/composer/oci.go @@ -104,7 +104,6 @@ func (ic *ImportChain) fetchOCISkeleton(ctx context.Context) error { if err != nil { return err } - } } diff --git a/src/pkg/packager/creator/skeleton.go b/src/pkg/packager/creator/skeleton.go index 091874c84f..3c95623542 100644 --- a/src/pkg/packager/creator/skeleton.go +++ b/src/pkg/packager/creator/skeleton.go @@ -182,7 +182,6 @@ func (sc *SkeletonCreator) addComponent(component types.ZarfComponent, dst *layo // If any helm charts are defined, process them. for chartIdx, chart := range component.Charts { - if chart.LocalPath != "" { rel := filepath.Join(layout.ChartsDir, fmt.Sprintf("%s-%d", chart.Name, chartIdx)) dst := filepath.Join(componentPaths.Base, rel) diff --git a/src/pkg/packager/deploy.go b/src/pkg/packager/deploy.go index 73aec8f006..735a0b69db 100644 --- a/src/pkg/packager/deploy.go +++ b/src/pkg/packager/deploy.go @@ -142,7 +142,6 @@ func (p *Packager) deployComponents(ctx context.Context) (deployedComponents []t // Process all the components we are deploying for _, component := range p.cfg.Pkg.Components { - deployedComponent := types.DeployedComponent{ Name: component.Name, Status: types.ComponentStatusDeploying, @@ -716,7 +715,6 @@ func (p *Packager) installChartAndManifests(ctx context.Context, componentPaths } func (p *Packager) printTablesForDeployment(ctx context.Context, componentsToDeploy []types.DeployedComponent) { - // If not init config, print the application connection table if !p.cfg.Pkg.IsInitConfig() { message.PrintConnectStringTable(p.connectStrings) diff --git a/src/pkg/packager/filters/deploy_test.go b/src/pkg/packager/filters/deploy_test.go index 5b31a2269e..7c69007223 100644 --- a/src/pkg/packager/filters/deploy_test.go +++ b/src/pkg/packager/filters/deploy_test.go @@ -111,7 +111,6 @@ func componentMatrix(_ *testing.T) []types.ZarfComponent { } func TestDeployFilter_Apply(t *testing.T) { - possibilities := componentMatrix(t) tests := map[string]struct { diff --git a/src/pkg/packager/filters/os_test.go b/src/pkg/packager/filters/os_test.go index 4dcc4b5279..98c5678c96 100644 --- a/src/pkg/packager/filters/os_test.go +++ b/src/pkg/packager/filters/os_test.go @@ -12,7 +12,6 @@ import ( ) func TestLocalOSFilter(t *testing.T) { - pkg := types.ZarfPackage{} for _, os := range types.SupportedOS() { pkg.Components = append(pkg.Components, types.ZarfComponent{ diff --git a/src/pkg/packager/prepare.go b/src/pkg/packager/prepare.go index 2b888c3966..ea883d6970 100644 --- a/src/pkg/packager/prepare.go +++ b/src/pkg/packager/prepare.go @@ -118,7 +118,6 @@ func (p *Packager) findImages(ctx context.Context) (imgMap map[string][]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 @@ -163,7 +162,6 @@ func (p *Packager) findImages(ctx context.Context) (imgMap map[string][]string, } for _, chart := range component.Charts { - helmCfg := helm.New( chart, componentPaths.Charts, diff --git a/src/pkg/utils/bytes.go b/src/pkg/utils/bytes.go index 032cc65334..7dd159b91f 100644 --- a/src/pkg/utils/bytes.go +++ b/src/pkg/utils/bytes.go @@ -60,7 +60,6 @@ func ByteFormat(inputNum float64, precision int) string { // RenderProgressBarForLocalDirWrite creates a progress bar that continuously tracks the progress of writing files to a local directory and all of its subdirectories. // NOTE: This function runs infinitely until either completeChan or errChan is triggered, this function should be run in a goroutine while a different thread/process is writing to the directory. func RenderProgressBarForLocalDirWrite(filepath string, expectedTotal int64, completeChan chan error, updateText string, successText string) { - // Create a progress bar title := fmt.Sprintf("%s (%s of %s)", updateText, ByteFormat(float64(0), 2), ByteFormat(float64(expectedTotal), 2)) progressBar := message.NewProgressBar(expectedTotal, title) diff --git a/src/pkg/utils/image.go b/src/pkg/utils/image.go index 828fea84ad..3756a759e1 100644 --- a/src/pkg/utils/image.go +++ b/src/pkg/utils/image.go @@ -35,7 +35,6 @@ func LoadOCIImage(imgPath string, refInfo transform.Image) (v1.Image, error) { if manifest.Annotations[ocispec.AnnotationBaseImageName] == refInfo.Reference || // A backwards compatibility shim for older Zarf versions that would leave docker.io off of image annotations (manifest.Annotations[ocispec.AnnotationBaseImageName] == refInfo.Path+refInfo.TagOrDigest && refInfo.Host == "docker.io") { - // This is the image we are looking for, load it and then return return layoutPath.Image(manifest.Digest) } diff --git a/src/pkg/utils/wait.go b/src/pkg/utils/wait.go index fd2d7f1422..a6727d9e35 100644 --- a/src/pkg/utils/wait.go +++ b/src/pkg/utils/wait.go @@ -153,10 +153,8 @@ func waitForNetworkEndpoint(resource, name, condition string, timeout time.Durat select { case <-expired: return errors.New("wait timed out") - default: switch resource { - case "http", "https": // Handle HTTP and HTTPS endpoints. url := fmt.Sprintf("%s://%s", resource, name) @@ -191,7 +189,6 @@ func waitForNetworkEndpoint(resource, name, condition string, timeout time.Durat message.Debug(err) continue } - default: // Fallback to any generic protocol using net.Dial conn, err := net.Dial(resource, name) diff --git a/src/pkg/zoci/copier.go b/src/pkg/zoci/copier.go index 74c8636a74..f1564bfaed 100644 --- a/src/pkg/zoci/copier.go +++ b/src/pkg/zoci/copier.go @@ -17,7 +17,6 @@ import ( // CopyPackage copies a zarf package from one OCI registry to another func CopyPackage(ctx context.Context, src *Remote, dst *Remote, concurrency int) error { - srcManifest, err := src.FetchRoot(ctx) if err != nil { return err diff --git a/src/test/e2e/02_component_actions_test.go b/src/test/e2e/02_component_actions_test.go index 94f9d997db..8ef710ee90 100644 --- a/src/test/e2e/02_component_actions_test.go +++ b/src/test/e2e/02_component_actions_test.go @@ -88,7 +88,6 @@ func TestComponentActions(t *testing.T) { stdOut, stdErr, err = e2e.Zarf(t, "package", "deploy", path, "--components=on-deploy-with-variable", "--confirm") require.NoError(t, err, stdOut, stdErr) require.Contains(t, stdErr, "the dog says ruff") - }) t.Run("action on-deploy-with-dynamic-variable", func(t *testing.T) { @@ -100,7 +99,6 @@ func TestComponentActions(t *testing.T) { require.Contains(t, stdErr, "the dog says ruff") require.Contains(t, stdErr, "the snake says hiss") require.Contains(t, stdErr, "with a TF_VAR, the snake also says hiss") - }) t.Run("action on-deploy-with-env-var", func(t *testing.T) { diff --git a/src/test/e2e/12_lint_test.go b/src/test/e2e/12_lint_test.go index 6b7239a17a..58e19536ce 100644 --- a/src/test/e2e/12_lint_test.go +++ b/src/test/e2e/12_lint_test.go @@ -55,7 +55,5 @@ func TestLint(t *testing.T) { // Check reported filepaths require.Contains(t, strippedStderr, "Linting package \"dos-games\" at oci://🦄/dos-games:1.0.0") require.Contains(t, strippedStderr, fmt.Sprintf("Linting package \"lint\" at %s", testPackagePath)) - }) - } diff --git a/src/test/e2e/13_find_images_test.go b/src/test/e2e/13_find_images_test.go index a161ed15f6..474aa27eb8 100644 --- a/src/test/e2e/13_find_images_test.go +++ b/src/test/e2e/13_find_images_test.go @@ -85,7 +85,5 @@ func TestFindImages(t *testing.T) { require.Contains(t, stdOut, "component: httpd-local") require.Contains(t, stdOut, "manifest: simple-httpd-deployment") require.Contains(t, stdOut, "image: httpd:alpine3.18") - }) - } diff --git a/src/test/e2e/14_create_sha_index_test.go b/src/test/e2e/14_create_sha_index_test.go index eb2849975a..40b198738b 100644 --- a/src/test/e2e/14_create_sha_index_test.go +++ b/src/test/e2e/14_create_sha_index_test.go @@ -37,5 +37,4 @@ func TestCreateIndexShaErrors(t *testing.T) { require.Contains(t, stderr, tc.expectedImageInStderr) }) } - } diff --git a/src/test/e2e/50_oci_publish_deploy_test.go b/src/test/e2e/50_oci_publish_deploy_test.go index f72fbb28b5..905a5f7ed7 100644 --- a/src/test/e2e/50_oci_publish_deploy_test.go +++ b/src/test/e2e/50_oci_publish_deploy_test.go @@ -164,6 +164,5 @@ func (suite *PublishDeploySuiteTestSuite) Test_3_Copy() { } func TestPublishDeploySuite(t *testing.T) { - suite.Run(t, new(PublishDeploySuiteTestSuite)) } diff --git a/src/test/e2e/51_oci_compose_test.go b/src/test/e2e/51_oci_compose_test.go index 0d98d13c8b..034fc0e15a 100644 --- a/src/test/e2e/51_oci_compose_test.go +++ b/src/test/e2e/51_oci_compose_test.go @@ -185,7 +185,6 @@ func (suite *SkeletonSuite) DirOrFileExists(path string) { } func (suite *SkeletonSuite) verifyComponentPaths(unpackedPath string, components []types.ZarfComponent, isSkeleton bool) { - if isSkeleton { suite.NoDirExists(filepath.Join(unpackedPath, "images")) suite.NoDirExists(filepath.Join(unpackedPath, "sboms")) @@ -280,10 +279,8 @@ func (suite *SkeletonSuite) verifyComponentPaths(unpackedPath string, components } } } - } func TestSkeletonSuite(t *testing.T) { - suite.Run(t, new(SkeletonSuite)) } diff --git a/src/test/external/ext_out_cluster_test.go b/src/test/external/ext_out_cluster_test.go index dfcc9da580..86f2ef0edd 100644 --- a/src/test/external/ext_out_cluster_test.go +++ b/src/test/external/ext_out_cluster_test.go @@ -54,7 +54,6 @@ type ExtOutClusterTestSuite struct { } func (suite *ExtOutClusterTestSuite) SetupSuite() { - suite.Assertions = require.New(suite.T()) // Teardown any leftovers from previous tests diff --git a/src/types/validate.go b/src/types/validate.go index 4d39d36b23..63ee4584d9 100644 --- a/src/types/validate.go +++ b/src/types/validate.go @@ -241,7 +241,6 @@ func (as ZarfComponentActionSet) Validate() error { if actionErr := action.Validate(); actionErr != nil { err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrAction, actionErr)) } - } } From 3d6c3423975b6d2fdc13646be37396ee7e8937c0 Mon Sep 17 00:00:00 2001 From: schristoff <28318173+schristoff@users.noreply.github.com> Date: Thu, 25 Jul 2024 07:42:09 -0600 Subject: [PATCH 25/68] chore: move context.TODO to context.Background() (5) (#2750) Signed-off-by: schristoff-du <167717759+schristoff-du@users.noreply.github.com> Co-authored-by: schristoff-du <167717759+schristoff-du@users.noreply.github.com> --- src/cmd/dev.go | 4 ++-- src/internal/packager/helm/repo.go | 22 +++++++++++----------- src/pkg/packager/creator/normal.go | 8 ++++---- src/pkg/packager/prepare.go | 2 +- src/pkg/packager/sources/url.go | 4 ++-- src/pkg/utils/network.go | 4 ++-- src/pkg/utils/network_test.go | 4 +++- src/test/e2e/50_oci_publish_deploy_test.go | 4 ++-- src/test/external/ext_in_cluster_test.go | 3 ++- src/test/external/ext_out_cluster_test.go | 3 ++- src/test/testutil/testutil.go | 18 ++++++++++++++++++ 11 files changed, 49 insertions(+), 27 deletions(-) create mode 100644 src/test/testutil/testutil.go diff --git a/src/cmd/dev.go b/src/cmd/dev.go index b10f2dde51..80a602afdb 100644 --- a/src/cmd/dev.go +++ b/src/cmd/dev.go @@ -142,7 +142,7 @@ var devSha256SumCmd = &cobra.Command{ Aliases: []string{"s"}, Short: lang.CmdDevSha256sumShort, Args: cobra.ExactArgs(1), - RunE: func(_ *cobra.Command, args []string) error { + RunE: func(cmd *cobra.Command, args []string) error { hashErr := errors.New("unable to compute the SHA256SUM hash") fileName := args[0] @@ -169,7 +169,7 @@ var devSha256SumCmd = &cobra.Command{ } downloadPath := filepath.Join(tmp, fileBase) - err = utils.DownloadToFile(fileName, downloadPath, "") + err = utils.DownloadToFile(cmd.Context(), fileName, downloadPath, "") if err != nil { return errors.Join(hashErr, err) } diff --git a/src/internal/packager/helm/repo.go b/src/internal/packager/helm/repo.go index 1e47b6e6bf..9397a7f760 100644 --- a/src/internal/packager/helm/repo.go +++ b/src/internal/packager/helm/repo.go @@ -53,13 +53,13 @@ func (h *Helm) PackageChart(ctx context.Context, cosignKeyPath string) error { return fmt.Errorf("unable to pull the chart %q from git: %w", h.chart.Name, err) } } else { - err = h.DownloadPublishedChart(cosignKeyPath) + err = h.DownloadPublishedChart(ctx, cosignKeyPath) if err != nil { return fmt.Errorf("unable to download the published chart %q: %w", h.chart.Name, err) } } } else { - err := h.PackageChartFromLocalFiles(cosignKeyPath) + err := h.PackageChartFromLocalFiles(ctx, cosignKeyPath) if err != nil { return fmt.Errorf("unable to package the %q chart: %w", h.chart.Name, err) } @@ -68,7 +68,7 @@ func (h *Helm) PackageChart(ctx context.Context, cosignKeyPath string) error { } // PackageChartFromLocalFiles creates a chart archive from a path to a chart on the host os. -func (h *Helm) PackageChartFromLocalFiles(cosignKeyPath string) error { +func (h *Helm) PackageChartFromLocalFiles(ctx context.Context, cosignKeyPath string) error { spinner := message.NewProgressSpinner("Processing helm chart %s:%s from %s", h.chart.Name, h.chart.Version, h.chart.LocalPath) defer spinner.Stop() @@ -102,7 +102,7 @@ func (h *Helm) PackageChartFromLocalFiles(cosignKeyPath string) error { } // Finalize the chart - err = h.finalizeChartPackage(saved, cosignKeyPath) + err = h.finalizeChartPackage(ctx, saved, cosignKeyPath) if err != nil { return err } @@ -126,11 +126,11 @@ func (h *Helm) PackageChartFromGit(ctx context.Context, cosignKeyPath string) er // Set the directory for the chart and package it h.chart.LocalPath = filepath.Join(gitPath, h.chart.GitPath) - return h.PackageChartFromLocalFiles(cosignKeyPath) + return h.PackageChartFromLocalFiles(ctx, cosignKeyPath) } // DownloadPublishedChart loads a specific chart version from a remote repo. -func (h *Helm) DownloadPublishedChart(cosignKeyPath string) error { +func (h *Helm) DownloadPublishedChart(ctx context.Context, cosignKeyPath string) error { spinner := message.NewProgressSpinner("Processing helm chart %s:%s from repo %s", h.chart.Name, h.chart.Version, h.chart.URL) defer spinner.Stop() @@ -221,7 +221,7 @@ func (h *Helm) DownloadPublishedChart(cosignKeyPath string) error { } // Finalize the chart - err = h.finalizeChartPackage(saved, cosignKeyPath) + err = h.finalizeChartPackage(ctx, saved, cosignKeyPath) if err != nil { return err } @@ -245,7 +245,7 @@ func DownloadChartFromGitToTemp(ctx context.Context, url string, spinner *messag return gitCfg.GitPath, nil } -func (h *Helm) finalizeChartPackage(saved, cosignKeyPath string) error { +func (h *Helm) finalizeChartPackage(ctx context.Context, saved, cosignKeyPath string) error { // Ensure the name is consistent for deployments destinationTarball := StandardName(h.chartPath, h.chart) + ".tgz" err := os.Rename(saved, destinationTarball) @@ -253,19 +253,19 @@ func (h *Helm) finalizeChartPackage(saved, cosignKeyPath string) error { return fmt.Errorf("unable to save the final chart tarball: %w", err) } - err = h.packageValues(cosignKeyPath) + err = h.packageValues(ctx, cosignKeyPath) if err != nil { return fmt.Errorf("unable to process the values for the package: %w", err) } return nil } -func (h *Helm) packageValues(cosignKeyPath string) error { +func (h *Helm) packageValues(ctx context.Context, cosignKeyPath string) error { for valuesIdx, path := range h.chart.ValuesFiles { dst := StandardValuesName(h.valuesPath, h.chart, valuesIdx) if helpers.IsURL(path) { - if err := utils.DownloadToFile(path, dst, cosignKeyPath); err != nil { + if err := utils.DownloadToFile(ctx, path, dst, cosignKeyPath); err != nil { return fmt.Errorf(lang.ErrDownloading, path, err.Error()) } } else { diff --git a/src/pkg/packager/creator/normal.go b/src/pkg/packager/creator/normal.go index 52baa708e4..32e2ea1bbb 100644 --- a/src/pkg/packager/creator/normal.go +++ b/src/pkg/packager/creator/normal.go @@ -390,7 +390,7 @@ func (pc *PackageCreator) addComponent(ctx context.Context, component types.Zarf compressedFile := filepath.Join(componentPaths.Temp, compressedFileName) // If the file is an archive, download it to the componentPath.Temp - if err := utils.DownloadToFile(file.Source, compressedFile, component.DeprecatedCosignKeyPath); err != nil { + if err := utils.DownloadToFile(ctx, file.Source, compressedFile, component.DeprecatedCosignKeyPath); err != nil { return fmt.Errorf(lang.ErrDownloading, file.Source, err.Error()) } @@ -399,7 +399,7 @@ func (pc *PackageCreator) addComponent(ctx context.Context, component types.Zarf return fmt.Errorf(lang.ErrFileExtract, file.ExtractPath, compressedFileName, err.Error()) } } else { - if err := utils.DownloadToFile(file.Source, dst, component.DeprecatedCosignKeyPath); err != nil { + if err := utils.DownloadToFile(ctx, file.Source, dst, component.DeprecatedCosignKeyPath); err != nil { return fmt.Errorf(lang.ErrDownloading, file.Source, err.Error()) } } @@ -450,7 +450,7 @@ func (pc *PackageCreator) addComponent(ctx context.Context, component types.Zarf dst := filepath.Join(componentPaths.Base, rel) if helpers.IsURL(data.Source) { - if err := utils.DownloadToFile(data.Source, dst, component.DeprecatedCosignKeyPath); err != nil { + if err := utils.DownloadToFile(ctx, data.Source, dst, component.DeprecatedCosignKeyPath); err != nil { return fmt.Errorf(lang.ErrDownloading, data.Source, err.Error()) } } else { @@ -483,7 +483,7 @@ func (pc *PackageCreator) addComponent(ctx context.Context, component types.Zarf // Copy manifests without any processing. spinner.Updatef("Copying manifest %s", path) if helpers.IsURL(path) { - if err := utils.DownloadToFile(path, dst, component.DeprecatedCosignKeyPath); err != nil { + if err := utils.DownloadToFile(ctx, path, dst, component.DeprecatedCosignKeyPath); err != nil { return fmt.Errorf(lang.ErrDownloading, path, err.Error()) } } else { diff --git a/src/pkg/packager/prepare.go b/src/pkg/packager/prepare.go index ea883d6970..0ca1f35f91 100644 --- a/src/pkg/packager/prepare.go +++ b/src/pkg/packager/prepare.go @@ -231,7 +231,7 @@ func (p *Packager) findImages(ctx context.Context) (imgMap map[string][]string, if helpers.IsURL(f) { mname := fmt.Sprintf("manifest-%s-%d.yaml", manifest.Name, idx) destination := filepath.Join(componentPaths.Manifests, mname) - if err := utils.DownloadToFile(f, destination, component.DeprecatedCosignKeyPath); err != nil { + if err := utils.DownloadToFile(ctx, f, destination, component.DeprecatedCosignKeyPath); err != nil { return nil, fmt.Errorf(lang.ErrDownloading, f, err.Error()) } f = destination diff --git a/src/pkg/packager/sources/url.go b/src/pkg/packager/sources/url.go index 02fc785d81..d3d79af237 100644 --- a/src/pkg/packager/sources/url.go +++ b/src/pkg/packager/sources/url.go @@ -30,7 +30,7 @@ type URLSource struct { } // Collect downloads a package from the source URL. -func (s *URLSource) Collect(_ context.Context, dir string) (string, error) { +func (s *URLSource) Collect(ctx context.Context, dir string) (string, error) { if !config.CommonOptions.Insecure && s.Shasum == "" && !strings.HasPrefix(s.PackageSource, helpers.SGETURLPrefix) { return "", fmt.Errorf("remote package provided without a shasum, use --insecure to ignore, or provide one w/ --shasum") } @@ -43,7 +43,7 @@ func (s *URLSource) Collect(_ context.Context, dir string) (string, error) { dstTarball := filepath.Join(dir, "zarf-package-url-unknown") - if err := utils.DownloadToFile(packageURL, dstTarball, s.SGetKeyPath); err != nil { + if err := utils.DownloadToFile(ctx, packageURL, dstTarball, s.SGetKeyPath); err != nil { return "", err } diff --git a/src/pkg/utils/network.go b/src/pkg/utils/network.go index e17c086161..4bd6945f36 100644 --- a/src/pkg/utils/network.go +++ b/src/pkg/utils/network.go @@ -39,7 +39,7 @@ func parseChecksum(src string) (string, string, error) { } // DownloadToFile downloads a given URL to the target filepath (including the cosign key if necessary). -func DownloadToFile(src string, dst string, cosignKeyPath string) (err error) { +func DownloadToFile(ctx context.Context, src string, dst string, cosignKeyPath string) (err error) { message.Debugf("Downloading %s to %s", src, dst) // check if the parsed URL has a checksum // if so, remove it and use the checksum to validate the file @@ -66,7 +66,7 @@ func DownloadToFile(src string, dst string, cosignKeyPath string) (err error) { } // If the source url starts with the sget protocol use that, otherwise do a typical GET call if parsed.Scheme == helpers.SGETURLScheme { - err = Sget(context.TODO(), src, cosignKeyPath, file) + err = Sget(ctx, src, cosignKeyPath, file) if err != nil { return fmt.Errorf("unable to download file with sget: %s: %w", src, err) } diff --git a/src/pkg/utils/network_test.go b/src/pkg/utils/network_test.go index d2357f907d..02e308f170 100644 --- a/src/pkg/utils/network_test.go +++ b/src/pkg/utils/network_test.go @@ -13,6 +13,8 @@ import ( "strings" "testing" + "github.com/zarf-dev/zarf/src/test/testutil" + "github.com/stretchr/testify/require" "github.com/defenseunicorns/pkg/helpers/v2" @@ -136,7 +138,7 @@ func TestDownloadToFile(t *testing.T) { } fmt.Println(src) dst := filepath.Join(t.TempDir(), tt.fileName) - err := DownloadToFile(src, dst, "") + err := DownloadToFile(testutil.TestContext(t), src, dst, "") if tt.expectedErr != "" { require.ErrorContains(t, err, tt.expectedErr) return diff --git a/src/test/e2e/50_oci_publish_deploy_test.go b/src/test/e2e/50_oci_publish_deploy_test.go index 905a5f7ed7..217c1b2de6 100644 --- a/src/test/e2e/50_oci_publish_deploy_test.go +++ b/src/test/e2e/50_oci_publish_deploy_test.go @@ -5,7 +5,6 @@ package test import ( - "context" "fmt" "path/filepath" "strings" @@ -16,6 +15,7 @@ import ( "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" "github.com/zarf-dev/zarf/src/pkg/zoci" + "github.com/zarf-dev/zarf/src/test/testutil" "oras.land/oras-go/v2/registry" "oras.land/oras-go/v2/registry/remote" ) @@ -139,7 +139,7 @@ func (suite *PublishDeploySuiteTestSuite) Test_3_Copy() { suite.NoError(err) reg.PlainHTTP = true attempt := 0 - ctx := context.TODO() + ctx := testutil.TestContext(t) for attempt <= 5 { err = reg.Ping(ctx) if err == nil { diff --git a/src/test/external/ext_in_cluster_test.go b/src/test/external/ext_in_cluster_test.go index bddc84fbf6..ffe5a08b73 100644 --- a/src/test/external/ext_in_cluster_test.go +++ b/src/test/external/ext_in_cluster_test.go @@ -19,6 +19,7 @@ import ( "github.com/stretchr/testify/suite" "github.com/zarf-dev/zarf/src/pkg/cluster" "github.com/zarf-dev/zarf/src/pkg/utils/exec" + "github.com/zarf-dev/zarf/src/test/testutil" "k8s.io/apimachinery/pkg/runtime/schema" "sigs.k8s.io/cli-utils/pkg/object" ) @@ -103,7 +104,7 @@ func (suite *ExtInClusterTestSuite) Test_0_Mirror() { c, err := cluster.NewCluster() suite.NoError(err) - ctx := context.TODO() + ctx := testutil.TestContext(suite.T()) // Check that the registry contains the images we want tunnelReg, err := c.NewTunnel("external-registry", "svc", "external-registry-docker-registry", "", 0, 5000) diff --git a/src/test/external/ext_out_cluster_test.go b/src/test/external/ext_out_cluster_test.go index 86f2ef0edd..e2cbaccefb 100644 --- a/src/test/external/ext_out_cluster_test.go +++ b/src/test/external/ext_out_cluster_test.go @@ -20,6 +20,7 @@ import ( "github.com/stretchr/testify/suite" "github.com/zarf-dev/zarf/src/pkg/utils" "github.com/zarf-dev/zarf/src/pkg/utils/exec" + "github.com/zarf-dev/zarf/src/test/testutil" "helm.sh/helm/v3/pkg/repo" ) @@ -206,7 +207,7 @@ func (suite *ExtOutClusterTestSuite) createHelmChartInGitea(baseURL string, user podinfoTarballPath := filepath.Join(tempDir, fmt.Sprintf("podinfo-%s.tgz", podInfoVersion)) suite.NoError(err, "Unable to package chart") - err = utils.DownloadToFile(fmt.Sprintf("https://stefanprodan.github.io/podinfo/podinfo-%s.tgz", podInfoVersion), podinfoTarballPath, "") + err = utils.DownloadToFile(testutil.TestContext(suite.T()), fmt.Sprintf("https://stefanprodan.github.io/podinfo/podinfo-%s.tgz", podInfoVersion), podinfoTarballPath, "") suite.NoError(err) url := fmt.Sprintf("%s/api/packages/%s/helm/api/charts", baseURL, username) diff --git a/src/test/testutil/testutil.go b/src/test/testutil/testutil.go new file mode 100644 index 0000000000..862bca937d --- /dev/null +++ b/src/test/testutil/testutil.go @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2021-Present The Zarf Authors + +// Package testutil provides global testing helper functions +package testutil + +import ( + "context" + "testing" +) + +// TestContext takes a testing.T and returns a context that is +// attached to the test by t.Cleanup() +func TestContext(t *testing.T) context.Context { + ctx, cancel := context.WithCancel(context.Background()) + t.Cleanup(cancel) + return ctx +} From 70e8b8def7a91e054f9763250cd464877f5e6fc7 Mon Sep 17 00:00:00 2001 From: Austin Abro <37223396+AustinAbro321@users.noreply.github.com> Date: Thu, 25 Jul 2024 09:48:27 -0400 Subject: [PATCH 26/68] feat: run schema validation on create (#2585) Signed-off-by: Austin Abro --- main.go | 2 +- src/cmd/dev.go | 4 +- src/config/lang/english.go | 7 - src/pkg/lint/findings.go | 115 ++++++++ src/pkg/lint/findings_test.go | 105 +++++++ src/pkg/lint/lint.go | 136 +++++++++ src/pkg/lint/lint_test.go | 71 +++++ src/pkg/lint/rules.go | 108 +++++++ src/pkg/lint/rules_test.go | 137 +++++++++ src/pkg/lint/schema.go | 79 +++++ .../lint/lint_test.go => lint/schema_test.go} | 164 +---------- src/pkg/packager/creator/creator_test.go | 38 ++- src/pkg/packager/creator/normal.go | 3 +- src/pkg/packager/creator/skeleton.go | 2 +- src/pkg/packager/creator/utils.go | 22 ++ src/pkg/packager/dev.go | 75 +---- src/pkg/packager/lint/findings.go | 41 --- src/pkg/packager/lint/findings_test.go | 122 -------- src/pkg/packager/lint/lint.go | 278 ------------------ src/pkg/variables/types.go | 13 - src/types/package.go | 2 + src/types/validate.go | 34 --- src/types/validate_test.go | 45 +-- 23 files changed, 825 insertions(+), 778 deletions(-) create mode 100644 src/pkg/lint/findings.go create mode 100644 src/pkg/lint/findings_test.go create mode 100644 src/pkg/lint/lint.go create mode 100644 src/pkg/lint/lint_test.go create mode 100644 src/pkg/lint/rules.go create mode 100644 src/pkg/lint/rules_test.go create mode 100644 src/pkg/lint/schema.go rename src/pkg/{packager/lint/lint_test.go => lint/schema_test.go} (56%) delete mode 100644 src/pkg/packager/lint/findings.go delete mode 100644 src/pkg/packager/lint/findings_test.go delete mode 100644 src/pkg/packager/lint/lint.go diff --git a/main.go b/main.go index 70feb480f4..f424789b54 100644 --- a/main.go +++ b/main.go @@ -13,7 +13,7 @@ import ( "github.com/zarf-dev/zarf/src/cmd" "github.com/zarf-dev/zarf/src/config" - "github.com/zarf-dev/zarf/src/pkg/packager/lint" + "github.com/zarf-dev/zarf/src/pkg/lint" ) //go:embed cosign.pub diff --git a/src/cmd/dev.go b/src/cmd/dev.go index 80a602afdb..322b82fb84 100644 --- a/src/cmd/dev.go +++ b/src/cmd/dev.go @@ -22,6 +22,7 @@ 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/pkg/lint" "github.com/zarf-dev/zarf/src/pkg/message" "github.com/zarf-dev/zarf/src/pkg/packager" "github.com/zarf-dev/zarf/src/pkg/transform" @@ -269,6 +270,7 @@ var devLintCmd = &cobra.Command{ Short: lang.CmdDevLintShort, Long: lang.CmdDevLintLong, RunE: func(cmd *cobra.Command, args []string) error { + config.CommonOptions.Confirm = true pkgConfig.CreateOpts.BaseDir = common.SetBaseDirectory(args) v := common.GetViper() pkgConfig.CreateOpts.SetVariables = helpers.TransformAndMergeMap( @@ -280,7 +282,7 @@ var devLintCmd = &cobra.Command{ } defer pkgClient.ClearTempPaths() - return pkgClient.Lint(cmd.Context()) + return lint.Validate(cmd.Context(), pkgConfig.CreateOpts) }, } diff --git a/src/config/lang/english.go b/src/config/lang/english.go index 9b90c23b22..33698de7a5 100644 --- a/src/config/lang/english.go +++ b/src/config/lang/english.go @@ -630,19 +630,15 @@ const ( // Package validate const ( PkgValidateTemplateDeprecation = "Package template %q is using the deprecated syntax ###ZARF_PKG_VAR_%s###. This will be removed in Zarf v1.0.0. Please update to ###ZARF_PKG_TMPL_%s###." - PkgValidateMustBeUppercase = "variable name %q must be all uppercase and contain no special characters except _" PkgValidateErrAction = "invalid action: %w" PkgValidateErrActionCmdWait = "action %q cannot be both a command and wait action" PkgValidateErrActionClusterNetwork = "a single wait action must contain only one of cluster or network" PkgValidateErrChart = "invalid chart definition: %w" PkgValidateErrChartName = "chart %q exceed the maximum length of %d characters" - PkgValidateErrChartNameMissing = "chart must include a name" PkgValidateErrChartNameNotUnique = "chart name %q is not unique" PkgValidateErrChartNamespaceMissing = "chart %q must include a namespace" PkgValidateErrChartURLOrPath = "chart %q must have either a url or localPath" PkgValidateErrChartVersion = "chart %q must include a chart version" - PkgValidateErrComponentName = "component name %q must be all lowercase and contain no special characters except '-' and cannot start with a '-'" - PkgValidateErrComponentLocalOS = "component %q contains a localOS value that is not supported: %s (supported: %s)" PkgValidateErrComponentNameNotUnique = "component name %q is not unique" PkgValidateErrComponentReqDefault = "component %q cannot be both required and default" PkgValidateErrComponentReqGrouped = "component %q cannot be both required and grouped" @@ -654,11 +650,8 @@ const ( PkgValidateErrManifest = "invalid manifest definition: %w" PkgValidateErrManifestFileOrKustomize = "manifest %q must have at least one file or kustomization" PkgValidateErrManifestNameLength = "manifest %q exceed the maximum length of %d characters" - PkgValidateErrManifestNameMissing = "manifest must include a name" PkgValidateErrManifestNameNotUnique = "manifest name %q is not unique" - PkgValidateErrPkgConstantName = "constant name %q must be all uppercase and contain no special characters except _" PkgValidateErrPkgConstantPattern = "provided value for constant %q does not match pattern %q" - PkgValidateErrPkgName = "package name %q must be all lowercase and contain no special characters except '-' and cannot start with a '-'" PkgValidateErrVariable = "invalid package variable: %w" PkgValidateErrYOLONoArch = "cluster architecture not allowed in YOLO" PkgValidateErrYOLONoDistro = "cluster distros not allowed in YOLO" diff --git a/src/pkg/lint/findings.go b/src/pkg/lint/findings.go new file mode 100644 index 0000000000..a8ad9b5eac --- /dev/null +++ b/src/pkg/lint/findings.go @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2021-Present The Zarf Authors + +// Package lint contains functions for verifying zarf yaml files are valid +package lint + +import ( + "fmt" + "path/filepath" + + "github.com/defenseunicorns/pkg/helpers/v2" + "github.com/fatih/color" + "github.com/zarf-dev/zarf/src/pkg/message" +) + +// PackageFinding is a struct that contains a finding about something wrong with a package +type PackageFinding struct { + // YqPath is the path to the key where the error originated from, this is sometimes empty in the case of a general error + YqPath string + Description string + // Item is the value of a key that is causing an error, for example a bad image name + Item string + // PackageNameOverride shows the name of the package that the error originated from + // If it is not set the base package will be used when displaying the error + PackageNameOverride string + // PackagePathOverride shows the path to the package that the error originated from + // If it is not set the base package will be used when displaying the error + PackagePathOverride string + Severity Severity +} + +// Severity is the type of finding +type Severity int + +// different severities of package errors +const ( + SevErr Severity = iota + 1 + SevWarn +) + +func (f PackageFinding) itemizedDescription() string { + if f.Item == "" { + return f.Description + } + return fmt.Sprintf("%s - %s", f.Description, f.Item) +} + +func colorWrapSev(s Severity) string { + if s == SevErr { + return message.ColorWrap("Error", color.FgRed) + } else if s == SevWarn { + return message.ColorWrap("Warning", color.FgYellow) + } + return "unknown" +} + +func filterLowerSeverity(findings []PackageFinding, severity Severity) []PackageFinding { + findings = helpers.RemoveMatches(findings, func(finding PackageFinding) bool { + return finding.Severity > severity + }) + return findings +} + +// PrintFindings prints the findings of the given severity in a table +func PrintFindings(findings []PackageFinding, severity Severity, baseDir string, packageName string) { + findings = filterLowerSeverity(findings, severity) + if len(findings) == 0 { + return + } + mapOfFindingsByPath := GroupFindingsByPath(findings, packageName) + + header := []string{"Type", "Path", "Message"} + + for _, findings := range mapOfFindingsByPath { + lintData := [][]string{} + for _, finding := range findings { + lintData = append(lintData, []string{ + colorWrapSev(finding.Severity), + message.ColorWrap(finding.YqPath, color.FgCyan), + finding.itemizedDescription(), + }) + } + var packagePathFromUser string + if helpers.IsOCIURL(findings[0].PackagePathOverride) { + packagePathFromUser = findings[0].PackagePathOverride + } else { + packagePathFromUser = filepath.Join(baseDir, findings[0].PackagePathOverride) + } + message.Notef("Linting package %q at %s", findings[0].PackageNameOverride, packagePathFromUser) + message.Table(header, lintData) + } +} + +// GroupFindingsByPath groups findings by their package path +func GroupFindingsByPath(findings []PackageFinding, packageName string) map[string][]PackageFinding { + for i := range findings { + if findings[i].PackageNameOverride == "" { + findings[i].PackageNameOverride = packageName + } + if findings[i].PackagePathOverride == "" { + findings[i].PackagePathOverride = "." + } + } + + mapOfFindingsByPath := make(map[string][]PackageFinding) + for _, finding := range findings { + mapOfFindingsByPath[finding.PackagePathOverride] = append(mapOfFindingsByPath[finding.PackagePathOverride], finding) + } + return mapOfFindingsByPath +} + +// HasSevOrHigher returns true if the findings contain a severity equal to or greater than the given severity +func HasSevOrHigher(findings []PackageFinding, severity Severity) bool { + return len(filterLowerSeverity(findings, severity)) > 0 +} diff --git a/src/pkg/lint/findings_test.go b/src/pkg/lint/findings_test.go new file mode 100644 index 0000000000..f3c09673c8 --- /dev/null +++ b/src/pkg/lint/findings_test.go @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2021-Present The Zarf Authors + +// Package lint contains functions for verifying zarf yaml files are valid +package lint + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestGroupFindingsByPath(t *testing.T) { + t.Parallel() + tests := []struct { + name string + findings []PackageFinding + severity Severity + packageName string + want map[string][]PackageFinding + }{ + { + name: "same package multiple findings", + findings: []PackageFinding{ + {Severity: SevWarn, PackageNameOverride: "import", PackagePathOverride: "path"}, + {Severity: SevWarn, PackageNameOverride: "import", PackagePathOverride: "path"}, + }, + packageName: "testPackage", + want: map[string][]PackageFinding{ + "path": { + {Severity: SevWarn, PackageNameOverride: "import", PackagePathOverride: "path"}, + {Severity: SevWarn, PackageNameOverride: "import", PackagePathOverride: "path"}, + }, + }, + }, + { + name: "different packages single finding", + findings: []PackageFinding{ + {Severity: SevWarn, PackageNameOverride: "import", PackagePathOverride: "path"}, + {Severity: SevErr, PackageNameOverride: "", PackagePathOverride: ""}, + }, + packageName: "testPackage", + want: map[string][]PackageFinding{ + "path": {{Severity: SevWarn, PackageNameOverride: "import", PackagePathOverride: "path"}}, + ".": {{Severity: SevErr, PackageNameOverride: "testPackage", PackagePathOverride: "."}}, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + require.Equal(t, tt.want, GroupFindingsByPath(tt.findings, tt.packageName)) + }) + } +} + +func TestHasSeverity(t *testing.T) { + t.Parallel() + tests := []struct { + name string + severity Severity + expected bool + findings []PackageFinding + }{ + { + name: "error severity present", + findings: []PackageFinding{ + { + Severity: SevErr, + }, + }, + severity: SevErr, + expected: true, + }, + { + name: "error severity not present", + findings: []PackageFinding{ + { + Severity: SevWarn, + }, + }, + severity: SevErr, + expected: false, + }, + { + name: "err and warning severity present", + findings: []PackageFinding{ + { + Severity: SevWarn, + }, + { + Severity: SevErr, + }, + }, + severity: SevErr, + expected: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + require.Equal(t, tt.expected, HasSevOrHigher(tt.findings, tt.severity)) + }) + } +} diff --git a/src/pkg/lint/lint.go b/src/pkg/lint/lint.go new file mode 100644 index 0000000000..fda3da01f9 --- /dev/null +++ b/src/pkg/lint/lint.go @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2021-Present The Zarf Authors + +// Package lint contains functions for verifying zarf yaml files are valid +package lint + +import ( + "context" + "errors" + "fmt" + "os" + + "github.com/zarf-dev/zarf/src/config" + "github.com/zarf-dev/zarf/src/config/lang" + "github.com/zarf-dev/zarf/src/pkg/layout" + "github.com/zarf-dev/zarf/src/pkg/message" + "github.com/zarf-dev/zarf/src/pkg/packager/composer" + "github.com/zarf-dev/zarf/src/pkg/utils" + "github.com/zarf-dev/zarf/src/types" +) + +// Validate lints the given Zarf package +func Validate(ctx context.Context, createOpts types.ZarfCreateOptions) error { + var findings []PackageFinding + if err := os.Chdir(createOpts.BaseDir); err != nil { + return fmt.Errorf("unable to access directory %q: %w", createOpts.BaseDir, err) + } + var pkg types.ZarfPackage + if err := utils.ReadYaml(layout.ZarfYAML, &pkg); err != nil { + return err + } + + compFindings, err := lintComponents(ctx, pkg, createOpts) + if err != nil { + return err + } + findings = append(findings, compFindings...) + schemaFindings, err := ValidatePackageSchema() + if err != nil { + return err + } + findings = append(findings, schemaFindings...) + + if len(findings) == 0 { + message.Successf("0 findings for %q", pkg.Metadata.Name) + return nil + } + PrintFindings(findings, SevWarn, createOpts.BaseDir, pkg.Metadata.Name) + if HasSevOrHigher(findings, SevErr) { + return errors.New("errors during lint") + } + return nil +} + +func lintComponents(ctx context.Context, pkg types.ZarfPackage, createOpts types.ZarfCreateOptions) ([]PackageFinding, error) { + var findings []PackageFinding + + for i, component := range pkg.Components { + arch := config.GetArch(pkg.Metadata.Architecture) + if !composer.CompatibleComponent(component, arch, createOpts.Flavor) { + continue + } + + chain, err := composer.NewImportChain(ctx, component, i, pkg.Metadata.Name, arch, createOpts.Flavor) + + if err != nil { + return nil, err + } + + node := chain.Head() + for node != nil { + component := node.ZarfComponent + compFindings, err := fillComponentTemplate(&component, createOpts) + if err != nil { + return nil, err + } + compFindings = append(compFindings, CheckComponentValues(component, node.Index())...) + for i := range compFindings { + compFindings[i].PackagePathOverride = node.ImportLocation() + compFindings[i].PackageNameOverride = node.OriginalPackageName() + } + findings = append(findings, compFindings...) + node = node.Next() + } + } + return findings, nil +} + +func fillComponentTemplate(c *types.ZarfComponent, createOpts types.ZarfCreateOptions) ([]PackageFinding, error) { + var findings []PackageFinding + templateMap := map[string]string{} + + setVarsAndWarn := func(templatePrefix string, deprecated bool) error { + yamlTemplates, err := utils.FindYamlTemplates(c, templatePrefix, "###") + if err != nil { + return err + } + + var unSetTemplates bool + for key := range yamlTemplates { + if deprecated { + findings = append(findings, PackageFinding{ + Description: fmt.Sprintf(lang.PkgValidateTemplateDeprecation, key, key, key), + Severity: SevWarn, + }) + } + if _, present := createOpts.SetVariables[key]; !present { + unSetTemplates = true + } + } + if unSetTemplates { + findings = append(findings, PackageFinding{ + Description: lang.UnsetVarLintWarning, + Severity: SevWarn, + }) + } + for key, value := range createOpts.SetVariables { + templateMap[fmt.Sprintf("%s%s###", templatePrefix, key)] = value + } + return nil + } + + if err := setVarsAndWarn(types.ZarfPackageTemplatePrefix, false); err != nil { + return nil, err + } + + // [DEPRECATION] Set the Package Variable syntax as well for backward compatibility + if err := setVarsAndWarn(types.ZarfPackageVariablePrefix, true); err != nil { + return nil, err + } + + if err := utils.ReloadYamlTemplate(c, 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 new file mode 100644 index 0000000000..d5c5a03495 --- /dev/null +++ b/src/pkg/lint/lint_test.go @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2021-Present The Zarf Authors + +// Package lint contains functions for verifying zarf yaml files are valid +package lint + +import ( + "context" + "fmt" + "testing" + + "github.com/stretchr/testify/require" + "github.com/zarf-dev/zarf/src/config/lang" + "github.com/zarf-dev/zarf/src/types" +) + +func TestLintComponents(t *testing.T) { + t.Run("Test composable components with bad path", func(t *testing.T) { + t.Parallel() + zarfPackage := types.ZarfPackage{ + Components: []types.ZarfComponent{ + { + Import: types.ZarfComponentImport{Path: "bad-path"}, + }, + }, + Metadata: types.ZarfMetadata{Name: "test-zarf-package"}, + } + + createOpts := types.ZarfCreateOptions{Flavor: "", BaseDir: "."} + _, err := lintComponents(context.Background(), zarfPackage, createOpts) + require.Error(t, err) + }) +} +func TestFillComponentTemplate(t *testing.T) { + createOpts := types.ZarfCreateOptions{ + SetVariables: map[string]string{ + "KEY1": "value1", + "KEY2": "value2", + }, + } + + component := types.ZarfComponent{ + Images: []string{ + fmt.Sprintf("%s%s###", types.ZarfPackageTemplatePrefix, "KEY1"), + fmt.Sprintf("%s%s###", types.ZarfPackageVariablePrefix, "KEY2"), + fmt.Sprintf("%s%s###", types.ZarfPackageTemplatePrefix, "KEY3"), + }, + } + + findings, err := fillComponentTemplate(&component, createOpts) + require.NoError(t, err) + expectedFindings := []PackageFinding{ + { + Severity: SevWarn, + Description: "There are templates that are not set and won't be evaluated during lint", + }, + { + Severity: SevWarn, + Description: fmt.Sprintf(lang.PkgValidateTemplateDeprecation, "KEY2", "KEY2", "KEY2"), + }, + } + expectedComponent := types.ZarfComponent{ + Images: []string{ + "value1", + "value2", + fmt.Sprintf("%s%s###", types.ZarfPackageTemplatePrefix, "KEY3"), + }, + } + require.ElementsMatch(t, expectedFindings, findings) + require.Equal(t, expectedComponent, component) +} diff --git a/src/pkg/lint/rules.go b/src/pkg/lint/rules.go new file mode 100644 index 0000000000..17c22256a4 --- /dev/null +++ b/src/pkg/lint/rules.go @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2021-Present The Zarf Authors + +// Package lint contains functions for verifying zarf yaml files are valid +package lint + +import ( + "fmt" + "strings" + + "github.com/defenseunicorns/pkg/helpers/v2" + "github.com/zarf-dev/zarf/src/pkg/transform" + "github.com/zarf-dev/zarf/src/types" +) + +func isPinnedImage(image string) (bool, error) { + transformedImage, err := transform.ParseImageRef(image) + if err != nil { + if strings.Contains(image, types.ZarfPackageTemplatePrefix) || + strings.Contains(image, types.ZarfPackageVariablePrefix) { + return true, nil + } + return false, err + } + if isCosignSignature(transformedImage.Tag) || isCosignAttestation(transformedImage.Tag) { + return true, nil + } + return (transformedImage.Digest != ""), err +} + +func isCosignSignature(image string) bool { + return strings.HasSuffix(image, ".sig") +} + +func isCosignAttestation(image string) bool { + return strings.HasSuffix(image, ".att") +} + +func isPinnedRepo(repo string) bool { + return (strings.Contains(repo, "@")) +} + +// CheckComponentValues runs lint rules validating values on component keys, should be run after templating +func CheckComponentValues(c types.ZarfComponent, i int) []PackageFinding { + var findings []PackageFinding + findings = append(findings, checkForUnpinnedRepos(c, i)...) + findings = append(findings, checkForUnpinnedImages(c, i)...) + findings = append(findings, checkForUnpinnedFiles(c, i)...) + return findings +} + +func checkForUnpinnedRepos(c types.ZarfComponent, i int) []PackageFinding { + var findings []PackageFinding + for j, repo := range c.Repos { + repoYqPath := fmt.Sprintf(".components.[%d].repos.[%d]", i, j) + if !isPinnedRepo(repo) { + findings = append(findings, PackageFinding{ + YqPath: repoYqPath, + Description: "Unpinned repository", + Item: repo, + Severity: SevWarn, + }) + } + } + return findings +} + +func checkForUnpinnedImages(c types.ZarfComponent, i int) []PackageFinding { + var findings []PackageFinding + for j, image := range c.Images { + imageYqPath := fmt.Sprintf(".components.[%d].images.[%d]", i, j) + pinnedImage, err := isPinnedImage(image) + if err != nil { + findings = append(findings, PackageFinding{ + YqPath: imageYqPath, + Description: "Failed to parse image reference", + Item: image, + Severity: SevWarn, + }) + continue + } + if !pinnedImage { + findings = append(findings, PackageFinding{ + YqPath: imageYqPath, + Description: "Image not pinned with digest", + Item: image, + Severity: SevWarn, + }) + } + } + return findings +} + +func checkForUnpinnedFiles(c types.ZarfComponent, i int) []PackageFinding { + var findings []PackageFinding + for j, file := range c.Files { + fileYqPath := fmt.Sprintf(".components.[%d].files.[%d]", i, j) + if file.Shasum == "" && helpers.IsURL(file.Source) { + findings = append(findings, PackageFinding{ + YqPath: fileYqPath, + Description: "No shasum for remote file", + Item: file.Source, + Severity: SevWarn, + }) + } + } + return findings +} diff --git a/src/pkg/lint/rules_test.go b/src/pkg/lint/rules_test.go new file mode 100644 index 0000000000..bf080ac506 --- /dev/null +++ b/src/pkg/lint/rules_test.go @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2021-Present The Zarf Authors + +// Package lint contains functions for verifying zarf yaml files are valid +package lint + +import ( + "errors" + "testing" + + "github.com/stretchr/testify/require" + "github.com/zarf-dev/zarf/src/types" +) + +func TestUnpinnedRepo(t *testing.T) { + t.Parallel() + unpinnedRepo := "https://github.com/zarf-dev/zarf-public-test.git" + component := types.ZarfComponent{Repos: []string{ + unpinnedRepo, + "https://dev.azure.com/zarf-dev/zarf-public-test/_git/zarf-public-test@v0.0.1", + }} + findings := checkForUnpinnedRepos(component, 0) + expected := []PackageFinding{ + { + Item: unpinnedRepo, + Description: "Unpinned repository", + Severity: SevWarn, + YqPath: ".components.[0].repos.[0]", + }, + } + require.Equal(t, expected, findings) +} + +func TestUnpinnedImageWarning(t *testing.T) { + t.Parallel() + unpinnedImage := "registry.com:9001/whatever/image:1.0.0" + badImage := "badimage:badimage@@sha256:3fbc632167424a6d997e74f5" + cosignSignature := "ghcr.io/stefanprodan/podinfo:sha256-57a654ace69ec02ba8973093b6a786faa15640575fbf0dbb603db55aca2ccec8.sig" + cosignAttestation := "ghcr.io/stefanprodan/podinfo:sha256-57a654ace69ec02ba8973093b6a786faa15640575fbf0dbb603db55aca2ccec8.att" + component := types.ZarfComponent{Images: []string{ + unpinnedImage, + "busybox:latest@sha256:3fbc632167424a6d997e74f52b878d7cc478225cffac6bc977eedfe51c7f4e79", + badImage, + cosignSignature, + cosignAttestation, + }} + findings := checkForUnpinnedImages(component, 0) + expected := []PackageFinding{ + { + Item: unpinnedImage, + Description: "Image not pinned with digest", + Severity: SevWarn, + YqPath: ".components.[0].images.[0]", + }, + { + Item: badImage, + Description: "Failed to parse image reference", + Severity: SevWarn, + YqPath: ".components.[0].images.[2]", + }, + } + require.Equal(t, expected, findings) +} + +func TestUnpinnnedFileWarning(t *testing.T) { + t.Parallel() + fileURL := "http://example.com/file.zip" + localFile := "local.txt" + zarfFiles := []types.ZarfFile{ + { + Source: fileURL, + }, + { + Source: localFile, + }, + { + Source: fileURL, + Shasum: "fake-shasum", + }, + } + component := types.ZarfComponent{Files: zarfFiles} + findings := checkForUnpinnedFiles(component, 0) + expected := []PackageFinding{ + { + Item: fileURL, + Description: "No shasum for remote file", + Severity: SevWarn, + YqPath: ".components.[0].files.[0]", + }, + } + require.Equal(t, expected, findings) + require.Len(t, findings, 1) +} + +func TestIsImagePinned(t *testing.T) { + t.Parallel() + tests := []struct { + input string + expected bool + err error + }{ + { + input: "registry.com:8080/zarf-dev/whatever", + expected: false, + err: nil, + }, + { + input: "ghcr.io/zarf-dev/pepr/controller:v0.15.0", + expected: false, + err: nil, + }, + { + input: "busybox:latest@sha256:3fbc632167424a6d997e74f52b878d7cc478225cffac6bc977eedfe51c7f4e79", + expected: true, + err: nil, + }, + { + input: "busybox:bad/image", + expected: false, + err: errors.New("invalid reference format"), + }, + { + input: "busybox:###ZARF_PKG_TMPL_BUSYBOX_IMAGE###", + expected: true, + err: nil, + }, + } + for _, tc := range tests { + t.Run(tc.input, func(t *testing.T) { + actual, err := isPinnedImage(tc.input) + if err != nil { + require.EqualError(t, err, tc.err.Error()) + } + require.Equal(t, tc.expected, actual) + }) + } +} diff --git a/src/pkg/lint/schema.go b/src/pkg/lint/schema.go new file mode 100644 index 0000000000..ae3e991863 --- /dev/null +++ b/src/pkg/lint/schema.go @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2021-Present The Zarf Authors + +// Package lint contains functions for verifying zarf yaml files are valid +package lint + +import ( + "fmt" + "io/fs" + "regexp" + + "github.com/xeipuuv/gojsonschema" + "github.com/zarf-dev/zarf/src/pkg/layout" + "github.com/zarf-dev/zarf/src/pkg/utils" +) + +// ZarfSchema is exported so main.go can embed the schema file +var ZarfSchema fs.ReadFileFS + +// ValidatePackageSchema checks the Zarf package in the current directory against the Zarf schema +func ValidatePackageSchema() ([]PackageFinding, error) { + var untypedZarfPackage interface{} + if err := utils.ReadYaml(layout.ZarfYAML, &untypedZarfPackage); err != nil { + return nil, err + } + + jsonSchema, err := ZarfSchema.ReadFile("zarf.schema.json") + if err != nil { + return nil, err + } + + return getSchemaFindings(jsonSchema, untypedZarfPackage) +} + +func makeFieldPathYqCompat(field string) string { + if field == "(root)" { + return field + } + // \b is a metacharacter that will stop at the next non-word character (including .) + // https://regex101.com/r/pIRPk0/1 + re := regexp.MustCompile(`(\b\d+\b)`) + + wrappedField := re.ReplaceAllString(field, "[$1]") + + return fmt.Sprintf(".%s", wrappedField) +} + +func getSchemaFindings(jsonSchema []byte, obj interface{}) ([]PackageFinding, error) { + var findings []PackageFinding + schemaErrors, err := runSchema(jsonSchema, obj) + if err != nil { + return nil, err + } + + for _, schemaErr := range schemaErrors { + findings = append(findings, PackageFinding{ + YqPath: makeFieldPathYqCompat(schemaErr.Field()), + Description: schemaErr.Description(), + Severity: SevErr, + }) + } + + return findings, nil +} + +func runSchema(jsonSchema []byte, pkg interface{}) ([]gojsonschema.ResultError, error) { + schemaLoader := gojsonschema.NewBytesLoader(jsonSchema) + documentLoader := gojsonschema.NewGoLoader(pkg) + + result, err := gojsonschema.Validate(schemaLoader, documentLoader) + if err != nil { + return nil, err + } + + if !result.Valid() { + return result.Errors(), nil + } + return nil, nil +} diff --git a/src/pkg/packager/lint/lint_test.go b/src/pkg/lint/schema_test.go similarity index 56% rename from src/pkg/packager/lint/lint_test.go rename to src/pkg/lint/schema_test.go index 213c0938d2..bb6adde541 100644 --- a/src/pkg/packager/lint/lint_test.go +++ b/src/pkg/lint/schema_test.go @@ -5,8 +5,6 @@ package lint import ( - "context" - "errors" "fmt" "os" "testing" @@ -19,7 +17,7 @@ import ( func TestZarfSchema(t *testing.T) { t.Parallel() - zarfSchema, err := os.ReadFile("../../../../zarf.schema.json") + zarfSchema, err := os.ReadFile("../../../zarf.schema.json") require.NoError(t, err) tests := []struct { @@ -119,7 +117,6 @@ func TestZarfSchema(t *testing.T) { }, } for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() findings, err := runSchema(zarfSchema, tt.pkg) @@ -173,17 +170,17 @@ components: t.Run("test schema findings is created as expected", func(t *testing.T) { t.Parallel() - findings, err := validateSchema(zarfSchema, types.ZarfPackage{ + findings, err := getSchemaFindings(zarfSchema, types.ZarfPackage{ Kind: types.ZarfInitConfig, Metadata: types.ZarfMetadata{ Name: "invalid", }, }) require.NoError(t, err) - expected := []types.PackageFinding{ + expected := []PackageFinding{ { Description: "Invalid type. Expected: array, given: null", - Severity: types.SevErr, + Severity: SevErr, YqPath: ".components", }, } @@ -191,89 +188,8 @@ components: }) } -func TestValidateComponent(t *testing.T) { +func TestYqCompat(t *testing.T) { t.Parallel() - - t.Run("Unpinnned repo warning", func(t *testing.T) { - t.Parallel() - unpinnedRepo := "https://github.com/zarf-dev/zarf-public-test.git" - component := types.ZarfComponent{Repos: []string{ - unpinnedRepo, - "https://dev.azure.com/defenseunicorns/zarf-public-test/_git/zarf-public-test@v0.0.1", - }} - findings := checkForUnpinnedRepos(component, 0) - expected := []types.PackageFinding{ - { - Item: unpinnedRepo, - Description: "Unpinned repository", - Severity: types.SevWarn, - YqPath: ".components.[0].repos.[0]", - }, - } - require.Equal(t, expected, findings) - }) - - t.Run("Unpinnned image warning", func(t *testing.T) { - t.Parallel() - unpinnedImage := "registry.com:9001/whatever/image:1.0.0" - badImage := "badimage:badimage@@sha256:3fbc632167424a6d997e74f5" - cosignSignature := "ghcr.io/stefanprodan/podinfo:sha256-57a654ace69ec02ba8973093b6a786faa15640575fbf0dbb603db55aca2ccec8.sig" - cosignAttestation := "ghcr.io/stefanprodan/podinfo:sha256-57a654ace69ec02ba8973093b6a786faa15640575fbf0dbb603db55aca2ccec8.att" - component := types.ZarfComponent{Images: []string{ - unpinnedImage, - "busybox:latest@sha256:3fbc632167424a6d997e74f52b878d7cc478225cffac6bc977eedfe51c7f4e79", - badImage, - cosignSignature, - cosignAttestation, - }} - findings := checkForUnpinnedImages(component, 0) - expected := []types.PackageFinding{ - { - Item: unpinnedImage, - Description: "Image not pinned with digest", - Severity: types.SevWarn, - YqPath: ".components.[0].images.[0]", - }, - { - Item: badImage, - Description: "Failed to parse image reference", - Severity: types.SevWarn, - YqPath: ".components.[0].images.[2]", - }, - } - require.Equal(t, expected, findings) - }) - - t.Run("Unpinnned file warning", func(t *testing.T) { - t.Parallel() - fileURL := "http://example.com/file.zip" - localFile := "local.txt" - zarfFiles := []types.ZarfFile{ - { - Source: fileURL, - }, - { - Source: localFile, - }, - { - Source: fileURL, - Shasum: "fake-shasum", - }, - } - component := types.ZarfComponent{Files: zarfFiles} - findings := checkForUnpinnedFiles(component, 0) - expectedErr := []types.PackageFinding{ - { - Item: fileURL, - Description: "No shasum for remote file", - Severity: types.SevWarn, - YqPath: ".components.[0].files.[0]", - }, - } - require.Equal(t, expectedErr, findings) - require.Len(t, findings, 1) - }) - t.Run("Wrap standalone numbers in bracket", func(t *testing.T) { t.Parallel() input := "components12.12.import.path" @@ -288,74 +204,4 @@ func TestValidateComponent(t *testing.T) { actual := makeFieldPathYqCompat(input) require.Equal(t, input, actual) }) - - t.Run("Test composable components with bad path", func(t *testing.T) { - t.Parallel() - zarfPackage := types.ZarfPackage{ - Components: []types.ZarfComponent{ - { - Import: types.ZarfComponentImport{Path: "bad-path"}, - }, - }, - Metadata: types.ZarfMetadata{Name: "test-zarf-package"}, - } - - createOpts := types.ZarfCreateOptions{Flavor: "", BaseDir: "."} - _, err := lintComponents(context.Background(), zarfPackage, createOpts) - require.Error(t, err) - }) - - t.Run("isImagePinned", func(t *testing.T) { - t.Parallel() - tests := []struct { - input string - expected bool - err error - }{ - { - input: "registry.com:8080/defenseunicorns/whatever", - expected: false, - err: nil, - }, - { - input: "ghcr.io/defenseunicorns/pepr/controller:v0.15.0", - expected: false, - err: nil, - }, - { - input: "busybox:latest@sha256:3fbc632167424a6d997e74f52b878d7cc478225cffac6bc977eedfe51c7f4e79", - expected: true, - err: nil, - }, - { - input: "busybox:bad/image", - expected: false, - err: errors.New("invalid reference format"), - }, - { - input: "busybox:###ZARF_PKG_TMPL_BUSYBOX_IMAGE###", - expected: true, - err: nil, - }, - { - input: "ghcr.io/stefanprodan/podinfo:sha256-57a654ace69ec02ba8973093b6a786faa15640575fbf0dbb603db55aca2ccec8.sig", - expected: true, - err: nil, - }, - { - input: "ghcr.io/stefanprodan/podinfo:sha256-57a654ace69ec02ba8973093b6a786faa15640575fbf0dbb603db55aca2ccec8.att", - expected: true, - err: nil, - }, - } - for _, tc := range tests { - t.Run(tc.input, func(t *testing.T) { - actual, err := isPinnedImage(tc.input) - if err != nil { - require.EqualError(t, err, tc.err.Error()) - } - require.Equal(t, tc.expected, actual) - }) - } - }) } diff --git a/src/pkg/packager/creator/creator_test.go b/src/pkg/packager/creator/creator_test.go index 1c2e3b7153..9312fe0a2c 100644 --- a/src/pkg/packager/creator/creator_test.go +++ b/src/pkg/packager/creator/creator_test.go @@ -6,16 +6,33 @@ package creator import ( "context" + "io/fs" + "os" "path/filepath" "testing" "github.com/stretchr/testify/require" "github.com/zarf-dev/zarf/src/pkg/layout" + "github.com/zarf-dev/zarf/src/pkg/lint" "github.com/zarf-dev/zarf/src/types" ) +type mockSchemaLoader struct { + b []byte +} + +func (m *mockSchemaLoader) ReadFile(_ string) ([]byte, error) { + return m.b, nil +} + +// Satisfy fs.ReadFileFS interface +func (m *mockSchemaLoader) Open(_ string) (fs.File, error) { + return nil, nil +} + func TestLoadPackageDefinition(t *testing.T) { - t.Parallel() + // TODO once creator is refactored to not expect to be in the same directory as the zarf.yaml file + // this test can be re-parallelized tests := []struct { name string testDir string @@ -31,7 +48,7 @@ func TestLoadPackageDefinition(t *testing.T) { { name: "invalid package definition", testDir: "invalid", - expectedErr: "package must have at least 1 component", + expectedErr: "found errors in schema", creator: NewPackageCreator(types.ZarfCreateOptions{}, ""), }, { @@ -43,17 +60,28 @@ func TestLoadPackageDefinition(t *testing.T) { { name: "invalid package definition", testDir: "invalid", - expectedErr: "package must have at least 1 component", + expectedErr: "found errors in schema", creator: NewSkeletonCreator(types.ZarfCreateOptions{}, types.ZarfPublishOptions{}), }, } + b, err := os.ReadFile("../../../../zarf.schema.json") + require.NoError(t, err) + lint.ZarfSchema = &mockSchemaLoader{b: b} for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { - t.Parallel() + cwd, err := os.Getwd() + require.NoError(t, err) + defer func() { + err = os.Chdir(cwd) + require.NoError(t, err) + }() + path := filepath.Join("testdata", tt.testDir) + err = os.Chdir(path) + require.NoError(t, err) - src := layout.New(filepath.Join("testdata", tt.testDir)) + src := layout.New(".") pkg, _, err := tt.creator.LoadPackageDefinition(context.Background(), src) if tt.expectedErr == "" { diff --git a/src/pkg/packager/creator/normal.go b/src/pkg/packager/creator/normal.go index 32e2ea1bbb..6f42c55865 100644 --- a/src/pkg/packager/creator/normal.go +++ b/src/pkg/packager/creator/normal.go @@ -74,7 +74,6 @@ func (pc *PackageCreator) LoadPackageDefinition(ctx context.Context, src *layout if err != nil { return types.ZarfPackage{}, nil, err } - warnings = append(warnings, composeWarnings...) // After components are composed, template the active package. @@ -119,7 +118,7 @@ func (pc *PackageCreator) LoadPackageDefinition(ctx context.Context, src *layout } } - if err := pkg.Validate(); err != nil { + if err := Validate(pkg, pc.createOpts.BaseDir); err != nil { return types.ZarfPackage{}, nil, err } diff --git a/src/pkg/packager/creator/skeleton.go b/src/pkg/packager/creator/skeleton.go index 3c95623542..9ddf24379a 100644 --- a/src/pkg/packager/creator/skeleton.go +++ b/src/pkg/packager/creator/skeleton.go @@ -70,7 +70,7 @@ func (sc *SkeletonCreator) LoadPackageDefinition(ctx context.Context, src *layou message.Warn(warning) } - if err := pkg.Validate(); err != nil { + if err := Validate(pkg, sc.createOpts.BaseDir); err != nil { return types.ZarfPackage{}, nil, err } diff --git a/src/pkg/packager/creator/utils.go b/src/pkg/packager/creator/utils.go index 5c3f962766..4d72edb59f 100644 --- a/src/pkg/packager/creator/utils.go +++ b/src/pkg/packager/creator/utils.go @@ -5,15 +5,37 @@ package creator import ( + "fmt" "os" "runtime" "time" "github.com/zarf-dev/zarf/src/config" + "github.com/zarf-dev/zarf/src/pkg/lint" "github.com/zarf-dev/zarf/src/pkg/packager/deprecated" "github.com/zarf-dev/zarf/src/types" ) +// 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 types.ZarfPackage, baseDir string) error { + if err := pkg.Validate(); err != nil { + return fmt.Errorf("package validation failed: %w", err) + } + + findings, err := lint.ValidatePackageSchema() + if err != nil { + return fmt.Errorf("unable to check schema: %w", err) + } + + if lint.HasSevOrHigher(findings, lint.SevErr) { + lint.PrintFindings(findings, lint.SevErr, baseDir, pkg.Metadata.Name) + return fmt.Errorf("found errors in schema") + } + + return nil +} + // recordPackageMetadata records various package metadata during package create. func recordPackageMetadata(pkg *types.ZarfPackage, createOpts types.ZarfCreateOptions) error { now := time.Now() diff --git a/src/pkg/packager/dev.go b/src/pkg/packager/dev.go index 4363c0b49a..1c1208be14 100644 --- a/src/pkg/packager/dev.go +++ b/src/pkg/packager/dev.go @@ -6,21 +6,16 @@ package packager import ( "context" - "errors" "fmt" "os" - "path/filepath" "runtime" "github.com/defenseunicorns/pkg/helpers/v2" - "github.com/fatih/color" "github.com/zarf-dev/zarf/src/config" "github.com/zarf-dev/zarf/src/pkg/layout" "github.com/zarf-dev/zarf/src/pkg/message" "github.com/zarf-dev/zarf/src/pkg/packager/creator" "github.com/zarf-dev/zarf/src/pkg/packager/filters" - "github.com/zarf-dev/zarf/src/pkg/packager/lint" - "github.com/zarf-dev/zarf/src/pkg/utils" "github.com/zarf-dev/zarf/src/types" ) @@ -58,8 +53,8 @@ func (p *Packager) DevDeploy(ctx context.Context) error { return err } - if err := p.cfg.Pkg.Validate(); err != nil { - return fmt.Errorf("unable to validate package: %w", err) + if err := creator.Validate(p.cfg.Pkg, p.cfg.CreateOpts.BaseDir); err != nil { + return fmt.Errorf("package validation failed: %w", err) } if err := p.populatePackageVariableConfig(); err != nil { @@ -110,69 +105,3 @@ func (p *Packager) DevDeploy(ctx context.Context) error { // cd back return os.Chdir(cwd) } - -// Lint ensures a package is valid & follows suggested conventions -func (p *Packager) Lint(ctx context.Context) error { - if err := os.Chdir(p.cfg.CreateOpts.BaseDir); err != nil { - return fmt.Errorf("unable to access directory %q: %w", p.cfg.CreateOpts.BaseDir, err) - } - - if err := utils.ReadYaml(layout.ZarfYAML, &p.cfg.Pkg); err != nil { - return err - } - - findings, err := lint.Validate(ctx, p.cfg.Pkg, p.cfg.CreateOpts) - if err != nil { - return fmt.Errorf("linting failed: %w", err) - } - - if len(findings) == 0 { - message.Successf("0 findings for %q", p.cfg.Pkg.Metadata.Name) - return nil - } - - mapOfFindingsByPath := lint.GroupFindingsByPath(findings, types.SevWarn, p.cfg.Pkg.Metadata.Name) - - header := []string{"Type", "Path", "Message"} - - for _, findings := range mapOfFindingsByPath { - lintData := [][]string{} - for _, finding := range findings { - lintData = append(lintData, []string{ - colorWrapSev(finding.Severity), - message.ColorWrap(finding.YqPath, color.FgCyan), - itemizedDescription(finding.Description, finding.Item), - }) - } - var packagePathFromUser string - if helpers.IsOCIURL(findings[0].PackagePathOverride) { - packagePathFromUser = findings[0].PackagePathOverride - } else { - packagePathFromUser = filepath.Join(p.cfg.CreateOpts.BaseDir, findings[0].PackagePathOverride) - } - message.Notef("Linting package %q at %s", findings[0].PackageNameOverride, packagePathFromUser) - message.Table(header, lintData) - } - - if lint.HasSeverity(findings, types.SevErr) { - return errors.New("errors during lint") - } - - return nil -} - -func itemizedDescription(description string, item string) string { - if item == "" { - return description - } - return fmt.Sprintf("%s - %s", description, item) -} - -func colorWrapSev(s types.Severity) string { - if s == types.SevErr { - return message.ColorWrap("Error", color.FgRed) - } else if s == types.SevWarn { - return message.ColorWrap("Warning", color.FgYellow) - } - return "unknown" -} diff --git a/src/pkg/packager/lint/findings.go b/src/pkg/packager/lint/findings.go deleted file mode 100644 index 8b48bdea78..0000000000 --- a/src/pkg/packager/lint/findings.go +++ /dev/null @@ -1,41 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2021-Present The Zarf Authors - -// Package lint contains functions for verifying zarf yaml files are valid -package lint - -import ( - "github.com/defenseunicorns/pkg/helpers/v2" - "github.com/zarf-dev/zarf/src/types" -) - -// GroupFindingsByPath groups findings by their package path -func GroupFindingsByPath(findings []types.PackageFinding, severity types.Severity, packageName string) map[string][]types.PackageFinding { - findings = helpers.RemoveMatches(findings, func(finding types.PackageFinding) bool { - return finding.Severity > severity - }) - for i := range findings { - if findings[i].PackageNameOverride == "" { - findings[i].PackageNameOverride = packageName - } - if findings[i].PackagePathOverride == "" { - findings[i].PackagePathOverride = "." - } - } - - mapOfFindingsByPath := make(map[string][]types.PackageFinding) - for _, finding := range findings { - mapOfFindingsByPath[finding.PackagePathOverride] = append(mapOfFindingsByPath[finding.PackagePathOverride], finding) - } - return mapOfFindingsByPath -} - -// HasSeverity returns true if the findings contain a severity equal to or greater than the given severity -func HasSeverity(findings []types.PackageFinding, severity types.Severity) bool { - for _, finding := range findings { - if finding.Severity <= severity { - return true - } - } - return false -} diff --git a/src/pkg/packager/lint/findings_test.go b/src/pkg/packager/lint/findings_test.go deleted file mode 100644 index 522135eb96..0000000000 --- a/src/pkg/packager/lint/findings_test.go +++ /dev/null @@ -1,122 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2021-Present The Zarf Authors - -// Package lint contains functions for verifying zarf yaml files are valid -package lint - -import ( - "testing" - - "github.com/stretchr/testify/require" - "github.com/zarf-dev/zarf/src/types" -) - -func TestGroupFindingsByPath(t *testing.T) { - t.Parallel() - tests := []struct { - name string - findings []types.PackageFinding - severity types.Severity - packageName string - want map[string][]types.PackageFinding - }{ - { - name: "same package multiple findings", - findings: []types.PackageFinding{ - {Severity: types.SevWarn, PackageNameOverride: "import", PackagePathOverride: "path"}, - {Severity: types.SevWarn, PackageNameOverride: "import", PackagePathOverride: "path"}, - }, - severity: types.SevWarn, - packageName: "testPackage", - want: map[string][]types.PackageFinding{ - "path": { - {Severity: types.SevWarn, PackageNameOverride: "import", PackagePathOverride: "path"}, - {Severity: types.SevWarn, PackageNameOverride: "import", PackagePathOverride: "path"}, - }, - }, - }, - { - name: "different packages single finding", - findings: []types.PackageFinding{ - {Severity: types.SevWarn, PackageNameOverride: "import", PackagePathOverride: "path"}, - {Severity: types.SevErr, PackageNameOverride: "", PackagePathOverride: ""}, - }, - severity: types.SevWarn, - packageName: "testPackage", - want: map[string][]types.PackageFinding{ - "path": {{Severity: types.SevWarn, PackageNameOverride: "import", PackagePathOverride: "path"}}, - ".": {{Severity: types.SevErr, PackageNameOverride: "testPackage", PackagePathOverride: "."}}, - }, - }, - { - name: "Multiple findings, mixed severity", - findings: []types.PackageFinding{ - {Severity: types.SevWarn, PackageNameOverride: "", PackagePathOverride: ""}, - {Severity: types.SevErr, PackageNameOverride: "", PackagePathOverride: ""}, - }, - severity: types.SevErr, - packageName: "testPackage", - want: map[string][]types.PackageFinding{ - ".": {{Severity: types.SevErr, PackageNameOverride: "testPackage", PackagePathOverride: "."}}, - }, - }, - } - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - t.Parallel() - require.Equal(t, tt.want, GroupFindingsByPath(tt.findings, tt.severity, tt.packageName)) - }) - } -} - -func TestHasSeverity(t *testing.T) { - t.Parallel() - tests := []struct { - name string - severity types.Severity - expected bool - findings []types.PackageFinding - }{ - { - name: "error severity present", - findings: []types.PackageFinding{ - { - Severity: types.SevErr, - }, - }, - severity: types.SevErr, - expected: true, - }, - { - name: "error severity not present", - findings: []types.PackageFinding{ - { - Severity: types.SevWarn, - }, - }, - severity: types.SevErr, - expected: false, - }, - { - name: "err and warning severity present", - findings: []types.PackageFinding{ - { - Severity: types.SevWarn, - }, - { - Severity: types.SevErr, - }, - }, - severity: types.SevErr, - expected: true, - }, - } - for _, tt := range tests { - tt := tt - t.Run(tt.name, func(t *testing.T) { - t.Parallel() - require.Equal(t, tt.expected, HasSeverity(tt.findings, tt.severity)) - }) - } -} diff --git a/src/pkg/packager/lint/lint.go b/src/pkg/packager/lint/lint.go deleted file mode 100644 index 34ab432fe0..0000000000 --- a/src/pkg/packager/lint/lint.go +++ /dev/null @@ -1,278 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2021-Present The Zarf Authors - -// Package lint contains functions for verifying zarf yaml files are valid -package lint - -import ( - "context" - "fmt" - "io/fs" - "regexp" - "strings" - - "github.com/defenseunicorns/pkg/helpers/v2" - "github.com/xeipuuv/gojsonschema" - "github.com/zarf-dev/zarf/src/config" - "github.com/zarf-dev/zarf/src/config/lang" - "github.com/zarf-dev/zarf/src/pkg/layout" - "github.com/zarf-dev/zarf/src/pkg/packager/composer" - "github.com/zarf-dev/zarf/src/pkg/packager/creator" - "github.com/zarf-dev/zarf/src/pkg/transform" - "github.com/zarf-dev/zarf/src/pkg/utils" - "github.com/zarf-dev/zarf/src/types" -) - -// ZarfSchema is exported so main.go can embed the schema file -var ZarfSchema fs.ReadFileFS - -// Validate the given Zarf package. The Zarf package should not already be composed when sent to this function. -func Validate(ctx context.Context, pkg types.ZarfPackage, createOpts types.ZarfCreateOptions) ([]types.PackageFinding, error) { - var findings []types.PackageFinding - compFindings, err := lintComponents(ctx, pkg, createOpts) - if err != nil { - return nil, err - } - findings = append(findings, compFindings...) - - jsonSchema, err := ZarfSchema.ReadFile("zarf.schema.json") - if err != nil { - return nil, err - } - - var untypedZarfPackage interface{} - if err := utils.ReadYaml(layout.ZarfYAML, &untypedZarfPackage); err != nil { - return nil, err - } - - schemaFindings, err := validateSchema(jsonSchema, untypedZarfPackage) - if err != nil { - return nil, err - } - findings = append(findings, schemaFindings...) - - return findings, nil -} - -func lintComponents(ctx context.Context, pkg types.ZarfPackage, createOpts types.ZarfCreateOptions) ([]types.PackageFinding, error) { - var findings []types.PackageFinding - - for i, component := range pkg.Components { - arch := config.GetArch(pkg.Metadata.Architecture) - if !composer.CompatibleComponent(component, arch, createOpts.Flavor) { - continue - } - - chain, err := composer.NewImportChain(ctx, component, i, pkg.Metadata.Name, arch, createOpts.Flavor) - if err != nil { - return nil, err - } - - node := chain.Head() - for node != nil { - component := node.ZarfComponent - compFindings := fillComponentTemplate(&component, &createOpts) - compFindings = append(compFindings, checkComponent(component, node.Index())...) - for i := range compFindings { - compFindings[i].PackagePathOverride = node.ImportLocation() - compFindings[i].PackageNameOverride = node.OriginalPackageName() - } - findings = append(findings, compFindings...) - node = node.Next() - } - } - return findings, nil -} - -func fillComponentTemplate(c *types.ZarfComponent, createOpts *types.ZarfCreateOptions) []types.PackageFinding { - var findings []types.PackageFinding - err := creator.ReloadComponentTemplate(c) - if err != nil { - findings = append(findings, types.PackageFinding{ - Description: err.Error(), - Severity: types.SevWarn, - }) - } - templateMap := map[string]string{} - - setVarsAndWarn := func(templatePrefix string, deprecated bool) { - yamlTemplates, err := utils.FindYamlTemplates(c, templatePrefix, "###") - if err != nil { - findings = append(findings, types.PackageFinding{ - Description: err.Error(), - Severity: types.SevWarn, - }) - } - - for key := range yamlTemplates { - if deprecated { - findings = append(findings, types.PackageFinding{ - Description: fmt.Sprintf(lang.PkgValidateTemplateDeprecation, key, key, key), - Severity: types.SevWarn, - }) - } - _, present := createOpts.SetVariables[key] - if !present { - findings = append(findings, types.PackageFinding{ - Description: lang.UnsetVarLintWarning, - Severity: types.SevWarn, - }) - } - } - for key, value := range createOpts.SetVariables { - templateMap[fmt.Sprintf("%s%s###", templatePrefix, key)] = value - } - } - - setVarsAndWarn(types.ZarfPackageTemplatePrefix, false) - - // [DEPRECATION] Set the Package Variable syntax as well for backward compatibility - setVarsAndWarn(types.ZarfPackageVariablePrefix, true) - - //nolint: errcheck // This error should bubble up - utils.ReloadYamlTemplate(c, templateMap) - return findings -} - -func isPinnedImage(image string) (bool, error) { - transformedImage, err := transform.ParseImageRef(image) - if err != nil { - if strings.Contains(image, types.ZarfPackageTemplatePrefix) || - strings.Contains(image, types.ZarfPackageVariablePrefix) { - return true, nil - } - return false, err - } - if isCosignSignature(transformedImage.Tag) || isCosignAttestation(transformedImage.Tag) { - return true, nil - } - return (transformedImage.Digest != ""), err -} - -func isCosignSignature(image string) bool { - return strings.HasSuffix(image, ".sig") -} - -func isCosignAttestation(image string) bool { - return strings.HasSuffix(image, ".att") -} - -func isPinnedRepo(repo string) bool { - return (strings.Contains(repo, "@")) -} - -// checkComponent runs lint rules against a component -func checkComponent(c types.ZarfComponent, i int) []types.PackageFinding { - var findings []types.PackageFinding - findings = append(findings, checkForUnpinnedRepos(c, i)...) - findings = append(findings, checkForUnpinnedImages(c, i)...) - findings = append(findings, checkForUnpinnedFiles(c, i)...) - return findings -} - -func checkForUnpinnedRepos(c types.ZarfComponent, i int) []types.PackageFinding { - var findings []types.PackageFinding - for j, repo := range c.Repos { - repoYqPath := fmt.Sprintf(".components.[%d].repos.[%d]", i, j) - if !isPinnedRepo(repo) { - findings = append(findings, types.PackageFinding{ - YqPath: repoYqPath, - Description: "Unpinned repository", - Item: repo, - Severity: types.SevWarn, - }) - } - } - return findings -} - -func checkForUnpinnedImages(c types.ZarfComponent, i int) []types.PackageFinding { - var findings []types.PackageFinding - for j, image := range c.Images { - imageYqPath := fmt.Sprintf(".components.[%d].images.[%d]", i, j) - pinnedImage, err := isPinnedImage(image) - if err != nil { - findings = append(findings, types.PackageFinding{ - YqPath: imageYqPath, - Description: "Failed to parse image reference", - Item: image, - Severity: types.SevWarn, - }) - continue - } - if !pinnedImage { - findings = append(findings, types.PackageFinding{ - YqPath: imageYqPath, - Description: "Image not pinned with digest", - Item: image, - Severity: types.SevWarn, - }) - } - } - return findings -} - -func checkForUnpinnedFiles(c types.ZarfComponent, i int) []types.PackageFinding { - var findings []types.PackageFinding - for j, file := range c.Files { - fileYqPath := fmt.Sprintf(".components.[%d].files.[%d]", i, j) - if file.Shasum == "" && helpers.IsURL(file.Source) { - findings = append(findings, types.PackageFinding{ - YqPath: fileYqPath, - Description: "No shasum for remote file", - Item: file.Source, - Severity: types.SevWarn, - }) - } - } - return findings -} - -func makeFieldPathYqCompat(field string) string { - if field == "(root)" { - return field - } - // \b is a metacharacter that will stop at the next non-word character (including .) - // https://regex101.com/r/pIRPk0/1 - re := regexp.MustCompile(`(\b\d+\b)`) - - wrappedField := re.ReplaceAllString(field, "[$1]") - - return fmt.Sprintf(".%s", wrappedField) -} - -func validateSchema(jsonSchema []byte, untypedZarfPackage interface{}) ([]types.PackageFinding, error) { - var findings []types.PackageFinding - - schemaErrors, err := runSchema(jsonSchema, untypedZarfPackage) - if err != nil { - return nil, err - } - - if len(schemaErrors) != 0 { - for _, schemaErr := range schemaErrors { - findings = append(findings, types.PackageFinding{ - YqPath: makeFieldPathYqCompat(schemaErr.Field()), - Description: schemaErr.Description(), - Severity: types.SevErr, - }) - } - } - - return findings, err -} - -func runSchema(jsonSchema []byte, pkg interface{}) ([]gojsonschema.ResultError, error) { - schemaLoader := gojsonschema.NewBytesLoader(jsonSchema) - documentLoader := gojsonschema.NewGoLoader(pkg) - - result, err := gojsonschema.Validate(schemaLoader, documentLoader) - if err != nil { - return nil, err - } - - if !result.Valid() { - return result.Errors(), nil - } - return nil, nil -} diff --git a/src/pkg/variables/types.go b/src/pkg/variables/types.go index 3fb8d18d80..b106e911fa 100644 --- a/src/pkg/variables/types.go +++ b/src/pkg/variables/types.go @@ -60,21 +60,8 @@ type SetVariable struct { Value string `json:"value" jsonschema:"description=The value the variable is currently set with"` } -// Validate runs all validation checks on a package variable. -func (v Variable) Validate() error { - if !IsUppercaseNumberUnderscore(v.Name) { - return fmt.Errorf(lang.PkgValidateMustBeUppercase, v.Name) - } - return nil -} - // Validate runs all validation checks on a package constant. func (c Constant) Validate() error { - // ensure the constant name is only capitals and underscores - if !IsUppercaseNumberUnderscore(c.Name) { - return fmt.Errorf(lang.PkgValidateErrPkgConstantName, c.Name) - } - if !regexp.MustCompile(c.Pattern).MatchString(c.Value) { return fmt.Errorf(lang.PkgValidateErrPkgConstantPattern, c.Name, c.Pattern) } diff --git a/src/types/package.go b/src/types/package.go index 17419dd6e3..cb097d6e42 100644 --- a/src/types/package.go +++ b/src/types/package.go @@ -43,6 +43,8 @@ func (pkg ZarfPackage) IsSBOMAble() bool { // ZarfMetadata lists information about the current ZarfPackage. type ZarfMetadata struct { + // The Name regex permits lowercase letters, numbers, and hyphens not at the start + // https://regex101.com/r/FLdG9G/2 Name string `json:"name" jsonschema:"description=Name to identify this Zarf package,pattern=^[a-z0-9][a-z0-9\\-]*$"` Description string `json:"description,omitempty" jsonschema:"description=Additional information about this package"` Version string `json:"version,omitempty" jsonschema:"description=Generic string set by a package author to track the package version (Note: ZarfInitConfigs will always be versioned to the CLIVersion they were created with)"` diff --git a/src/types/validate.go b/src/types/validate.go index 63ee4584d9..e045e69520 100644 --- a/src/types/validate.go +++ b/src/types/validate.go @@ -9,7 +9,6 @@ import ( "fmt" "path/filepath" "regexp" - "slices" "github.com/defenseunicorns/pkg/helpers/v2" "github.com/zarf-dev/zarf/src/config/lang" @@ -45,20 +44,6 @@ func (pkg ZarfPackage) Validate() error { err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrInitNoYOLO)) } - if !IsLowercaseNumberHyphenNoStartHyphen(pkg.Metadata.Name) { - err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrPkgName, pkg.Metadata.Name)) - } - - if len(pkg.Components) == 0 { - err = errors.Join(err, fmt.Errorf("package must have at least 1 component")) - } - - for _, variable := range pkg.Variables { - if varErr := variable.Validate(); varErr != nil { - err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrVariable, varErr)) - } - } - for _, constant := range pkg.Constants { if varErr := constant.Validate(); varErr != nil { err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrConstant, varErr)) @@ -96,14 +81,6 @@ func (pkg ZarfPackage) Validate() error { } uniqueComponentNames[component.Name] = true - if !IsLowercaseNumberHyphenNoStartHyphen(component.Name) { - err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrComponentName, component.Name)) - } - - if !slices.Contains(supportedOS, component.Only.LocalOS) { - err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrComponentLocalOS, component.Name, component.Only.LocalOS, supportedOS)) - } - if component.IsRequired() { if component.Default { err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrComponentReqDefault, component.Name)) @@ -254,9 +231,6 @@ func (as ZarfComponentActionSet) Validate() error { // Validate runs all validation checks on an action. func (action ZarfComponentAction) Validate() error { var err error - for _, variable := range action.SetVariables { - err = errors.Join(err, variable.Validate()) - } if action.Wait != nil { // Validate only cmd or wait, not both @@ -282,10 +256,6 @@ func (action ZarfComponentAction) Validate() error { func (chart ZarfChart) Validate() error { var err error - if chart.Name == "" { - err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrChartNameMissing)) - } - if len(chart.Name) > ZarfMaxChartNameLength { err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrChartName, chart.Name, ZarfMaxChartNameLength)) } @@ -314,10 +284,6 @@ func (chart ZarfChart) Validate() error { func (manifest ZarfManifest) Validate() error { var err error - if manifest.Name == "" { - err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrManifestNameMissing)) - } - if len(manifest.Name) > ZarfMaxChartNameLength { err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrManifestNameLength, manifest.Name, ZarfMaxChartNameLength)) } diff --git a/src/types/validate_test.go b/src/types/validate_test.go index f283302675..b0ebc60e8f 100644 --- a/src/types/validate_test.go +++ b/src/types/validate_test.go @@ -38,30 +38,16 @@ func TestZarfPackageValidate(t *testing.T) { }, expectedErrs: nil, }, - { - name: "no components", - pkg: ZarfPackage{ - Kind: ZarfPackageConfig, - Metadata: ZarfMetadata{ - Name: "empty-components", - }, - Components: []ZarfComponent{}, - }, - expectedErrs: []string{"package must have at least 1 component"}, - }, { name: "invalid package", pkg: ZarfPackage{ Kind: ZarfPackageConfig, Metadata: ZarfMetadata{ - Name: "-invalid-package", + Name: "invalid-package", }, Components: []ZarfComponent{ { - Name: "-invalid", - Only: ZarfComponentOnlyTarget{ - LocalOS: "unsupportedOS", - }, + Name: "invalid", Required: helpers.BoolPtr(true), Default: true, Charts: []ZarfChart{ @@ -95,15 +81,7 @@ func TestZarfPackageValidate(t *testing.T) { Name: "duplicate", }, }, - Variables: []variables.InteractiveVariable{ - { - Variable: variables.Variable{Name: "not_uppercase"}, - }, - }, Constants: []variables.Constant{ - { - Name: "not_uppercase", - }, { Name: "BAD", Pattern: "^good_val$", @@ -112,13 +90,8 @@ func TestZarfPackageValidate(t *testing.T) { }, }, expectedErrs: []string{ - fmt.Sprintf(lang.PkgValidateErrPkgName, "-invalid-package"), - fmt.Errorf(lang.PkgValidateErrVariable, fmt.Errorf(lang.PkgValidateMustBeUppercase, "not_uppercase")).Error(), - fmt.Errorf(lang.PkgValidateErrConstant, fmt.Errorf(lang.PkgValidateErrPkgConstantName, "not_uppercase")).Error(), fmt.Errorf(lang.PkgValidateErrConstant, fmt.Errorf(lang.PkgValidateErrPkgConstantPattern, "BAD", "^good_val$")).Error(), - fmt.Sprintf(lang.PkgValidateErrComponentName, "-invalid"), - fmt.Sprintf(lang.PkgValidateErrComponentLocalOS, "-invalid", "unsupportedOS", supportedOS), - fmt.Sprintf(lang.PkgValidateErrComponentReqDefault, "-invalid"), + fmt.Sprintf(lang.PkgValidateErrComponentReqDefault, "invalid"), fmt.Sprintf(lang.PkgValidateErrChartNameNotUnique, "chart1"), fmt.Sprintf(lang.PkgValidateErrManifestNameNotUnique, "manifest1"), fmt.Sprintf(lang.PkgValidateErrComponentReqGrouped, "required-in-group"), @@ -187,11 +160,6 @@ func TestValidateManifest(t *testing.T) { manifest: ZarfManifest{Name: "valid", Files: []string{"a-file"}}, expectedErrs: nil, }, - { - name: "empty name", - manifest: ZarfManifest{Name: "", Files: []string{"a-file"}}, - expectedErrs: []string{lang.PkgValidateErrManifestNameMissing}, - }, { name: "long name", manifest: ZarfManifest{Name: longName, Files: []string{"a-file"}}, @@ -231,11 +199,6 @@ func TestValidateChart(t *testing.T) { chart: ZarfChart{Name: "chart1", Namespace: "whatever", URL: "http://whatever", Version: "v1.0.0"}, expectedErrs: nil, }, - { - name: "empty name", - chart: ZarfChart{Name: "", Namespace: "whatever", URL: "http://whatever", Version: "v1.0.0"}, - expectedErrs: []string{lang.PkgValidateErrChartNameMissing}, - }, { name: "long name", chart: ZarfChart{Name: longName, Namespace: "whatever", URL: "http://whatever", Version: "v1.0.0"}, @@ -244,7 +207,7 @@ func TestValidateChart(t *testing.T) { }, }, { - name: "no url or local path", + name: "no url, local path, version, or namespace", chart: ZarfChart{Name: "invalid"}, expectedErrs: []string{ fmt.Sprintf(lang.PkgValidateErrChartNamespaceMissing, "invalid"), From a93d65a5518daf3d598a3586a3fae8ced126b7eb Mon Sep 17 00:00:00 2001 From: Philip Laine Date: Thu, 25 Jul 2024 17:22:11 +0200 Subject: [PATCH 27/68] refactor: remove overly verbose debug logs (#2751) Signed-off-by: Philip Laine --- src/internal/agent/hooks/argocd-application.go | 2 -- src/internal/agent/http/admission/handler.go | 3 --- src/internal/agent/http/server.go | 5 ----- src/internal/agent/operations/hook.go | 3 --- src/internal/packager/git/checkout.go | 6 ------ src/internal/packager/git/gitea.go | 10 ---------- src/internal/packager/helm/chart.go | 10 ++-------- src/internal/packager/helm/images.go | 2 -- src/internal/packager/helm/post-render.go | 2 -- src/internal/packager/images/push.go | 2 -- src/pkg/cluster/tunnel.go | 2 -- src/pkg/packager/common.go | 16 ++++------------ src/pkg/packager/creator/compose.go | 2 -- src/pkg/packager/creator/normal.go | 2 -- src/pkg/packager/creator/skeleton.go | 2 -- src/pkg/packager/prepare.go | 3 +-- src/pkg/packager/sources/new.go | 3 --- src/pkg/packager/sources/oci.go | 2 -- src/pkg/utils/io.go | 5 ----- src/pkg/utils/network.go | 1 - src/test/e2e/00_use_cli_test.go | 2 ++ 21 files changed, 9 insertions(+), 76 deletions(-) diff --git a/src/internal/agent/hooks/argocd-application.go b/src/internal/agent/hooks/argocd-application.go index 8886ba2ff9..f9d3238aee 100644 --- a/src/internal/agent/hooks/argocd-application.go +++ b/src/internal/agent/hooks/argocd-application.go @@ -72,8 +72,6 @@ func mutateApplication(ctx context.Context, r *v1.AdmissionRequest, cluster *clu return nil, fmt.Errorf(lang.ErrUnmarshal, err) } - message.Debugf("Data %v", string(r.Object.Raw)) - patches := []operations.PatchOperation{} if app.Spec.Source != nil { diff --git a/src/internal/agent/http/admission/handler.go b/src/internal/agent/http/admission/handler.go index 56589a7c73..4b4d69323b 100644 --- a/src/internal/agent/http/admission/handler.go +++ b/src/internal/agent/http/admission/handler.go @@ -117,9 +117,6 @@ func (h *Handler) Serve(hook operations.Hook) http.HandlerFunc { return } - message.Debug("PATCH: ", string(admissionResponse.Response.Patch)) - message.Debug("RESPONSE: ", string(jsonResponse)) - message.Infof(lang.AgentInfoWebhookAllowed, r.URL.Path, review.Request.Operation, result.Allowed) w.WriteHeader(http.StatusOK) //nolint: errcheck // ignore diff --git a/src/internal/agent/http/server.go b/src/internal/agent/http/server.go index b5953ee0e2..6a79aaa449 100644 --- a/src/internal/agent/http/server.go +++ b/src/internal/agent/http/server.go @@ -14,13 +14,10 @@ import ( "github.com/zarf-dev/zarf/src/internal/agent/hooks" "github.com/zarf-dev/zarf/src/internal/agent/http/admission" "github.com/zarf-dev/zarf/src/pkg/cluster" - "github.com/zarf-dev/zarf/src/pkg/message" ) // NewAdmissionServer creates a http.Server for the mutating webhook admission handler. func NewAdmissionServer(ctx context.Context, port string) (*http.Server, error) { - message.Debugf("http.NewAdmissionServer(%s)", port) - c, err := cluster.NewCluster() if err != nil { return nil, err @@ -56,8 +53,6 @@ func NewAdmissionServer(ctx context.Context, port string) (*http.Server, error) // NewProxyServer creates and returns an http proxy server. func NewProxyServer(port string) *http.Server { - message.Debugf("http.NewHTTPProxy(%s)", port) - mux := http.NewServeMux() mux.Handle("/healthz", healthz()) mux.Handle("/", ProxyHandler()) diff --git a/src/internal/agent/operations/hook.go b/src/internal/agent/operations/hook.go index 627ce58094..8c411adee7 100644 --- a/src/internal/agent/operations/hook.go +++ b/src/internal/agent/operations/hook.go @@ -8,7 +8,6 @@ import ( "fmt" "github.com/zarf-dev/zarf/src/config/lang" - "github.com/zarf-dev/zarf/src/pkg/message" admission "k8s.io/api/admission/v1" ) @@ -32,8 +31,6 @@ type Hook struct { // Execute evaluates the request and try to execute the function for operation specified in the request. func (h *Hook) Execute(r *admission.AdmissionRequest) (*Result, error) { - message.Debugf("operations.Execute(*admission.AdmissionRequest) - %#v , %s/%s: %#v", r.Kind, r.Namespace, r.Name, r.Operation) - switch r.Operation { case admission.Create: return wrapperExecution(h.Create, r) diff --git a/src/internal/packager/git/checkout.go b/src/internal/packager/git/checkout.go index 4441e48873..2ee91d96b5 100644 --- a/src/internal/packager/git/checkout.go +++ b/src/internal/packager/git/checkout.go @@ -15,8 +15,6 @@ import ( // CheckoutTag performs a `git checkout` of the provided tag to a detached HEAD. func (g *Git) CheckoutTag(tag string) error { - message.Debugf("git checkout tag %s", tag) - options := &git.CheckoutOptions{ Branch: ParseRef(tag), } @@ -35,8 +33,6 @@ func (g *Git) checkoutRefAsBranch(ref string, branch plumbing.ReferenceName) err // than checking out to a detached head, checks out to the provided branch ref // It will delete the branch provided if it exists. func (g *Git) checkoutTagAsBranch(tag string, branch plumbing.ReferenceName) error { - message.Debugf("git checkout tag %s on %s", tag, branch) - repo, err := git.PlainOpen(g.GitPath) if err != nil { return fmt.Errorf("not a valid git repo or unable to open: %w", err) @@ -54,8 +50,6 @@ func (g *Git) checkoutTagAsBranch(tag string, branch plumbing.ReferenceName) err // with the provided hash // It will delete the branch provided if it exists. func (g *Git) checkoutHashAsBranch(hash plumbing.Hash, branch plumbing.ReferenceName) error { - message.Debugf("git checkout hash %s on %s", hash, branch) - repo, err := git.PlainOpen(g.GitPath) if err != nil { return fmt.Errorf("not a valid git repo or unable to open: %w", err) diff --git a/src/internal/packager/git/gitea.go b/src/internal/packager/git/gitea.go index 4bfbcf60ab..a6715d29d5 100644 --- a/src/internal/packager/git/gitea.go +++ b/src/internal/packager/git/gitea.go @@ -32,8 +32,6 @@ type CreateTokenResponse struct { // CreateReadOnlyUser uses the Gitea API to create a non-admin Zarf user. func (g *Git) CreateReadOnlyUser(ctx context.Context) error { - message.Debugf("git.CreateReadOnlyUser()") - c, err := cluster.NewCluster() if err != nil { return err @@ -119,8 +117,6 @@ func (g *Git) UpdateZarfGiteaUsers(ctx context.Context, oldState *types.ZarfStat // UpdateGitUser updates Zarf git server users func (g *Git) UpdateGitUser(ctx context.Context, oldAdminPass string, username string, userpass string) error { - message.Debugf("git.UpdateGitUser()") - c, err := cluster.NewCluster() if err != nil { return err @@ -157,8 +153,6 @@ func (g *Git) UpdateGitUser(ctx context.Context, oldAdminPass string, username s // CreatePackageRegistryToken uses the Gitea API to create a package registry token. func (g *Git) CreatePackageRegistryToken(ctx context.Context) (CreateTokenResponse, error) { - message.Debugf("git.CreatePackageRegistryToken()") - c, err := cluster.NewCluster() if err != nil { return CreateTokenResponse{}, err @@ -287,8 +281,6 @@ func UpdateGiteaPVC(ctx context.Context, shouldRollBack bool) (string, error) { // DoHTTPThings adds http request boilerplate and perform the request, checking for a successful response. func (g *Git) DoHTTPThings(request *netHttp.Request, username, secret string) ([]byte, int, error) { - message.Debugf("git.DoHttpThings()") - // Prep the request with boilerplate client := &netHttp.Client{Timeout: time.Second * 20} request.SetBasicAuth(username, secret) @@ -312,8 +304,6 @@ func (g *Git) DoHTTPThings(request *netHttp.Request, username, secret string) ([ } func (g *Git) addReadOnlyUserToRepo(tunnelURL, repo string) error { - message.Debugf("git.addReadOnlyUserToRepo()") - // Add the readonly user to the repo addCollabBody := map[string]string{ "permission": "read", diff --git a/src/internal/packager/helm/chart.go b/src/internal/packager/helm/chart.go index 0bd483df7f..bca8773294 100644 --- a/src/internal/packager/helm/chart.go +++ b/src/internal/packager/helm/chart.go @@ -61,7 +61,6 @@ func (h *Helm) InstallOrUpgradeChart(ctx context.Context) (types.ConnectStrings, histClient := action.NewHistory(h.actionConfig) tryHelm := func() error { var err error - var output *release.Release releases, histErr := histClient.Run(h.chart.ReleaseName) @@ -71,14 +70,14 @@ func (h *Helm) InstallOrUpgradeChart(ctx context.Context) (types.ConnectStrings, // No prior release, try to install it. spinner.Updatef("Attempting chart installation") - output, err = h.installChart(postRender) + _, err = h.installChart(postRender) } else if histErr == nil && len(releases) > 0 { // Otherwise, there is a prior release so upgrade it. spinner.Updatef("Attempting chart upgrade") lastRelease := releases[len(releases)-1] - output, err = h.upgradeChart(lastRelease, postRender) + _, err = h.upgradeChart(lastRelease, postRender) } else { // 😭 things aren't working return fmt.Errorf("unable to verify the chart installation status: %w", histErr) @@ -88,7 +87,6 @@ func (h *Helm) InstallOrUpgradeChart(ctx context.Context) (types.ConnectStrings, return err } - message.Debug(output.Info.Description) spinner.Success() return nil } @@ -128,7 +126,6 @@ func (h *Helm) InstallOrUpgradeChart(ctx context.Context) (types.ConnectStrings, // TemplateChart generates a helm template from a given chart. func (h *Helm) TemplateChart(ctx context.Context) (manifest string, chartValues chartutil.Values, err error) { - message.Debugf("helm.TemplateChart()") spinner := message.NewProgressSpinner("Templating helm chart %s", h.chart.Name) defer spinner.Stop() @@ -324,7 +321,6 @@ func (h *Helm) upgradeChart(lastRelease *release.Release, postRender *renderer) } func (h *Helm) rollbackChart(name string, version int) error { - message.Debugf("helm.rollbackChart(%s)", name) client := action.NewRollback(h.actionConfig) client.CleanupOnFail = true client.Force = true @@ -335,7 +331,6 @@ func (h *Helm) rollbackChart(name string, version int) error { } func (h *Helm) uninstallChart(name string) (*release.UninstallReleaseResponse, error) { - message.Debugf("helm.uninstallChart(%s)", name) client := action.NewUninstall(h.actionConfig) client.KeepHistory = false client.Wait = true @@ -344,7 +339,6 @@ func (h *Helm) uninstallChart(name string) (*release.UninstallReleaseResponse, e } func (h *Helm) loadChartData() (*chart.Chart, chartutil.Values, error) { - message.Debugf("helm.loadChartData()") var ( loadedChart *chart.Chart chartValues chartutil.Values diff --git a/src/internal/packager/helm/images.go b/src/internal/packager/helm/images.go index 390ce5c8be..b5399f2590 100644 --- a/src/internal/packager/helm/images.go +++ b/src/internal/packager/helm/images.go @@ -6,7 +6,6 @@ package helm import ( "github.com/defenseunicorns/pkg/helpers/v2" "github.com/goccy/go-yaml" - "github.com/zarf-dev/zarf/src/pkg/message" "helm.sh/helm/v3/pkg/chart/loader" "helm.sh/helm/v3/pkg/chartutil" ) @@ -45,7 +44,6 @@ func FindAnnotatedImagesForChart(chartPath string, values chartutil.Values) (ima // Only include the image if the current values/condition specify it should be included if i.Condition != "" { value, err := values.PathValue(i.Condition) - message.Debugf("%#v - %#v - %#v\n", value, i.Condition, err) // We intentionally ignore the error here because the key could be missing from the values.yaml if err == nil && value == true { images = append(images, i.Image) diff --git a/src/internal/packager/helm/post-render.go b/src/internal/packager/helm/post-render.go index 60d8fde0e3..b115b33ddf 100644 --- a/src/internal/packager/helm/post-render.go +++ b/src/internal/packager/helm/post-render.go @@ -38,8 +38,6 @@ type renderer struct { } func (h *Helm) newRenderer(ctx context.Context) (*renderer, error) { - message.Debugf("helm.NewRenderer()") - rend := &renderer{ Helm: h, connectStrings: types.ConnectStrings{}, diff --git a/src/internal/packager/images/push.go b/src/internal/packager/images/push.go index 08625ab385..0d0752f9fe 100644 --- a/src/internal/packager/images/push.go +++ b/src/internal/packager/images/push.go @@ -99,8 +99,6 @@ func Push(ctx context.Context, cfg PushConfig) error { return err } - message.Debugf("push %s -> %s)", refInfo.Reference, offlineNameCRC) - if err = pushImage(img, offlineNameCRC); err != nil { return err } diff --git a/src/pkg/cluster/tunnel.go b/src/pkg/cluster/tunnel.go index f0a1a660e0..719d81e008 100644 --- a/src/pkg/cluster/tunnel.go +++ b/src/pkg/cluster/tunnel.go @@ -185,8 +185,6 @@ func (c *Cluster) checkForZarfConnectLabel(ctx context.Context, name string) (Tu var err error var zt TunnelInfo - message.Debugf("Looking for a Zarf Connect Label in the cluster") - selector, err := metav1.LabelSelectorAsSelector(&metav1.LabelSelector{ MatchLabels: map[string]string{ ZarfConnectLabelName: name, diff --git a/src/pkg/packager/common.go b/src/pkg/packager/common.go index a5b77ff9d1..a753ec29d4 100644 --- a/src/pkg/packager/common.go +++ b/src/pkg/packager/common.go @@ -107,25 +107,17 @@ func New(cfg *types.PackagerConfig, mods ...Modifier) (*Packager, error) { // If the temp directory is not set, set it to the default if pkgr.layout == nil { - if err = pkgr.setTempDirectory(config.CommonOptions.TempDirectory); err != nil { + dir, err := utils.MakeTempDir(config.CommonOptions.TempDirectory) + if err != nil { return nil, fmt.Errorf("unable to create package temp paths: %w", err) } + message.Debug("Using temporary directory:", dir) + pkgr.layout = layout.New(dir) } return pkgr, nil } -// setTempDirectory sets the temp directory for the packager. -func (p *Packager) setTempDirectory(path string) error { - dir, err := utils.MakeTempDir(path) - if err != nil { - return fmt.Errorf("unable to create package temp paths: %w", err) - } - - p.layout = layout.New(dir) - return nil -} - // ClearTempPaths removes the temp directory and any files within it. func (p *Packager) ClearTempPaths() { // Remove the temp directory, but don't throw an error if it fails diff --git a/src/pkg/packager/creator/compose.go b/src/pkg/packager/creator/compose.go index 8844c0305f..bbd1325b31 100644 --- a/src/pkg/packager/creator/compose.go +++ b/src/pkg/packager/creator/compose.go @@ -7,7 +7,6 @@ package creator import ( "context" - "github.com/zarf-dev/zarf/src/pkg/message" "github.com/zarf-dev/zarf/src/pkg/packager/composer" "github.com/zarf-dev/zarf/src/types" ) @@ -37,7 +36,6 @@ func ComposeComponents(ctx context.Context, pkg types.ZarfPackage, flavor string if err != nil { return types.ZarfPackage{}, nil, err } - message.Debugf("%s", chain) // migrate any deprecated component configurations now warning := chain.Migrate(pkg.Build) diff --git a/src/pkg/packager/creator/normal.go b/src/pkg/packager/creator/normal.go index 6f42c55865..99b0f572b4 100644 --- a/src/pkg/packager/creator/normal.go +++ b/src/pkg/packager/creator/normal.go @@ -372,8 +372,6 @@ func (pc *PackageCreator) addComponent(ctx context.Context, component types.Zarf } for filesIdx, file := range component.Files { - message.Debugf("Loading %#v", file) - rel := filepath.Join(layout.FilesDir, strconv.Itoa(filesIdx), filepath.Base(file.Target)) dst := filepath.Join(componentPaths.Base, rel) destinationDir := filepath.Dir(dst) diff --git a/src/pkg/packager/creator/skeleton.go b/src/pkg/packager/creator/skeleton.go index 9ddf24379a..c7b2d3d706 100644 --- a/src/pkg/packager/creator/skeleton.go +++ b/src/pkg/packager/creator/skeleton.go @@ -209,8 +209,6 @@ func (sc *SkeletonCreator) addComponent(component types.ZarfComponent, dst *layo } for filesIdx, file := range component.Files { - message.Debugf("Loading %#v", file) - if helpers.IsURL(file.Source) { continue } diff --git a/src/pkg/packager/prepare.go b/src/pkg/packager/prepare.go index 0ca1f35f91..a52cc9c0f4 100644 --- a/src/pkg/packager/prepare.go +++ b/src/pkg/packager/prepare.go @@ -255,8 +255,7 @@ func (p *Packager) findImages(ctx context.Context) (imgMap map[string][]string, } // Break the manifest into separate resources - contentString := string(contents) - message.Debugf("%s", contentString) + // TODO: Do not dogsled error yamls, _ := utils.SplitYAML(contents) resources = append(resources, yamls...) diff --git a/src/pkg/packager/sources/new.go b/src/pkg/packager/sources/new.go index 9018632085..4d43cc229c 100644 --- a/src/pkg/packager/sources/new.go +++ b/src/pkg/packager/sources/new.go @@ -14,7 +14,6 @@ import ( "github.com/defenseunicorns/pkg/oci" "github.com/zarf-dev/zarf/src/config" "github.com/zarf-dev/zarf/src/pkg/layout" - "github.com/zarf-dev/zarf/src/pkg/message" "github.com/zarf-dev/zarf/src/pkg/packager/filters" "github.com/zarf-dev/zarf/src/pkg/zoci" "github.com/zarf-dev/zarf/src/types" @@ -85,7 +84,5 @@ func New(pkgOpts *types.ZarfPackageOptions) (PackageSource, error) { return nil, fmt.Errorf("could not identify source type for %q", pkgSrc) } - message.Debugf("Using %T for %q", source, pkgSrc) - return source, nil } diff --git a/src/pkg/packager/sources/oci.go b/src/pkg/packager/sources/oci.go index 99a98137fc..33e4ba3fad 100644 --- a/src/pkg/packager/sources/oci.go +++ b/src/pkg/packager/sources/oci.go @@ -35,8 +35,6 @@ type OCISource struct { // LoadPackage loads a package from an OCI registry. func (s *OCISource) LoadPackage(ctx context.Context, dst *layout.PackagePaths, filter filters.ComponentFilterStrategy, unarchiveAll bool) (pkg types.ZarfPackage, warnings []string, err error) { - message.Debugf("Loading package from %q", s.PackageSource) - pkg, err = s.FetchZarfYAML(ctx) if err != nil { return pkg, nil, err diff --git a/src/pkg/utils/io.go b/src/pkg/utils/io.go index 06885d623a..7edee56422 100755 --- a/src/pkg/utils/io.go +++ b/src/pkg/utils/io.go @@ -11,7 +11,6 @@ import ( "github.com/defenseunicorns/pkg/helpers/v2" "github.com/zarf-dev/zarf/src/config" - "github.com/zarf-dev/zarf/src/pkg/message" ) const ( @@ -25,14 +24,10 @@ func MakeTempDir(basePath string) (string, error) { return "", err } } - tmp, err := os.MkdirTemp(basePath, tmpPathPrefix) if err != nil { return "", err } - - message.Debug("Using temporary directory:", tmp) - return tmp, nil } diff --git a/src/pkg/utils/network.go b/src/pkg/utils/network.go index 4bd6945f36..be0b80a2ed 100644 --- a/src/pkg/utils/network.go +++ b/src/pkg/utils/network.go @@ -40,7 +40,6 @@ func parseChecksum(src string) (string, string, error) { // DownloadToFile downloads a given URL to the target filepath (including the cosign key if necessary). func DownloadToFile(ctx context.Context, src string, dst string, cosignKeyPath string) (err error) { - message.Debugf("Downloading %s to %s", src, dst) // check if the parsed URL has a checksum // if so, remove it and use the checksum to validate the file src, checksum, err := parseChecksum(src) diff --git a/src/test/e2e/00_use_cli_test.go b/src/test/e2e/00_use_cli_test.go index ff8a07106b..b663d58454 100644 --- a/src/test/e2e/00_use_cli_test.go +++ b/src/test/e2e/00_use_cli_test.go @@ -143,6 +143,7 @@ func TestUseCLI(t *testing.T) { require.Greater(t, len(files), 1) }) + // TODO: Refactor test as it depends on debug log output for validation. t.Run("zarf package inspect with tmpdir", func(t *testing.T) { t.Parallel() path := fmt.Sprintf("build/zarf-package-component-actions-%s.tar.zst", e2e.Arch) @@ -152,6 +153,7 @@ func TestUseCLI(t *testing.T) { require.NoError(t, err, stdOut, stdErr) }) + // TODO: Refactor test as it depends on debug log output for validation. t.Run("zarf package deploy with tmpdir", func(t *testing.T) { t.Parallel() tmpdir := t.TempDir() From eae2a02a690fa409c7a7a064786c6d68324941aa Mon Sep 17 00:00:00 2001 From: Austin Abro <37223396+AustinAbro321@users.noreply.github.com> Date: Thu, 25 Jul 2024 15:36:26 -0400 Subject: [PATCH 28/68] ci: improve nightly eks test (#2759) Signed-off-by: Austin Abro --- .github/workflows/nightly-eks.yml | 18 +++++++++++++++++- examples/kiwix/manifests/deployment.yaml | 2 ++ packages/distros/eks/eks.yaml | 18 ++++++++---------- packages/distros/eks/zarf.yaml | 12 ++++++------ 4 files changed, 33 insertions(+), 17 deletions(-) diff --git a/.github/workflows/nightly-eks.yml b/.github/workflows/nightly-eks.yml index 1fe4f4ad7c..eee9191155 100644 --- a/.github/workflows/nightly-eks.yml +++ b/.github/workflows/nightly-eks.yml @@ -41,7 +41,7 @@ jobs: role-to-assume: ${{ secrets.AWS_NIGHTLY_ROLE }} role-session-name: ${{ github.job || github.event.client_payload.pull_request.head.sha || github.sha }} aws-region: us-east-1 - role-duration-seconds: 3600 + role-duration-seconds: 7200 - name: Build the eks package run: ./build/zarf package create packages/distros/eks -o build --confirm @@ -57,6 +57,22 @@ jobs: - name: Run tests run: make test-e2e-with-cluster ARCH=amd64 + - name: get pods + if: always() + run: kubectl get pods -n kiwix -o yaml + + - name: describe pod + if: always() + run: kubectl describe pods -n kiwix + + - name: get nodes + if: always() + run: kubectl get nodes -o yaml + + - name: describe nodes + if: always() + run: kubectl describe nodes + - name: Teardown the cluster if: always() run: | diff --git a/examples/kiwix/manifests/deployment.yaml b/examples/kiwix/manifests/deployment.yaml index e187c684e6..ba05eb767c 100644 --- a/examples/kiwix/manifests/deployment.yaml +++ b/examples/kiwix/manifests/deployment.yaml @@ -6,6 +6,8 @@ metadata: labels: app: kiwix-serve spec: + strategy: + type: Recreate selector: matchLabels: app: kiwix-serve diff --git a/packages/distros/eks/eks.yaml b/packages/distros/eks/eks.yaml index 530da71f8c..cf859f77a5 100644 --- a/packages/distros/eks/eks.yaml +++ b/packages/distros/eks/eks.yaml @@ -4,29 +4,27 @@ kind: ClusterConfig metadata: name: ###ZARF_VAR_EKS_CLUSTER_NAME### region: ###ZARF_VAR_EKS_CLUSTER_REGION### - version: "###ZARF_VAR_EKS_CLUSTER_VERSION###" tags: - PermissionsBoundary: "zarf_dev_base_policy" + PermissionsBoundary: "###ZARF_VAR_PERMISSIONS_BOUNDARY_TAG###" iam: withOIDC: true - serviceRolePermissionsBoundary: "arn:aws:iam::173911864621:policy/zarf_dev_base_policy" + serviceRolePermissionsBoundary: "###ZARF_VAR_PERMISSIONS_BOUNDARY_ARN###" addons: - name: aws-ebs-csi-driver - version: "###ZARF_VAR_EBS_DRIVER_VERSION###" attachPolicyARNs: - arn:aws:iam::aws:policy/service-role/AmazonEBSCSIDriverPolicy - permissionsBoundary: "arn:aws:iam::173911864621:policy/zarf_dev_base_policy" + permissionsBoundary: "###ZARF_VAR_PERMISSIONS_BOUNDARY_ARN###" tags: - PermissionsBoundary: "zarf_dev_base_policy" + PermissionsBoundary: "###ZARF_VAR_PERMISSIONS_BOUNDARY_TAG###" - name: vpc-cni attachPolicyARNs: - arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy - permissionsBoundary: "arn:aws:iam::173911864621:policy/zarf_dev_base_policy" + permissionsBoundary: "###ZARF_VAR_PERMISSIONS_BOUNDARY_ARN###" tags: - PermissionsBoundary: "zarf_dev_base_policy" + PermissionsBoundary: "###ZARF_VAR_PERMISSIONS_BOUNDARY_TAG###" managedNodeGroups: - instanceType: ###ZARF_VAR_EKS_INSTANCE_TYPE### @@ -35,6 +33,6 @@ managedNodeGroups: maxSize: 6 spot: true tags: - PermissionsBoundary: "zarf_dev_base_policy" + PermissionsBoundary: "###ZARF_VAR_PERMISSIONS_BOUNDARY_TAG###" iam: - instanceRolePermissionsBoundary: "arn:aws:iam::173911864621:policy/zarf_dev_base_policy" + instanceRolePermissionsBoundary: "###ZARF_VAR_PERMISSIONS_BOUNDARY_ARN###" diff --git a/packages/distros/eks/zarf.yaml b/packages/distros/eks/zarf.yaml index 8172dfdf60..1fed3b20a1 100644 --- a/packages/distros/eks/zarf.yaml +++ b/packages/distros/eks/zarf.yaml @@ -17,13 +17,13 @@ variables: description: The AWS region to setup the cluster and associated networking default: us-east-1 - - name: EKS_CLUSTER_VERSION - description: The Kubernetes version to use for the cluster - default: "1.27" + - name: PERMISSIONS_BOUNDARY_ARN + description: The ARN of the IAM permissions boundary to apply to the cluster resources + default: arn:aws:iam::173911864621:policy/zarf_dev_base_policy - - name: EBS_DRIVER_VERSION - description: The AEBS driver version to use for the cluster (must be available on the K8s version) - default: "v1.21.0-eksbuild.1" + - name: PERMISSIONS_BOUNDARY_TAG + description: The tag to apply to the cluster resources to indicate the permissions boundary + default: zarf_dev_base_policy components: - name: load-eksctl From 3770e6cc8f83d25b2f04ad3deaa2dc8eee8c8d8e Mon Sep 17 00:00:00 2001 From: Philip Laine Date: Thu, 25 Jul 2024 22:29:29 +0200 Subject: [PATCH 29/68] chore: logging ADR (#2588) Signed-off-by: Philip Laine Co-authored-by: schristoff <28318173+schristoff@users.noreply.github.com> --- adr/0025-logging.md | 235 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 235 insertions(+) create mode 100644 adr/0025-logging.md diff --git a/adr/0025-logging.md b/adr/0025-logging.md new file mode 100644 index 0000000000..dbd8664c7c --- /dev/null +++ b/adr/0025-logging.md @@ -0,0 +1,235 @@ +# 25. Logging + +Date: 2024-06-06 + +## Status + +Proposed + +## Context + +Zarf is currently using an in-house built logging solution which in turn depends on pterm. This solution is used to output information to the end user who is using the Zarf CLI. This output is for the most part formatted with the purpose of CLI user experience. Logging function calls are done both in the CLI specific code as well as in the packages. The logging is implemented in such a way that different levels exist with different impacts and log destinations. A common pattern that is used is to call `message.Fatal` whenever an error occurs. This will output the message to STDERR while writing the actual error message to a debug log and exiting the program. Exiting the program in this manner makes unit testing difficult while also skipping proper context handling and skipping any clean-up that was intended to run before exiting the program. Some logging components like the progress bar and spinner are accessed through a shared global state that is not thread safe. The coupling to logging becomes complicated as disabling the progress bar is a challenge while multi threading these functions which access the global state resulting in complicated access patterns. + +## Decision + +I am proposing to completely refactor the logging functionality to follow a more standardized format using the newish slog interfaces. On top of that we would refactor the current internationalization by converting them to standardized errors. + +* Replace the message package with a slog interface. +* Replace the lang package with static errors. +* Remove any use of `message.Fatal` and instead return errors. +* Refactor use of `message.WarnErr` to either return error or to log the error. +* Refactor existing functions that print formatted outputs to defer the printing to the CLI. +* Define a new interface for spinner and progress bar that is passed in as a function parameter. + +The message package currently exports the following functions which should be replaced by its logr counterpart. + +| Function | Replacement | Comment | +| --- | --- | --- | +| ZarfCommand | Info | Just formats a slice as a command. | +| Command | Info | Outputs a command with a prefix and style. | +| Debug | Debug | | +| Debugf | Debug | | +| ErrorWebf | N/A | Not used anywhere. | +| Warn | Warn | | +| Warnf | Warn | | +| WarnErr | Warn | | +| WarnErrf | Warn | | +| Fatal | N/A | Should not be used. | +| Fatalf | N/A | Should not be used. | +| Info | Info | | +| Infof | Info | | +| Success | Info | Seems to be a info log with a checkmark prefix. | +| Successf | Info | Seems to be a info log with a checkmark prefix. | +| Question | ? | Open question how to resolve this. | +| Questionf | ? | Open question how to resolve this. | +| Note | Info | Should just be an info or maybe a debug log. | +| Notef | Info | Should just be an info or maybe a debug log. | +| Title | ? | Not sure how this should be replaced as it formats with separator. | +| HeaderInfof | ? | | +| HorizontalRule | ? | | +| JSONValue | N/A | Should be replaced with a marshal. | +| Paragraph | ? | | +| Paragraphn | ? | | +| PrintDiff | ? | | +| Table | ? | Need to come up with a good syntax for functions to return output that can print as a table. | +| ColorWrap | ? | Should this be used? | +| PrintConnectStringTable | N/A | This logic should not exist in the message package. | +| PrintCredentialTable | N/A | This logic should not exist in the message package. | +| PrintComponentCredential | N/A | This logic should not exist in the message package. | +| PrintCredentialUpdates | N/A | This logic should not exist in the message package. | +| Spinner | Interface | New Spinner interface. | +| ProgressBar | Interface | New progress bar interface. | + +The majority of simple logging changes should be possible with little signature changes. Replacing the existing output with a slog interface would allow other implementations to be used. A challenge initially may be the changes to table output formatting to make it work properly. This change will require some refactoring of existing code. A requirement for the changes is that they have to improve the UX for users looking at log files. As I understand the present day the spinners will cause a new line everytime they update, resulting in a lot of bloat. A goal should be to make sure that this does not happen in the future. + +Spinners and progress bars however are a bit more challenging. They need to be refactored so that they are no longer instantiated outside of the CLI code. They should instead be passed as a function parameter to each function that needs them. A good example of a project that solves the problem in a similar manner is Kind. In Kind they create a [status object from the logger](https://github.com/kubernetes-sigs/kind/blob/7799e72306db315ea4f4b1cac90ff68404da4f28/pkg/internal/cli/status.go#L39) which they then [pass to where it is needed](https://github.com/kubernetes-sigs/kind/blob/7799e72306db315ea4f4b1cac90ff68404da4f28/pkg/cluster/internal/create/create.go#L133). Doing so results in a single status object created which is reused where ever it is needed. A lot of inspiration can be take from how Kind deals with CLI output. While they use klog instead of slog there are a lot of similarities. They have for example a check if the output is in a terminal or not, and will disable the spinner accordingly. + +Here is a suggestion for how a thread safe spinner could be implemented with a shared logger. This also allows for parallel spinners and progress bars. + +```golang +package main + +import ( + "context" + "fmt" + "io" + "log/slog" + "os" + "sync" + "time" + + "github.com/pterm/pterm" +) + +func main() { + err := run() + if err != nil { + panic(err) + } +} + +func run() error { + h := NewPtermHandler(os.Stderr) + log := slog.New(h) + + log.Info("before") + + spinner := NewSpinner(log) + spinner.Update("Running some job") + log.Info("after") + time.Sleep(1 * time.Second) + spinner.Update("Doing some update") + + time.Sleep(2 * time.Second) + + spinner.Succeed() + + time.Sleep(2 * time.Second) + + return nil +} + +type PtermHandler struct { + printer *pterm.MultiPrinter + attrs []slog.Attr + group string +} + +func NewPtermHandler(w io.Writer) *PtermHandler { + printer, _ := pterm.DefaultMultiPrinter.WithWriter(w).Start() + return &PtermHandler{ + printer: printer, + } +} + +func (h *PtermHandler) Enabled(context.Context, slog.Level) bool { + return true +} + +func (h *PtermHandler) Handle(ctx context.Context, r slog.Record) error { + l := fmt.Sprintf("%s: %s\n", r.Level, r.Message) + _, err := h.printer.NewWriter().Write([]byte(l)) + return err +} + +func (h *PtermHandler) WithAttrs(attrs []slog.Attr) slog.Handler { + return &PtermHandler{ + printer: h.printer, + attrs: append(h.attrs, attrs...), + group: h.group, + } +} + +func (h *PtermHandler) WithGroup(name string) slog.Handler { + return &PtermHandler{ + printer: h.printer, + attrs: h.attrs, + group: name, + } +} + +type Spinner struct { + sequence []string + mx sync.Mutex + log *slog.Logger + printer *pterm.MultiPrinter + firstStatus string + status string + spinner *pterm.SpinnerPrinter +} + +func NewSpinner(log *slog.Logger) *Spinner { + h, ok := log.Handler().(*PtermHandler) + if !ok { + return &Spinner{ + log: log, + } + } + return &Spinner{ + sequence: []string{` ⠋ `, ` ⠙ `, ` ⠹ `, ` ⠸ `, ` ⠼ `, ` ⠴ `, ` ⠦ `, ` ⠧ `, ` ⠇ `, ` ⠏ `}, + log: log, + printer: h.printer, + } +} + +func (s *Spinner) Update(status string) { + s.mx.Lock() + defer s.mx.Unlock() + + // Do not update if status is the same. + if s.status == status { + return + } + if s.firstStatus == "" { + s.firstStatus = status + } + s.status = status + + // If no printer we log normally. + if s.printer == nil { + s.log.Info(status) + return + } + + // Create or update the spinner. + if s.spinner == nil { + spinner, _ := pterm.DefaultSpinner.WithWriter(s.printer.NewWriter()).WithSequence(s.sequence...).Start(status) + s.spinner = spinner + return + } + s.spinner.UpdateText(status) +} + +func (s *Spinner) Fail() { + s.mx.Lock() + defer s.mx.Lock() + + if s.printer == nil { + return + } + s.spinner.Fail(s.firstStatus) +} + +func (s *Spinner) Succeed() { + s.mx.Lock() + defer s.mx.Unlock() + + if s.printer == nil { + return + } + s.spinner.Success(s.firstStatus) +} +``` + +The work will most likely have to be split into a couple of steps. + +1. Remove any use of message fatal. +2. Refactor table printing functions. +3. Replace message logging with a structured logger. +4. Replace spinner and progress bars. + +## Consequences + +Refactoring the message package would make importing Zarf packages as a library simpler. It would also simplify any unit testing and debugging efforts by using predictable errors. Additionally it should allow us to enable parallel testing where we have disabled it currently. + +While not intended it may have some user facing change if we chose to change the format of the log output slightly. While that may not be the intention currently it may become so in the future. From 81f1c7085ea954fd0d8e1610bc516d2b342965e8 Mon Sep 17 00:00:00 2001 From: Austin Abro <37223396+AustinAbro321@users.noreply.github.com> Date: Fri, 26 Jul 2024 03:51:53 -0400 Subject: [PATCH 30/68] test: decrease reliance on dockerhub (#2766) Signed-off-by: Austin Abro --- src/test/e2e/04_create_templating_test.go | 11 +++++------ src/test/e2e/13_find_images_test.go | 18 ++++++++++-------- .../00-find-images-with-vars/values.yaml | 1 - src/test/packages/04-templating/zarf.yaml | 14 ++++++++++++++ .../deployment.yaml | 2 +- .../simple-helm/Chart.yaml | 0 .../simple-helm/templates/deployment.yaml | 4 ++-- .../13-find-images-with-vars/values.yaml | 1 + .../zarf.yaml | 8 ++++---- .../28-helm-no-wait/never-ready.pod.yaml | 4 ++-- src/test/packages/28-helm-no-wait/zarf.yaml | 2 +- 11 files changed, 40 insertions(+), 25 deletions(-) delete mode 100644 src/test/packages/00-find-images-with-vars/values.yaml create mode 100644 src/test/packages/04-templating/zarf.yaml rename src/test/packages/{00-find-images-with-vars => 13-find-images-with-vars}/deployment.yaml (86%) rename src/test/packages/{00-find-images-with-vars => 13-find-images-with-vars}/simple-helm/Chart.yaml (100%) rename src/test/packages/{00-find-images-with-vars => 13-find-images-with-vars}/simple-helm/templates/deployment.yaml (82%) create mode 100644 src/test/packages/13-find-images-with-vars/values.yaml rename src/test/packages/{00-find-images-with-vars => 13-find-images-with-vars}/zarf.yaml (77%) diff --git a/src/test/e2e/04_create_templating_test.go b/src/test/e2e/04_create_templating_test.go index d69839547b..a93f23027d 100644 --- a/src/test/e2e/04_create_templating_test.go +++ b/src/test/e2e/04_create_templating_test.go @@ -21,15 +21,14 @@ func TestCreateTemplating(t *testing.T) { decompressPath := filepath.Join(tmpdir, ".package-decompressed") sbomPath := filepath.Join(tmpdir, ".sbom-location") - pkgName := fmt.Sprintf("zarf-package-variables-%s.tar.zst", e2e.Arch) + pkgName := fmt.Sprintf("zarf-package-templating-%s.tar.zst", e2e.Arch) // Test that not specifying a package variable results in an error - _, stdErr, _ := e2e.Zarf(t, "package", "create", "examples/variables", "--confirm") - expectedOutString := "variable 'NGINX_VERSION' must be '--set' when using the '--confirm' flag" - require.Contains(t, stdErr, "", expectedOutString) + _, _, err := e2e.Zarf(t, "package", "create", "src/test/packages/04-templating", "--confirm") + require.Error(t, err) // Test a simple package variable example with `--set` (will fail to pull an image if this is not set correctly) - stdOut, stdErr, err := e2e.Zarf(t, "package", "create", "examples/variables", "--set", "NGINX_VERSION=1.23.3", "--confirm") + stdOut, stdErr, err := e2e.Zarf(t, "package", "create", "src/test/packages/04-templating", "--set", "PODINFO_VERSION=6.4.0", "--confirm") require.NoError(t, err, stdOut, stdErr) stdOut, stdErr, err = e2e.Zarf(t, "t", "archiver", "decompress", pkgName, decompressPath, "--unarchive-all") @@ -38,7 +37,7 @@ func TestCreateTemplating(t *testing.T) { // Check that the constant in the zarf.yaml is replaced correctly builtConfig, err := os.ReadFile(decompressPath + "/zarf.yaml") require.NoError(t, err) - require.Contains(t, string(builtConfig), "name: NGINX_VERSION\n value: 1.23.3") + require.Contains(t, string(builtConfig), "name: PODINFO_VERSION\n value: 6.4.0") // Test that files and file folders template and handle SBOMs correctly stdOut, stdErr, err = e2e.Zarf(t, "package", "create", "src/test/packages/04-file-folders-templating-sbom/", "--sbom-out", sbomPath, "--confirm") diff --git a/src/test/e2e/13_find_images_test.go b/src/test/e2e/13_find_images_test.go index 474aa27eb8..39f6691b16 100644 --- a/src/test/e2e/13_find_images_test.go +++ b/src/test/e2e/13_find_images_test.go @@ -48,20 +48,22 @@ func TestFindImages(t *testing.T) { t.Run("zarf dev find-images with helm or manifest vars", func(t *testing.T) { t.Parallel() - registry := "coolregistry.gov" + registry := "zarf.dev" agentTag := "test" - stdOut, _, err := e2e.Zarf(t, "prepare", "find-images", ".", "--registry-url", registry, "--create-set", fmt.Sprintf("agent_image_tag=%s", agentTag)) + stdOut, _, err := e2e.Zarf(t, "dev", "find-images", ".", "--registry-url", registry, "--create-set", fmt.Sprintf("agent_image_tag=%s", agentTag), "--skip-cosign") + require.NoError(t, err) internalRegistryImage := fmt.Sprintf("%s/%s:%s", registry, "zarf-dev/zarf/agent", agentTag) - require.Contains(t, stdOut, internalRegistryImage, "registry image should be found with registry url") - require.Contains(t, stdOut, "busybox:latest", "Busybox image should be found as long as helm chart doesn't error") + require.Contains(t, stdOut, internalRegistryImage) + // busybox image is in git init package + require.Contains(t, stdOut, "busybox:latest") - path := filepath.Join("src", "test", "packages", "00-find-images-with-vars") - stdOut, _, err = e2e.Zarf(t, "prepare", "find-images", path, "--deploy-set", "BUSYBOX_IMAGE=busybox:earliest") + path := filepath.Join("src", "test", "packages", "13-find-images-with-vars") + stdOut, _, err = e2e.Zarf(t, "dev", "find-images", path, "--deploy-set", "PODINFO_IMAGE=zarf.dev/podinfo:latest", "--skip-cosign") require.NoError(t, err) - require.Contains(t, stdOut, "nginx:latest", "Manifests aren't interpreting vars") - require.Contains(t, stdOut, "busybox:earliest", "Values files aren't interpreting vars") + require.Contains(t, stdOut, "ghcr.io/zarf-dev/zarf/agent:v0.36.1") + require.Contains(t, stdOut, "zarf.dev/podinfo:latest") }) t.Run("zarf test find images --why w/ helm chart success", func(t *testing.T) { diff --git a/src/test/packages/00-find-images-with-vars/values.yaml b/src/test/packages/00-find-images-with-vars/values.yaml deleted file mode 100644 index da10dacc6b..0000000000 --- a/src/test/packages/00-find-images-with-vars/values.yaml +++ /dev/null @@ -1 +0,0 @@ -busybox: ###ZARF_VAR_BUSYBOX_IMAGE### diff --git a/src/test/packages/04-templating/zarf.yaml b/src/test/packages/04-templating/zarf.yaml new file mode 100644 index 0000000000..bcc8e5cc35 --- /dev/null +++ b/src/test/packages/04-templating/zarf.yaml @@ -0,0 +1,14 @@ +kind: ZarfPackageConfig +metadata: + name: templating + +constants: + - name: PODINFO_VERSION + value: "###ZARF_PKG_TMPL_PODINFO_VERSION###" + pattern: "^[\\w\\-\\.]+$" + +components: + - name: variables-with-podinfo + images: + # This sets the nginx image tag to the same PKG_TMPL used for the constant above to keep the zarf.yaml and nginx-deployment.yaml in sync + - "ghcr.io/stefanprodan/podinfo:###ZARF_PKG_TMPL_PODINFO_VERSION###" diff --git a/src/test/packages/00-find-images-with-vars/deployment.yaml b/src/test/packages/13-find-images-with-vars/deployment.yaml similarity index 86% rename from src/test/packages/00-find-images-with-vars/deployment.yaml rename to src/test/packages/13-find-images-with-vars/deployment.yaml index 8d4b344dae..c0f766fd9b 100644 --- a/src/test/packages/00-find-images-with-vars/deployment.yaml +++ b/src/test/packages/13-find-images-with-vars/deployment.yaml @@ -16,4 +16,4 @@ spec: spec: containers: - name: server - image: "###ZARF_CONST_SAMPLE_IMAGE###" + image: "###ZARF_CONST_AGENT_IMAGE###" diff --git a/src/test/packages/00-find-images-with-vars/simple-helm/Chart.yaml b/src/test/packages/13-find-images-with-vars/simple-helm/Chart.yaml similarity index 100% rename from src/test/packages/00-find-images-with-vars/simple-helm/Chart.yaml rename to src/test/packages/13-find-images-with-vars/simple-helm/Chart.yaml diff --git a/src/test/packages/00-find-images-with-vars/simple-helm/templates/deployment.yaml b/src/test/packages/13-find-images-with-vars/simple-helm/templates/deployment.yaml similarity index 82% rename from src/test/packages/00-find-images-with-vars/simple-helm/templates/deployment.yaml rename to src/test/packages/13-find-images-with-vars/simple-helm/templates/deployment.yaml index 335cb8afbb..c5bb598e7d 100644 --- a/src/test/packages/00-find-images-with-vars/simple-helm/templates/deployment.yaml +++ b/src/test/packages/13-find-images-with-vars/simple-helm/templates/deployment.yaml @@ -15,5 +15,5 @@ spec: app: simple-deployment spec: containers: - - name: busybox - image: {{.Values.busybox}} + - name: podinfo + image: {{.Values.podinfo}} diff --git a/src/test/packages/13-find-images-with-vars/values.yaml b/src/test/packages/13-find-images-with-vars/values.yaml new file mode 100644 index 0000000000..525c3d3bd8 --- /dev/null +++ b/src/test/packages/13-find-images-with-vars/values.yaml @@ -0,0 +1 @@ +podinfo: ###ZARF_VAR_PODINFO_IMAGE### diff --git a/src/test/packages/00-find-images-with-vars/zarf.yaml b/src/test/packages/13-find-images-with-vars/zarf.yaml similarity index 77% rename from src/test/packages/00-find-images-with-vars/zarf.yaml rename to src/test/packages/13-find-images-with-vars/zarf.yaml index b58911d993..bc234638c6 100644 --- a/src/test/packages/00-find-images-with-vars/zarf.yaml +++ b/src/test/packages/13-find-images-with-vars/zarf.yaml @@ -4,12 +4,12 @@ metadata: description: Simple zarf package with variables variables: - - name: BUSYBOX_IMAGE - default: "busybox:latest" + - name: PODINFO_IMAGE + default: "ghcr.io/stefanprodan/podinfo:latest" constants: - - name: SAMPLE_IMAGE - value: "nginx:latest" + - name: AGENT_IMAGE + value: "ghcr.io/zarf-dev/zarf/agent:v0.36.1" components: - name: simple-var diff --git a/src/test/packages/28-helm-no-wait/never-ready.pod.yaml b/src/test/packages/28-helm-no-wait/never-ready.pod.yaml index 6fa1682d52..3ad9bd944e 100644 --- a/src/test/packages/28-helm-no-wait/never-ready.pod.yaml +++ b/src/test/packages/28-helm-no-wait/never-ready.pod.yaml @@ -4,8 +4,8 @@ metadata: name: never-ready-zarf-wait-test spec: containers: - - name: alpine - image: alpine:latest + - name: podinfo + image: ghcr.io/stefanprodan/podinfo:6.4.0 command: - "sleep" - "infinity" diff --git a/src/test/packages/28-helm-no-wait/zarf.yaml b/src/test/packages/28-helm-no-wait/zarf.yaml index 177fe6792a..7b8881f886 100644 --- a/src/test/packages/28-helm-no-wait/zarf.yaml +++ b/src/test/packages/28-helm-no-wait/zarf.yaml @@ -13,4 +13,4 @@ components: files: - never-ready.pod.yaml images: - - alpine:latest + - ghcr.io/stefanprodan/podinfo:6.4.0 From 58d55b9e6a5f1711d020490fc969cf290a69b162 Mon Sep 17 00:00:00 2001 From: Philip Laine Date: Fri, 26 Jul 2024 14:02:19 +0200 Subject: [PATCH 31/68] refactor: replace warning logs with returning errors (#2762) Signed-off-by: Philip Laine --- src/config/lang/english.go | 1 - src/internal/agent/hooks/pods.go | 10 +++------- src/internal/agent/http/proxy.go | 11 ++--------- src/internal/packager/git/checkout.go | 7 +------ src/internal/packager/git/push.go | 8 ++------ src/pkg/packager/actions/actions.go | 1 - 6 files changed, 8 insertions(+), 30 deletions(-) diff --git a/src/config/lang/english.go b/src/config/lang/english.go index 33698de7a5..780a50a3bc 100644 --- a/src/config/lang/english.go +++ b/src/config/lang/english.go @@ -611,7 +611,6 @@ const ( AgentErrGetState = "failed to load zarf state: %w" AgentErrParsePod = "failed to parse pod: %w" AgentErrHostnameMatch = "failed to complete hostname matching: %w" - AgentErrImageSwap = "Unable to swap the host for (%s)" AgentErrInvalidMethod = "invalid method only POST requests are allowed" AgentErrInvalidOp = "invalid operation: %s" AgentErrInvalidType = "only content type 'application/json' is supported" diff --git a/src/internal/agent/hooks/pods.go b/src/internal/agent/hooks/pods.go index 60362785a5..7d7a6a8023 100644 --- a/src/internal/agent/hooks/pods.go +++ b/src/internal/agent/hooks/pods.go @@ -13,7 +13,6 @@ import ( "github.com/zarf-dev/zarf/src/config/lang" "github.com/zarf-dev/zarf/src/internal/agent/operations" "github.com/zarf-dev/zarf/src/pkg/cluster" - "github.com/zarf-dev/zarf/src/pkg/message" "github.com/zarf-dev/zarf/src/pkg/transform" v1 "k8s.io/api/admission/v1" @@ -82,8 +81,7 @@ func mutatePod(ctx context.Context, r *v1.AdmissionRequest, cluster *cluster.Clu path := fmt.Sprintf("/spec/initContainers/%d/image", idx) replacement, err := transform.ImageTransformHost(registryURL, container.Image) if err != nil { - message.Warnf(lang.AgentErrImageSwap, container.Image) - continue // Continue, because we might as well attempt to mutate the other containers for this pod + return nil, err } updatedAnnotations[getImageAnnotationKey(container.Name)] = container.Image patches = append(patches, operations.ReplacePatchOperation(path, replacement)) @@ -94,8 +92,7 @@ func mutatePod(ctx context.Context, r *v1.AdmissionRequest, cluster *cluster.Clu path := fmt.Sprintf("/spec/ephemeralContainers/%d/image", idx) replacement, err := transform.ImageTransformHost(registryURL, container.Image) if err != nil { - message.Warnf(lang.AgentErrImageSwap, container.Image) - continue // Continue, because we might as well attempt to mutate the other containers for this pod + return nil, err } updatedAnnotations[getImageAnnotationKey(container.Name)] = container.Image patches = append(patches, operations.ReplacePatchOperation(path, replacement)) @@ -106,8 +103,7 @@ func mutatePod(ctx context.Context, r *v1.AdmissionRequest, cluster *cluster.Clu path := fmt.Sprintf("/spec/containers/%d/image", idx) replacement, err := transform.ImageTransformHost(registryURL, container.Image) if err != nil { - message.Warnf(lang.AgentErrImageSwap, container.Image) - continue // Continue, because we might as well attempt to mutate the other containers for this pod + return nil, err } updatedAnnotations[getImageAnnotationKey(container.Name)] = container.Image patches = append(patches, operations.ReplacePatchOperation(path, replacement)) diff --git a/src/internal/agent/http/proxy.go b/src/internal/agent/http/proxy.go index 719ef17281..33709dfff7 100644 --- a/src/internal/agent/http/proxy.go +++ b/src/internal/agent/http/proxy.go @@ -146,22 +146,15 @@ func replaceBodyLinks(resp *http.Response) error { forwardedPrefix := fmt.Sprintf("%s%s%s", getTLSScheme(resp.Request.TLS), resp.Request.Header.Get("X-Forwarded-Host"), transform.NoTransform) targetPrefix := fmt.Sprintf("%s%s", getTLSScheme(resp.TLS), resp.Request.Host) - body, err := io.ReadAll(resp.Body) + b, err := io.ReadAll(resp.Body) if err != nil { return err } - err = resp.Body.Close() if err != nil { return err } - - bodyString := string(body) - message.Warnf("%s", bodyString) - - bodyString = strings.ReplaceAll(bodyString, targetPrefix, forwardedPrefix) - - message.Warnf("%s", bodyString) + bodyString := strings.ReplaceAll(string(b), targetPrefix, forwardedPrefix) // Setup the new reader, and correct the content length resp.Body = io.NopCloser(strings.NewReader(bodyString)) diff --git a/src/internal/packager/git/checkout.go b/src/internal/packager/git/checkout.go index 2ee91d96b5..5a9a960508 100644 --- a/src/internal/packager/git/checkout.go +++ b/src/internal/packager/git/checkout.go @@ -10,7 +10,6 @@ import ( "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing" "github.com/go-git/go-git/v5/plumbing/object" - "github.com/zarf-dev/zarf/src/pkg/message" ) // CheckoutTag performs a `git checkout` of the provided tag to a detached HEAD. @@ -54,7 +53,6 @@ func (g *Git) checkoutHashAsBranch(hash plumbing.Hash, branch plumbing.Reference if err != nil { return fmt.Errorf("not a valid git repo or unable to open: %w", err) } - objRef, err := repo.Object(plumbing.AnyObject, hash) if err != nil { return fmt.Errorf("an error occurred when getting the repo's object reference: %w", err) @@ -67,10 +65,7 @@ func (g *Git) checkoutHashAsBranch(hash plumbing.Hash, branch plumbing.Reference case *object.Commit: commitHash = objRef.Hash default: - // This shouldn't ever hit, but we should at least log it if someday it - // does get hit - message.Warnf("Checkout failed. Hash type %s not supported.", objRef.Type().String()) - return err + return fmt.Errorf("hash type %s not supported", objRef.Type().String()) } options := &git.CheckoutOptions{ diff --git a/src/internal/packager/git/push.go b/src/internal/packager/git/push.go index 494ee40db6..98236d2316 100644 --- a/src/internal/packager/git/push.go +++ b/src/internal/packager/git/push.go @@ -45,8 +45,7 @@ func (g *Git) PushRepo(srcURL, targetFolder string) error { repo, err := g.prepRepoForPush() if err != nil { - message.Warnf("error when prepping the repo for push.. %v", err) - return err + return fmt.Errorf("could not prepare the repo for push: %w", err) } if err := g.push(repo, spinner); err != nil { @@ -64,14 +63,11 @@ func (g *Git) PushRepo(srcURL, targetFolder string) error { remoteURL := remote.Config().URLs[0] repoName, err := transform.GitURLtoRepoName(remoteURL) if err != nil { - message.Warnf("Unable to add the read-only user to the repo: %s\n", repoName) return err } - err = g.addReadOnlyUserToRepo(g.Server.Address, repoName) if err != nil { - message.Warnf("Unable to add the read-only user to the repo: %s\n", repoName) - return err + return fmt.Errorf("unable to add the read only user to the repo %s: %w", repoName, err) } } diff --git a/src/pkg/packager/actions/actions.go b/src/pkg/packager/actions/actions.go index 541c73b0fe..250e7bf100 100644 --- a/src/pkg/packager/actions/actions.go +++ b/src/pkg/packager/actions/actions.go @@ -110,7 +110,6 @@ retryCmd: for _, v := range action.SetVariables { variableConfig.SetVariable(v.Name, out, v.Sensitive, v.AutoIndent, v.Type) if err := variableConfig.CheckVariablePattern(v.Name, v.Pattern); err != nil { - message.WarnErr(err, err.Error()) return err } } From 754c615a96518172f18927a2f3c8226074bcde7d Mon Sep 17 00:00:00 2001 From: Philip Laine Date: Fri, 26 Jul 2024 14:32:38 +0200 Subject: [PATCH 32/68] fix: type assertion error checking and enforce linter (#2770) Signed-off-by: Philip Laine --- .golangci.yaml | 1 + src/extensions/bigbang/test/bigbang_test.go | 5 ++++- src/pkg/cluster/injector_test.go | 5 ++++- src/test/e2e/22_git_and_gitops_test.go | 3 ++- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.golangci.yaml b/.golangci.yaml index 37d811f119..9426dd911e 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -57,6 +57,7 @@ linters-settings: testifylint: enable-all: true errcheck: + check-type-assertions: true exclude-functions: - (*github.com/spf13/cobra.Command).Help - (*github.com/spf13/cobra.Command).MarkFlagRequired diff --git a/src/extensions/bigbang/test/bigbang_test.go b/src/extensions/bigbang/test/bigbang_test.go index 641ba566d1..f8bf1cd448 100644 --- a/src/extensions/bigbang/test/bigbang_test.go +++ b/src/extensions/bigbang/test/bigbang_test.go @@ -186,7 +186,10 @@ func getReleases() (latest, previous string, err error) { // Iterate over the tags returned by the API, and filter out tags that don't match the regular expression for _, tag := range data { - name := tag["name"].(string) + name, ok := tag["name"].(string) + if !ok { + return "", "", fmt.Errorf("name key is not of type string") + } if re.MatchString(name) { releases = append(releases, name) } diff --git a/src/pkg/cluster/injector_test.go b/src/pkg/cluster/injector_test.go index 07abc3bb6c..67dff422f2 100644 --- a/src/pkg/cluster/injector_test.go +++ b/src/pkg/cluster/injector_test.go @@ -34,7 +34,10 @@ func TestInjector(t *testing.T) { Watcher: pkgkubernetes.NewImmediateWatcher(status.CurrentStatus), } cs.PrependReactor("delete-collection", "configmaps", func(action k8stesting.Action) (bool, runtime.Object, error) { - delAction := action.(k8stesting.DeleteCollectionActionImpl) + delAction, ok := action.(k8stesting.DeleteCollectionActionImpl) + if !ok { + return false, nil, fmt.Errorf("action is not of type DeleteCollectionActionImpl") + } if delAction.GetListRestrictions().Labels.String() != "zarf-injector=payload" { return false, nil, nil } diff --git a/src/test/e2e/22_git_and_gitops_test.go b/src/test/e2e/22_git_and_gitops_test.go index 363d5be1df..9394354e2c 100644 --- a/src/test/e2e/22_git_and_gitops_test.go +++ b/src/test/e2e/22_git_and_gitops_test.go @@ -86,7 +86,8 @@ func testGitServerReadOnly(ctx context.Context, t *testing.T, gitURL string) { var bodyMap map[string]interface{} err = json.Unmarshal(getRepoResponseBody, &bodyMap) require.NoError(t, err) - permissionsMap := bodyMap["permissions"].(map[string]interface{}) + permissionsMap, ok := bodyMap["permissions"].(map[string]interface{}) + require.True(t, ok, "permissions key is not of right type") require.False(t, permissionsMap["admin"].(bool)) require.False(t, permissionsMap["push"].(bool)) require.True(t, permissionsMap["pull"].(bool)) From 4886043a8883fe26591dc677f9050b7c13e77e35 Mon Sep 17 00:00:00 2001 From: Jonathan Perry Date: Fri, 26 Jul 2024 08:47:33 -0400 Subject: [PATCH 33/68] chore: fix string formatting for several debug statements (#2769) Signed-off-by: Jon Perry Co-authored-by: Austin Abro <37223396+AustinAbro321@users.noreply.github.com> --- src/pkg/cluster/cluster.go | 4 ++-- src/pkg/cluster/data.go | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/pkg/cluster/cluster.go b/src/pkg/cluster/cluster.go index b4eb28051b..801fd50173 100644 --- a/src/pkg/cluster/cluster.go +++ b/src/pkg/cluster/cluster.go @@ -93,7 +93,7 @@ func waitForHealthyCluster(ctx context.Context, client kubernetes.Interface) err // Make sure there is at least one running Node nodeList, err := client.CoreV1().Nodes().List(ctx, metav1.ListOptions{}) if err != nil || len(nodeList.Items) < 1 { - message.Debug("No nodes reporting healthy yet: %v\n", err) + message.Debugf("No nodes reporting healthy yet: %v\n", err) timer.Reset(waitDuration) continue } @@ -101,7 +101,7 @@ func waitForHealthyCluster(ctx context.Context, client kubernetes.Interface) err // Get the cluster pod list pods, err := client.CoreV1().Pods(corev1.NamespaceAll).List(ctx, metav1.ListOptions{}) if err != nil { - message.Debug("Could not get the pod list: %w", err) + message.Debugf("Could not get the pod list: %v", err) timer.Reset(waitDuration) continue } diff --git a/src/pkg/cluster/data.go b/src/pkg/cluster/data.go index cd46dbb28b..8d9c2070cc 100644 --- a/src/pkg/cluster/data.go +++ b/src/pkg/cluster/data.go @@ -197,7 +197,7 @@ func waitForPodsAndContainers(ctx context.Context, clientset kubernetes.Interfac return nil, err } - message.Debug("Found %d pods for target %#v", len(podList.Items), target) + message.Debugf("Found %d pods for target %#v", len(podList.Items), target) var readyPods = []corev1.Pod{} @@ -207,7 +207,7 @@ func waitForPodsAndContainers(ctx context.Context, clientset kubernetes.Interfac }) for _, pod := range podList.Items { - message.Debug("Testing pod %q", pod.Name) + message.Debugf("Testing pod %q", pod.Name) // If an include function is provided, only keep pods that return true if include != nil && !include(pod) { @@ -216,7 +216,7 @@ func waitForPodsAndContainers(ctx context.Context, clientset kubernetes.Interfac // Handle container targeting if target.Container != "" { - message.Debug("Testing pod %q for container %q", pod.Name, target.Container) + message.Debugf("Testing pod %q for container %q", pod.Name, target.Container) // Check the status of initContainers for a running match for _, initContainer := range pod.Status.InitContainerStatuses { @@ -238,7 +238,7 @@ func waitForPodsAndContainers(ctx context.Context, clientset kubernetes.Interfac } } else { status := pod.Status.Phase - message.Debug("Testing pod %q phase, want (%q) got (%q)", pod.Name, corev1.PodRunning, status) + message.Debugf("Testing pod %q phase, want (%q) got (%q)", pod.Name, corev1.PodRunning, status) // Regular status checking without a container if status == corev1.PodRunning { readyPods = append(readyPods, pod) From cdd3824bbd451719123905ad915c8958e350082b Mon Sep 17 00:00:00 2001 From: Austin Abro <37223396+AustinAbro321@users.noreply.github.com> Date: Fri, 26 Jul 2024 09:18:14 -0400 Subject: [PATCH 34/68] chore: stop releasing to s3 (#2774) Signed-off-by: Austin Abro --- .github/workflows/release.yml | 8 -------- .goreleaser.yaml | 7 ------- 2 files changed, 15 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f8e6e36604..485c2055d6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -139,14 +139,6 @@ jobs: name: build-artifacts path: build/ - # Set up AWS credentials for GoReleaser to upload backups of artifacts to S3 - - name: Set AWS Credentials - uses: aws-actions/configure-aws-credentials@010d0da01d0b5a38af31e9c3470dbfdabdecca3a # v4.0.1 - with: - aws-access-key-id: ${{ secrets.AWS_GOV_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ secrets.AWS_GOV_SECRET_ACCESS_KEY }} - aws-region: us-gov-west-1 - - name: Make zarf executable and skip brew latest for pre-release tags run: | chmod +x build/zarf diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 8af7ee7d5b..0a24d0b938 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -107,10 +107,3 @@ brews: commit_msg_template: "build(release): {{ .ProjectName }}@{{ .Tag }}" homepage: "https://zarf.dev/" description: "DevSecOps for Air Gap" - -# Upload artifact backups to s3 -blobs: - - provider: s3 - region: us-gov-west-1 - bucket: zarf-public - directory: "release/{{.Version}}" From 05fdaefa7862b156d549e44b4bb1ed174f501e86 Mon Sep 17 00:00:00 2001 From: Philip Laine Date: Fri, 26 Jul 2024 15:42:06 +0200 Subject: [PATCH 35/68] fix: error formatting and comparison and enable errorlint (#2771) Signed-off-by: Philip Laine --- .golangci.yaml | 1 + src/cmd/common/viper.go | 14 ++++++-------- src/extensions/bigbang/bigbang.go | 4 ++-- src/internal/packager/helm/chart.go | 6 +++--- src/internal/packager/helm/post-render.go | 2 +- src/internal/packager/helm/repo.go | 15 +++++++++------ src/pkg/layout/component.go | 6 ------ src/pkg/packager/sources/oci.go | 2 +- src/pkg/packager/sources/split.go | 4 ++-- src/pkg/packager/sources/tarball.go | 2 +- src/pkg/utils/yaml.go | 7 ++++--- 11 files changed, 30 insertions(+), 33 deletions(-) diff --git a/.golangci.yaml b/.golangci.yaml index 9426dd911e..58aaa823f9 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -15,6 +15,7 @@ linters: - nolintlint - testifylint - whitespace + - errorlint linters-settings: govet: enable-all: true diff --git a/src/cmd/common/viper.go b/src/cmd/common/viper.go index bbd0f64c0c..a28e30544e 100644 --- a/src/cmd/common/viper.go +++ b/src/cmd/common/viper.go @@ -5,6 +5,7 @@ package common import ( + "errors" "os" "strings" @@ -166,16 +167,13 @@ func printViperConfigUsed() { if !vInitialized { return } - // Optional, so ignore file not found errors - if vConfigError != nil { - // Config file not found; ignore - if _, ok := vConfigError.(viper.ConfigFileNotFoundError); !ok { - message.WarnErrf(vConfigError, lang.CmdViperErrLoadingConfigFile, vConfigError.Error()) - } - } else { - message.Notef(lang.CmdViperInfoUsingConfigFile, v.ConfigFileUsed()) + var notFoundErr *viper.ConfigFileNotFoundError + if vConfigError != nil && !errors.As(vConfigError, ¬FoundErr) { + message.WarnErrf(vConfigError, lang.CmdViperErrLoadingConfigFile, vConfigError.Error()) + return } + message.Notef(lang.CmdViperInfoUsingConfigFile, v.ConfigFileUsed()) } func setDefaults() { diff --git a/src/extensions/bigbang/bigbang.go b/src/extensions/bigbang/bigbang.go index ebe068f003..7eedf66255 100644 --- a/src/extensions/bigbang/bigbang.go +++ b/src/extensions/bigbang/bigbang.go @@ -50,12 +50,12 @@ func Run(ctx context.Context, YOLO bool, tmpPaths *layout.ComponentPaths, c type validVersionResponse, err := isValidVersion(cfg.Version) if err != nil { - return c, fmt.Errorf("invalid Big Bang version: %s, parsing issue %s", cfg.Version, err) + return c, fmt.Errorf("could not parse the Big Bang version %s: %w", cfg.Version, err) } // Make sure the version is valid. if !validVersionResponse { - return c, fmt.Errorf("invalid Big Bang version: %s, must be at least %s", cfg.Version, bbMinRequiredVersion) + return c, fmt.Errorf("Big Bang version %s must be at least %s", cfg.Version, bbMinRequiredVersion) } // Print the banner for Big Bang. diff --git a/src/internal/packager/helm/chart.go b/src/internal/packager/helm/chart.go index bca8773294..26f81e1a9b 100644 --- a/src/internal/packager/helm/chart.go +++ b/src/internal/packager/helm/chart.go @@ -149,7 +149,7 @@ func (h *Helm) TemplateChart(ctx context.Context) (manifest string, chartValues if h.kubeVersion != "" { parsedKubeVersion, err := chartutil.ParseKubeVersion(h.kubeVersion) if err != nil { - return "", nil, fmt.Errorf("invalid kube version '%s': %s", h.kubeVersion, err) + return "", nil, fmt.Errorf("invalid kube version %s: %w", h.kubeVersion, err) } client.KubeVersion = parsedKubeVersion } @@ -392,13 +392,13 @@ func (h *Helm) migrateDeprecatedAPIs(latestRelease *release.Release) error { // parse to unstructured to have access to more data than just the name rawData := &unstructured.Unstructured{} if err := yaml.Unmarshal([]byte(resource.Content), rawData); err != nil { - return fmt.Errorf("failed to unmarshal manifest: %#v", err) + return fmt.Errorf("failed to unmarshal manifest: %w", err) } rawData, manifestModified, _ := handleDeprecations(rawData, *kubeGitVersion) manifestContent, err := yaml.Marshal(rawData) if err != nil { - return fmt.Errorf("failed to marshal raw manifest after deprecation check: %#v", err) + return fmt.Errorf("failed to marshal raw manifest after deprecation check: %w", err) } // If this is not a bad object, place it back into the manifest diff --git a/src/internal/packager/helm/post-render.go b/src/internal/packager/helm/post-render.go index b115b33ddf..c316375acb 100644 --- a/src/internal/packager/helm/post-render.go +++ b/src/internal/packager/helm/post-render.go @@ -222,7 +222,7 @@ func (r *renderer) editHelmResources(ctx context.Context, resources []releaseuti // parse to unstructured to have access to more data than just the name rawData := &unstructured.Unstructured{} if err := yaml.Unmarshal([]byte(resource.Content), rawData); err != nil { - return fmt.Errorf("failed to unmarshal manifest: %#v", err) + return fmt.Errorf("failed to unmarshal manifest: %w", err) } switch rawData.GetKind() { diff --git a/src/internal/packager/helm/repo.go b/src/internal/packager/helm/repo.go index 9397a7f760..dad0e59aab 100644 --- a/src/internal/packager/helm/repo.go +++ b/src/internal/packager/helm/repo.go @@ -6,6 +6,7 @@ package helm import ( "context" + "errors" "fmt" "os" "path/filepath" @@ -307,18 +308,20 @@ func (h *Helm) buildChartDependencies() error { // Build the deps from the helm chart err = man.Build() - if e, ok := err.(downloader.ErrRepoNotFound); ok { + var notFoundErr *downloader.ErrRepoNotFound + if errors.As(err, ¬FoundErr) { // If we encounter a repo not found error point the user to `zarf tools helm repo add` - message.Warnf("%s. Please add the missing repo(s) via the following:", e.Error()) - for _, repository := range e.Repos { + message.Warnf("%s. Please add the missing repo(s) via the following:", notFoundErr.Error()) + for _, repository := range notFoundErr.Repos { message.ZarfCommand(fmt.Sprintf("tools helm repo add %s", repository)) } - } else if err != nil { - // Warn the user of any issues but don't fail - any actual issues will cause a fail during packaging (e.g. the charts we are building may exist already, we just can't get updates) + return err + } + if err != nil { message.ZarfCommand("tools helm dependency build --verify") message.Warnf("Unable to perform a rebuild of Helm dependencies: %s", err.Error()) + return err } - return nil } diff --git a/src/pkg/layout/component.go b/src/pkg/layout/component.go index f52e6bbe06..ec5e82507b 100644 --- a/src/pkg/layout/component.go +++ b/src/pkg/layout/component.go @@ -38,12 +38,6 @@ type Components struct { // ErrNotLoaded is returned when a path is not loaded. var ErrNotLoaded = fmt.Errorf("not loaded") -// IsNotLoaded checks if an error is ErrNotLoaded. -func IsNotLoaded(err error) bool { - u, ok := err.(*fs.PathError) - return ok && u.Unwrap() == ErrNotLoaded -} - // Archive archives a component. func (c *Components) Archive(component types.ZarfComponent, cleanupTemp bool) (err error) { name := component.Name diff --git a/src/pkg/packager/sources/oci.go b/src/pkg/packager/sources/oci.go index 33e4ba3fad..f22547d520 100644 --- a/src/pkg/packager/sources/oci.go +++ b/src/pkg/packager/sources/oci.go @@ -86,7 +86,7 @@ func (s *OCISource) LoadPackage(ctx context.Context, dst *layout.PackagePaths, f if unarchiveAll { for _, component := range pkg.Components { if err := dst.Components.Unarchive(component); err != nil { - if layout.IsNotLoaded(err) { + if errors.Is(err, layout.ErrNotLoaded) { _, err := dst.Components.Create(component) if err != nil { return pkg, nil, err diff --git a/src/pkg/packager/sources/split.go b/src/pkg/packager/sources/split.go index 473aa0008a..8176b68882 100644 --- a/src/pkg/packager/sources/split.go +++ b/src/pkg/packager/sources/split.go @@ -36,7 +36,7 @@ func (s *SplitTarballSource) Collect(_ context.Context, dir string) (string, err pattern := strings.Replace(s.PackageSource, ".part000", ".part*", 1) fileList, err := filepath.Glob(pattern) if err != nil { - return "", fmt.Errorf("unable to find split tarball files: %s", err) + return "", fmt.Errorf("unable to find split tarball files: %w", err) } // Ensure the files are in order so they are appended in the correct order @@ -46,7 +46,7 @@ func (s *SplitTarballSource) Collect(_ context.Context, dir string) (string, err // Create the new package pkgFile, err := os.Create(reassembled) if err != nil { - return "", fmt.Errorf("unable to create new package file: %s", err) + return "", fmt.Errorf("unable to create new package file: %w", err) } defer pkgFile.Close() diff --git a/src/pkg/packager/sources/tarball.go b/src/pkg/packager/sources/tarball.go index b99253c0a5..9cbbf1b071 100644 --- a/src/pkg/packager/sources/tarball.go +++ b/src/pkg/packager/sources/tarball.go @@ -114,7 +114,7 @@ func (s *TarballSource) LoadPackage(_ context.Context, dst *layout.PackagePaths, if unarchiveAll { for _, component := range pkg.Components { if err := dst.Components.Unarchive(component); err != nil { - if layout.IsNotLoaded(err) { + if errors.Is(err, layout.ErrNotLoaded) { _, err := dst.Components.Create(component) if err != nil { return pkg, nil, err diff --git a/src/pkg/utils/yaml.go b/src/pkg/utils/yaml.go index 5f86202970..f3fdaa53b7 100644 --- a/src/pkg/utils/yaml.go +++ b/src/pkg/utils/yaml.go @@ -8,6 +8,7 @@ package utils import ( "bytes" + "errors" "fmt" "io" "io/fs" @@ -196,7 +197,7 @@ func SplitYAML(yamlData []byte) ([]*unstructured.Unstructured, error) { for _, yml := range ymls { u := &unstructured.Unstructured{} if err := k8syaml.Unmarshal([]byte(yml), u); err != nil { - return objs, fmt.Errorf("failed to unmarshal manifest: %#v", err) + return objs, fmt.Errorf("failed to unmarshal manifest: %w", err) } objs = append(objs, u) } @@ -216,10 +217,10 @@ func SplitYAMLToString(yamlData []byte) ([]string, error) { for { ext := runtime.RawExtension{} if err := d.Decode(&ext); err != nil { - if err == io.EOF { + if errors.Is(err, io.EOF) { break } - return objs, fmt.Errorf("failed to unmarshal manifest: %#v", err) + return objs, fmt.Errorf("failed to unmarshal manifest: %w", err) } ext.Raw = bytes.TrimSpace(ext.Raw) if len(ext.Raw) == 0 || bytes.Equal(ext.Raw, []byte("null")) { From 6153b6af4b4c1d6cf8f89d5fa17df1f3fadde034 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 29 Jul 2024 10:20:44 -0400 Subject: [PATCH 36/68] fix(deps): update module github.com/fluxcd/helm-controller/api to v1 (#2487) Signed-off-by: schristoff <28318173+schristoff@users.noreply.github.com> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: schristoff <28318173+schristoff@users.noreply.github.com> --- go.mod | 4 ++-- go.sum | 8 ++++---- src/extensions/bigbang/manifests.go | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index d69363783f..db29e4a620 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( github.com/distribution/reference v0.5.0 github.com/fairwindsops/pluto/v5 v5.18.4 github.com/fatih/color v1.16.0 - github.com/fluxcd/helm-controller/api v0.37.4 + github.com/fluxcd/helm-controller/api v1.0.1 github.com/fluxcd/pkg/apis/meta v1.5.0 github.com/fluxcd/source-controller/api v1.3.0 github.com/go-git/go-git/v5 v5.11.0 @@ -233,7 +233,7 @@ require ( github.com/felixge/fgprof v0.9.3 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fluxcd/pkg/apis/acl v0.3.0 // indirect - github.com/fluxcd/pkg/apis/kustomize v1.3.0 // indirect + github.com/fluxcd/pkg/apis/kustomize v1.5.0 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/fvbommel/sortorder v1.1.0 // indirect github.com/gabriel-vasile/mimetype v1.4.3 // indirect diff --git a/go.sum b/go.sum index a0be8e7f61..23759f5ede 100644 --- a/go.sum +++ b/go.sum @@ -706,12 +706,12 @@ github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g= github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/fluxcd/helm-controller/api v0.37.4 h1:rkBMqYXexyf1s5BS8QpxGi691DsCi+yugIFCM5fNKLU= -github.com/fluxcd/helm-controller/api v0.37.4/go.mod h1:KFdP5Lbrc4Vv+Jt4xRj6UUo3qiwdBqBPl1xiiAnBe9c= +github.com/fluxcd/helm-controller/api v1.0.1 h1:Gn9qEVuif6D5+gHmVwTEZkR4+nmLOcOhKx4Sw2gL2EA= +github.com/fluxcd/helm-controller/api v1.0.1/go.mod h1:/6AD5a2qjo/ttxVM8GR33syLZwqigta60DCLdy8GrME= github.com/fluxcd/pkg/apis/acl v0.3.0 h1:UOrKkBTOJK+OlZX7n8rWt2rdBmDCoTK+f5TY2LcZi8A= github.com/fluxcd/pkg/apis/acl v0.3.0/go.mod h1:WVF9XjSMVBZuU+HTTiSebGAWMgM7IYexFLyVWbK9bNY= -github.com/fluxcd/pkg/apis/kustomize v1.3.0 h1:qvB46CfaOWcL1SyR2RiVWN/j7/035D0OtB1ltLN7rgI= -github.com/fluxcd/pkg/apis/kustomize v1.3.0/go.mod h1:PCXf5kktTzNav0aH2Ns3jsowqwmA9xTcsrEOoPzx/K8= +github.com/fluxcd/pkg/apis/kustomize v1.5.0 h1:ah4sfqccnio+/5Edz/tVz6LetFhiBoDzXAElj6fFCzU= +github.com/fluxcd/pkg/apis/kustomize v1.5.0/go.mod h1:nEzhnhHafhWOUUV8VMFLojUOH+HHDEsL75y54mt/c30= github.com/fluxcd/pkg/apis/meta v1.5.0 h1:/G82d2Az5D9op3F+wJUpD8jw/eTV0suM6P7+cSURoUM= github.com/fluxcd/pkg/apis/meta v1.5.0/go.mod h1:Y3u7JomuuKtr5fvP1Iji2/50FdRe5GcBug2jawNVkdM= github.com/fluxcd/source-controller/api v1.3.0 h1:Z5Lq0aJY87yg0cQDEuwGLKS60GhdErCHtsi546HUt10= diff --git a/src/extensions/bigbang/manifests.go b/src/extensions/bigbang/manifests.go index 3eb88bee6c..686458c6cc 100644 --- a/src/extensions/bigbang/manifests.go +++ b/src/extensions/bigbang/manifests.go @@ -166,7 +166,7 @@ func manifestHelmRelease(values []fluxHelmCtrl.ValuesReference) fluxHelmCtrl.Hel }, Spec: fluxHelmCtrl.HelmReleaseSpec{ Timeout: &tenMins, - Chart: fluxHelmCtrl.HelmChartTemplate{ + Chart: &fluxHelmCtrl.HelmChartTemplate{ Spec: fluxHelmCtrl.HelmChartTemplateSpec{ Chart: "./chart", SourceRef: fluxHelmCtrl.CrossNamespaceObjectReference{ From fccaaff1eb0e3eaaf9544e7ceae43fc405e41ff6 Mon Sep 17 00:00:00 2001 From: Philip Laine Date: Mon, 29 Jul 2024 16:26:42 +0200 Subject: [PATCH 37/68] refactor: load state to return error if loading fails (#2763) Signed-off-by: Philip Laine --- src/cmd/destroy.go | 2 +- src/cmd/internal.go | 33 +++++++-------- src/cmd/tools/crane.go | 2 +- src/config/lang/english.go | 6 --- .../agent/hooks/argocd-application.go | 2 +- src/internal/agent/hooks/argocd-repository.go | 2 +- src/internal/agent/hooks/flux-gitrepo.go | 2 +- src/internal/agent/hooks/flux-helmrepo.go | 2 +- src/internal/agent/hooks/flux-ocirepo.go | 2 +- src/internal/agent/hooks/pods.go | 2 +- src/pkg/cluster/state.go | 7 ++-- src/pkg/packager/deploy.go | 41 +++++++++++-------- 12 files changed, 51 insertions(+), 52 deletions(-) diff --git a/src/cmd/destroy.go b/src/cmd/destroy.go index 1e3d1bb646..1b71740aa3 100644 --- a/src/cmd/destroy.go +++ b/src/cmd/destroy.go @@ -44,7 +44,7 @@ var destroyCmd = &cobra.Command{ // the scripts to remove k3s, we will still try to remove a locally installed k3s cluster state, err := c.LoadZarfState(ctx) if err != nil { - message.WarnErr(err, lang.ErrLoadState) + message.WarnErr(err, err.Error()) } // If Zarf deployed the cluster, burn it all down diff --git a/src/cmd/internal.go b/src/cmd/internal.go index 7ff0315356..907125688d 100644 --- a/src/cmd/internal.go +++ b/src/cmd/internal.go @@ -204,14 +204,12 @@ var createReadOnlyGiteaUser = &cobra.Command{ if err != nil { return err } - // Load the state so we can get the credentials for the admin git user state, err := c.LoadZarfState(cmd.Context()) if err != nil { - message.WarnErr(err, lang.ErrLoadState) + return err } - // Create the non-admin user if err = git.New(state.GitServer).CreateReadOnlyUser(cmd.Context()); err != nil { - message.WarnErr(err, lang.CmdInternalCreateReadOnlyGiteaUserErr) + return fmt.Errorf("unable to create a read only user in Gitea: %w", err) } return nil }, @@ -228,25 +226,22 @@ var createPackageRegistryToken = &cobra.Command{ if err != nil { return err } - ctx := cmd.Context() state, err := c.LoadZarfState(ctx) if err != nil { - message.WarnErr(err, lang.ErrLoadState) + return err } - - // If we are setup to use an internal artifact server, create the artifact registry token - if state.ArtifactServer.InternalServer { - token, err := git.New(state.GitServer).CreatePackageRegistryToken(ctx) - if err != nil { - message.WarnErr(err, lang.CmdInternalArtifactRegistryGiteaTokenErr) - } - - state.ArtifactServer.PushToken = token.Sha1 - - if err := c.SaveZarfState(ctx, state); err != nil { - return err - } + if !state.ArtifactServer.InternalServer { + return nil + } + token, err := git.New(state.GitServer).CreatePackageRegistryToken(ctx) + if err != nil { + return fmt.Errorf("unable to create an artifact registry token for Gitea: %w", err) + } + state.ArtifactServer.PushToken = token.Sha1 + err = c.SaveZarfState(ctx, state) + if err != nil { + return err } return nil }, diff --git a/src/cmd/tools/crane.go b/src/cmd/tools/crane.go index 4df8daebb3..dd76955339 100644 --- a/src/cmd/tools/crane.go +++ b/src/cmd/tools/crane.go @@ -176,7 +176,7 @@ func zarfCraneInternalWrapper(commandToWrap func(*[]crane.Option) *cobra.Command zarfState, err := c.LoadZarfState(ctx) if err != nil { - message.Warnf(lang.CmdToolsCraneConnectedButBadStateErr, err.Error()) + message.Warnf("could not get Zarf state from Kubernetes cluster, continuing without state information %s", err.Error()) return originalListFn(cmd, args) } diff --git a/src/config/lang/english.go b/src/config/lang/english.go index 780a50a3bc..5cb2db2d61 100644 --- a/src/config/lang/english.go +++ b/src/config/lang/english.go @@ -17,14 +17,12 @@ import ( // Debug messages will not be a part of the language strings since they are not intended to be user facing // Include sprintf formatting directives in the string if needed. const ( - ErrLoadState = "Failed to load the Zarf State from the cluster." ErrUnmarshal = "failed to unmarshal file: %w" ErrWritingFile = "failed to write file %s: %s" ErrDownloading = "failed to download %s: %s" ErrCreatingDir = "failed to create directory %s: %s" ErrRemoveFile = "failed to remove file %s: %s" ErrUnarchive = "failed to unarchive %s: %s" - ErrConfirmCancel = "confirm selection canceled: %s" ErrFileExtract = "failed to extract filename %s from archive %s: %s" ErrFileNameExtract = "failed to extract filename from URL %s: %s" ErrUnableToGenerateRandomSecret = "unable to generate a random secret" @@ -199,7 +197,6 @@ $ zarf init --artifact-push-password={PASSWORD} --artifact-push-username={USERNA CmdInternalArtifactRegistryGiteaTokenShort = "Creates an artifact registry token for Gitea" CmdInternalArtifactRegistryGiteaTokenLong = "Creates an artifact registry token in Gitea using the Gitea API. " + "This is called internally by the supported Gitea package component." - CmdInternalArtifactRegistryGiteaTokenErr = "Unable to create an artifact registry token for the Gitea service." CmdInternalUpdateGiteaPVCShort = "Updates an existing Gitea persistent volume claim" CmdInternalUpdateGiteaPVCLong = "Updates an existing Gitea persistent volume claim by assessing if claim is a custom user provided claim or default." + @@ -489,8 +486,6 @@ zarf tools yq e '.a.b = "cool"' -i file.yaml CmdToolsClearCacheSuccess = "Successfully cleared the cache from %s" CmdToolsClearCacheFlagCachePath = "Specify the location of the Zarf artifact cache (images and git repositories)" - CmdToolsCraneConnectedButBadStateErr = "Detected a K8s cluster but was unable to get Zarf state - continuing without state information: %s" - CmdToolsDownloadInitShort = "Downloads the init package for the current Zarf version into the specified directory" CmdToolsDownloadInitFlagOutputDirectory = "Specify a directory to place the init package in." @@ -608,7 +603,6 @@ const ( AgentErrBadRequest = "could not read request body: %s" AgentErrBindHandler = "Unable to bind the webhook handler" AgentErrCouldNotDeserializeReq = "could not deserialize request: %s" - AgentErrGetState = "failed to load zarf state: %w" AgentErrParsePod = "failed to parse pod: %w" AgentErrHostnameMatch = "failed to complete hostname matching: %w" AgentErrInvalidMethod = "invalid method only POST requests are allowed" diff --git a/src/internal/agent/hooks/argocd-application.go b/src/internal/agent/hooks/argocd-application.go index f9d3238aee..b234f29e84 100644 --- a/src/internal/agent/hooks/argocd-application.go +++ b/src/internal/agent/hooks/argocd-application.go @@ -62,7 +62,7 @@ func NewApplicationMutationHook(ctx context.Context, cluster *cluster.Cluster) o func mutateApplication(ctx context.Context, r *v1.AdmissionRequest, cluster *cluster.Cluster) (result *operations.Result, err error) { state, err := cluster.LoadZarfState(ctx) if err != nil { - return nil, fmt.Errorf(lang.AgentErrGetState, err) + return nil, err } message.Debugf("Using the url of (%s) to mutate the ArgoCD Application", state.GitServer.Address) diff --git a/src/internal/agent/hooks/argocd-repository.go b/src/internal/agent/hooks/argocd-repository.go index 2311b50511..1875772d05 100644 --- a/src/internal/agent/hooks/argocd-repository.go +++ b/src/internal/agent/hooks/argocd-repository.go @@ -54,7 +54,7 @@ func mutateRepositorySecret(ctx context.Context, r *v1.AdmissionRequest, cluster state, err := cluster.LoadZarfState(ctx) if err != nil { - return nil, fmt.Errorf(lang.AgentErrGetState, err) + return nil, err } message.Infof("Using the url of (%s) to mutate the ArgoCD Repository Secret", state.GitServer.Address) diff --git a/src/internal/agent/hooks/flux-gitrepo.go b/src/internal/agent/hooks/flux-gitrepo.go index 38a5aedadb..2fda2969bb 100644 --- a/src/internal/agent/hooks/flux-gitrepo.go +++ b/src/internal/agent/hooks/flux-gitrepo.go @@ -48,7 +48,7 @@ func mutateGitRepo(ctx context.Context, r *v1.AdmissionRequest, cluster *cluster state, err := cluster.LoadZarfState(ctx) if err != nil { - return nil, fmt.Errorf(lang.AgentErrGetState, err) + return nil, err } message.Debugf("Using the url of (%s) to mutate the flux repository", state.GitServer.Address) diff --git a/src/internal/agent/hooks/flux-helmrepo.go b/src/internal/agent/hooks/flux-helmrepo.go index c053bb669b..64ad78e40a 100644 --- a/src/internal/agent/hooks/flux-helmrepo.go +++ b/src/internal/agent/hooks/flux-helmrepo.go @@ -56,7 +56,7 @@ func mutateHelmRepo(ctx context.Context, r *v1.AdmissionRequest, cluster *cluste zarfState, err := cluster.LoadZarfState(ctx) if err != nil { - return nil, fmt.Errorf(lang.AgentErrGetState, err) + return nil, err } // Get the registry service info if this is a NodePort service to use the internal kube-dns diff --git a/src/internal/agent/hooks/flux-ocirepo.go b/src/internal/agent/hooks/flux-ocirepo.go index 021a0a619d..e00362c906 100644 --- a/src/internal/agent/hooks/flux-ocirepo.go +++ b/src/internal/agent/hooks/flux-ocirepo.go @@ -59,7 +59,7 @@ func mutateOCIRepo(ctx context.Context, r *v1.AdmissionRequest, cluster *cluster zarfState, err := cluster.LoadZarfState(ctx) if err != nil { - return nil, fmt.Errorf(lang.AgentErrGetState, err) + return nil, err } // Get the registry service info if this is a NodePort service to use the internal kube-dns diff --git a/src/internal/agent/hooks/pods.go b/src/internal/agent/hooks/pods.go index 7d7a6a8023..86fae81e0f 100644 --- a/src/internal/agent/hooks/pods.go +++ b/src/internal/agent/hooks/pods.go @@ -61,7 +61,7 @@ func mutatePod(ctx context.Context, r *v1.AdmissionRequest, cluster *cluster.Clu state, err := cluster.LoadZarfState(ctx) if err != nil { - return nil, fmt.Errorf(lang.AgentErrGetState, err) + return nil, err } registryURL := state.RegistryInfo.Address diff --git a/src/pkg/cluster/state.go b/src/pkg/cluster/state.go index bdc14e5989..82ee49424b 100644 --- a/src/pkg/cluster/state.go +++ b/src/pkg/cluster/state.go @@ -7,11 +7,11 @@ package cluster import ( "context" "encoding/json" + "errors" "fmt" "slices" "time" - "github.com/fatih/color" corev1 "k8s.io/api/core/v1" kerrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -210,13 +210,14 @@ func (c *Cluster) InitZarfState(ctx context.Context, initOptions types.ZarfInitO // LoadZarfState returns the current zarf/zarf-state secret data or an empty ZarfState. func (c *Cluster) LoadZarfState(ctx context.Context) (state *types.ZarfState, err error) { + stateErr := errors.New("failed to load the Zarf State from the cluster, has Zarf been initiated?") secret, err := c.Clientset.CoreV1().Secrets(ZarfNamespaceName).Get(ctx, ZarfStateSecretName, metav1.GetOptions{}) if err != nil { - return nil, fmt.Errorf("%w. %s", err, message.ColorWrap("Did you remember to zarf init?", color.Bold)) + return nil, fmt.Errorf("%w: %w", stateErr, err) } err = json.Unmarshal(secret.Data[ZarfStateDataKey], &state) if err != nil { - return nil, err + return nil, fmt.Errorf("%w: %w", stateErr, err) } c.debugPrintZarfState(state) return state, nil diff --git a/src/pkg/packager/deploy.go b/src/pkg/packager/deploy.go index 735a0b69db..2f7304580b 100644 --- a/src/pkg/packager/deploy.go +++ b/src/pkg/packager/deploy.go @@ -25,7 +25,6 @@ import ( "github.com/defenseunicorns/pkg/helpers/v2" "github.com/zarf-dev/zarf/src/config" - "github.com/zarf-dev/zarf/src/config/lang" "github.com/zarf-dev/zarf/src/internal/packager/git" "github.com/zarf-dev/zarf/src/internal/packager/helm" "github.com/zarf-dev/zarf/src/internal/packager/images" @@ -128,7 +127,10 @@ func (p *Packager) Deploy(ctx context.Context) error { // Notify all the things about the successful deployment message.Successf("Zarf deployment complete") - p.printTablesForDeployment(ctx, deployedComponents) + err = p.printTablesForDeployment(ctx, deployedComponents) + if err != nil { + return err + } return nil } @@ -453,10 +455,15 @@ func (p *Packager) setupState(ctx context.Context) (err error) { defer spinner.Stop() state, err := p.cluster.LoadZarfState(ctx) - // Return on error if we are not in YOLO mode + // We ignore the error if in YOLO mode because Zarf should not be initiated. if err != nil && !p.cfg.Pkg.Metadata.YOLO { - return fmt.Errorf("%s %w", lang.ErrLoadState, err) - } else if state == nil && p.cfg.Pkg.Metadata.YOLO { + return err + } + // Only ignore state load error in yolo mode when secret could not be found. + if err != nil && !kerrors.IsNotFound(err) && p.cfg.Pkg.Metadata.YOLO { + return err + } + if state == nil && p.cfg.Pkg.Metadata.YOLO { state = &types.ZarfState{} // YOLO mode, so minimal state needed state.Distro = "YOLO" @@ -714,21 +721,23 @@ func (p *Packager) installChartAndManifests(ctx context.Context, componentPaths return installedCharts, nil } -func (p *Packager) printTablesForDeployment(ctx context.Context, componentsToDeploy []types.DeployedComponent) { +func (p *Packager) printTablesForDeployment(ctx context.Context, componentsToDeploy []types.DeployedComponent) error { // If not init config, print the application connection table if !p.cfg.Pkg.IsInitConfig() { message.PrintConnectStringTable(p.connectStrings) - } else { - if p.cluster != nil { - // Grab a fresh copy of the state (if we are able) to print the most up-to-date version of the creds - freshState, err := p.cluster.LoadZarfState(ctx) - if err != nil { - freshState = p.state - } - // otherwise, print the init config connection and passwords - message.PrintCredentialTable(freshState, componentsToDeploy) - } + return nil + } + // Don't print if cluster is not configured + if p.cluster == nil { + return nil } + // Grab a fresh copy of the state to print the most up-to-date version of the creds + latestState, err := p.cluster.LoadZarfState(ctx) + if err != nil { + return err + } + message.PrintCredentialTable(latestState, componentsToDeploy) + return nil } // ServiceInfoFromServiceURL takes a serviceURL and parses it to find the service info for connecting to the cluster. The string is expected to follow the following format: From 0e02d9b4bf8cd8ac26070fff98b29e4d2ce0acd3 Mon Sep 17 00:00:00 2001 From: Austin Abro <37223396+AustinAbro321@users.noreply.github.com> Date: Mon, 29 Jul 2024 12:05:20 -0400 Subject: [PATCH 38/68] fix: zarf dev instead of zerf-dev (#2779) 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 485c2055d6..00dda8debb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -63,7 +63,7 @@ jobs: - name: Publish Init Package as OCI and Skeleton run: | - make publish-init-package ARCH=amd64 REPOSITORY_URL=ghcr.io/zerf-dev/packages + make publish-init-package ARCH=amd64 REPOSITORY_URL=ghcr.io/zarf-dev/packages make publish-init-package ARCH=arm64 REPOSITORY_URL=ghcr.io/zarf-dev/packages # Create a CVE report based on this build From 1b95916005d4547cbd6b76bc2d3437a88eae3a73 Mon Sep 17 00:00:00 2001 From: Austin Abro <37223396+AustinAbro321@users.noreply.github.com> Date: Mon, 29 Jul 2024 14:41:02 -0400 Subject: [PATCH 39/68] fix: goreleaser (#2782) Signed-off-by: Austin Abro --- .goreleaser.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 0a24d0b938..013fa21c9a 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -64,7 +64,7 @@ changelog: # NOTE: We are explicitly adding the init-packages that are built prior to GoReleaser stage in the GitHub Actions workflow release: github: - owner: defenseunicorns + owner: zarf-dev name: zarf prerelease: auto mode: append From 568a16092cd448e266c075cb2992c77541ffdbcc Mon Sep 17 00:00:00 2001 From: Austin Abro <37223396+AustinAbro321@users.noreply.github.com> Date: Wed, 31 Jul 2024 09:07:38 -0400 Subject: [PATCH 40/68] refactor: utilize invopop comment feature (#2781) Signed-off-by: Austin Abro --- src/cmd/internal.go | 26 ++- src/extensions/bigbang/bigbang.go | 10 +- src/pkg/packager/actions/actions.go | 2 +- src/pkg/packager/composer/list.go | 4 +- src/pkg/packager/publish.go | 4 +- src/pkg/variables/types.go | 45 ++-- src/types/component.go | 327 +++++++++++++++++----------- src/types/extensions/bigbang.go | 17 +- src/types/extensions/common.go | 6 +- src/types/k8s.go | 95 +++++--- src/types/package.go | 95 +++++--- src/types/runtime.go | 200 +++++++++-------- zarf.schema.json | 282 +++++++++++++----------- 13 files changed, 666 insertions(+), 447 deletions(-) diff --git a/src/cmd/internal.go b/src/cmd/internal.go index 907125688d..3d77c01190 100644 --- a/src/cmd/internal.go +++ b/src/cmd/internal.go @@ -7,6 +7,7 @@ package cmd import ( "context" "encoding/json" + "errors" "fmt" "os" "path/filepath" @@ -156,12 +157,30 @@ tableOfContents: false }, } +func addGoComments(reflector *jsonschema.Reflector) error { + addCommentErr := errors.New("this command must be called from the root of the Zarf repo") + + typePackagePath := filepath.Join("src", "types") + if err := reflector.AddGoComments("github.com/zarf-dev/zarf", typePackagePath); err != nil { + return fmt.Errorf("%w: %w", addCommentErr, err) + } + varPackagePath := filepath.Join("src", "pkg", "variables") + if err := reflector.AddGoComments("github.com/zarf-dev/zarf", varPackagePath); err != nil { + return fmt.Errorf("%w: %w", addCommentErr, err) + } + return nil +} + var genConfigSchemaCmd = &cobra.Command{ Use: "gen-config-schema", Aliases: []string{"gc"}, Short: lang.CmdInternalConfigSchemaShort, RunE: func(_ *cobra.Command, _ []string) error { reflector := jsonschema.Reflector(jsonschema.Reflector{ExpandedStruct: true}) + if err := addGoComments(&reflector); err != nil { + return err + } + schema := reflector.Reflect(&types.ZarfPackage{}) output, err := json.MarshalIndent(schema, "", " ") if err != nil { @@ -183,7 +202,12 @@ var genTypesSchemaCmd = &cobra.Command{ Aliases: []string{"gt"}, Short: lang.CmdInternalTypesSchemaShort, RunE: func(_ *cobra.Command, _ []string) error { - schema := jsonschema.Reflect(&zarfTypes{}) + reflector := jsonschema.Reflector(jsonschema.Reflector{ExpandedStruct: true}) + if err := addGoComments(&reflector); err != nil { + return err + } + + schema := reflector.Reflect(&zarfTypes{}) output, err := json.MarshalIndent(schema, "", " ") if err != nil { return fmt.Errorf("unable to generate the JSON schema for the Zarf types DeployedPackage, ZarfPackage, and ZarfState: %w", err) diff --git a/src/extensions/bigbang/bigbang.go b/src/extensions/bigbang/bigbang.go index 7eedf66255..951ae88ccf 100644 --- a/src/extensions/bigbang/bigbang.go +++ b/src/extensions/bigbang/bigbang.go @@ -154,10 +154,10 @@ func Run(ctx context.Context, YOLO bool, tmpPaths *layout.ComponentPaths, c type MaxTotalSeconds: &maxTotalSeconds, Wait: &types.ZarfComponentActionWait{ Cluster: &types.ZarfComponentActionWaitCluster{ - Kind: "HelmRelease", - Identifier: hr.Metadata.Name, - Namespace: hr.Metadata.Namespace, - Condition: "ready", + Kind: "HelmRelease", + Name: hr.Metadata.Name, + Namespace: hr.Metadata.Namespace, + Condition: "ready", }, }, } @@ -171,7 +171,7 @@ func Run(ctx context.Context, YOLO bool, tmpPaths *layout.ComponentPaths, c type action.Wait.Cluster = &types.ZarfComponentActionWaitCluster{ Kind: "APIService", // https://github.com/kubernetes-sigs/metrics-server#compatibility-matrix - Identifier: "v1beta1.metrics.k8s.io", + Name: "v1beta1.metrics.k8s.io", } } diff --git a/src/pkg/packager/actions/actions.go b/src/pkg/packager/actions/actions.go index 250e7bf100..ee66b84c39 100644 --- a/src/pkg/packager/actions/actions.go +++ b/src/pkg/packager/actions/actions.go @@ -183,7 +183,7 @@ func convertWaitToCmd(wait types.ZarfComponentActionWait, timeout *int) (string, // Build a call to the zarf tools wait-for command. return fmt.Sprintf("./zarf tools wait-for %s %s %s %s %s", - cluster.Kind, cluster.Identifier, cluster.Condition, ns, timeoutString), nil + cluster.Kind, cluster.Name, cluster.Condition, ns, timeoutString), nil } network := wait.Network diff --git a/src/pkg/packager/composer/list.go b/src/pkg/packager/composer/list.go index 06f67ec816..0edb04d448 100644 --- a/src/pkg/packager/composer/list.go +++ b/src/pkg/packager/composer/list.go @@ -71,8 +71,8 @@ func (n *Node) Prev() *Node { // otherwise the name of the component will be used func (n *Node) ImportName() string { name := n.ZarfComponent.Name - if n.Import.ComponentName != "" { - name = n.Import.ComponentName + if n.Import.Name != "" { + name = n.Import.Name } return name } diff --git a/src/pkg/packager/publish.go b/src/pkg/packager/publish.go index bf664f2739..4cefc1d872 100644 --- a/src/pkg/packager/publish.go +++ b/src/pkg/packager/publish.go @@ -112,8 +112,8 @@ func (p *Packager) Publish(ctx context.Context) (err error) { ex = append(ex, types.ZarfComponent{ Name: fmt.Sprintf("import-%s", c.Name), Import: types.ZarfComponentImport{ - ComponentName: c.Name, - URL: helpers.OCIURLPrefix + remote.Repo().Reference.String(), + Name: c.Name, + URL: helpers.OCIURLPrefix + remote.Repo().Reference.String(), }, }) } diff --git a/src/pkg/variables/types.go b/src/pkg/variables/types.go index b106e911fa..6b3be2863b 100644 --- a/src/pkg/variables/types.go +++ b/src/pkg/variables/types.go @@ -29,35 +29,48 @@ var ( // Variable represents a variable that has a value set programmatically type Variable struct { - Name string `json:"name" jsonschema:"description=The name to be used for the variable,pattern=^[A-Z0-9_]+$"` - Sensitive bool `json:"sensitive,omitempty" jsonschema:"description=Whether to mark this variable as sensitive to not print it in the log"` - AutoIndent bool `json:"autoIndent,omitempty" jsonschema:"description=Whether to automatically indent the variable's value (if multiline) when templating. Based on the number of chars before the start of ###ZARF_VAR_."` - Pattern string `json:"pattern,omitempty" jsonschema:"description=An optional regex pattern that a variable value must match before a package deployment can continue."` - Type VariableType `json:"type,omitempty" jsonschema:"description=Changes the handling of a variable to load contents differently (i.e. from a file rather than as a raw variable - templated files should be kept below 1 MiB),enum=raw,enum=file"` + // The name to be used for the variable + Name string `json:"name" jsonschema:"pattern=^[A-Z0-9_]+$"` + // Whether to mark this variable as sensitive to not print it in the log + Sensitive bool `json:"sensitive,omitempty"` + // Whether to automatically indent the variable's value (if multiline) when templating. Based on the number of chars before the start of ###ZARF_VAR_. + AutoIndent bool `json:"autoIndent,omitempty"` + // An optional regex pattern that a variable value must match before a package deployment can continue. + Pattern string `json:"pattern,omitempty"` + // Changes the handling of a variable to load contents differently (i.e. from a file rather than as a raw variable - templated files should be kept below 1 MiB) + Type VariableType `json:"type,omitempty" jsonschema:"enum=raw,enum=file"` } // InteractiveVariable is a variable that can be used to prompt a user for more information type InteractiveVariable struct { - Variable `json:",inline"` - Description string `json:"description,omitempty" jsonschema:"description=A description of the variable to be used when prompting the user a value"` - Default string `json:"default,omitempty" jsonschema:"description=The default value to use for the variable"` - Prompt bool `json:"prompt,omitempty" jsonschema:"description=Whether to prompt the user for input for this variable"` + Variable `json:",inline"` + // A description of the variable to be used when prompting the user a value + Description string `json:"description,omitempty"` + // The default value to use for the variable + Default string `json:"default,omitempty"` + // Whether to prompt the user for input for this variable + Prompt bool `json:"prompt,omitempty"` } // Constant are constants that can be used to dynamically template K8s resources or run in actions. type Constant struct { - Name string `json:"name" jsonschema:"description=The name to be used for the constant,pattern=^[A-Z0-9_]+$"` - Value string `json:"value" jsonschema:"description=The value to set for the constant during deploy"` - // Include a description that will only be displayed during package create/deploy confirm prompts - Description string `json:"description,omitempty" jsonschema:"description=A description of the constant to explain its purpose on package create or deploy confirmation prompts"` - AutoIndent bool `json:"autoIndent,omitempty" jsonschema:"description=Whether to automatically indent the variable's value (if multiline) when templating. Based on the number of chars before the start of ###ZARF_CONST_."` - Pattern string `json:"pattern,omitempty" jsonschema:"description=An optional regex pattern that a constant value must match before a package can be created."` + // The name to be used for the constant + Name string `json:"name" jsonschema:"pattern=^[A-Z0-9_]+$"` + // The value to set for the constant during deploy + Value string `json:"value"` + // A description of the constant to explain its purpose on package create or deploy confirmation prompts + Description string `json:"description,omitempty"` + // Whether to automatically indent the variable's value (if multiline) when templating. Based on the number of chars before the start of ###ZARF_CONST_. + AutoIndent bool `json:"autoIndent,omitempty"` + // An optional regex pattern that a constant value must match before a package can be created. + Pattern string `json:"pattern,omitempty"` } // SetVariable tracks internal variables that have been set during this run of Zarf type SetVariable struct { Variable `json:",inline"` - Value string `json:"value" jsonschema:"description=The value the variable is currently set with"` + // The value the variable is currently set with + Value string `json:"value"` } // Validate runs all validation checks on a package constant. diff --git a/src/types/component.go b/src/types/component.go index 4ccf392970..b43493ad0a 100644 --- a/src/types/component.go +++ b/src/types/component.go @@ -13,61 +13,59 @@ import ( // ZarfComponent is the primary functional grouping of assets to deploy by Zarf. type ZarfComponent struct { - // Name is the unique identifier for this component - Name string `json:"name" jsonschema:"description=The name of the component,pattern=^[a-z0-9][a-z0-9\\-]*$"` + // The name of the component. + Name string `json:"name" jsonschema:"pattern=^[a-z0-9][a-z0-9\\-]*$"` - // Description is a message given to a user when deciding to enable this component or not - Description string `json:"description,omitempty" jsonschema:"description=Message to include during package deploy describing the purpose of this component"` + // Message to include during package deploy describing the purpose of this component. + Description string `json:"description,omitempty"` - // Default changes the default option when deploying this component - Default bool `json:"default,omitempty" jsonschema:"description=Determines the default Y/N state for installing this component on package deploy"` + // Determines the default Y/N state for installing this component on package deploy. + Default bool `json:"default,omitempty"` - // Required makes this component mandatory for package deployment - Required *bool `json:"required,omitempty" jsonschema:"description=Do not prompt user to install this component, always install on package deploy."` + // Do not prompt user to install this component. + Required *bool `json:"required,omitempty"` - // Only include compatible components during package deployment - Only ZarfComponentOnlyTarget `json:"only,omitempty" jsonschema:"description=Filter when this component is included in package creation or deployment"` + // Filter when this component is included in package creation or deployment. + Only ZarfComponentOnlyTarget `json:"only,omitempty"` - // DeprecatedGroup is a key to match other components to produce a user selector field, used to create a BOOLEAN XOR for a set of components - // - // Note: ignores default and required flags - DeprecatedGroup string `json:"group,omitempty" jsonschema:"description=[Deprecated] Create a user selector field based on all components in the same group. This will be removed in Zarf v1.0.0. Consider using 'only.flavor' instead.,deprecated=true"` + // [Deprecated] Create a user selector field based on all components in the same group. This will be removed in Zarf v1.0.0. Consider using 'only.flavor' instead. + DeprecatedGroup string `json:"group,omitempty" jsonschema:"deprecated=true"` - // DeprecatedCosignKeyPath to cosign public key for signed online resources - DeprecatedCosignKeyPath string `json:"cosignKeyPath,omitempty" jsonschema:"description=[Deprecated] Specify a path to a public key to validate signed online resources. This will be removed in Zarf v1.0.0.,deprecated=true"` + // [Deprecated] Specify a path to a public key to validate signed online resources. This will be removed in Zarf v1.0.0. + DeprecatedCosignKeyPath string `json:"cosignKeyPath,omitempty" jsonschema:"deprecated=true"` - // Import refers to another zarf.yaml package component. - Import ZarfComponentImport `json:"import,omitempty" jsonschema:"description=Import a component from another Zarf package"` + // Import a component from another Zarf package. + Import ZarfComponentImport `json:"import,omitempty"` - // Manifests are raw manifests that get converted into zarf-generated helm charts during deploy - Manifests []ZarfManifest `json:"manifests,omitempty" jsonschema:"description=Kubernetes manifests to be included in a generated Helm chart on package deploy"` + // Kubernetes manifests to be included in a generated Helm chart on package deploy. + Manifests []ZarfManifest `json:"manifests,omitempty"` - // Charts are helm charts to install during package deploy - Charts []ZarfChart `json:"charts,omitempty" jsonschema:"description=Helm charts to install during package deploy"` + // Helm charts to install during package deploy. + Charts []ZarfChart `json:"charts,omitempty"` - // Data packages to push into a running cluster - DataInjections []ZarfDataInjection `json:"dataInjections,omitempty" jsonschema:"description=Datasets to inject into a container in the target cluster"` + // Datasets to inject into a container in the target cluster. + DataInjections []ZarfDataInjection `json:"dataInjections,omitempty"` - // Files are files to place on disk during deploy - Files []ZarfFile `json:"files,omitempty" jsonschema:"description=Files or folders to place on disk during package deployment"` + // Files or folders to place on disk during package deployment. + Files []ZarfFile `json:"files,omitempty"` - // Images are the online images needed to be included in the zarf package - Images []string `json:"images,omitempty" jsonschema:"description=List of OCI images to include in the package"` + // List of OCI images to include in the package. + Images []string `json:"images,omitempty"` - // Repos are any git repos that need to be pushed into the git server - Repos []string `json:"repos,omitempty" jsonschema:"description=List of git repos to include in the package"` + // List of git repos to include in the package. + Repos []string `json:"repos,omitempty"` - // Extensions provide additional functionality to a component - Extensions extensions.ZarfComponentExtensions `json:"extensions,omitempty" jsonschema:"description=Extend component functionality with additional features"` + // Extend component functionality with additional features. + Extensions extensions.ZarfComponentExtensions `json:"extensions,omitempty"` - // DeprecatedScripts are custom commands that run before or after package deployment - DeprecatedScripts DeprecatedZarfComponentScripts `json:"scripts,omitempty" jsonschema:"description=[Deprecated] (replaced by actions) Custom commands to run before or after package deployment. This will be removed in Zarf v1.0.0.,deprecated=true"` + // [Deprecated] (replaced by actions) Custom commands to run before or after package deployment. This will be removed in Zarf v1.0.0. + DeprecatedScripts DeprecatedZarfComponentScripts `json:"scripts,omitempty" jsonschema:"deprecated=true"` - // Replaces scripts, fine-grained control over commands to run at various stages of a package lifecycle - Actions ZarfComponentActions `json:"actions,omitempty" jsonschema:"description=Custom commands to run at various stages of a package lifecycle"` + // Custom commands to run at various stages of a package lifecycle. + Actions ZarfComponentActions `json:"actions,omitempty"` } -// RequiresCluster returns if the component requires a cluster connection to deploy +// RequiresCluster returns if the component requires a cluster connection to deploy. func (c ZarfComponent) RequiresCluster() bool { hasImages := len(c.Images) > 0 hasCharts := len(c.Charts) > 0 @@ -93,153 +91,232 @@ func (c ZarfComponent) IsRequired() bool { // ZarfComponentOnlyTarget filters a component to only show it for a given local OS and cluster. type ZarfComponentOnlyTarget struct { - LocalOS string `json:"localOS,omitempty" jsonschema:"description=Only deploy component to specified OS,enum=linux,enum=darwin,enum=windows"` - Cluster ZarfComponentOnlyCluster `json:"cluster,omitempty" jsonschema:"description=Only deploy component to specified clusters"` - Flavor string `json:"flavor,omitempty" jsonschema:"description=Only include this component when a matching '--flavor' is specified on 'zarf package create'"` + // Only deploy component to specified OS. + LocalOS string `json:"localOS,omitempty" jsonschema:"enum=linux,enum=darwin,enum=windows"` + // Only deploy component to specified clusters. + Cluster ZarfComponentOnlyCluster `json:"cluster,omitempty"` + // Only include this component when a matching '--flavor' is specified on 'zarf package create'. + Flavor string `json:"flavor,omitempty"` } // ZarfComponentOnlyCluster represents the architecture and K8s cluster distribution to filter on. type ZarfComponentOnlyCluster struct { - Architecture string `json:"architecture,omitempty" jsonschema:"description=Only create and deploy to clusters of the given architecture,enum=amd64,enum=arm64"` - Distros []string `json:"distros,omitempty" jsonschema:"description=A list of kubernetes distros this package works with (Reserved for future use),example=k3s,example=eks"` + // Only create and deploy to clusters of the given architecture. + Architecture string `json:"architecture,omitempty" jsonschema:"enum=amd64,enum=arm64"` + // A list of kubernetes distros this package works with (Reserved for future use). + Distros []string `json:"distros,omitempty" jsonschema:"example=k3s,example=eks"` } // ZarfFile defines a file to deploy. type ZarfFile struct { - Source string `json:"source" jsonschema:"description=Local folder or file path or remote URL to pull into the package"` - Shasum string `json:"shasum,omitempty" jsonschema:"description=(files only) Optional SHA256 checksum of the file"` - Target string `json:"target" jsonschema:"description=The absolute or relative path where the file or folder should be copied to during package deploy"` - Executable bool `json:"executable,omitempty" jsonschema:"description=(files only) Determines if the file should be made executable during package deploy"` - Symlinks []string `json:"symlinks,omitempty" jsonschema:"description=List of symlinks to create during package deploy"` - ExtractPath string `json:"extractPath,omitempty" jsonschema:"description=Local folder or file to be extracted from a 'source' archive"` + // Local folder or file path or remote URL to pull into the package. + Source string `json:"source"` + // (files only) Optional SHA256 checksum of the file. + Shasum string `json:"shasum,omitempty"` + // The absolute or relative path where the file or folder should be copied to during package deploy. + Target string `json:"target"` + // (files only) Determines if the file should be made executable during package deploy. + Executable bool `json:"executable,omitempty"` + // List of symlinks to create during package deploy. + Symlinks []string `json:"symlinks,omitempty"` + // Local folder or file to be extracted from a 'source' archive. + ExtractPath string `json:"extractPath,omitempty"` } // ZarfChart defines a helm chart to be deployed. type ZarfChart struct { - Name string `json:"name" jsonschema:"description=The name of the chart within Zarf; note that this must be unique and does not need to be the same as the name in the chart repo"` - Version string `json:"version,omitempty" jsonschema:"description=The version of the chart to deploy; for git-based charts this is also the tag of the git repo by default (when not using the '@' syntax for 'repos')"` - URL string `json:"url,omitempty" jsonschema:"example=OCI registry: oci://ghcr.io/stefanprodan/charts/podinfo,example=helm chart repo: https://stefanprodan.github.io/podinfo,example=git repo: https://github.com/stefanprodan/podinfo (note the '@' syntax for 'repos' is supported here too)" jsonschema_description:"The URL of the OCI registry, chart repository, or git repo where the helm chart is stored"` - RepoName string `json:"repoName,omitempty" jsonschema:"description=The name of a chart within a Helm repository (defaults to the Zarf name of the chart)"` - GitPath string `json:"gitPath,omitempty" jsonschema:"description=(git repo only) The sub directory to the chart within a git repo,example=charts/your-chart"` - LocalPath string `json:"localPath,omitempty" jsonschema:"description=The path to a local chart's folder or .tgz archive"` - Namespace string `json:"namespace,omitempty" jsonschema:"description=The namespace to deploy the chart to"` - ReleaseName string `json:"releaseName,omitempty" jsonschema:"description=The name of the Helm release to create (defaults to the Zarf name of the chart)"` - NoWait bool `json:"noWait,omitempty" jsonschema:"description=Whether to not wait for chart resources to be ready before continuing"` - ValuesFiles []string `json:"valuesFiles,omitempty" jsonschema:"description=List of local values file paths or remote URLs to include in the package; these will be merged together when deployed"` - Variables []ZarfChartVariable `json:"variables,omitempty" jsonschema:"description=[alpha] List of variables to set in the Helm chart"` + // The name of the chart within Zarf; note that this must be unique and does not need to be the same as the name in the chart repo. + Name string `json:"name"` + // The version of the chart to deploy; for git-based charts this is also the tag of the git repo by default (when not using the '@' syntax for 'repos'). + Version string `json:"version,omitempty"` + // The URL of the OCI registry, chart repository, or git repo where the helm chart is stored. + URL string `json:"url,omitempty" jsonschema:"example=OCI registry: oci://ghcr.io/stefanprodan/charts/podinfo,example=helm chart repo: https://stefanprodan.github.io/podinfo,example=git repo: https://github.com/stefanprodan/podinfo (note the '@' syntax for 'repos' is supported here too)"` + // The name of a chart within a Helm repository (defaults to the Zarf name of the chart). + RepoName string `json:"repoName,omitempty"` + // (git repo only) The sub directory to the chart within a git repo. + GitPath string `json:"gitPath,omitempty" jsonschema:"example=charts/your-chart"` + // The path to a local chart's folder or .tgz archive. + LocalPath string `json:"localPath,omitempty"` + // The namespace to deploy the chart to. + Namespace string `json:"namespace,omitempty"` + // The name of the Helm release to create (defaults to the Zarf name of the chart). + ReleaseName string `json:"releaseName,omitempty"` + // Whether to not wait for chart resources to be ready before continuing. + NoWait bool `json:"noWait,omitempty"` + // List of local values file paths or remote URLs to include in the package; these will be merged together when deployed. + ValuesFiles []string `json:"valuesFiles,omitempty"` + // [alpha] List of variables to set in the Helm chart. + Variables []ZarfChartVariable `json:"variables,omitempty"` } // ZarfChartVariable represents a variable that can be set for a Helm chart overrides. type ZarfChartVariable struct { - Name string `json:"name" jsonschema:"description=The name of the variable,pattern=^[A-Z0-9_]+$"` - Description string `json:"description" jsonschema:"description=A brief description of what the variable controls"` - Path string `json:"path" jsonschema:"description=The path within the Helm chart values where this variable applies"` + // The name of the variable. + Name string `json:"name" jsonschema:"pattern=^[A-Z0-9_]+$"` + // A brief description of what the variable controls. + Description string `json:"description"` + // The path within the Helm chart values where this variable applies. + Path string `json:"path"` } // ZarfManifest defines raw manifests Zarf will deploy as a helm chart. type ZarfManifest struct { - Name string `json:"name" jsonschema:"description=A name to give this collection of manifests; this will become the name of the dynamically-created helm chart"` - Namespace string `json:"namespace,omitempty" jsonschema:"description=The namespace to deploy the manifests to"` - Files []string `json:"files,omitempty" jsonschema:"description=List of local K8s YAML files or remote URLs to deploy (in order)"` - KustomizeAllowAnyDirectory bool `json:"kustomizeAllowAnyDirectory,omitempty" jsonschema:"description=Allow traversing directory above the current directory if needed for kustomization"` - Kustomizations []string `json:"kustomizations,omitempty" jsonschema:"description=List of local kustomization paths or remote URLs to include in the package"` - NoWait bool `json:"noWait,omitempty" jsonschema:"description=Whether to not wait for manifest resources to be ready before continuing"` + // A name to give this collection of manifests; this will become the name of the dynamically-created helm chart. + Name string `json:"name"` + // The namespace to deploy the manifests to. + Namespace string `json:"namespace,omitempty"` + // List of local K8s YAML files or remote URLs to deploy (in order). + Files []string `json:"files,omitempty"` + // Allow traversing directory above the current directory if needed for kustomization. + KustomizeAllowAnyDirectory bool `json:"kustomizeAllowAnyDirectory,omitempty"` + // List of local kustomization paths or remote URLs to include in the package. + Kustomizations []string `json:"kustomizations,omitempty"` + // Whether to not wait for manifest resources to be ready before continuing. + NoWait bool `json:"noWait,omitempty"` } -// DeprecatedZarfComponentScripts are scripts that run before or after a component is deployed +// DeprecatedZarfComponentScripts are scripts that run before or after a component is deployed. type DeprecatedZarfComponentScripts struct { - ShowOutput bool `json:"showOutput,omitempty" jsonschema:"description=Show the output of the script during package deployment"` - TimeoutSeconds int `json:"timeoutSeconds,omitempty" jsonschema:"description=Timeout in seconds for the script"` - Retry bool `json:"retry,omitempty" jsonschema:"description=Retry the script if it fails"` - Prepare []string `json:"prepare,omitempty" jsonschema:"description=Scripts to run before the component is added during package create"` - Before []string `json:"before,omitempty" jsonschema:"description=Scripts to run before the component is deployed"` - After []string `json:"after,omitempty" jsonschema:"description=Scripts to run after the component successfully deploys"` + // Show the output of the script during package deployment. + ShowOutput bool `json:"showOutput,omitempty"` + // Timeout in seconds for the script. + TimeoutSeconds int `json:"timeoutSeconds,omitempty"` + // Retry the script if it fails. + Retry bool `json:"retry,omitempty"` + // Scripts to run before the component is added during package create. + Prepare []string `json:"prepare,omitempty"` + // Scripts to run before the component is deployed. + Before []string `json:"before,omitempty"` + // Scripts to run after the component successfully deploys. + After []string `json:"after,omitempty"` } -// ZarfComponentActions are ActionSets that map to different zarf package operations +// ZarfComponentActions are ActionSets that map to different zarf package operations. type ZarfComponentActions struct { - OnCreate ZarfComponentActionSet `json:"onCreate,omitempty" jsonschema:"description=Actions to run during package creation"` - OnDeploy ZarfComponentActionSet `json:"onDeploy,omitempty" jsonschema:"description=Actions to run during package deployment"` - OnRemove ZarfComponentActionSet `json:"onRemove,omitempty" jsonschema:"description=Actions to run during package removal"` + // Actions to run during package creation. + OnCreate ZarfComponentActionSet `json:"onCreate,omitempty"` + // Actions to run during package deployment. + OnDeploy ZarfComponentActionSet `json:"onDeploy,omitempty"` + // Actions to run during package removal. + OnRemove ZarfComponentActionSet `json:"onRemove,omitempty"` } -// ZarfComponentActionSet is a set of actions to run during a zarf package operation +// ZarfComponentActionSet is a set of actions to run during a zarf package operation. type ZarfComponentActionSet struct { - Defaults ZarfComponentActionDefaults `json:"defaults,omitempty" jsonschema:"description=Default configuration for all actions in this set"` - Before []ZarfComponentAction `json:"before,omitempty" jsonschema:"description=Actions to run at the start of an operation"` - After []ZarfComponentAction `json:"after,omitempty" jsonschema:"description=Actions to run at the end of an operation"` - OnSuccess []ZarfComponentAction `json:"onSuccess,omitempty" jsonschema:"description=Actions to run if all operations succeed"` - OnFailure []ZarfComponentAction `json:"onFailure,omitempty" jsonschema:"description=Actions to run if all operations fail"` + // Default configuration for all actions in this set. + Defaults ZarfComponentActionDefaults `json:"defaults,omitempty"` + // Actions to run at the start of an operation. + Before []ZarfComponentAction `json:"before,omitempty"` + // Actions to run at the end of an operation. + After []ZarfComponentAction `json:"after,omitempty"` + // Actions to run if all operations succeed. + OnSuccess []ZarfComponentAction `json:"onSuccess,omitempty"` + // Actions to run if all operations fail. + OnFailure []ZarfComponentAction `json:"onFailure,omitempty"` } -// ZarfComponentActionDefaults sets the default configs for child actions +// ZarfComponentActionDefaults sets the default configs for child actions. type ZarfComponentActionDefaults struct { - Mute bool `json:"mute,omitempty" jsonschema:"description=Hide the output of commands during execution (default false)"` - MaxTotalSeconds int `json:"maxTotalSeconds,omitempty" jsonschema:"description=Default timeout in seconds for commands (default to 0, no timeout)"` - MaxRetries int `json:"maxRetries,omitempty" jsonschema:"description=Retry commands given number of times if they fail (default 0)"` - Dir string `json:"dir,omitempty" jsonschema:"description=Working directory for commands (default CWD)"` - Env []string `json:"env,omitempty" jsonschema:"description=Additional environment variables for commands"` - Shell exec.Shell `json:"shell,omitempty" jsonschema:"description=(cmd only) Indicates a preference for a shell for the provided cmd to be executed in on supported operating systems"` + // Hide the output of commands during execution (default false). + Mute bool `json:"mute,omitempty"` + // Default timeout in seconds for commands (default to 0, no timeout). + MaxTotalSeconds int `json:"maxTotalSeconds,omitempty"` + // Retry commands given number of times if they fail (default 0). + MaxRetries int `json:"maxRetries,omitempty"` + // Working directory for commands (default CWD). + Dir string `json:"dir,omitempty"` + // Additional environment variables for commands. + Env []string `json:"env,omitempty"` + // (cmd only) Indicates a preference for a shell for the provided cmd to be executed in on supported operating systems. + Shell exec.Shell `json:"shell,omitempty"` } -// ZarfComponentAction represents a single action to run during a zarf package operation +// ZarfComponentAction represents a single action to run during a zarf package operation. type ZarfComponentAction struct { - Mute *bool `json:"mute,omitempty" jsonschema:"description=Hide the output of the command during package deployment (default false)"` - MaxTotalSeconds *int `json:"maxTotalSeconds,omitempty" jsonschema:"description=Timeout in seconds for the command (default to 0, no timeout for cmd actions and 300, 5 minutes for wait actions)"` - MaxRetries *int `json:"maxRetries,omitempty" jsonschema:"description=Retry the command if it fails up to given number of times (default 0)"` - Dir *string `json:"dir,omitempty" jsonschema:"description=The working directory to run the command in (default is CWD)"` - Env []string `json:"env,omitempty" jsonschema:"description=Additional environment variables to set for the command"` - Cmd string `json:"cmd,omitempty" jsonschema:"description=The command to run. Must specify either cmd or wait for the action to do anything."` - Shell *exec.Shell `json:"shell,omitempty" jsonschema:"description=(cmd only) Indicates a preference for a shell for the provided cmd to be executed in on supported operating systems"` - DeprecatedSetVariable string `json:"setVariable,omitempty" jsonschema:"description=[Deprecated] (replaced by setVariables) (onDeploy/cmd only) The name of a variable to update with the output of the command. This variable will be available to all remaining actions and components in the package. This will be removed in Zarf v1.0.0,pattern=^[A-Z0-9_]+$"` - SetVariables []variables.Variable `json:"setVariables,omitempty" jsonschema:"description=(onDeploy/cmd only) An array of variables to update with the output of the command. These variables will be available to all remaining actions and components in the package."` - Description string `json:"description,omitempty" jsonschema:"description=Description of the action to be displayed during package execution instead of the command"` - Wait *ZarfComponentActionWait `json:"wait,omitempty" jsonschema:"description=Wait for a condition to be met before continuing. Must specify either cmd or wait for the action. See the 'zarf tools wait-for' command for more info."` + // Hide the output of the command during package deployment (default false). + Mute *bool `json:"mute,omitempty"` + // Timeout in seconds for the command (default to 0, no timeout for cmd actions and 300, 5 minutes for wait actions). + MaxTotalSeconds *int `json:"maxTotalSeconds,omitempty"` + // Retry the command if it fails up to given number of times (default 0). + MaxRetries *int `json:"maxRetries,omitempty"` + // The working directory to run the command in (default is CWD). + Dir *string `json:"dir,omitempty"` + // Additional environment variables to set for the command. + Env []string `json:"env,omitempty"` + // The command to run. Must specify either cmd or wait for the action to do anything. + Cmd string `json:"cmd,omitempty"` + // (cmd only) Indicates a preference for a shell for the provided cmd to be executed in on supported operating systems. + Shell *exec.Shell `json:"shell,omitempty"` + // [Deprecated] (replaced by setVariables) (onDeploy/cmd only) The name of a variable to update with the output of the command. This variable will be available to all remaining actions and components in the package. This will be removed in Zarf v1.0.0. + DeprecatedSetVariable string `json:"setVariable,omitempty" jsonschema:"pattern=^[A-Z0-9_]+$"` + // (onDeploy/cmd only) An array of variables to update with the output of the command. These variables will be available to all remaining actions and components in the package. + SetVariables []variables.Variable `json:"setVariables,omitempty"` + // Description of the action to be displayed during package execution instead of the command. + Description string `json:"description,omitempty"` + // Wait for a condition to be met before continuing. Must specify either cmd or wait for the action. See the 'zarf tools wait-for' command for more info. + Wait *ZarfComponentActionWait `json:"wait,omitempty"` } // ZarfComponentActionWait specifies a condition to wait for before continuing type ZarfComponentActionWait struct { - Cluster *ZarfComponentActionWaitCluster `json:"cluster,omitempty" jsonschema:"description=Wait for a condition to be met in the cluster before continuing. Only one of cluster or network can be specified."` - Network *ZarfComponentActionWaitNetwork `json:"network,omitempty" jsonschema:"description=Wait for a condition to be met on the network before continuing. Only one of cluster or network can be specified."` + // Wait for a condition to be met in the cluster before continuing. Only one of cluster or network can be specified. + Cluster *ZarfComponentActionWaitCluster `json:"cluster,omitempty"` + // Wait for a condition to be met on the network before continuing. Only one of cluster or network can be specified. + Network *ZarfComponentActionWaitNetwork `json:"network,omitempty"` } // ZarfComponentActionWaitCluster specifies a condition to wait for before continuing type ZarfComponentActionWaitCluster struct { - Kind string `json:"kind" jsonschema:"description=The kind of resource to wait for,example=Pod,example=Deployment)"` - Identifier string `json:"name" jsonschema:"description=The name of the resource or selector to wait for,example=podinfo,example=app=podinfo"` - Namespace string `json:"namespace,omitempty" jsonschema:"description=The namespace of the resource to wait for"` - Condition string `json:"condition,omitempty" jsonschema:"description=The condition or jsonpath state to wait for; defaults to exist, a special condition that will wait for the resource to exist,example=Ready,example=Available,'{.status.availableReplicas}'=23"` + // The kind of resource to wait for. + Kind string `json:"kind" jsonschema:"example=Pod,example=Deployment"` + // The name of the resource or selector to wait for. + Name string `json:"name" jsonschema:"example=podinfo,example=app=podinfo"` + // The namespace of the resource to wait for. + Namespace string `json:"namespace,omitempty"` + // The condition or jsonpath state to wait for; defaults to exist, a special condition that will wait for the resource to exist. + Condition string `json:"condition,omitempty" jsonschema:"example=Ready,example=Available,'{.status.availableReplicas}'=23"` } // ZarfComponentActionWaitNetwork specifies a condition to wait for before continuing type ZarfComponentActionWaitNetwork struct { - Protocol string `json:"protocol" jsonschema:"description=The protocol to wait for,enum=tcp,enum=http,enum=https"` - Address string `json:"address" jsonschema:"description=The address to wait for,example=localhost:8080,example=1.1.1.1"` - Code int `json:"code,omitempty" jsonschema:"description=The HTTP status code to wait for if using http or https,example=200,example=404"` + // The protocol to wait for. + Protocol string `json:"protocol" jsonschema:"enum=tcp,enum=http,enum=https"` + // The address to wait for. + Address string `json:"address" jsonschema:"example=localhost:8080,example=1.1.1.1"` + // The HTTP status code to wait for if using http or https. + Code int `json:"code,omitempty" jsonschema:"example=200,example=404"` } // ZarfContainerTarget defines the destination info for a ZarfData target type ZarfContainerTarget struct { - Namespace string `json:"namespace" jsonschema:"description=The namespace to target for data injection"` - Selector string `json:"selector" jsonschema:"description=The K8s selector to target for data injection,example=app=data-injection"` - Container string `json:"container" jsonschema:"description=The container name to target for data injection"` - Path string `json:"path" jsonschema:"description=The path within the container to copy the data into"` + // The namespace to target for data injection. + Namespace string `json:"namespace"` + // The K8s selector to target for data injection. + Selector string `json:"selector" jsonschema:"example=app=data-injection"` + // The container name to target for data injection. + Container string `json:"container"` + // The path within the container to copy the data into. + Path string `json:"path"` } // ZarfDataInjection is a data-injection definition. type ZarfDataInjection struct { - Source string `json:"source" jsonschema:"description=Either a path to a local folder/file or a remote URL of a file to inject into the given target pod + container"` - Target ZarfContainerTarget `json:"target" jsonschema:"description=The target pod + container to inject the data into"` - Compress bool `json:"compress,omitempty" jsonschema:"description=Compress the data before transmitting using gzip. Note: this requires support for tar/gzip locally and in the target image."` + // Either a path to a local folder/file or a remote URL of a file to inject into the given target pod + container. + Source string `json:"source"` + // The target pod + container to inject the data into. + Target ZarfContainerTarget `json:"target"` + // Compress the data before transmitting using gzip. Note: this requires support for tar/gzip locally and in the target image. + Compress bool `json:"compress,omitempty"` } // ZarfComponentImport structure for including imported Zarf components. type ZarfComponentImport struct { - ComponentName string `json:"name,omitempty" jsonschema:"description=The name of the component to import from the referenced zarf.yaml"` - // For further explanation see https://regex101.com/r/nxX8vx/1 - Path string `json:"path,omitempty" jsonschema:"description=The relative path to a directory containing a zarf.yaml to import from"` - // For further explanation see https://regex101.com/r/nxX8vx/1 - URL string `json:"url,omitempty" jsonschema:"description=[beta] The URL to a Zarf package to import via OCI,pattern=^oci://.*$"` + // The name of the component to import from the referenced zarf.yaml. + Name string `json:"name,omitempty"` + // The path to the directory containing the zarf.yaml to import. + Path string `json:"path,omitempty"` + // [beta] The URL to a Zarf package to import via OCI. + URL string `json:"url,omitempty" jsonschema:"pattern=^oci://.*$"` } // JSONSchemaExtend extends the generated json schema during `zarf internal gen-config-schema` diff --git a/src/types/extensions/bigbang.go b/src/types/extensions/bigbang.go index 8078e0be04..af357d5990 100644 --- a/src/types/extensions/bigbang.go +++ b/src/types/extensions/bigbang.go @@ -4,11 +4,16 @@ // Package extensions contains the types for all official extensions. package extensions -// BigBang defines a file to deploy. +// BigBang holds the configuration for the Big Bang extension. type BigBang struct { - Version string `json:"version" jsonschema:"description=The version of Big Bang to use"` - Repo string `json:"repo,omitempty" jsonschema:"description=Override repo to pull Big Bang from instead of Repo One"` - ValuesFiles []string `json:"valuesFiles,omitempty" jsonschema:"description=The list of values files to pass to Big Bang; these will be merged together"` - SkipFlux bool `json:"skipFlux,omitempty" jsonschema:"description=Whether to skip deploying flux; Defaults to false"` - FluxPatchFiles []string `json:"fluxPatchFiles,omitempty" jsonschema:"description=Optional paths to Flux kustomize strategic merge patch files"` + // The version of Big Bang to use. + Version string `json:"version"` + // Override repo to pull Big Bang from instead of Repo One. + Repo string `json:"repo,omitempty"` + // The list of values files to pass to Big Bang; these will be merged together. + ValuesFiles []string `json:"valuesFiles,omitempty"` + // Whether to skip deploying flux; Defaults to false. + SkipFlux bool `json:"skipFlux,omitempty"` + // Optional paths to Flux kustomize strategic merge patch files. + FluxPatchFiles []string `json:"fluxPatchFiles,omitempty"` } diff --git a/src/types/extensions/common.go b/src/types/extensions/common.go index e84091e339..1df82730ab 100644 --- a/src/types/extensions/common.go +++ b/src/types/extensions/common.go @@ -4,8 +4,8 @@ // Package extensions contains the types for all official extensions. package extensions -// ZarfComponentExtensions is a struct that contains all the official extensions +// ZarfComponentExtensions is a struct that contains all the official extensions. type ZarfComponentExtensions struct { - // Big Bang Configurations - BigBang *BigBang `json:"bigbang,omitempty" jsonschema:"description=Configurations for installing Big Bang and Flux in the cluster"` + // Configurations for installing Big Bang and Flux in the cluster. + BigBang *BigBang `json:"bigbang,omitempty"` } diff --git a/src/types/k8s.go b/src/types/k8s.go index a8f61856ce..6804de17ee 100644 --- a/src/types/k8s.go +++ b/src/types/k8s.go @@ -58,15 +58,23 @@ type GeneratedPKI struct { // ZarfState is maintained as a secret in the Zarf namespace to track Zarf init data. type ZarfState struct { - ZarfAppliance bool `json:"zarfAppliance" jsonschema:"description=Indicates if Zarf was initialized while deploying its own k8s cluster"` - Distro string `json:"distro" jsonschema:"description=K8s distribution of the cluster Zarf was deployed to"` - Architecture string `json:"architecture" jsonschema:"description=Machine architecture of the k8s node(s)"` - StorageClass string `json:"storageClass" jsonschema:"Default StorageClass value Zarf uses for variable templating"` - AgentTLS GeneratedPKI `json:"agentTLS" jsonschema:"PKI certificate information for the agent pods Zarf manages"` - - GitServer GitServerInfo `json:"gitServer" jsonschema:"description=Information about the repository Zarf is configured to use"` - RegistryInfo RegistryInfo `json:"registryInfo" jsonschema:"description=Information about the container registry Zarf is configured to use"` - ArtifactServer ArtifactServerInfo `json:"artifactServer" jsonschema:"description=Information about the artifact registry Zarf is configured to use"` + // Indicates if Zarf was initialized while deploying its own k8s cluster + ZarfAppliance bool `json:"zarfAppliance"` + // K8s distribution of the cluster Zarf was deployed to + Distro string `json:"distro"` + // Machine architecture of the k8s node(s) + Architecture string `json:"architecture"` + // Default StorageClass value Zarf uses for variable templating + StorageClass string `json:"storageClass"` + // PKI certificate information for the agent pods Zarf manages + AgentTLS GeneratedPKI `json:"agentTLS"` + + // Information about the repository Zarf is configured to use + GitServer GitServerInfo `json:"gitServer"` + // Information about the container registry Zarf is configured to use + RegistryInfo RegistryInfo `json:"registryInfo"` + // Information about the artifact registry Zarf is configured to use + ArtifactServer ArtifactServerInfo `json:"artifactServer"` } // DeployedPackage contains information about a Zarf Package that has been deployed to a cluster @@ -81,6 +89,17 @@ type DeployedPackage struct { ConnectStrings ConnectStrings `json:"connectStrings,omitempty"` } +// ConnectString contains information about a connection made with Zarf connect. +type ConnectString struct { + // Descriptive text that explains what the resource you would be connecting to is used for + Description string `json:"description"` + // URL path that gets appended to the k8s port-forward result + URL string `json:"url"` +} + +// ConnectStrings is a map of connect names to connection information. +type ConnectStrings map[string]ConnectString + // DeployedComponent contains information about a Zarf Package Component that has been deployed to a cluster. type DeployedComponent struct { Name string `json:"name"` @@ -105,13 +124,18 @@ type InstalledChart struct { // GitServerInfo contains information Zarf uses to communicate with a git repository to push/pull repositories to. type GitServerInfo struct { - PushUsername string `json:"pushUsername" jsonschema:"description=Username of a user with push access to the git repository"` - PushPassword string `json:"pushPassword" jsonschema:"description=Password of a user with push access to the git repository"` - PullUsername string `json:"pullUsername" jsonschema:"description=Username of a user with pull-only access to the git repository. If not provided for an external repository then the push-user is used"` - PullPassword string `json:"pullPassword" jsonschema:"description=Password of a user with pull-only access to the git repository. If not provided for an external repository then the push-user is used"` - - Address string `json:"address" jsonschema:"description=URL address of the git server"` - InternalServer bool `json:"internalServer" jsonschema:"description=Indicates if we are using a git server that Zarf is directly managing"` + // Username of a user with push access to the git repository + PushUsername string `json:"pushUsername"` + // Password of a user with push access to the git repository + PushPassword string `json:"pushPassword"` + // Username of a user with pull-only access to the git repository. If not provided for an external repository then the push-user is used + PullUsername string `json:"pullUsername"` + // Password of a user with pull-only access to the git repository. If not provided for an external repository then the push-user is used + PullPassword string `json:"pullPassword"` + // URL address of the git server + Address string `json:"address"` + // Indicates if we are using a git server that Zarf is directly managing + InternalServer bool `json:"internalServer"` } // FillInEmptyValues sets every necessary value that's currently empty to a reasonable default @@ -153,11 +177,14 @@ func (gs *GitServerInfo) FillInEmptyValues() error { // ArtifactServerInfo contains information Zarf uses to communicate with a artifact registry to push/pull repositories to. type ArtifactServerInfo struct { - PushUsername string `json:"pushUsername" jsonschema:"description=Username of a user with push access to the artifact registry"` - PushToken string `json:"pushPassword" jsonschema:"description=Password of a user with push access to the artifact registry"` - - Address string `json:"address" jsonschema:"description=URL address of the artifact registry"` - InternalServer bool `json:"internalServer" jsonschema:"description=Indicates if we are using a artifact registry that Zarf is directly managing"` + // Username of a user with push access to the artifact registry + PushUsername string `json:"pushUsername"` + // Password of a user with push access to the artifact registry + PushToken string `json:"pushPassword"` + // URL address of the artifact registry + Address string `json:"address"` + // Indicates if we are using a artifact registry that Zarf is directly managing + InternalServer bool `json:"internalServer"` } // FillInEmptyValues sets every necessary value that's currently empty to a reasonable default @@ -176,16 +203,22 @@ func (as *ArtifactServerInfo) FillInEmptyValues() { // RegistryInfo contains information Zarf uses to communicate with a container registry to push/pull images. type RegistryInfo struct { - PushUsername string `json:"pushUsername" jsonschema:"description=Username of a user with push access to the registry"` - PushPassword string `json:"pushPassword" jsonschema:"description=Password of a user with push access to the registry"` - PullUsername string `json:"pullUsername" jsonschema:"description=Username of a user with pull-only access to the registry. If not provided for an external registry than the push-user is used"` - PullPassword string `json:"pullPassword" jsonschema:"description=Password of a user with pull-only access to the registry. If not provided for an external registry than the push-user is used"` - - Address string `json:"address" jsonschema:"description=URL address of the registry"` - NodePort int `json:"nodePort" jsonschema:"description=Nodeport of the registry. Only needed if the registry is running inside the kubernetes cluster"` - InternalRegistry bool `json:"internalRegistry" jsonschema:"description=Indicates if we are using a registry that Zarf is directly managing"` - - Secret string `json:"secret" jsonschema:"description=Secret value that the registry was seeded with"` + // Username of a user with push access to the registry + PushUsername string `json:"pushUsername"` + // Password of a user with push access to the registry + PushPassword string `json:"pushPassword"` + // Username of a user with pull-only access to the registry. If not provided for an external registry than the push-user is used + PullUsername string `json:"pullUsername"` + // Password of a user with pull-only access to the registry. If not provided for an external registry than the push-user is used + PullPassword string `json:"pullPassword"` + // URL address of the registry + Address string `json:"address"` + // Nodeport of the registry. Only needed if the registry is running inside the kubernetes cluster + NodePort int `json:"nodePort"` + // Indicates if we are using a registry that Zarf is directly managing + InternalRegistry bool `json:"internalRegistry"` + // Secret value that the registry was seeded with + Secret string `json:"secret"` } // FillInEmptyValues sets every necessary value not already set to a reasonable default diff --git a/src/types/package.go b/src/types/package.go index cb097d6e42..bb4b0edc0a 100644 --- a/src/types/package.go +++ b/src/types/package.go @@ -18,12 +18,18 @@ const ( // ZarfPackage the top-level structure of a Zarf config file. type ZarfPackage struct { - Kind ZarfPackageKind `json:"kind" jsonschema:"description=The kind of Zarf package,enum=ZarfInitConfig,enum=ZarfPackageConfig,default=ZarfPackageConfig"` - Metadata ZarfMetadata `json:"metadata,omitempty" jsonschema:"description=Package metadata"` - Build ZarfBuildData `json:"build,omitempty" jsonschema:"description=Zarf-generated package build data"` - Components []ZarfComponent `json:"components" jsonschema:"description=List of components to deploy in this package,minItems=1"` - Constants []variables.Constant `json:"constants,omitempty" jsonschema:"description=Constant template values applied on deploy for K8s resources"` - Variables []variables.InteractiveVariable `json:"variables,omitempty" jsonschema:"description=Variable template values applied on deploy for K8s resources"` + // The kind of Zarf package. + Kind ZarfPackageKind `json:"kind" jsonschema:"enum=ZarfInitConfig,enum=ZarfPackageConfig,default=ZarfPackageConfig"` + // Package metadata. + Metadata ZarfMetadata `json:"metadata,omitempty"` + // Zarf-generated package build data. + Build ZarfBuildData `json:"build,omitempty"` + // List of components to deploy in this package. + Components []ZarfComponent `json:"components" jsonschema:"minItems=1"` + // Constant template values applied on deploy for K8s resources. + Constants []variables.Constant `json:"constants,omitempty"` + // Variable template values applied on deploy for K8s resources. + Variables []variables.InteractiveVariable `json:"variables,omitempty"` } // IsInitConfig returns whether a Zarf package is an init config. @@ -43,35 +49,58 @@ func (pkg ZarfPackage) IsSBOMAble() bool { // ZarfMetadata lists information about the current ZarfPackage. type ZarfMetadata struct { - // The Name regex permits lowercase letters, numbers, and hyphens not at the start - // https://regex101.com/r/FLdG9G/2 - Name string `json:"name" jsonschema:"description=Name to identify this Zarf package,pattern=^[a-z0-9][a-z0-9\\-]*$"` - Description string `json:"description,omitempty" jsonschema:"description=Additional information about this package"` - Version string `json:"version,omitempty" jsonschema:"description=Generic string set by a package author to track the package version (Note: ZarfInitConfigs will always be versioned to the CLIVersion they were created with)"` - URL string `json:"url,omitempty" jsonschema:"description=Link to package information when online"` - Image string `json:"image,omitempty" jsonschema:"description=An image URL to embed in this package (Reserved for future use in Zarf UI)"` - Uncompressed bool `json:"uncompressed,omitempty" jsonschema:"description=Disable compression of this package"` - Architecture string `json:"architecture,omitempty" jsonschema:"description=The target cluster architecture for this package,example=arm64,example=amd64"` - YOLO bool `json:"yolo,omitempty" jsonschema:"description=Yaml OnLy Online (YOLO): True enables deploying a Zarf package without first running zarf init against the cluster. This is ideal for connected environments where you want to use existing VCS and container registries."` - Authors string `json:"authors,omitempty" jsonschema:"description=Comma-separated list of package authors (including contact info),example=Doug <hello@defenseunicorns.com>, Pepr <hello@defenseunicorns.com>"` - Documentation string `json:"documentation,omitempty" jsonschema:"description=Link to package documentation when online"` - Source string `json:"source,omitempty" jsonschema:"description=Link to package source code when online"` - Vendor string `json:"vendor,omitempty" jsonschema_description:"Name of the distributing entity, organization or individual."` - AggregateChecksum string `json:"aggregateChecksum,omitempty" jsonschema:"description=Checksum of a checksums.txt file that contains checksums all the layers within the package."` + // Name to identify this Zarf package. + Name string `json:"name" jsonschema:"pattern=^[a-z0-9][a-z0-9\\-]*$"` + // Additional information about this package. + Description string `json:"description,omitempty"` + // Generic string set by a package author to track the package version (Note: ZarfInitConfigs will always be versioned to the CLIVersion they were created with). + Version string `json:"version,omitempty"` + // Link to package information when online. + URL string `json:"url,omitempty"` + // An image URL to embed in this package (Reserved for future use in Zarf UI). + Image string `json:"image,omitempty"` + // Disable compression of this package. + Uncompressed bool `json:"uncompressed,omitempty"` + // The target cluster architecture for this package. + Architecture string `json:"architecture,omitempty" jsonschema:"example=arm64,example=amd64"` + // Yaml OnLy Online (YOLO): True enables deploying a Zarf package without first running zarf init against the cluster. This is ideal for connected environments where you want to use existing VCS and container registries. + YOLO bool `json:"yolo,omitempty"` + // Comma-separated list of package authors (including contact info). + Authors string `json:"authors,omitempty" jsonschema:"example=Doug <hello@defenseunicorns.com>, Pepr <hello@defenseunicorns.com>"` + // Link to package documentation when online. + Documentation string `json:"documentation,omitempty"` + // Link to package source code when online. + Source string `json:"source,omitempty"` + // Name of the distributing entity, organization or individual. + Vendor string `json:"vendor,omitempty"` + // Checksum of a checksums.txt file that contains checksums all the layers within the package. + AggregateChecksum string `json:"aggregateChecksum,omitempty"` } // ZarfBuildData is written during the packager.Create() operation to track details of the created package. type ZarfBuildData struct { - Terminal string `json:"terminal" jsonschema:"description=The machine name that created this package"` - User string `json:"user" jsonschema:"description=The username who created this package"` - Architecture string `json:"architecture" jsonschema:"description=The architecture this package was created on"` - Timestamp string `json:"timestamp" jsonschema:"description=The timestamp when this package was created"` - Version string `json:"version" jsonschema:"description=The version of Zarf used to build this package"` - Migrations []string `json:"migrations,omitempty" jsonschema:"description=Any migrations that have been run on this package"` - RegistryOverrides map[string]string `json:"registryOverrides,omitempty" jsonschema:"description=Any registry domains that were overridden on package create when pulling images"` - Differential bool `json:"differential,omitempty" jsonschema:"description=Whether this package was created with differential components"` - DifferentialPackageVersion string `json:"differentialPackageVersion,omitempty" jsonschema:"description=Version of a previously built package used as the basis for creating this differential package"` - DifferentialMissing []string `json:"differentialMissing,omitempty" jsonschema:"description=List of components that were not included in this package due to differential packaging"` - LastNonBreakingVersion string `json:"lastNonBreakingVersion,omitempty" jsonschema:"description=The minimum version of Zarf that does not have breaking package structure changes"` - Flavor string `json:"flavor,omitempty" jsonschema:"description=The flavor of Zarf used to build this package"` + // The machine name that created this package. + Terminal string `json:"terminal"` + // The username who created this package. + User string `json:"user"` + // The architecture this package was created on. + Architecture string `json:"architecture"` + // The timestamp when this package was created. + Timestamp string `json:"timestamp"` + // The version of Zarf used to build this package. + Version string `json:"version"` + // Any migrations that have been run on this package. + Migrations []string `json:"migrations,omitempty"` + // Any registry domains that were overridden on package create when pulling images. + RegistryOverrides map[string]string `json:"registryOverrides,omitempty"` + // Whether this package was created with differential components. + Differential bool `json:"differential,omitempty"` + // Version of a previously built package used as the basis for creating this differential package. + DifferentialPackageVersion string `json:"differentialPackageVersion,omitempty"` + // List of components that were not included in this package due to differential packaging. + DifferentialMissing []string `json:"differentialMissing,omitempty"` + // The minimum version of Zarf that does not have breaking package structure changes. + LastNonBreakingVersion string `json:"lastNonBreakingVersion,omitempty"` + // The flavor of Zarf used to build this package. + Flavor string `json:"flavor,omitempty"` } diff --git a/src/types/runtime.go b/src/types/runtime.go index b4a7d44ad2..0298d80346 100644 --- a/src/types/runtime.go +++ b/src/types/runtime.go @@ -18,22 +18,34 @@ const ( // ZarfCommonOptions tracks the user-defined preferences used across commands. type ZarfCommonOptions struct { - Confirm bool `json:"confirm" jsonschema:"description=Verify that Zarf should perform an action"` - Insecure bool `json:"insecure" jsonschema:"description=Allow insecure connections for remote packages"` - CachePath string `json:"cachePath" jsonschema:"description=Path to use to cache images and git repos on package create"` - TempDirectory string `json:"tempDirectory" jsonschema:"description=Location Zarf should use as a staging ground when managing files and images for package creation and deployment"` - OCIConcurrency int `jsonschema:"description=Number of concurrent layer operations to perform when interacting with a remote package"` + // Verify that Zarf should perform an action + Confirm bool + // Allow insecure connections for remote packages + Insecure bool + // Path to use to cache images and git repos on package create + CachePath string + // Location Zarf should use as a staging ground when managing files and images for package creation and deployment + TempDirectory string + // Number of concurrent layer operations to perform when interacting with a remote package + OCIConcurrency int } // ZarfPackageOptions tracks the user-defined preferences during common package operations. type ZarfPackageOptions struct { - Shasum string `json:"shasum" jsonschema:"description=The SHA256 checksum of the package"` - PackageSource string `json:"packageSource" jsonschema:"description=Location where a Zarf package can be found"` - OptionalComponents string `json:"optionalComponents" jsonschema:"description=Comma separated list of optional components"` - SGetKeyPath string `json:"sGetKeyPath" jsonschema:"description=Location where the public key component of a cosign key-pair can be found"` - SetVariables map[string]string `json:"setVariables" jsonschema:"description=Key-Value map of variable names and their corresponding values that will be used to template manifests and files in the Zarf package"` - PublicKeyPath string `json:"publicKeyPath" jsonschema:"description=Location where the public key component of a cosign key-pair can be found"` - Retries int `json:"retries" jsonschema:"description=The number of retries to perform for Zarf deploy operations like image pushes or Helm installs"` + // The SHA256 checksum of the package + Shasum string + // Location where a Zarf package can be found + PackageSource string + // Comma separated list of optional components + OptionalComponents string + // Location where the public key component of a cosign key-pair can be found + SGetKeyPath string + // Key-Value map of variable names and their corresponding values that will be used to template manifests and files in the Zarf package + SetVariables map[string]string + // Location where the public key component of a cosign key-pair can be found + PublicKeyPath string + // The number of retries to perform for Zarf deploy operations like image pushes or Helm installs + Retries int } // ZarfInspectOptions tracks the user-defined preferences during a package inspection. @@ -48,125 +60,125 @@ type ZarfInspectOptions struct { // ZarfFindImagesOptions tracks the user-defined preferences during a prepare find-images search. type ZarfFindImagesOptions struct { - RepoHelmChartPath string `json:"repoHelmChartPath" jsonschema:"description=Path to the helm chart directory"` - KubeVersionOverride string `json:"kubeVersionOverride" jsonschema:"description=Kubernetes version to use for the helm chart"` - RegistryURL string `json:"registryURL" jsonschema:"description=Manual override for ###ZARF_REGISTRY###"` - Why string `json:"why" jsonschema:"description=Find the location of the image given as an argument and print it to the console"` - SkipCosign bool `json:"skip-cosign" jsonschema:"description=Optionally skip lookup of cosign artifacts when finding images"` + // Path to the helm chart directory + RepoHelmChartPath string + // Kubernetes version to use for the helm chart + KubeVersionOverride string + // Manual override for ###ZARF_REGISTRY### + RegistryURL string + // Find the location of the image given as an argument and print it to the console + Why string + // Optionally skip lookup of cosign artifacts when finding images + SkipCosign bool } // ZarfDeployOptions tracks the user-defined preferences during a package deploy. type ZarfDeployOptions struct { - AdoptExistingResources bool `json:"adoptExistingResources" jsonschema:"description=Whether to adopt any pre-existing K8s resources into the Helm charts managed by Zarf"` - SkipWebhooks bool `json:"componentWebhooks" jsonschema:"description=Skip waiting for external webhooks to execute as each package component is deployed"` - Timeout time.Duration `json:"timeout" jsonschema:"description=Timeout for performing Helm operations"` - - // TODO (@WSTARR): This is a library only addition to Zarf and should be refactored in the future (potentially to utilize component composability). As is it should NOT be exposed directly on the CLI - ValuesOverridesMap map[string]map[string]map[string]interface{} `json:"valuesOverridesMap" jsonschema:"description=[Library Only] A map of component names to chart names containing Helm Chart values to override values on deploy"` + // Whether to adopt any pre-existing K8s resources into the Helm charts managed by Zarf + AdoptExistingResources bool + // Skip waiting for external webhooks to execute as each package component is deployed + SkipWebhooks bool + // Timeout for performing Helm operations + Timeout time.Duration + // [Library Only] A map of component names to chart names containing Helm Chart values to override values on deploy + ValuesOverridesMap map[string]map[string]map[string]interface{} } // ZarfMirrorOptions tracks the user-defined preferences during a package mirror. type ZarfMirrorOptions struct { - NoImgChecksum bool `json:"noImgChecksum" jsonschema:"description=Whether to skip adding a Zarf checksum to image references."` + // Whether to skip adding a Zarf checksum to image references + NoImgChecksum bool } // ZarfPublishOptions tracks the user-defined preferences during a package publish. type ZarfPublishOptions struct { - PackageDestination string `json:"packageDestination" jsonschema:"description=Location where the Zarf package will be published to"` - SigningKeyPassword string `json:"signingKeyPassword" jsonschema:"description=Password to the private key signature file that will be used to sign the published package"` - SigningKeyPath string `json:"signingKeyPath" jsonschema:"description=Location where the private key component of a cosign key-pair can be found"` + // Location where the Zarf package will be published to + PackageDestination string + // Password to the private key signature file that will be used to sign the published package + SigningKeyPassword string + // Location where the private key component of a cosign key-pair can be found + SigningKeyPath string } // ZarfPullOptions tracks the user-defined preferences during a package pull. type ZarfPullOptions struct { - OutputDirectory string `json:"outputDirectory" jsonschema:"description=Location where the pulled Zarf package will be placed"` + // Location where the pulled Zarf package will be placed + OutputDirectory string } // ZarfGenerateOptions tracks the user-defined options during package generation. type ZarfGenerateOptions struct { - Name string `json:"name" jsonschema:"description=Name of the package being generated"` - URL string `json:"url" jsonschema:"description=URL to the source git repository"` - Version string `json:"version" jsonschema:"description=Version of the chart to use"` - GitPath string `json:"gitPath" jsonschema:"description=Relative path to the chart in the git repository"` - Output string `json:"output" jsonschema:"description=Location where the finalized zarf.yaml will be placed"` + // Name of the package being generated + Name string + // URL to the source git repository + URL string + // Version of the chart to use + Version string + // Relative path to the chart in the git repository + GitPath string + // Location where the finalized zarf.yaml will be placed + Output string } // ZarfInitOptions tracks the user-defined options during cluster initialization. type ZarfInitOptions struct { - // Zarf init is installing the k3s component - ApplianceMode bool `json:"applianceMode" jsonschema:"description=Indicates if Zarf was initialized while deploying its own k8s cluster"` - - // Using alternative services - GitServer GitServerInfo `json:"gitServer" jsonschema:"description=Information about the repository Zarf is going to be using"` - RegistryInfo RegistryInfo `json:"registryInfo" jsonschema:"description=Information about the container registry Zarf is going to be using"` - ArtifactServer ArtifactServerInfo `json:"artifactServer" jsonschema:"description=Information about the artifact registry Zarf is going to be using"` - - StorageClass string `json:"storageClass" jsonschema:"description=StorageClass of the k8s cluster Zarf is initializing"` + // Indicates if Zarf was initialized while deploying its own k8s cluster + ApplianceMode bool + // Information about the repository Zarf is going to be using + GitServer GitServerInfo + // Information about the container registry Zarf is going to be using + RegistryInfo RegistryInfo + // Information about the artifact registry Zarf is going to be using + ArtifactServer ArtifactServerInfo + // StorageClass of the k8s cluster Zarf is initializing + StorageClass string } // ZarfCreateOptions tracks the user-defined options used to create the package. type ZarfCreateOptions struct { - SkipSBOM bool `json:"skipSBOM" jsonschema:"description=Disable the generation of SBOM materials during package creation"` - BaseDir string `json:"baseDir" jsonschema:"description=Location where the Zarf package will be created from"` - Output string `json:"output" jsonschema:"description=Location where the finalized Zarf package will be placed"` - ViewSBOM bool `json:"sbom" jsonschema:"description=Whether to pause to allow for viewing the SBOM post-creation"` - SBOMOutputDir string `json:"sbomOutput" jsonschema:"description=Location to output an SBOM into after package creation"` - SetVariables map[string]string `json:"setVariables" jsonschema:"description=Key-Value map of variable names and their corresponding values that will be used to template against the Zarf package being used"` - MaxPackageSizeMB int `json:"maxPackageSizeMB" jsonschema:"description=Size of chunks to use when splitting a zarf package into multiple files in megabytes"` - SigningKeyPath string `json:"signingKeyPath" jsonschema:"description=Location where the private key component of a cosign key-pair can be found"` - SigningKeyPassword string `json:"signingKeyPassword" jsonschema:"description=Password to the private key signature file that will be used to sigh the created package"` - DifferentialPackagePath string `json:"differentialPackagePath" jsonschema:"description=Path to a previously built package used as the basis for creating a differential package"` - RegistryOverrides map[string]string `json:"registryOverrides" jsonschema:"description=A map of domains to override on package create when pulling images"` - Flavor string `json:"flavor" jsonschema:"description=An optional variant that controls which components will be included in a package"` - IsSkeleton bool `json:"isSkeleton" jsonschema:"description=Whether to create a skeleton package"` - NoYOLO bool `json:"noYOLO" jsonschema:"description=Whether to create a YOLO package"` + // Disable the generation of SBOM materials during package creation + SkipSBOM bool + // Location where the Zarf package will be created from + BaseDir string + // Location where the finalized Zarf package will be placed + Output string + // Whether to pause to allow for viewing the SBOM post-creation + ViewSBOM bool + // Location to output an SBOM into after package creation + SBOMOutputDir string + // Key-Value map of variable names and their corresponding values that will be used to template against the Zarf package being used + SetVariables map[string]string + // Size of chunks to use when splitting a zarf package into multiple files in megabytes + MaxPackageSizeMB int + // Location where the private key component of a cosign key-pair can be found + SigningKeyPath string + // Password to the private key signature file that will be used to sigh the created package + SigningKeyPassword string + // Path to a previously built package used as the basis for creating a differential package + DifferentialPackagePath string + // A map of domains to override on package create when pulling images + RegistryOverrides map[string]string + // An optional variant that controls which components will be included in a package + Flavor string + // Whether to create a skeleton package + IsSkeleton bool + // Whether to create a YOLO package + NoYOLO bool } // ZarfSplitPackageData contains info about a split package. type ZarfSplitPackageData struct { - Sha256Sum string `json:"sha256Sum" jsonschema:"description=The sha256sum of the package"` - Bytes int64 `json:"bytes" jsonschema:"description=The size of the package in bytes"` - Count int `json:"count" jsonschema:"description=The number of parts the package is split into"` -} - -// ConnectString contains information about a connection made with Zarf connect. -type ConnectString struct { - Description string `json:"description" jsonschema:"description=Descriptive text that explains what the resource you would be connecting to is used for"` - URL string `json:"url" jsonschema:"description=URL path that gets appended to the k8s port-forward result"` + // The sha256sum of the package + Sha256Sum string + // The size of the package in bytes + Bytes int64 + // The number of parts the package is split into + Count int } -// ConnectStrings is a map of connect names to connection information. -type ConnectStrings map[string]ConnectString - // DifferentialData contains image and repository information about the package a Differential Package is Based on. type DifferentialData struct { DifferentialImages map[string]bool DifferentialRepos map[string]bool DifferentialPackageVersion string } - -// PackageFinding is a struct that contains a finding about something wrong with a package -type PackageFinding struct { - // YqPath is the path to the key where the error originated from, this is sometimes empty in the case of a general error - YqPath string - Description string - // Item is the value of a key that is causing an error, for example a bad image name - Item string - // PackageNameOverride shows the name of the package that the error originated from - // If it is not set the base package will be used when displaying the error - PackageNameOverride string - // PackagePathOverride shows the path to the package that the error originated from - // If it is not set the base package will be used when displaying the error - PackagePathOverride string - Severity Severity -} - -// Severity is the type of package error -// Either Err or Warning -type Severity int - -// different severities of package errors -const ( - SevErr Severity = iota + 1 - SevWarn -) diff --git a/zarf.schema.json b/zarf.schema.json index b5c7a971d4..f4a0690553 100644 --- a/zarf.schema.json +++ b/zarf.schema.json @@ -6,29 +6,29 @@ "properties": { "version": { "type": "string", - "description": "The version of Big Bang to use" + "description": "The version of Big Bang to use." }, "repo": { "type": "string", - "description": "Override repo to pull Big Bang from instead of Repo One" + "description": "Override repo to pull Big Bang from instead of Repo One." }, "valuesFiles": { "items": { "type": "string" }, "type": "array", - "description": "The list of values files to pass to Big Bang; these will be merged together" + "description": "The list of values files to pass to Big Bang; these will be merged together." }, "skipFlux": { "type": "boolean", - "description": "Whether to skip deploying flux; Defaults to false" + "description": "Whether to skip deploying flux; Defaults to false." }, "fluxPatchFiles": { "items": { "type": "string" }, "type": "array", - "description": "Optional paths to Flux kustomize strategic merge patch files" + "description": "Optional paths to Flux kustomize strategic merge patch files." } }, "additionalProperties": false, @@ -36,6 +36,7 @@ "required": [ "version" ], + "description": "BigBang holds the configuration for the Big Bang extension.", "patternProperties": { "^x-": {} } @@ -70,6 +71,7 @@ "name", "value" ], + "description": "Constant are constants that can be used to dynamically template K8s resources or run in actions.", "patternProperties": { "^x-": {} } @@ -78,40 +80,41 @@ "properties": { "showOutput": { "type": "boolean", - "description": "Show the output of the script during package deployment" + "description": "Show the output of the script during package deployment." }, "timeoutSeconds": { "type": "integer", - "description": "Timeout in seconds for the script" + "description": "Timeout in seconds for the script." }, "retry": { "type": "boolean", - "description": "Retry the script if it fails" + "description": "Retry the script if it fails." }, "prepare": { "items": { "type": "string" }, "type": "array", - "description": "Scripts to run before the component is added during package create" + "description": "Scripts to run before the component is added during package create." }, "before": { "items": { "type": "string" }, "type": "array", - "description": "Scripts to run before the component is deployed" + "description": "Scripts to run before the component is deployed." }, "after": { "items": { "type": "string" }, "type": "array", - "description": "Scripts to run after the component successfully deploys" + "description": "Scripts to run after the component successfully deploys." } }, "additionalProperties": false, "type": "object", + "description": "DeprecatedZarfComponentScripts are scripts that run before or after a component is deployed.", "patternProperties": { "^x-": {} } @@ -161,6 +164,7 @@ "required": [ "name" ], + "description": "InteractiveVariable is a variable that can be used to prompt a user for more information", "patternProperties": { "^x-": {} } @@ -241,6 +245,7 @@ "required": [ "name" ], + "description": "Variable represents a variable that has a value set programmatically", "patternProperties": { "^x-": {} } @@ -249,60 +254,60 @@ "properties": { "terminal": { "type": "string", - "description": "The machine name that created this package" + "description": "The machine name that created this package." }, "user": { "type": "string", - "description": "The username who created this package" + "description": "The username who created this package." }, "architecture": { "type": "string", - "description": "The architecture this package was created on" + "description": "The architecture this package was created on." }, "timestamp": { "type": "string", - "description": "The timestamp when this package was created" + "description": "The timestamp when this package was created." }, "version": { "type": "string", - "description": "The version of Zarf used to build this package" + "description": "The version of Zarf used to build this package." }, "migrations": { "items": { "type": "string" }, "type": "array", - "description": "Any migrations that have been run on this package" + "description": "Any migrations that have been run on this package." }, "registryOverrides": { "additionalProperties": { "type": "string" }, "type": "object", - "description": "Any registry domains that were overridden on package create when pulling images" + "description": "Any registry domains that were overridden on package create when pulling images." }, "differential": { "type": "boolean", - "description": "Whether this package was created with differential components" + "description": "Whether this package was created with differential components." }, "differentialPackageVersion": { "type": "string", - "description": "Version of a previously built package used as the basis for creating this differential package" + "description": "Version of a previously built package used as the basis for creating this differential package." }, "differentialMissing": { "items": { "type": "string" }, "type": "array", - "description": "List of components that were not included in this package due to differential packaging" + "description": "List of components that were not included in this package due to differential packaging." }, "lastNonBreakingVersion": { "type": "string", - "description": "The minimum version of Zarf that does not have breaking package structure changes" + "description": "The minimum version of Zarf that does not have breaking package structure changes." }, "flavor": { "type": "string", - "description": "The flavor of Zarf used to build this package" + "description": "The flavor of Zarf used to build this package." } }, "additionalProperties": false, @@ -314,6 +319,7 @@ "timestamp", "version" ], + "description": "ZarfBuildData is written during the packager.Create() operation to track details of the created package.", "patternProperties": { "^x-": {} } @@ -322,15 +328,15 @@ "properties": { "name": { "type": "string", - "description": "The name of the chart within Zarf; note that this must be unique and does not need to be the same as the name in the chart repo" + "description": "The name of the chart within Zarf; note that this must be unique and does not need to be the same as the name in the chart repo." }, "version": { "type": "string", - "description": "The version of the chart to deploy; for git-based charts this is also the tag of the git repo by default (when not using the '@' syntax for 'repos')" + "description": "The version of the chart to deploy; for git-based charts this is also the tag of the git repo by default (when not using the '@' syntax for 'repos')." }, "url": { "type": "string", - "description": "The URL of the OCI registry, chart repository, or git repo where the helm chart is stored", + "description": "The URL of the OCI registry, chart repository, or git repo where the helm chart is stored.", "examples": [ "OCI registry: oci://ghcr.io/stefanprodan/charts/podinfo", "helm chart repo: https://stefanprodan.github.io/podinfo", @@ -339,44 +345,44 @@ }, "repoName": { "type": "string", - "description": "The name of a chart within a Helm repository (defaults to the Zarf name of the chart)" + "description": "The name of a chart within a Helm repository (defaults to the Zarf name of the chart)." }, "gitPath": { "type": "string", - "description": "(git repo only) The sub directory to the chart within a git repo", + "description": "(git repo only) The sub directory to the chart within a git repo.", "examples": [ "charts/your-chart" ] }, "localPath": { "type": "string", - "description": "The path to a local chart's folder or .tgz archive" + "description": "The path to a local chart's folder or .tgz archive." }, "namespace": { "type": "string", - "description": "The namespace to deploy the chart to" + "description": "The namespace to deploy the chart to." }, "releaseName": { "type": "string", - "description": "The name of the Helm release to create (defaults to the Zarf name of the chart)" + "description": "The name of the Helm release to create (defaults to the Zarf name of the chart)." }, "noWait": { "type": "boolean", - "description": "Whether to not wait for chart resources to be ready before continuing" + "description": "Whether to not wait for chart resources to be ready before continuing." }, "valuesFiles": { "items": { "type": "string" }, "type": "array", - "description": "List of local values file paths or remote URLs to include in the package; these will be merged together when deployed" + "description": "List of local values file paths or remote URLs to include in the package; these will be merged together when deployed." }, "variables": { "items": { "$ref": "#/$defs/ZarfChartVariable" }, "type": "array", - "description": "[alpha] List of variables to set in the Helm chart" + "description": "[alpha] List of variables to set in the Helm chart." } }, "additionalProperties": false, @@ -384,6 +390,7 @@ "required": [ "name" ], + "description": "ZarfChart defines a helm chart to be deployed.", "patternProperties": { "^x-": {} } @@ -393,15 +400,15 @@ "name": { "type": "string", "pattern": "^[A-Z0-9_]+$", - "description": "The name of the variable" + "description": "The name of the variable." }, "description": { "type": "string", - "description": "A brief description of what the variable controls" + "description": "A brief description of what the variable controls." }, "path": { "type": "string", - "description": "The path within the Helm chart values where this variable applies" + "description": "The path within the Helm chart values where this variable applies." } }, "additionalProperties": false, @@ -411,6 +418,7 @@ "description", "path" ], + "description": "ZarfChartVariable represents a variable that can be set for a Helm chart overrides.", "patternProperties": { "^x-": {} } @@ -420,23 +428,23 @@ "name": { "type": "string", "pattern": "^[a-z0-9][a-z0-9\\-]*$", - "description": "The name of the component" + "description": "The name of the component." }, "description": { "type": "string", - "description": "Message to include during package deploy describing the purpose of this component" + "description": "Message to include during package deploy describing the purpose of this component." }, "default": { "type": "boolean", - "description": "Determines the default Y/N state for installing this component on package deploy" + "description": "Determines the default Y/N state for installing this component on package deploy." }, "required": { "type": "boolean", - "description": "Do not prompt user to install this component" + "description": "Do not prompt user to install this component." }, "only": { "$ref": "#/$defs/ZarfComponentOnlyTarget", - "description": "Filter when this component is included in package creation or deployment" + "description": "Filter when this component is included in package creation or deployment." }, "group": { "type": "string", @@ -448,61 +456,61 @@ }, "import": { "$ref": "#/$defs/ZarfComponentImport", - "description": "Import a component from another Zarf package" + "description": "Import a component from another Zarf package." }, "manifests": { "items": { "$ref": "#/$defs/ZarfManifest" }, "type": "array", - "description": "Kubernetes manifests to be included in a generated Helm chart on package deploy" + "description": "Kubernetes manifests to be included in a generated Helm chart on package deploy." }, "charts": { "items": { "$ref": "#/$defs/ZarfChart" }, "type": "array", - "description": "Helm charts to install during package deploy" + "description": "Helm charts to install during package deploy." }, "dataInjections": { "items": { "$ref": "#/$defs/ZarfDataInjection" }, "type": "array", - "description": "Datasets to inject into a container in the target cluster" + "description": "Datasets to inject into a container in the target cluster." }, "files": { "items": { "$ref": "#/$defs/ZarfFile" }, "type": "array", - "description": "Files or folders to place on disk during package deployment" + "description": "Files or folders to place on disk during package deployment." }, "images": { "items": { "type": "string" }, "type": "array", - "description": "List of OCI images to include in the package" + "description": "List of OCI images to include in the package." }, "repos": { "items": { "type": "string" }, "type": "array", - "description": "List of git repos to include in the package" + "description": "List of git repos to include in the package." }, "extensions": { "$ref": "#/$defs/ZarfComponentExtensions", - "description": "Extend component functionality with additional features" + "description": "Extend component functionality with additional features." }, "scripts": { "$ref": "#/$defs/DeprecatedZarfComponentScripts", - "description": "[Deprecated] (replaced by actions) Custom commands to run before or after package deployment. This will be removed in Zarf v1.0.0." + "description": "[Deprecated] (replaced by actions) Custom commands to run before or after package deployment. This will be removed in Zarf v1.0.0." }, "actions": { "$ref": "#/$defs/ZarfComponentActions", - "description": "Custom commands to run at various stages of a package lifecycle" + "description": "Custom commands to run at various stages of a package lifecycle." } }, "additionalProperties": false, @@ -510,6 +518,7 @@ "required": [ "name" ], + "description": "ZarfComponent is the primary functional grouping of assets to deploy by Zarf.", "patternProperties": { "^x-": {} } @@ -518,26 +527,26 @@ "properties": { "mute": { "type": "boolean", - "description": "Hide the output of the command during package deployment (default false)" + "description": "Hide the output of the command during package deployment (default false)." }, "maxTotalSeconds": { "type": "integer", - "description": "Timeout in seconds for the command (default to 0" + "description": "Timeout in seconds for the command (default to 0, no timeout for cmd actions and 300, 5 minutes for wait actions)." }, "maxRetries": { "type": "integer", - "description": "Retry the command if it fails up to given number of times (default 0)" + "description": "Retry the command if it fails up to given number of times (default 0)." }, "dir": { "type": "string", - "description": "The working directory to run the command in (default is CWD)" + "description": "The working directory to run the command in (default is CWD)." }, "env": { "items": { "type": "string" }, "type": "array", - "description": "Additional environment variables to set for the command" + "description": "Additional environment variables to set for the command." }, "cmd": { "type": "string", @@ -545,12 +554,12 @@ }, "shell": { "$ref": "#/$defs/Shell", - "description": "(cmd only) Indicates a preference for a shell for the provided cmd to be executed in on supported operating systems" + "description": "(cmd only) Indicates a preference for a shell for the provided cmd to be executed in on supported operating systems." }, "setVariable": { "type": "string", "pattern": "^[A-Z0-9_]+$", - "description": "[Deprecated] (replaced by setVariables) (onDeploy/cmd only) The name of a variable to update with the output of the command. This variable will be available to all remaining actions and components in the package. This will be removed in Zarf v1.0.0" + "description": "[Deprecated] (replaced by setVariables) (onDeploy/cmd only) The name of a variable to update with the output of the command. This variable will be available to all remaining actions and components in the package. This will be removed in Zarf v1.0.0." }, "setVariables": { "items": { @@ -561,7 +570,7 @@ }, "description": { "type": "string", - "description": "Description of the action to be displayed during package execution instead of the command" + "description": "Description of the action to be displayed during package execution instead of the command." }, "wait": { "$ref": "#/$defs/ZarfComponentActionWait", @@ -570,6 +579,7 @@ }, "additionalProperties": false, "type": "object", + "description": "ZarfComponentAction represents a single action to run during a zarf package operation.", "patternProperties": { "^x-": {} } @@ -578,34 +588,35 @@ "properties": { "mute": { "type": "boolean", - "description": "Hide the output of commands during execution (default false)" + "description": "Hide the output of commands during execution (default false)." }, "maxTotalSeconds": { "type": "integer", - "description": "Default timeout in seconds for commands (default to 0" + "description": "Default timeout in seconds for commands (default to 0, no timeout)." }, "maxRetries": { "type": "integer", - "description": "Retry commands given number of times if they fail (default 0)" + "description": "Retry commands given number of times if they fail (default 0)." }, "dir": { "type": "string", - "description": "Working directory for commands (default CWD)" + "description": "Working directory for commands (default CWD)." }, "env": { "items": { "type": "string" }, "type": "array", - "description": "Additional environment variables for commands" + "description": "Additional environment variables for commands." }, "shell": { "$ref": "#/$defs/Shell", - "description": "(cmd only) Indicates a preference for a shell for the provided cmd to be executed in on supported operating systems" + "description": "(cmd only) Indicates a preference for a shell for the provided cmd to be executed in on supported operating systems." } }, "additionalProperties": false, "type": "object", + "description": "ZarfComponentActionDefaults sets the default configs for child actions.", "patternProperties": { "^x-": {} } @@ -614,39 +625,40 @@ "properties": { "defaults": { "$ref": "#/$defs/ZarfComponentActionDefaults", - "description": "Default configuration for all actions in this set" + "description": "Default configuration for all actions in this set." }, "before": { "items": { "$ref": "#/$defs/ZarfComponentAction" }, "type": "array", - "description": "Actions to run at the start of an operation" + "description": "Actions to run at the start of an operation." }, "after": { "items": { "$ref": "#/$defs/ZarfComponentAction" }, "type": "array", - "description": "Actions to run at the end of an operation" + "description": "Actions to run at the end of an operation." }, "onSuccess": { "items": { "$ref": "#/$defs/ZarfComponentAction" }, "type": "array", - "description": "Actions to run if all operations succeed" + "description": "Actions to run if all operations succeed." }, "onFailure": { "items": { "$ref": "#/$defs/ZarfComponentAction" }, "type": "array", - "description": "Actions to run if all operations fail" + "description": "Actions to run if all operations fail." } }, "additionalProperties": false, "type": "object", + "description": "ZarfComponentActionSet is a set of actions to run during a zarf package operation.", "patternProperties": { "^x-": {} } @@ -664,6 +676,7 @@ }, "additionalProperties": false, "type": "object", + "description": "ZarfComponentActionWait specifies a condition to wait for before continuing", "patternProperties": { "^x-": {} } @@ -672,27 +685,27 @@ "properties": { "kind": { "type": "string", - "description": "The kind of resource to wait for", + "description": "The kind of resource to wait for.", "examples": [ "Pod", - "Deployment)" + "Deployment" ] }, "name": { "type": "string", - "description": "The name of the resource or selector to wait for", + "description": "The name of the resource or selector to wait for.", "examples": [ "podinfo", - "app=podinfo" + "app=podinfo" ] }, "namespace": { "type": "string", - "description": "The namespace of the resource to wait for" + "description": "The namespace of the resource to wait for." }, "condition": { "type": "string", - "description": "The condition or jsonpath state to wait for; defaults to exist", + "description": "The condition or jsonpath state to wait for; defaults to exist, a special condition that will wait for the resource to exist.", "examples": [ "Ready", "Available" @@ -705,6 +718,7 @@ "kind", "name" ], + "description": "ZarfComponentActionWaitCluster specifies a condition to wait for before continuing", "patternProperties": { "^x-": {} } @@ -718,11 +732,11 @@ "http", "https" ], - "description": "The protocol to wait for" + "description": "The protocol to wait for." }, "address": { "type": "string", - "description": "The address to wait for", + "description": "The address to wait for.", "examples": [ "localhost:8080", "1.1.1.1" @@ -730,7 +744,7 @@ }, "code": { "type": "integer", - "description": "The HTTP status code to wait for if using http or https", + "description": "The HTTP status code to wait for if using http or https.", "examples": [ 200, 404 @@ -743,6 +757,7 @@ "protocol", "address" ], + "description": "ZarfComponentActionWaitNetwork specifies a condition to wait for before continuing", "patternProperties": { "^x-": {} } @@ -751,19 +766,20 @@ "properties": { "onCreate": { "$ref": "#/$defs/ZarfComponentActionSet", - "description": "Actions to run during package creation" + "description": "Actions to run during package creation." }, "onDeploy": { "$ref": "#/$defs/ZarfComponentActionSet", - "description": "Actions to run during package deployment" + "description": "Actions to run during package deployment." }, "onRemove": { "$ref": "#/$defs/ZarfComponentActionSet", - "description": "Actions to run during package removal" + "description": "Actions to run during package removal." } }, "additionalProperties": false, "type": "object", + "description": "ZarfComponentActions are ActionSets that map to different zarf package operations.", "patternProperties": { "^x-": {} } @@ -772,11 +788,12 @@ "properties": { "bigbang": { "$ref": "#/$defs/BigBang", - "description": "Configurations for installing Big Bang and Flux in the cluster" + "description": "Configurations for installing Big Bang and Flux in the cluster." } }, "additionalProperties": false, "type": "object", + "description": "ZarfComponentExtensions is a struct that contains all the official extensions.", "patternProperties": { "^x-": {} } @@ -785,14 +802,14 @@ "properties": { "name": { "type": "string", - "description": "The name of the component to import from the referenced zarf.yaml" + "description": "The name of the component to import from the referenced zarf.yaml." }, "path": { "not": { "pattern": "###ZARF_PKG_TMPL_" }, "type": "string", - "description": "The relative path to a directory containing a zarf.yaml to import from" + "description": "The path to the directory containing the zarf.yaml to import." }, "url": { "not": { @@ -800,11 +817,12 @@ }, "type": "string", "pattern": "^oci://.*$", - "description": "[beta] The URL to a Zarf package to import via OCI" + "description": "[beta] The URL to a Zarf package to import via OCI." } }, "additionalProperties": false, "type": "object", + "description": "ZarfComponentImport structure for including imported Zarf components.", "patternProperties": { "^x-": {} } @@ -817,7 +835,7 @@ "amd64", "arm64" ], - "description": "Only create and deploy to clusters of the given architecture" + "description": "Only create and deploy to clusters of the given architecture." }, "distros": { "items": { @@ -828,11 +846,12 @@ ] }, "type": "array", - "description": "A list of kubernetes distros this package works with (Reserved for future use)" + "description": "A list of kubernetes distros this package works with (Reserved for future use)." } }, "additionalProperties": false, "type": "object", + "description": "ZarfComponentOnlyCluster represents the architecture and K8s cluster distribution to filter on.", "patternProperties": { "^x-": {} } @@ -846,19 +865,20 @@ "darwin", "windows" ], - "description": "Only deploy component to specified OS" + "description": "Only deploy component to specified OS." }, "cluster": { "$ref": "#/$defs/ZarfComponentOnlyCluster", - "description": "Only deploy component to specified clusters" + "description": "Only deploy component to specified clusters." }, "flavor": { "type": "string", - "description": "Only include this component when a matching '--flavor' is specified on 'zarf package create'" + "description": "Only include this component when a matching '--flavor' is specified on 'zarf package create'." } }, "additionalProperties": false, "type": "object", + "description": "ZarfComponentOnlyTarget filters a component to only show it for a given local OS and cluster.", "patternProperties": { "^x-": {} } @@ -867,22 +887,22 @@ "properties": { "namespace": { "type": "string", - "description": "The namespace to target for data injection" + "description": "The namespace to target for data injection." }, "selector": { "type": "string", - "description": "The K8s selector to target for data injection", + "description": "The K8s selector to target for data injection.", "examples": [ - "app=data-injection" + "app=data-injection" ] }, "container": { "type": "string", - "description": "The container name to target for data injection" + "description": "The container name to target for data injection." }, "path": { "type": "string", - "description": "The path within the container to copy the data into" + "description": "The path within the container to copy the data into." } }, "additionalProperties": false, @@ -893,6 +913,7 @@ "container", "path" ], + "description": "ZarfContainerTarget defines the destination info for a ZarfData target", "patternProperties": { "^x-": {} } @@ -901,15 +922,15 @@ "properties": { "source": { "type": "string", - "description": "Either a path to a local folder/file or a remote URL of a file to inject into the given target pod + container" + "description": "Either a path to a local folder/file or a remote URL of a file to inject into the given target pod + container." }, "target": { "$ref": "#/$defs/ZarfContainerTarget", - "description": "The target pod + container to inject the data into" + "description": "The target pod + container to inject the data into." }, "compress": { "type": "boolean", - "description": "Compress the data before transmitting using gzip. Note: this requires support for tar/gzip locally and in the target image." + "description": "Compress the data before transmitting using gzip. Note: this requires support for tar/gzip locally and in the target image." } }, "additionalProperties": false, @@ -918,6 +939,7 @@ "source", "target" ], + "description": "ZarfDataInjection is a data-injection definition.", "patternProperties": { "^x-": {} } @@ -926,30 +948,30 @@ "properties": { "source": { "type": "string", - "description": "Local folder or file path or remote URL to pull into the package" + "description": "Local folder or file path or remote URL to pull into the package." }, "shasum": { "type": "string", - "description": "(files only) Optional SHA256 checksum of the file" + "description": "(files only) Optional SHA256 checksum of the file." }, "target": { "type": "string", - "description": "The absolute or relative path where the file or folder should be copied to during package deploy" + "description": "The absolute or relative path where the file or folder should be copied to during package deploy." }, "executable": { "type": "boolean", - "description": "(files only) Determines if the file should be made executable during package deploy" + "description": "(files only) Determines if the file should be made executable during package deploy." }, "symlinks": { "items": { "type": "string" }, "type": "array", - "description": "List of symlinks to create during package deploy" + "description": "List of symlinks to create during package deploy." }, "extractPath": { "type": "string", - "description": "Local folder or file to be extracted from a 'source' archive" + "description": "Local folder or file to be extracted from a 'source' archive." } }, "additionalProperties": false, @@ -958,6 +980,7 @@ "source", "target" ], + "description": "ZarfFile defines a file to deploy.", "patternProperties": { "^x-": {} } @@ -966,33 +989,33 @@ "properties": { "name": { "type": "string", - "description": "A name to give this collection of manifests; this will become the name of the dynamically-created helm chart" + "description": "A name to give this collection of manifests; this will become the name of the dynamically-created helm chart." }, "namespace": { "type": "string", - "description": "The namespace to deploy the manifests to" + "description": "The namespace to deploy the manifests to." }, "files": { "items": { "type": "string" }, "type": "array", - "description": "List of local K8s YAML files or remote URLs to deploy (in order)" + "description": "List of local K8s YAML files or remote URLs to deploy (in order)." }, "kustomizeAllowAnyDirectory": { "type": "boolean", - "description": "Allow traversing directory above the current directory if needed for kustomization" + "description": "Allow traversing directory above the current directory if needed for kustomization." }, "kustomizations": { "items": { "type": "string" }, "type": "array", - "description": "List of local kustomization paths or remote URLs to include in the package" + "description": "List of local kustomization paths or remote URLs to include in the package." }, "noWait": { "type": "boolean", - "description": "Whether to not wait for manifest resources to be ready before continuing" + "description": "Whether to not wait for manifest resources to be ready before continuing." } }, "additionalProperties": false, @@ -1000,6 +1023,7 @@ "required": [ "name" ], + "description": "ZarfManifest defines raw manifests Zarf will deploy as a helm chart.", "patternProperties": { "^x-": {} } @@ -1009,31 +1033,31 @@ "name": { "type": "string", "pattern": "^[a-z0-9][a-z0-9\\-]*$", - "description": "Name to identify this Zarf package" + "description": "Name to identify this Zarf package." }, "description": { "type": "string", - "description": "Additional information about this package" + "description": "Additional information about this package." }, "version": { "type": "string", - "description": "Generic string set by a package author to track the package version (Note: ZarfInitConfigs will always be versioned to the CLIVersion they were created with)" + "description": "Generic string set by a package author to track the package version (Note: ZarfInitConfigs will always be versioned to the CLIVersion they were created with)." }, "url": { "type": "string", - "description": "Link to package information when online" + "description": "Link to package information when online." }, "image": { "type": "string", - "description": "An image URL to embed in this package (Reserved for future use in Zarf UI)" + "description": "An image URL to embed in this package (Reserved for future use in Zarf UI)." }, "uncompressed": { "type": "boolean", - "description": "Disable compression of this package" + "description": "Disable compression of this package." }, "architecture": { "type": "string", - "description": "The target cluster architecture for this package", + "description": "The target cluster architecture for this package.", "examples": [ "arm64", "amd64" @@ -1045,18 +1069,18 @@ }, "authors": { "type": "string", - "description": "Comma-separated list of package authors (including contact info)", + "description": "Comma-separated list of package authors (including contact info).", "examples": [ "Doug <hello@defenseunicorns.com>, Pepr <hello@defenseunicorns.com>" ] }, "documentation": { "type": "string", - "description": "Link to package documentation when online" + "description": "Link to package documentation when online." }, "source": { "type": "string", - "description": "Link to package source code when online" + "description": "Link to package source code when online." }, "vendor": { "type": "string", @@ -1072,6 +1096,7 @@ "required": [ "name" ], + "description": "ZarfMetadata lists information about the current ZarfPackage.", "patternProperties": { "^x-": {} } @@ -1084,16 +1109,16 @@ "ZarfInitConfig", "ZarfPackageConfig" ], - "description": "The kind of Zarf package", + "description": "The kind of Zarf package.", "default": "ZarfPackageConfig" }, "metadata": { "$ref": "#/$defs/ZarfMetadata", - "description": "Package metadata" + "description": "Package metadata." }, "build": { "$ref": "#/$defs/ZarfBuildData", - "description": "Zarf-generated package build data" + "description": "Zarf-generated package build data." }, "components": { "items": { @@ -1101,21 +1126,21 @@ }, "type": "array", "minItems": 1, - "description": "List of components to deploy in this package" + "description": "List of components to deploy in this package." }, "constants": { "items": { "$ref": "#/$defs/Constant" }, "type": "array", - "description": "Constant template values applied on deploy for K8s resources" + "description": "Constant template values applied on deploy for K8s resources." }, "variables": { "items": { "$ref": "#/$defs/InteractiveVariable" }, "type": "array", - "description": "Variable template values applied on deploy for K8s resources" + "description": "Variable template values applied on deploy for K8s resources." } }, "additionalProperties": false, @@ -1124,6 +1149,7 @@ "kind", "components" ], + "description": "ZarfPackage the top-level structure of a Zarf config file.", "patternProperties": { "^x-": {} } From 44fc6b76cc57e5a354e67e65c38a00bf98d4cf63 Mon Sep 17 00:00:00 2001 From: James Gardner Date: Wed, 31 Jul 2024 09:01:14 -0500 Subject: [PATCH 41/68] fix: detect invalid helm release names (#2784) Signed-off-by: jamestexas --- src/types/validate.go | 33 ++++++++++++- src/types/validate_test.go | 97 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 125 insertions(+), 5 deletions(-) diff --git a/src/types/validate.go b/src/types/validate.go index e045e69520..05289a1781 100644 --- a/src/types/validate.go +++ b/src/types/validate.go @@ -9,14 +9,18 @@ import ( "fmt" "path/filepath" "regexp" + "strings" "github.com/defenseunicorns/pkg/helpers/v2" "github.com/zarf-dev/zarf/src/config/lang" + "k8s.io/apimachinery/pkg/util/validation" ) const ( // ZarfMaxChartNameLength limits helm chart name size to account for K8s/helm limits and zarf prefix - ZarfMaxChartNameLength = 40 + ZarfMaxChartNameLength = 40 + errChartReleaseNameEmpty = "release name empty, unable to fallback to chart name" + errChartReleaseNameInvalid = "invalid release name %s: a DNS-1035 label must consist of lower case alphanumeric characters or -, start with an alphabetic character, and end with an alphanumeric character" ) var ( @@ -252,6 +256,29 @@ func (action ZarfComponentAction) Validate() error { return err } +// validateReleaseName validates a release name against DNS 1035 spec, using chartName as fallback. +// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#rfc-1035-label-names +func validateReleaseName(chartName, releaseName string) (err error) { + // Fallback to chartName if releaseName is empty + // NOTE: Similar fallback mechanism happens in src/internal/packager/helm/chart.go:InstallOrUpgradeChart + if releaseName == "" { + releaseName = chartName + } + + // Check if the final releaseName is empty and return an error if so + if releaseName == "" { + err = fmt.Errorf(errChartReleaseNameEmpty) + return + } + + // Validate the releaseName against DNS 1035 label spec + if errs := validation.IsDNS1035Label(releaseName); len(errs) > 0 { + err = fmt.Errorf("invalid release name '%s': %s", releaseName, strings.Join(errs, "; ")) + } + + return +} + // Validate runs all validation checks on a chart. func (chart ZarfChart) Validate() error { var err error @@ -277,6 +304,10 @@ func (chart ZarfChart) Validate() error { err = errors.Join(err, fmt.Errorf(lang.PkgValidateErrChartVersion, chart.Name)) } + if nameErr := validateReleaseName(chart.Name, chart.ReleaseName); nameErr != nil { + err = errors.Join(err, nameErr) + } + return err } diff --git a/src/types/validate_test.go b/src/types/validate_test.go index b0ebc60e8f..28895a8df8 100644 --- a/src/types/validate_test.go +++ b/src/types/validate_test.go @@ -186,17 +186,82 @@ func TestValidateManifest(t *testing.T) { } } +func TestValidateReleaseName(t *testing.T) { + tests := []struct { + name string + chartName string + releaseName string + expectError bool + errorSubstring string + }{ + { + name: "valid releaseName with hyphens", + chartName: "chart", + releaseName: "valid-release-hyphenated", + expectError: false, + }, + { + name: "valid releaseName with numbers", + chartName: "chart", + releaseName: "valid-0470", + expectError: false, + }, + { + name: "invalid releaseName with periods", + chartName: "chart", + releaseName: "namedwithperiods-a.b.c", + expectError: true, + errorSubstring: "invalid release name 'namedwithperiods-a.b.c'", + }, + { + name: "empty releaseName, valid chartName", + chartName: "valid-chart", + releaseName: "", + expectError: false, + }, + { + name: "empty releaseName and chartName", + chartName: "", + releaseName: "", + expectError: true, + errorSubstring: errChartReleaseNameEmpty, + }, + { + name: "empty releaseName, invalid chartName", + chartName: "invalid_chart!", + releaseName: "", + expectError: true, + errorSubstring: "invalid release name 'invalid_chart!'", + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + err := validateReleaseName(tt.chartName, tt.releaseName) + if tt.expectError { + require.Error(t, err) + require.Contains(t, err.Error(), tt.errorSubstring) + } else { + require.NoError(t, err) + } + }) + } +} + func TestValidateChart(t *testing.T) { t.Parallel() longName := strings.Repeat("a", ZarfMaxChartNameLength+1) tests := []struct { + name string chart ZarfChart expectedErrs []string - name string + partialMatch bool }{ { name: "valid", - chart: ZarfChart{Name: "chart1", Namespace: "whatever", URL: "http://whatever", Version: "v1.0.0"}, + chart: ZarfChart{Name: "chart1", Namespace: "whatever", URL: "http://whatever", Version: "v1.0.0", ReleaseName: "this-is-valid"}, expectedErrs: nil, }, { @@ -222,6 +287,22 @@ func TestValidateChart(t *testing.T) { fmt.Sprintf(lang.PkgValidateErrChartURLOrPath, "invalid"), }, }, + { + name: "invalid releaseName", + chart: ZarfChart{ReleaseName: "namedwithperiods-0.47.0", Name: "releaseName", Namespace: "whatever", URL: "http://whatever", Version: "v1.0.0"}, + expectedErrs: []string{"invalid release name 'namedwithperiods-0.47.0'"}, + partialMatch: true, + }, + { + name: "missing releaseName fallsback to name", + chart: ZarfChart{Name: "chart3", Namespace: "namespace", URL: "http://whatever", Version: "v1.0.0"}, + expectedErrs: nil, + }, + { + name: "missing name and releaseName", + chart: ZarfChart{Namespace: "namespace", URL: "http://whatever", Version: "v1.0.0"}, + expectedErrs: []string{errChartReleaseNameEmpty}, + }, } for _, tt := range tests { tt := tt @@ -232,8 +313,16 @@ func TestValidateChart(t *testing.T) { require.NoError(t, err) return } - errs := strings.Split(err.Error(), "\n") - require.ElementsMatch(t, tt.expectedErrs, errs) + require.Error(t, err) + errString := err.Error() + if tt.partialMatch { + for _, expectedErr := range tt.expectedErrs { + require.Contains(t, errString, expectedErr) + } + } else { + errs := strings.Split(errString, "\n") + require.ElementsMatch(t, tt.expectedErrs, errs) + } }) } } From 6c5e914b017a0e05c16a3afd21017640f5412581 Mon Sep 17 00:00:00 2001 From: Philip Laine Date: Wed, 31 Jul 2024 16:19:30 +0200 Subject: [PATCH 42/68] refactor: move gitea code to separate package (#2785) Signed-off-by: Philip Laine --- src/cmd/internal.go | 80 ++++-- src/cmd/tools/zarf.go | 55 ++++- src/config/config.go | 2 - src/internal/gitea/gitea.go | 195 +++++++++++++++ src/internal/gitea/gitea_test.go | 20 ++ src/internal/packager/git/gitea.go | 322 ------------------------- src/internal/packager/git/push.go | 19 -- src/pkg/cluster/pvc.go | 45 ++++ src/pkg/cluster/pvc_test.go | 63 +++++ src/pkg/packager/deploy.go | 29 ++- src/test/e2e/22_git_and_gitops_test.go | 39 ++- 11 files changed, 477 insertions(+), 392 deletions(-) create mode 100644 src/internal/gitea/gitea.go create mode 100644 src/internal/gitea/gitea_test.go delete mode 100644 src/internal/packager/git/gitea.go create mode 100644 src/pkg/cluster/pvc.go create mode 100644 src/pkg/cluster/pvc_test.go diff --git a/src/cmd/internal.go b/src/cmd/internal.go index 3d77c01190..d212445cde 100644 --- a/src/cmd/internal.go +++ b/src/cmd/internal.go @@ -21,7 +21,7 @@ import ( "github.com/zarf-dev/zarf/src/cmd/common" "github.com/zarf-dev/zarf/src/config/lang" "github.com/zarf-dev/zarf/src/internal/agent" - "github.com/zarf-dev/zarf/src/internal/packager/git" + "github.com/zarf-dev/zarf/src/internal/gitea" "github.com/zarf-dev/zarf/src/pkg/cluster" "github.com/zarf-dev/zarf/src/pkg/message" "github.com/zarf-dev/zarf/src/types" @@ -232,8 +232,29 @@ var createReadOnlyGiteaUser = &cobra.Command{ if err != nil { return err } - if err = git.New(state.GitServer).CreateReadOnlyUser(cmd.Context()); err != nil { - return fmt.Errorf("unable to create a read only user in Gitea: %w", err) + 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, state.GitServer.PushUsername, state.GitServer.PushPassword) + if err != nil { + return err + } + err = tunnel.Wrap(func() error { + err = giteaClient.CreateReadOnlyUser(cmd.Context(), state.GitServer.PullUsername, state.GitServer.PullPassword) + if err != nil { + return err + } + return nil + }) + if err != nil { + return err } return nil }, @@ -255,17 +276,37 @@ var createPackageRegistryToken = &cobra.Command{ if err != nil { return err } - if !state.ArtifactServer.InternalServer { - return nil - } - token, err := git.New(state.GitServer).CreatePackageRegistryToken(ctx) - if err != nil { - return fmt.Errorf("unable to create an artifact registry token for Gitea: %w", err) - } - state.ArtifactServer.PushToken = token.Sha1 - err = c.SaveZarfState(ctx, state) - if err != nil { - return err + + // If we are setup to use an internal artifact server, create the artifact registry token + if state.ArtifactServer.InternalServer { + 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, state.GitServer.PushUsername, state.GitServer.PushPassword) + if err != nil { + return err + } + err = tunnel.Wrap(func() error { + tokenSha1, err := giteaClient.CreatePackageRegistryToken(ctx) + if err != nil { + return fmt.Errorf("unable to create an artifact registry token for Gitea: %w", err) + } + state.ArtifactServer.PushToken = tokenSha1 + return nil + }) + if err != nil { + return err + } + if err := c.SaveZarfState(ctx, state); err != nil { + return err + } } return nil }, @@ -275,16 +316,21 @@ var updateGiteaPVC = &cobra.Command{ Use: "update-gitea-pvc", Short: lang.CmdInternalUpdateGiteaPVCShort, Long: lang.CmdInternalUpdateGiteaPVCLong, - Run: func(cmd *cobra.Command, _ []string) { + RunE: func(cmd *cobra.Command, _ []string) error { ctx := cmd.Context() + pvcName := os.Getenv("ZARF_VAR_GIT_SERVER_EXISTING_PVC") + c, err := cluster.NewCluster() + if err != nil { + return err + } // There is a possibility that the pvc does not yet exist and Gitea helm chart should create it - helmShouldCreate, err := git.UpdateGiteaPVC(ctx, rollback) + helmShouldCreate, err := c.UpdateGiteaPVC(ctx, pvcName, rollback) if err != nil { message.WarnErr(err, lang.CmdInternalUpdateGiteaPVCErr) } - fmt.Print(helmShouldCreate) + return nil }, } diff --git a/src/cmd/tools/zarf.go b/src/cmd/tools/zarf.go index 3f97be20eb..56198fe8ef 100644 --- a/src/cmd/tools/zarf.go +++ b/src/cmd/tools/zarf.go @@ -21,7 +21,7 @@ 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/packager/git" + "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" @@ -149,13 +149,31 @@ var updateCredsCmd = &cobra.Command{ // Update artifact token (if internal) if slices.Contains(args, message.ArtifactKey) && newState.ArtifactServer.PushToken == "" && newState.ArtifactServer.InternalServer { - g := git.New(oldState.GitServer) - tokenResponse, err := g.CreatePackageRegistryToken(ctx) + 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 { + 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()) - } else { - newState.ArtifactServer.PushToken = tokenResponse.Sha1 } } @@ -176,8 +194,31 @@ var updateCredsCmd = &cobra.Command{ } } if slices.Contains(args, message.GitKey) && newState.GitServer.InternalServer { - g := git.New(newState.GitServer) - err = g.UpdateZarfGiteaUsers(ctx, oldState) + 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 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()) diff --git a/src/config/config.go b/src/config/config.go index dc60ea2fd8..4a4001dce6 100644 --- a/src/config/config.go +++ b/src/config/config.go @@ -32,8 +32,6 @@ const ( // Zarf Constants for In-Cluster Services. const ( - ZarfArtifactTokenName = "zarf-artifact-registry-token" - ZarfImagePullSecretName = "private-registry" ZarfGitServerSecretName = "private-git-server" diff --git a/src/internal/gitea/gitea.go b/src/internal/gitea/gitea.go new file mode 100644 index 0000000000..94244d03f1 --- /dev/null +++ b/src/internal/gitea/gitea.go @@ -0,0 +1,195 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2021-Present The Zarf Authors + +// Package gitea contains Gitea client specific functionality. +package gitea + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "net/url" + "time" +) + +const artifactTokenName = "zarf-artifact-registry-token" + +// Client is a client that communicates with the Gitea API. +type Client struct { + httpClient *http.Client + endpoint *url.URL + username string + password string +} + +// NewClient creates and returns a new Gitea client. +func NewClient(endpoint, username, password string) (*Client, error) { + u, err := url.Parse(endpoint) + if err != nil { + return nil, err + } + transport := http.DefaultTransport.(*http.Transport).Clone() + transport.MaxIdleConnsPerHost = transport.MaxIdleConns + httpClient := &http.Client{ + Timeout: 10 * time.Second, + Transport: transport, + } + client := &Client{ + httpClient: httpClient, + endpoint: u, + username: username, + password: password, + } + return client, nil +} + +// DoRequest performs a request to the Gitea API at the given path. +func (g *Client) DoRequest(ctx context.Context, method string, path string, body []byte) ([]byte, int, error) { + u, err := g.endpoint.Parse(path) + if err != nil { + return nil, 0, err + } + req, err := http.NewRequestWithContext(ctx, method, u.String(), bytes.NewBuffer(body)) + if err != nil { + return nil, 0, err + } + req.SetBasicAuth(g.username, g.password) + req.Header.Add("accept", "application/json") + req.Header.Add("content-type", "application/json") + resp, err := g.httpClient.Do(req) + if err != nil { + return nil, 0, err + } + defer resp.Body.Close() + b, err := io.ReadAll(resp.Body) + if err != nil { + return nil, 0, err + } + return b, resp.StatusCode, nil +} + +// CreateReadOnlyUser creates a non-admin Zarf user. +func (g *Client) CreateReadOnlyUser(ctx context.Context, username, password string) error { + // Create the read only user + createUserData := map[string]interface{}{ + "username": username, + "password": password, + "email": "zarf-reader@localhost.local", + "must_change_password": false, + } + body, err := json.Marshal(createUserData) + if err != nil { + return err + } + _, statusCode, err := g.DoRequest(ctx, http.MethodPost, "/api/v1/admin/users", body) + if statusCode == 422 { + return nil + } + if err != nil { + return err + } + + // Make sure the user can't create their own repos or orgs + updateUserData := map[string]interface{}{ + "login_name": username, + "max_repo_creation": 0, + "allow_create_organization": false, + } + body, err = json.Marshal(updateUserData) + if err != nil { + return err + } + _, _, err = g.DoRequest(ctx, http.MethodPatch, fmt.Sprintf("/api/v1/admin/users/%s", username), body) + if err != nil { + return err + } + return nil +} + +// UpdateGitUser updates Zarf git server users. +func (g *Client) UpdateGitUser(ctx context.Context, username string, password string) error { + updateUserData := map[string]interface{}{ + "login_name": username, + "password": password, + } + body, err := json.Marshal(updateUserData) + if err != nil { + return err + } + _, _, err = g.DoRequest(ctx, http.MethodPatch, fmt.Sprintf("/api/v1/admin/users/%s", username), body) + if err != nil { + return err + } + return nil +} + +// CreatePackageRegistryToken creates or replaces an existing package registry token. +func (g *Client) CreatePackageRegistryToken(ctx context.Context) (string, error) { + // Determine if the package token already exists. + b, _, err := g.DoRequest(ctx, http.MethodGet, fmt.Sprintf("/api/v1/users/%s/tokens", g.username), nil) + if err != nil { + return "", err + } + var tokens []map[string]interface{} + err = json.Unmarshal(b, &tokens) + if err != nil { + return "", err + } + hasPackageToken := false + for _, token := range tokens { + if token["name"] != artifactTokenName { + continue + } + hasPackageToken = true + break + } + + // Delete the token if it already exists. + if hasPackageToken { + _, _, err := g.DoRequest(ctx, http.MethodDelete, fmt.Sprintf("/api/v1/users/%s/tokens/%s", g.username, artifactTokenName), nil) + if err != nil { + return "", err + } + } + + // Create the new token. + createTokensData := map[string]interface{}{ + "name": artifactTokenName, + "scopes": []string{"read:user", "read:package", "write:package"}, + } + body, err := json.Marshal(createTokensData) + if err != nil { + return "", err + } + b, _, err = g.DoRequest(ctx, http.MethodPost, fmt.Sprintf("/api/v1/users/%s/tokens", g.username), body) + if err != nil { + return "", err + } + createTokenResponse := struct { + Sha1 string `json:"sha1"` + }{} + err = json.Unmarshal(b, &createTokenResponse) + if err != nil { + return "", err + } + return createTokenResponse.Sha1, nil +} + +// AddReadOnlyUserToRepository adds a read only user to a repository. +func (g *Client) AddReadOnlyUserToRepository(ctx context.Context, repo, username string) error { + addCollabData := map[string]string{ + "permission": "read", + } + body, err := json.Marshal(addCollabData) + if err != nil { + return err + } + _, _, err = g.DoRequest(ctx, http.MethodPut, fmt.Sprintf("/api/v1/repos/%s/%s/collaborators/%s", g.username, repo, username), body) + if err != nil { + return err + } + return nil +} diff --git a/src/internal/gitea/gitea_test.go b/src/internal/gitea/gitea_test.go new file mode 100644 index 0000000000..984f6a7fae --- /dev/null +++ b/src/internal/gitea/gitea_test.go @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2021-Present The Zarf Authors + +package gitea + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestNewClient(t *testing.T) { + t.Parallel() + + c, err := NewClient("https://example.com", "foo", "bar") + require.NoError(t, err) + require.Equal(t, "https", c.endpoint.Scheme) + require.Equal(t, "foo", c.username) + require.Equal(t, "bar", c.password) +} diff --git a/src/internal/packager/git/gitea.go b/src/internal/packager/git/gitea.go deleted file mode 100644 index a6715d29d5..0000000000 --- a/src/internal/packager/git/gitea.go +++ /dev/null @@ -1,322 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2021-Present The Zarf Authors - -// Package git contains functions for interacting with git repositories. -package git - -import ( - "bytes" - "context" - "encoding/json" - "fmt" - "io" - netHttp "net/http" - "os" - "time" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - "github.com/zarf-dev/zarf/src/config" - "github.com/zarf-dev/zarf/src/pkg/cluster" - "github.com/zarf-dev/zarf/src/pkg/message" - "github.com/zarf-dev/zarf/src/types" -) - -// CreateTokenResponse is the response given from creating a token in Gitea -type CreateTokenResponse struct { - ID int64 `json:"id"` - Name string `json:"name"` - Sha1 string `json:"sha1"` - TokenLastEight string `json:"token_last_eight"` -} - -// CreateReadOnlyUser uses the Gitea API to create a non-admin Zarf user. -func (g *Git) CreateReadOnlyUser(ctx context.Context) error { - c, err := cluster.NewCluster() - if err != nil { - return err - } - - // Establish a git tunnel to send the repo - tunnel, err := c.NewTunnel(cluster.ZarfNamespaceName, cluster.SvcResource, cluster.ZarfGitServerName, "", 0, cluster.ZarfGitServerPort) - if err != nil { - return err - } - _, err = tunnel.Connect(ctx) - if err != nil { - return err - } - defer tunnel.Close() - - tunnelURL := tunnel.HTTPEndpoint() - - // Create json representation of the create-user request body - createUserBody := map[string]interface{}{ - "username": g.Server.PullUsername, - "password": g.Server.PullPassword, - "email": "zarf-reader@localhost.local", - "must_change_password": false, - } - createUserData, err := json.Marshal(createUserBody) - if err != nil { - return err - } - - var out []byte - var statusCode int - - // Send API request to create the user - createUserEndpoint := fmt.Sprintf("%s/api/v1/admin/users", tunnelURL) - createUserRequest, _ := netHttp.NewRequest("POST", createUserEndpoint, bytes.NewBuffer(createUserData)) - err = tunnel.Wrap(func() error { - out, statusCode, err = g.DoHTTPThings(createUserRequest, g.Server.PushUsername, g.Server.PushPassword) - return err - }) - message.Debugf("POST %s:\n%s", createUserEndpoint, string(out)) - if err != nil { - if statusCode == 422 { - message.Debugf("Read-only git user already exists. Skipping...") - return nil - } - - return err - } - - // Make sure the user can't create their own repos or orgs - updateUserBody := map[string]interface{}{ - "login_name": g.Server.PullUsername, - "max_repo_creation": 0, - "allow_create_organization": false, - } - updateUserData, _ := json.Marshal(updateUserBody) - updateUserEndpoint := fmt.Sprintf("%s/api/v1/admin/users/%s", tunnelURL, g.Server.PullUsername) - updateUserRequest, _ := netHttp.NewRequest("PATCH", updateUserEndpoint, bytes.NewBuffer(updateUserData)) - err = tunnel.Wrap(func() error { - out, _, err = g.DoHTTPThings(updateUserRequest, g.Server.PushUsername, g.Server.PushPassword) - return err - }) - message.Debugf("PATCH %s:\n%s", updateUserEndpoint, string(out)) - return err -} - -// UpdateZarfGiteaUsers updates Zarf gitea users -func (g *Git) UpdateZarfGiteaUsers(ctx context.Context, oldState *types.ZarfState) error { - //Update git read only user password - err := g.UpdateGitUser(ctx, oldState.GitServer.PushPassword, g.Server.PullUsername, g.Server.PullPassword) - if err != nil { - return fmt.Errorf("unable to update gitea read only user password: %w", err) - } - - // Update Git admin password - err = g.UpdateGitUser(ctx, oldState.GitServer.PushPassword, g.Server.PushUsername, g.Server.PushPassword) - if err != nil { - return fmt.Errorf("unable to update gitea admin user password: %w", err) - } - return nil -} - -// UpdateGitUser updates Zarf git server users -func (g *Git) UpdateGitUser(ctx context.Context, oldAdminPass string, username string, userpass string) error { - c, err := cluster.NewCluster() - if err != nil { - return err - } - // Establish a git tunnel to send the repo - tunnel, err := c.NewTunnel(cluster.ZarfNamespaceName, cluster.SvcResource, cluster.ZarfGitServerName, "", 0, cluster.ZarfGitServerPort) - if err != nil { - return err - } - _, err = tunnel.Connect(ctx) - if err != nil { - return err - } - defer tunnel.Close() - tunnelURL := tunnel.HTTPEndpoint() - - var out []byte - - // Update the existing user's password - updateUserBody := map[string]interface{}{ - "login_name": username, - "password": userpass, - } - updateUserData, _ := json.Marshal(updateUserBody) - updateUserEndpoint := fmt.Sprintf("%s/api/v1/admin/users/%s", tunnelURL, username) - updateUserRequest, _ := netHttp.NewRequest("PATCH", updateUserEndpoint, bytes.NewBuffer(updateUserData)) - err = tunnel.Wrap(func() error { - out, _, err = g.DoHTTPThings(updateUserRequest, g.Server.PushUsername, oldAdminPass) - return err - }) - message.Debugf("PATCH %s:\n%s", updateUserEndpoint, string(out)) - return err -} - -// CreatePackageRegistryToken uses the Gitea API to create a package registry token. -func (g *Git) CreatePackageRegistryToken(ctx context.Context) (CreateTokenResponse, error) { - c, err := cluster.NewCluster() - if err != nil { - return CreateTokenResponse{}, err - } - - // Establish a git tunnel to send the repo - tunnel, err := c.NewTunnel(cluster.ZarfNamespaceName, cluster.SvcResource, cluster.ZarfGitServerName, "", 0, cluster.ZarfGitServerPort) - if err != nil { - return CreateTokenResponse{}, err - } - _, err = tunnel.Connect(ctx) - if err != nil { - return CreateTokenResponse{}, err - } - defer tunnel.Close() - - tunnelURL := tunnel.Endpoint() - - var out []byte - - // Determine if the package token already exists - getTokensEndpoint := fmt.Sprintf("http://%s/api/v1/users/%s/tokens", tunnelURL, g.Server.PushUsername) - getTokensRequest, _ := netHttp.NewRequest("GET", getTokensEndpoint, nil) - err = tunnel.Wrap(func() error { - out, _, err = g.DoHTTPThings(getTokensRequest, g.Server.PushUsername, g.Server.PushPassword) - return err - }) - message.Debugf("GET %s:\n%s", getTokensEndpoint, string(out)) - if err != nil { - return CreateTokenResponse{}, err - } - - hasPackageToken := false - var tokens []map[string]interface{} - err = json.Unmarshal(out, &tokens) - if err != nil { - return CreateTokenResponse{}, err - } - - for _, token := range tokens { - if token["name"] == config.ZarfArtifactTokenName { - hasPackageToken = true - } - } - - if hasPackageToken { - // Delete the existing token to be replaced - deleteTokensEndpoint := fmt.Sprintf("http://%s/api/v1/users/%s/tokens/%s", tunnelURL, g.Server.PushUsername, config.ZarfArtifactTokenName) - deleteTokensRequest, _ := netHttp.NewRequest("DELETE", deleteTokensEndpoint, nil) - err = tunnel.Wrap(func() error { - out, _, err = g.DoHTTPThings(deleteTokensRequest, g.Server.PushUsername, g.Server.PushPassword) - return err - }) - message.Debugf("DELETE %s:\n%s", deleteTokensEndpoint, string(out)) - if err != nil { - return CreateTokenResponse{}, err - } - } - - createTokensEndpoint := fmt.Sprintf("http://%s/api/v1/users/%s/tokens", tunnelURL, g.Server.PushUsername) - createTokensBody := map[string]interface{}{ - "name": config.ZarfArtifactTokenName, - "scopes": []string{"read:user", "read:package", "write:package"}, - } - createTokensData, _ := json.Marshal(createTokensBody) - createTokensRequest, _ := netHttp.NewRequest("POST", createTokensEndpoint, bytes.NewBuffer(createTokensData)) - err = tunnel.Wrap(func() error { - out, _, err = g.DoHTTPThings(createTokensRequest, g.Server.PushUsername, g.Server.PushPassword) - return err - }) - message.Debugf("POST %s:\n%s", createTokensEndpoint, string(out)) - if err != nil { - return CreateTokenResponse{}, err - } - - createTokenResponse := CreateTokenResponse{} - err = json.Unmarshal(out, &createTokenResponse) - if err != nil { - return CreateTokenResponse{}, err - } - - return createTokenResponse, nil -} - -// UpdateGiteaPVC updates the existing Gitea persistent volume claim and tells Gitea whether to create or not. -func UpdateGiteaPVC(ctx context.Context, shouldRollBack bool) (string, error) { - c, err := cluster.NewCluster() - if err != nil { - return "false", err - } - - pvcName := os.Getenv("ZARF_VAR_GIT_SERVER_EXISTING_PVC") - - if shouldRollBack { - pvc, err := c.Clientset.CoreV1().PersistentVolumeClaims(cluster.ZarfNamespaceName).Get(ctx, pvcName, metav1.GetOptions{}) - if err != nil { - return "false", err - } - delete(pvc.Labels, "app.kubernetes.io/managed-by") - delete(pvc.Annotations, "meta.helm.sh/release-name") - delete(pvc.Annotations, "meta.helm.sh/release-namespace") - _, err = c.Clientset.CoreV1().PersistentVolumeClaims(cluster.ZarfNamespaceName).Update(ctx, pvc, metav1.UpdateOptions{}) - if err != nil { - return "false", err - } - return "false", nil - } - - if pvcName == "data-zarf-gitea-0" { - pvc, err := c.Clientset.CoreV1().PersistentVolumeClaims(cluster.ZarfNamespaceName).Get(ctx, pvcName, metav1.GetOptions{}) - if err != nil { - return "true", err - } - pvc.Labels["app.kubernetes.io/managed-by"] = "Helm" - pvc.Annotations["meta.helm.sh/release-name"] = "zarf-gitea" - pvc.Annotations["meta.helm.sh/release-namespace"] = "zarf" - _, err = c.Clientset.CoreV1().PersistentVolumeClaims(cluster.ZarfNamespaceName).Update(ctx, pvc, metav1.UpdateOptions{}) - if err != nil { - return "true", err - } - return "true", nil - } - - return "false", nil -} - -// DoHTTPThings adds http request boilerplate and perform the request, checking for a successful response. -func (g *Git) DoHTTPThings(request *netHttp.Request, username, secret string) ([]byte, int, error) { - // Prep the request with boilerplate - client := &netHttp.Client{Timeout: time.Second * 20} - request.SetBasicAuth(username, secret) - request.Header.Add("accept", "application/json") - request.Header.Add("Content-Type", "application/json") - - // Perform the request and get the response - response, err := client.Do(request) - if err != nil { - return []byte{}, 0, err - } - responseBody, _ := io.ReadAll(response.Body) - - // If we get a 'bad' status code we will have no error, create a useful one to return - if response.StatusCode < 200 || response.StatusCode >= 300 { - err = fmt.Errorf("got status code of %d during http request with body of: %s", response.StatusCode, string(responseBody)) - return []byte{}, response.StatusCode, err - } - - return responseBody, response.StatusCode, nil -} - -func (g *Git) addReadOnlyUserToRepo(tunnelURL, repo string) error { - // Add the readonly user to the repo - addCollabBody := map[string]string{ - "permission": "read", - } - addCollabData, err := json.Marshal(addCollabBody) - if err != nil { - return err - } - - // Send API request to add a user as a read-only collaborator to a repo - addCollabEndpoint := fmt.Sprintf("%s/api/v1/repos/%s/%s/collaborators/%s", tunnelURL, g.Server.PushUsername, repo, g.Server.PullUsername) - addCollabRequest, _ := netHttp.NewRequest("PUT", addCollabEndpoint, bytes.NewBuffer(addCollabData)) - out, _, err := g.DoHTTPThings(addCollabRequest, g.Server.PushUsername, g.Server.PushPassword) - message.Debugf("PUT %s:\n%s", addCollabEndpoint, string(out)) - return err -} diff --git a/src/internal/packager/git/push.go b/src/internal/packager/git/push.go index 98236d2316..60b7b2bdf6 100644 --- a/src/internal/packager/git/push.go +++ b/src/internal/packager/git/push.go @@ -52,25 +52,6 @@ func (g *Git) PushRepo(srcURL, targetFolder string) error { return fmt.Errorf("failed to push the git repo %q: %w", repoFolder, err) } - // Add the read-only user to this repo - if g.Server.InternalServer { - // Get the upstream URL - remote, err := repo.Remote(onlineRemoteName) - if err != nil { - message.Warn("unable to get the information needed to add the read-only user to the repo") - return err - } - remoteURL := remote.Config().URLs[0] - repoName, err := transform.GitURLtoRepoName(remoteURL) - if err != nil { - return err - } - err = g.addReadOnlyUserToRepo(g.Server.Address, repoName) - if err != nil { - return fmt.Errorf("unable to add the read only user to the repo %s: %w", repoName, err) - } - } - spinner.Success() return nil } diff --git a/src/pkg/cluster/pvc.go b/src/pkg/cluster/pvc.go new file mode 100644 index 0000000000..21a0a45ecf --- /dev/null +++ b/src/pkg/cluster/pvc.go @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2021-Present The Zarf Authors + +package cluster + +import ( + "context" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// UpdateGiteaPVC updates the existing Gitea persistent volume claim and tells Gitea whether to create or not. +func (c *Cluster) UpdateGiteaPVC(ctx context.Context, pvcName string, shouldRollBack bool) (string, error) { + if shouldRollBack { + pvc, err := c.Clientset.CoreV1().PersistentVolumeClaims(ZarfNamespaceName).Get(ctx, pvcName, metav1.GetOptions{}) + if err != nil { + return "false", err + } + delete(pvc.Labels, "app.kubernetes.io/managed-by") + delete(pvc.Annotations, "meta.helm.sh/release-name") + delete(pvc.Annotations, "meta.helm.sh/release-namespace") + _, err = c.Clientset.CoreV1().PersistentVolumeClaims(ZarfNamespaceName).Update(ctx, pvc, metav1.UpdateOptions{}) + if err != nil { + return "false", err + } + return "false", nil + } + + if pvcName == "data-zarf-gitea-0" { + pvc, err := c.Clientset.CoreV1().PersistentVolumeClaims(ZarfNamespaceName).Get(ctx, pvcName, metav1.GetOptions{}) + if err != nil { + return "true", err + } + pvc.Labels["app.kubernetes.io/managed-by"] = "Helm" + pvc.Annotations["meta.helm.sh/release-name"] = "zarf-gitea" + pvc.Annotations["meta.helm.sh/release-namespace"] = "zarf" + _, err = c.Clientset.CoreV1().PersistentVolumeClaims(ZarfNamespaceName).Update(ctx, pvc, metav1.UpdateOptions{}) + if err != nil { + return "true", err + } + return "true", nil + } + + return "false", nil +} diff --git a/src/pkg/cluster/pvc_test.go b/src/pkg/cluster/pvc_test.go new file mode 100644 index 0000000000..6c267d1500 --- /dev/null +++ b/src/pkg/cluster/pvc_test.go @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2021-Present The Zarf Authors + +package cluster + +import ( + "testing" + + "github.com/stretchr/testify/require" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes/fake" + + "github.com/zarf-dev/zarf/src/test/testutil" +) + +func TestUpdateGiteaPVC(t *testing.T) { + t.Parallel() + + ctx := testutil.TestContext(t) + c := &Cluster{ + Clientset: fake.NewSimpleClientset(), + } + pvc := &corev1.PersistentVolumeClaim{ + ObjectMeta: metav1.ObjectMeta{ + Name: "data-zarf-gitea-0", + Labels: map[string]string{}, + Annotations: map[string]string{}, + }, + } + _, err := c.Clientset.CoreV1().PersistentVolumeClaims(ZarfNamespaceName).Create(ctx, pvc, metav1.CreateOptions{}) + require.NoError(t, err) + + v, err := c.UpdateGiteaPVC(ctx, "foobar", false) + require.NoError(t, err) + require.Equal(t, "false", v) + + v, err = c.UpdateGiteaPVC(ctx, "foobar", true) + require.EqualError(t, err, "persistentvolumeclaims \"foobar\" not found") + require.Equal(t, "false", v) + + v, err = c.UpdateGiteaPVC(ctx, "data-zarf-gitea-0", true) + require.NoError(t, err) + require.Equal(t, "false", v) + + v, err = c.UpdateGiteaPVC(ctx, "data-zarf-gitea-0", false) + require.NoError(t, err) + require.Equal(t, "true", v) + pvc, err = c.Clientset.CoreV1().PersistentVolumeClaims(ZarfNamespaceName).Get(ctx, "data-zarf-gitea-0", metav1.GetOptions{}) + require.NoError(t, err) + require.Equal(t, "Helm", pvc.Labels["app.kubernetes.io/managed-by"]) + require.Equal(t, "zarf-gitea", pvc.Annotations["meta.helm.sh/release-name"]) + require.Equal(t, "zarf", pvc.Annotations["meta.helm.sh/release-namespace"]) + + v, err = c.UpdateGiteaPVC(ctx, "data-zarf-gitea-0", true) + require.NoError(t, err) + require.Equal(t, "false", v) + pvc, err = c.Clientset.CoreV1().PersistentVolumeClaims(ZarfNamespaceName).Get(ctx, "data-zarf-gitea-0", metav1.GetOptions{}) + require.NoError(t, err) + require.Empty(t, pvc.Labels["app.kubernetes.io/managed-by"]) + require.Empty(t, pvc.Labels["meta.helm.sh/release-name"]) + require.Empty(t, pvc.Labels["meta.helm.sh/release-namespace"]) +} diff --git a/src/pkg/packager/deploy.go b/src/pkg/packager/deploy.go index 2f7304580b..428f2e1726 100644 --- a/src/pkg/packager/deploy.go +++ b/src/pkg/packager/deploy.go @@ -25,6 +25,7 @@ import ( "github.com/defenseunicorns/pkg/helpers/v2" "github.com/zarf-dev/zarf/src/config" + "github.com/zarf-dev/zarf/src/internal/gitea" "github.com/zarf-dev/zarf/src/internal/packager/git" "github.com/zarf-dev/zarf/src/internal/packager/helm" "github.com/zarf-dev/zarf/src/internal/packager/images" @@ -546,8 +547,7 @@ func (p *Packager) pushReposToRepository(ctx context.Context, reposPath string, for _, repoURL := range repos { // Create an anonymous function to push the repo to the Zarf git server tryPush := func() error { - gitClient := git.New(p.state.GitServer) - namespace, name, port, err := serviceInfoFromServiceURL(gitClient.Server.Address) + namespace, name, port, err := serviceInfoFromServiceURL(p.state.GitServer.Address) // If this is a service (svcInfo is not nil), create a port-forward tunnel to that resource // TODO: Find a better way as ignoring the error is not a good solution to decide to port forward. @@ -565,17 +565,37 @@ func (p *Packager) pushReposToRepository(ctx context.Context, reposPath string, if err != nil { return err } - _, err = tunnel.Connect(ctx) if err != nil { return err } defer tunnel.Close() + gitClient := git.New(p.state.GitServer) gitClient.Server.Address = tunnel.HTTPEndpoint() + giteaClient, err := gitea.NewClient(tunnel.HTTPEndpoint(), p.state.GitServer.PushUsername, p.state.GitServer.PushPassword) + if err != nil { + return err + } + return tunnel.Wrap(func() error { + err = gitClient.PushRepo(repoURL, reposPath) + if err != nil { + return err + } - return tunnel.Wrap(func() error { return gitClient.PushRepo(repoURL, reposPath) }) + // Add the read-only user to this repo + repoName, err := transform.GitURLtoRepoName(repoURL) + if err != nil { + return err + } + err = giteaClient.AddReadOnlyUserToRepository(ctx, repoName, p.state.GitServer.PullUsername) + if err != nil { + return fmt.Errorf("unable to add the read only user to the repo %s: %w", repoName, err) + } + return nil + }) } + gitClient := git.New(p.state.GitServer) return gitClient.PushRepo(repoURL, reposPath) } @@ -584,7 +604,6 @@ func (p *Packager) pushReposToRepository(ctx context.Context, reposPath string, return fmt.Errorf("unable to push repo %s to the Git Server: %w", repoURL, err) } } - return nil } diff --git a/src/test/e2e/22_git_and_gitops_test.go b/src/test/e2e/22_git_and_gitops_test.go index 9394354e2c..901137125b 100644 --- a/src/test/e2e/22_git_and_gitops_test.go +++ b/src/test/e2e/22_git_and_gitops_test.go @@ -14,7 +14,7 @@ import ( "testing" "github.com/stretchr/testify/require" - "github.com/zarf-dev/zarf/src/internal/packager/git" + "github.com/zarf-dev/zarf/src/internal/gitea" "github.com/zarf-dev/zarf/src/pkg/cluster" "github.com/zarf-dev/zarf/src/types" ) @@ -71,20 +71,20 @@ func testGitServerReadOnly(ctx context.Context, t *testing.T, gitURL string) { require.NoError(t, err) // Init the state variable - zarfState, err := c.LoadZarfState(ctx) + state, err := c.LoadZarfState(ctx) require.NoError(t, err) - - gitCfg := git.New(zarfState.GitServer) + giteaClient, err := gitea.NewClient(gitURL, types.ZarfGitReadUser, state.GitServer.PullPassword) + require.NoError(t, err) + repoName := "zarf-public-test-2363058019" // Get the repo as the readonly user - repoName := "zarf-public-test-2363058019" - getRepoRequest, _ := http.NewRequest("GET", fmt.Sprintf("%s/api/v1/repos/%s/%s", gitURL, zarfState.GitServer.PushUsername, repoName), nil) - getRepoResponseBody, _, err := gitCfg.DoHTTPThings(getRepoRequest, types.ZarfGitReadUser, zarfState.GitServer.PullPassword) + b, statusCode, err := giteaClient.DoRequest(ctx, http.MethodGet, fmt.Sprintf("/api/v1/repos/%s/%s", state.GitServer.PushUsername, repoName), nil) require.NoError(t, err) + require.Equal(t, http.StatusOK, statusCode) // Make sure the only permissions are pull (read) var bodyMap map[string]interface{} - err = json.Unmarshal(getRepoResponseBody, &bodyMap) + err = json.Unmarshal(b, &bodyMap) require.NoError(t, err) permissionsMap, ok := bodyMap["permissions"].(map[string]interface{}) require.True(t, ok, "permissions key is not of right type") @@ -100,30 +100,29 @@ func testGitServerTagAndHash(ctx context.Context, t *testing.T, gitURL string) { require.NoError(t, err) // Init the state variable - zarfState, err := c.LoadZarfState(ctx) + state, err := c.LoadZarfState(ctx) require.NoError(t, err, "Failed to load Zarf state") + giteaClient, err := gitea.NewClient(gitURL, types.ZarfGitReadUser, state.GitServer.PullPassword) + require.NoError(t, err) repoName := "zarf-public-test-2363058019" - gitCfg := git.New(zarfState.GitServer) - - // Get the Zarf repo tag + // Make sure the pushed tag exists repoTag := "v0.0.1" - getRepoTagsRequest, _ := http.NewRequest("GET", fmt.Sprintf("%s/api/v1/repos/%s/%s/tags/%s", gitURL, types.ZarfGitPushUser, repoName, repoTag), nil) - getRepoTagsResponseBody, _, err := gitCfg.DoHTTPThings(getRepoTagsRequest, types.ZarfGitReadUser, zarfState.GitServer.PullPassword) + b, statusCode, err := giteaClient.DoRequest(ctx, http.MethodGet, fmt.Sprintf("/api/v1/repos/%s/%s/tags/%s", types.ZarfGitPushUser, repoName, repoTag), nil) require.NoError(t, err) - - // Make sure the pushed tag exists + require.Equal(t, http.StatusOK, statusCode) var tagMap map[string]interface{} - err = json.Unmarshal(getRepoTagsResponseBody, &tagMap) + err = json.Unmarshal(b, &tagMap) require.NoError(t, err) require.Equal(t, repoTag, tagMap["name"]) // Get the Zarf repo commit repoHash := "01a23218923f24194133b5eb11268cf8d73ff1bb" - getRepoCommitsRequest, _ := http.NewRequest("GET", fmt.Sprintf("%s/api/v1/repos/%s/%s/git/commits/%s", gitURL, types.ZarfGitPushUser, repoName, repoHash), nil) - getRepoCommitsResponseBody, _, err := gitCfg.DoHTTPThings(getRepoCommitsRequest, types.ZarfGitReadUser, zarfState.GitServer.PullPassword) + b, statusCode, err = giteaClient.DoRequest(ctx, http.MethodGet, fmt.Sprintf("/api/v1/repos/%s/%s/git/commits/%s", types.ZarfGitPushUser, repoName, repoHash), nil) + require.NoError(t, err) + require.Equal(t, http.StatusOK, statusCode) require.NoError(t, err) - require.Contains(t, string(getRepoCommitsResponseBody), repoHash) + require.Contains(t, string(b), repoHash) } func waitFluxPodInfoDeployment(t *testing.T) { From 347a09454638abcec357d4b484773c6df69d8a81 Mon Sep 17 00:00:00 2001 From: Austin Abro <37223396+AustinAbro321@users.noreply.github.com> Date: Wed, 31 Jul 2024 10:31:38 -0400 Subject: [PATCH 43/68] fix: add dependabot and disable renovate features (#2789) Signed-off-by: Austin Abro --- .github/dependabot.yaml | 18 ++++++++++++++++++ renovate.json | 41 ++--------------------------------------- 2 files changed, 20 insertions(+), 39 deletions(-) create mode 100644 .github/dependabot.yaml diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml new file mode 100644 index 0000000000..7465f35a07 --- /dev/null +++ b/.github/dependabot.yaml @@ -0,0 +1,18 @@ +version: 2 +updates: + - package-ecosystem: gomod + directory: / + schedule: + interval: daily + - package-ecosystem: github-actions + directory: / + schedule: + interval: daily + - package-ecosystem: npm + directory: / + schedule: + interval: daily + - package-ecosystem: cargo + directory: / + schedule: + interval: daily diff --git a/renovate.json b/renovate.json index 91e8dd55b0..40b519c928 100644 --- a/renovate.json +++ b/renovate.json @@ -3,41 +3,14 @@ "config:base", "group:allNonMajor" ], - "ignoreDeps": [ - "sigs.k8s.io/kustomize/kyaml" - ], - "ignorePaths": [ - "**/node_modules/**", - "**/bower_components/**", - "**/vendor/**", - "**/__tests__/**", - "**/test/**", - "**/tests/**", - "**/__fixtures__/**" - ], "packageRules": [ { - "matchUpdateTypes": [ - "patch", - "pin", - "digest" - ], - "automerge": true, - "automergeType": "pr" - }, - { - "matchDepTypes": [ - "devDependencies" - ], - "automerge": true, - "automergeType": "pr" + "matchManagers": ["gomod","npm","github-actions", "cargo"], + "enabled": false } ], "platformAutomerge": true, "platformCommit": true, - "postUpdateOptions": [ - "gomodTidy" - ], "regexManagers": [ { "fileMatch": [ @@ -82,16 +55,6 @@ "https:\\/\\/github.com\\/(?[\\w\\/\\-\\.\\+\\%]+?)\\/releases\\/download\\/(?[\\w\\/\\-\\.\\+\\%]+?)\\/" ], "datasourceTemplate": "github-releases" - }, - { - "fileMatch": [ - "\\.*\\.ya?ml$" - ], - "matchStrings": [ - "# renovate: datasource=github-tags depName=anchore/grype versioning=semver\n\\s*VERSION: (?v[\\d.]+)" - ], - "datasourceTemplate": "github-tags", - "depNameTemplate": "anchore/grype" } ] } From b31e3178370174b64e5b36b6f24f0f25b5516ddb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 31 Jul 2024 15:18:34 +0000 Subject: [PATCH 44/68] chore(deps): bump github/codeql-action from 3.24.0 to 3.25.15 (#2792) 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 dd72737ab2..b410931356 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@e8893c57a1f3a2b659b6b55564fdfdbbd2982911 # v3.24.0 + uses: github/codeql-action/init@afb54ba388a7dca6ecae48f608c4ff05ff4cc77a # v3.25.15 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@e8893c57a1f3a2b659b6b55564fdfdbbd2982911 # v3.24.0 + uses: github/codeql-action/analyze@afb54ba388a7dca6ecae48f608c4ff05ff4cc77a # v3.25.15 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/scorecard.yaml b/.github/workflows/scorecard.yaml index f98ea7bdd1..4d2c24cf50 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@e8893c57a1f3a2b659b6b55564fdfdbbd2982911 # v3.24.0 + uses: github/codeql-action/upload-sarif@afb54ba388a7dca6ecae48f608c4ff05ff4cc77a # v3.25.15 with: sarif_file: results.sarif From 410849ddbc62cf80ac7dc2845aca73dca626b613 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 31 Jul 2024 15:18:47 +0000 Subject: [PATCH 45/68] chore(deps): bump actions/upload-artifact from 4.3.1 to 4.3.4 (#2791) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 4 ++-- .github/workflows/scorecard.yaml | 2 +- .github/workflows/test-bigbang.yml | 2 +- .github/workflows/test-e2e.yml | 2 +- .github/workflows/test-upgrade.yml | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 00dda8debb..c9f6bb6724 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -72,7 +72,7 @@ jobs: # Upload the contents of the build directory for later stages to use - name: Upload build artifacts - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 + uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4 with: name: build-artifacts path: build/ @@ -186,7 +186,7 @@ jobs: HOMEBREW_TAP_GITHUB_TOKEN: ${{ steps.brew-tap-token.outputs.token }} - name: Save CVE report - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 + uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4 with: name: cve-report path: build/zarf-known-cves.csv diff --git a/.github/workflows/scorecard.yaml b/.github/workflows/scorecard.yaml index 4d2c24cf50..e776460573 100644 --- a/.github/workflows/scorecard.yaml +++ b/.github/workflows/scorecard.yaml @@ -36,7 +36,7 @@ jobs: # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF # format to the repository Actions tab. - name: "Upload artifact" - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 + uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4 with: name: SARIF file path: results.sarif diff --git a/.github/workflows/test-bigbang.yml b/.github/workflows/test-bigbang.yml index 1dd568bb26..c7f7b62efe 100644 --- a/.github/workflows/test-bigbang.yml +++ b/.github/workflows/test-bigbang.yml @@ -63,7 +63,7 @@ jobs: # Upload the contents of the build directory for later stages to use - name: Upload build artifacts - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 + uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4 with: name: build-artifacts path: build/ diff --git a/.github/workflows/test-e2e.yml b/.github/workflows/test-e2e.yml index 7a689ba7c0..e6026420b4 100644 --- a/.github/workflows/test-e2e.yml +++ b/.github/workflows/test-e2e.yml @@ -47,7 +47,7 @@ jobs: # Upload the contents of the build directory for later stages to use - name: Upload build artifacts - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 + uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4 with: name: build-artifacts path: build/ diff --git a/.github/workflows/test-upgrade.yml b/.github/workflows/test-upgrade.yml index 552d79e103..17179ff9ad 100644 --- a/.github/workflows/test-upgrade.yml +++ b/.github/workflows/test-upgrade.yml @@ -46,7 +46,7 @@ jobs: # Upload the contents of the build directory for later stages to use - name: Upload build artifacts - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 + uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4.3.4 with: name: build-artifacts path: build/ From 053fb3557617f3d3948a94335e86ded9777cd011 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 31 Jul 2024 15:19:10 +0000 Subject: [PATCH 46/68] chore(deps): bump docker/login-action from 3.0.0 to 3.3.0 (#2794) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/publish-application-packages.yml | 2 +- .github/workflows/release.yml | 2 +- .github/workflows/test-bigbang.yml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/publish-application-packages.yml b/.github/workflows/publish-application-packages.yml index 59be8e3ff3..d075c7cecf 100644 --- a/.github/workflows/publish-application-packages.yml +++ b/.github/workflows/publish-application-packages.yml @@ -26,7 +26,7 @@ jobs: uses: defenseunicorns/setup-zarf@10e539efed02f75ec39eb8823e22a5c795f492ae #v1.0.1 - name: "Login to GHCR" - uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0 + uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 with: registry: ghcr.io username: dummy diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c9f6bb6724..b3460ed000 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -32,7 +32,7 @@ jobs: make build-cli-linux-arm - name: "Zarf Agent: Login to GHCR" - uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0 + uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 with: registry: ghcr.io username: dummy diff --git a/.github/workflows/test-bigbang.yml b/.github/workflows/test-bigbang.yml index c7f7b62efe..1b5d47bb7f 100644 --- a/.github/workflows/test-bigbang.yml +++ b/.github/workflows/test-bigbang.yml @@ -46,7 +46,7 @@ jobs: build-examples: "false" - name: Login to Iron Bank - uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0 + uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 if: ${{ env.IRON_BANK_ROBOT_USERNAME != '' }} env: IRON_BANK_ROBOT_USERNAME: ${{ secrets.IRON_BANK_ROBOT_USERNAME }} @@ -97,7 +97,7 @@ jobs: uses: ./.github/actions/k3d - name: Login to Iron Bank - uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0 + uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 if: ${{ env.IRON_BANK_ROBOT_USERNAME != '' }} env: IRON_BANK_ROBOT_USERNAME: ${{ secrets.IRON_BANK_ROBOT_USERNAME }} From 49b0e72a5e190c4f1ea6de448e796e8dcfa3a58a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 31 Jul 2024 15:19:34 +0000 Subject: [PATCH 47/68] chore(deps): bump golangci/golangci-lint-action from 6.0.1 to 6.1.0 (#2793) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/scan-lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scan-lint.yml b/.github/workflows/scan-lint.yml index d72450d66e..66eab288a7 100644 --- a/.github/workflows/scan-lint.yml +++ b/.github/workflows/scan-lint.yml @@ -13,4 +13,4 @@ jobs: - name: Checkout uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Run golangci-lint - uses: golangci/golangci-lint-action@a4f60bb28d35aeee14e6880718e0c85ff1882e64 # v6.0.1 + uses: golangci/golangci-lint-action@aaa42aa0628b4ae2578232a66b541047968fac86 # v6.1.0 From 40a05a099413c1096dd871fffa491467c98e3608 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 31 Jul 2024 16:07:38 +0000 Subject: [PATCH 48/68] chore(deps): bump ossf/scorecard-action from 2.3.1 to 2.4.0 (#2795) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/scorecard.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecard.yaml b/.github/workflows/scorecard.yaml index e776460573..e53c293383 100644 --- a/.github/workflows/scorecard.yaml +++ b/.github/workflows/scorecard.yaml @@ -27,7 +27,7 @@ jobs: persist-credentials: false - name: "Run analysis" - uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1 + uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0 with: results_file: results.sarif results_format: sarif From 4a1f32e6caf6611cdc257273d7537092026fe8d6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 31 Jul 2024 12:47:07 -0400 Subject: [PATCH 49/68] chore(deps): bump k8s.io/component-base from 0.30.0 to 0.30.3 (#2798) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 8 ++++---- go.sum | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index db29e4a620..eebb5ea6b7 100644 --- a/go.mod +++ b/go.mod @@ -49,10 +49,10 @@ require ( golang.org/x/sync v0.7.0 golang.org/x/term v0.22.0 helm.sh/helm/v3 v3.14.2 - k8s.io/api v0.30.0 - k8s.io/apimachinery v0.30.0 - k8s.io/client-go v0.30.0 - k8s.io/component-base v0.30.0 + k8s.io/api v0.30.3 + k8s.io/apimachinery v0.30.3 + k8s.io/client-go v0.30.3 + k8s.io/component-base v0.30.3 k8s.io/klog/v2 v2.120.1 k8s.io/kubectl v0.29.1 oras.land/oras-go/v2 v2.5.0 diff --git a/go.sum b/go.sum index 23759f5ede..006c9add9a 100644 --- a/go.sum +++ b/go.sum @@ -2458,20 +2458,20 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.30.0 h1:siWhRq7cNjy2iHssOB9SCGNCl2spiF1dO3dABqZ8niA= -k8s.io/api v0.30.0/go.mod h1:OPlaYhoHs8EQ1ql0R/TsUgaRPhpKNxIMrKQfWUp8QSE= +k8s.io/api v0.30.3 h1:ImHwK9DCsPA9uoU3rVh4QHAHHK5dTSv1nxJUapx8hoQ= +k8s.io/api v0.30.3/go.mod h1:GPc8jlzoe5JG3pb0KJCSLX5oAFIW3/qNJITlDj8BH04= k8s.io/apiextensions-apiserver v0.30.0 h1:jcZFKMqnICJfRxTgnC4E+Hpcq8UEhT8B2lhBcQ+6uAs= k8s.io/apiextensions-apiserver v0.30.0/go.mod h1:N9ogQFGcrbWqAY9p2mUAL5mGxsLqwgtUce127VtRX5Y= -k8s.io/apimachinery v0.30.0 h1:qxVPsyDM5XS96NIh9Oj6LavoVFYff/Pon9cZeDIkHHA= -k8s.io/apimachinery v0.30.0/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc= +k8s.io/apimachinery v0.30.3 h1:q1laaWCmrszyQuSQCfNB8cFgCuDAoPszKY4ucAjDwHc= +k8s.io/apimachinery v0.30.3/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc= k8s.io/apiserver v0.30.0 h1:QCec+U72tMQ+9tR6A0sMBB5Vh6ImCEkoKkTDRABWq6M= k8s.io/apiserver v0.30.0/go.mod h1:smOIBq8t0MbKZi7O7SyIpjPsiKJ8qa+llcFCluKyqiY= k8s.io/cli-runtime v0.29.1 h1:By3WVOlEWYfyxhGko0f/IuAOLQcbBSMzwSaDren2JUs= k8s.io/cli-runtime v0.29.1/go.mod h1:vjEY9slFp8j8UoMhV5AlO8uulX9xk6ogfIesHobyBDU= -k8s.io/client-go v0.30.0 h1:sB1AGGlhY/o7KCyCEQ0bPWzYDL0pwOZO4vAtTSh/gJQ= -k8s.io/client-go v0.30.0/go.mod h1:g7li5O5256qe6TYdAMyX/otJqMhIiGgTapdLchhmOaY= -k8s.io/component-base v0.30.0 h1:cj6bp38g0ainlfYtaOQuRELh5KSYjhKxM+io7AUIk4o= -k8s.io/component-base v0.30.0/go.mod h1:V9x/0ePFNaKeKYA3bOvIbrNoluTSG+fSJKjLdjOoeXQ= +k8s.io/client-go v0.30.3 h1:bHrJu3xQZNXIi8/MoxYtZBBWQQXwy16zqJwloXXfD3k= +k8s.io/client-go v0.30.3/go.mod h1:8d4pf8vYu665/kUbsxWAQ/JDBNWqfFeZnvFiVdmx89U= +k8s.io/component-base v0.30.3 h1:Ci0UqKWf4oiwy8hr1+E3dsnliKnkMLZMVbWzeorlk7s= +k8s.io/component-base v0.30.3/go.mod h1:C1SshT3rGPCuNtBs14RmVD2xW0EhRSeLvBh7AGk1quA= k8s.io/component-helpers v0.29.1 h1:54MMEDu6xeJmMtAKztsPwu0kJKr4+jCUzaEIn2UXRoc= k8s.io/component-helpers v0.29.1/go.mod h1:+I7xz4kfUgxWAPJIVKrqe4ml4rb9UGpazlOmhXYo+cY= k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= From 7a5fb9ee0314adc3ade0f320699bb85c2e09b0be Mon Sep 17 00:00:00 2001 From: Austin Abro <37223396+AustinAbro321@users.noreply.github.com> Date: Wed, 31 Jul 2024 13:58:32 -0400 Subject: [PATCH 50/68] ci: remove unneeded cve checking (#2802) Signed-off-by: Austin Abro --- .github/actions/install-tools/action.yaml | 7 ---- .github/workflows/compare-cves.yml | 39 ----------------------- .github/workflows/scan-cves.yml | 24 -------------- .grype.yaml | 4 --- hack/check-vulnerabilities.sh | 30 ----------------- 5 files changed, 104 deletions(-) delete mode 100644 .github/workflows/compare-cves.yml delete mode 100644 .github/workflows/scan-cves.yml delete mode 100644 .grype.yaml delete mode 100755 hack/check-vulnerabilities.sh diff --git a/.github/actions/install-tools/action.yaml b/.github/actions/install-tools/action.yaml index e8e052b640..92372d73b8 100644 --- a/.github/actions/install-tools/action.yaml +++ b/.github/actions/install-tools/action.yaml @@ -8,11 +8,4 @@ runs: - uses: anchore/sbom-action/download-syft@b6a39da80722a2cb0ef5d197531764a89b5d48c3 # v0.15.8 - - name: install grype - env: - # renovate: datasource=github-tags depName=anchore/grype versioning=semver - VERSION: v0.74.6 - run: "curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin $VERSION" - shell: bash - - uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0 diff --git a/.github/workflows/compare-cves.yml b/.github/workflows/compare-cves.yml deleted file mode 100644 index dce4118ba5..0000000000 --- a/.github/workflows/compare-cves.yml +++ /dev/null @@ -1,39 +0,0 @@ -name: Compare CVEs to main - -permissions: - contents: read - -on: - pull_request: - paths: - - "go.mod" - - "go.sum" - - "cargo.toml" - - "cargo.lock" - merge_group: - paths: - - "go.mod" - - "go.sum" - - "cargo.toml" - - "cargo.lock" - -jobs: - validate: - runs-on: ubuntu-latest - steps: - - name: Checkout repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - with: - ref: ${{ github.head_ref || github.ref_name }} - - - name: fetch main - run: git fetch origin main --depth 1 - - - name: Setup golang - uses: ./.github/actions/golang - - - name: Install tools - uses: ./.github/actions/install-tools - - - name: Check for CVEs in Dependencies - run: "hack/check-vulnerabilities.sh" diff --git a/.github/workflows/scan-cves.yml b/.github/workflows/scan-cves.yml deleted file mode 100644 index 2851849bf7..0000000000 --- a/.github/workflows/scan-cves.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: Analyze CVEs - -permissions: - contents: read - -on: - schedule: - - cron: "0 10 * * *" - -jobs: - validate: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Setup golang - uses: ./.github/actions/golang - - - name: Install tools - uses: ./.github/actions/install-tools - - - name: Check for CVEs in Dependencies - run: "make test-cves" diff --git a/.grype.yaml b/.grype.yaml deleted file mode 100644 index 1ed8fe29e9..0000000000 --- a/.grype.yaml +++ /dev/null @@ -1,4 +0,0 @@ -ignore: - # From helm - This behavior was introduced intentionally, and cannot be removed without breaking backwards compatibility (some users may be relying on these values). - # https://helm.sh/blog/response-cve-2019-25210/ - - vulnerability: GHSA-jw44-4f3j-q396 diff --git a/hack/check-vulnerabilities.sh b/hack/check-vulnerabilities.sh deleted file mode 100755 index 903e59a01a..0000000000 --- a/hack/check-vulnerabilities.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - -MAIN_BRANCH="main" -TARGET_BRANCH=$(git rev-parse --abbrev-ref HEAD) -echo "target branch is $TARGET_BRANCH" - -mkdir -p build - -git checkout $MAIN_BRANCH -go run main.go tools sbom scan . -o json --exclude './site' --exclude './examples' > build/main-syft.json - -git checkout $TARGET_BRANCH -cat build/main-syft.json | grype -o template -t hack/compare.tmpl > build/main.json -go run main.go tools sbom scan . -o json --exclude './site' --exclude './examples' | grype -o template -t hack/compare.tmpl > build/target.json - - -result=$(jq --slurp '.[0] - .[1]' build/target.json build/main.json | jq '[.[] | select(.severity != "Low" and .severity != "Medium")]') - -echo "CVEs on $MAIN_BRANCH are $(cat build/main.json | jq )" -echo "CVEs on $TARGET_BRANCH are $(cat build/target.json | jq)" - -if [[ "$result" == "[]" ]]; then - echo "no new vulnerabilities on $TARGET_BRANCH" - exit 0 -else - echo "new CVEs have been added with IDs $result" - exit 1 -fi From 9be20095e7fdde34f317b80bacc8a796b8211e14 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 31 Jul 2024 16:56:08 -0600 Subject: [PATCH 51/68] chore(deps): bump github.com/mikefarah/yq/v4 from 4.43.1 to 4.44.2 (#2799) Signed-off-by: dependabot[bot] Signed-off-by: Austin Abro Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Austin Abro Co-authored-by: schristoff <28318173+schristoff@users.noreply.github.com> --- go.mod | 10 +- go.sum | 20 ++-- .../content/docs/commands/zarf_tools_yq.md | 1 + .../docs/commands/zarf_tools_yq_completion.md | 103 ++++++++++++++++++ 4 files changed, 119 insertions(+), 15 deletions(-) create mode 100644 site/src/content/docs/commands/zarf_tools_yq_completion.md diff --git a/go.mod b/go.mod index eebb5ea6b7..6c345a7fe3 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( github.com/derailed/k9s v0.31.7 github.com/distribution/reference v0.5.0 github.com/fairwindsops/pluto/v5 v5.18.4 - github.com/fatih/color v1.16.0 + github.com/fatih/color v1.17.0 github.com/fluxcd/helm-controller/api v1.0.1 github.com/fluxcd/pkg/apis/meta v1.5.0 github.com/fluxcd/source-controller/api v1.3.0 @@ -222,7 +222,7 @@ require ( github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/edsrzf/mmap-go v1.1.0 // indirect - github.com/elliotchance/orderedmap v1.5.1 // indirect + github.com/elliotchance/orderedmap v1.6.0 // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/emicklei/proto v1.12.1 // indirect github.com/emirpasic/gods v1.18.1 // indirect @@ -263,7 +263,7 @@ require ( github.com/go-restruct/restruct v1.2.0-alpha // indirect github.com/go-test/deep v1.1.0 // indirect github.com/gobwas/glob v0.2.3 // indirect - github.com/goccy/go-json v0.10.2 // indirect + github.com/goccy/go-json v0.10.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v4 v4.5.0 // indirect github.com/golang-jwt/jwt/v5 v5.2.1 // indirect @@ -348,7 +348,7 @@ require ( github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect github.com/microsoft/go-rustaudit v0.0.0-20220730194248-4b17361d90a5 // indirect github.com/miekg/pkcs11 v1.1.1 // indirect - github.com/mikefarah/yq/v4 v4.43.1 + github.com/mikefarah/yq/v4 v4.44.2 github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect @@ -392,7 +392,7 @@ require ( github.com/pborman/indent v1.2.1 // indirect github.com/pborman/uuid v1.2.1 // indirect github.com/pelletier/go-toml v1.9.5 // indirect - github.com/pelletier/go-toml/v2 v2.2.0 // indirect + github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/pierrec/lz4/v4 v4.1.18 // indirect github.com/pjbgf/sha1cd v0.3.0 // indirect diff --git a/go.sum b/go.sum index 006c9add9a..0e511de64e 100644 --- a/go.sum +++ b/go.sum @@ -662,8 +662,8 @@ github.com/edsrzf/mmap-go v1.1.0 h1:6EUwBLQ/Mcr1EYLE4Tn1VdW1A4ckqCQWZBw8Hr0kjpQ= github.com/edsrzf/mmap-go v1.1.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q= github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU= github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= -github.com/elliotchance/orderedmap v1.5.1 h1:G1X4PYlljzimbdQ3RXmtIZiQ9d6aRQ3sH1nzjq5mECE= -github.com/elliotchance/orderedmap v1.5.1/go.mod h1:wsDwEaX5jEoyhbs7x93zk2H/qv0zwuhg4inXhDkYqys= +github.com/elliotchance/orderedmap v1.6.0 h1:xjn+kbbKXeDq6v9RVE+WYwRbYfAZKvlWfcJNxM8pvEw= +github.com/elliotchance/orderedmap v1.6.0/go.mod h1:wsDwEaX5jEoyhbs7x93zk2H/qv0zwuhg4inXhDkYqys= github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/emicklei/proto v1.12.1 h1:6n/Z2pZAnBwuhU66Gs8160B8rrrYKo7h2F2sCOnNceE= @@ -698,8 +698,8 @@ github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwo github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= -github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= +github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= +github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= github.com/fatih/set v0.2.1 h1:nn2CaJyknWE/6txyUDGwysr3G5QC6xWB/PtVjPBbeaA= github.com/fatih/set v0.2.1/go.mod h1:+RKtMCH+favT2+3YecHGxcc0b4KyVWA1QWWJUs4E0CI= github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g= @@ -832,8 +832,8 @@ github.com/gobuffalo/packr/v2 v2.8.3 h1:xE1yzvnO56cUC0sTpKR3DIbxZgB54AftTFMhB2XE github.com/gobuffalo/packr/v2 v2.8.3/go.mod h1:0SahksCVcx4IMnigTjiFuyldmTrdTctXsOdiU5KwbKc= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= -github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= -github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= +github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/goccy/go-yaml v1.11.3 h1:B3W9IdWbvrUu2OYQGwvU1nZtvMQJPBKgBUuweJjLj6I= github.com/goccy/go-yaml v1.11.3/go.mod h1:wKnAMd44+9JAAnGQpWVEgBzGt3YuTaQ4uXoHvE4m7WU= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -1270,8 +1270,8 @@ github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60 github.com/miekg/pkcs11 v1.0.3-0.20190429190417-a667d056470f/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU= github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= -github.com/mikefarah/yq/v4 v4.43.1 h1:1bCrQwVDhjGnPboQidy30hu6U2TCd8sUQTy1hKCHOGI= -github.com/mikefarah/yq/v4 v4.43.1/go.mod h1:jcSqtyUKbPWvwaa8cNw8Ej4rmPb3iWE8zYvpkTvM7oc= +github.com/mikefarah/yq/v4 v4.44.2 h1:J+ezWCDTg+SUs0jXdcE0HIPH1+rEr0Tbn9Y1SwiWtH0= +github.com/mikefarah/yq/v4 v4.44.2/go.mod h1:9bnz36uZJDEyxdIjRronBcqStS953k3y3DrSRXr4F/w= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= @@ -1400,8 +1400,8 @@ github.com/pborman/uuid v1.2.1/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtP github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/pelletier/go-toml/v2 v2.2.0 h1:QLgLl2yMN7N+ruc31VynXs1vhMZa7CeHHejIeBAsoHo= -github.com/pelletier/go-toml/v2 v2.2.0/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= +github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/petergtz/pegomock v2.9.0+incompatible h1:BKfb5XfkJfehe5T+O1xD4Zm26Sb9dnRj7tHxLYwUPiI= diff --git a/site/src/content/docs/commands/zarf_tools_yq.md b/site/src/content/docs/commands/zarf_tools_yq.md index 1ab66ec79f..7e865330fa 100644 --- a/site/src/content/docs/commands/zarf_tools_yq.md +++ b/site/src/content/docs/commands/zarf_tools_yq.md @@ -84,6 +84,7 @@ zarf tools yq -P sample.json ### SEE ALSO * [zarf tools](/commands/zarf_tools/) - Collection of additional tools to make airgap easier +* [zarf tools yq completion](/commands/zarf_tools_yq_completion/) - Generate the autocompletion script for the specified shell * [zarf tools yq eval](/commands/zarf_tools_yq_eval/) - (default) Apply the expression to each document in each yaml file in sequence * [zarf tools yq eval-all](/commands/zarf_tools_yq_eval-all/) - Loads _all_ yaml documents of _all_ yaml files and runs expression once diff --git a/site/src/content/docs/commands/zarf_tools_yq_completion.md b/site/src/content/docs/commands/zarf_tools_yq_completion.md new file mode 100644 index 0000000000..c67ed20899 --- /dev/null +++ b/site/src/content/docs/commands/zarf_tools_yq_completion.md @@ -0,0 +1,103 @@ +--- +title: zarf tools yq completion +description: Zarf CLI command reference for zarf tools yq completion. +tableOfContents: false +--- + + + +## zarf tools yq completion + +Generate the autocompletion script for the specified shell + +### Synopsis + +To load completions: + +Bash: + +$ source <(yq completion bash) + +# To load completions for each session, execute once: +Linux: + $ yq completion bash > /etc/bash_completion.d/yq +MacOS: + $ yq completion bash > /usr/local/etc/bash_completion.d/yq + +Zsh: + +# If shell completion is not already enabled in your environment you will need +# to enable it. You can execute the following once: + +$ echo "autoload -U compinit; compinit" >> ~/.zshrc + +# To load completions for each session, execute once: +$ yq completion zsh > "${fpath[1]}/_yq" + +# You will need to start a new shell for this setup to take effect. + +Fish: + +$ yq completion fish | source + +# To load completions for each session, execute once: +$ yq completion fish > ~/.config/fish/completions/yq.fish + + +``` +zarf tools yq completion [bash|zsh|fish|powershell] +``` + +### Options + +``` + -h, --help help for completion +``` + +### Options inherited from parent commands + +``` + -C, --colors force print with colors + --csv-auto-parse parse CSV YAML/JSON values (default true) + --csv-separator char CSV Separator character (default ,) + -e, --exit-status set exit status if there are no matches or null or false is returned + --expression string forcibly set the expression argument. Useful when yq argument detection thinks your expression is a file. + --from-file string Load expression from specified file. + -f, --front-matter string (extract|process) first input as yaml front-matter. Extract will pull out the yaml content, process will run the expression against the yaml content, leaving the remaining data intact + --header-preprocess Slurp any header comments and separators before processing expression. (default true) + -I, --indent int sets indent level for output (default 2) + -i, --inplace update the file in place of first file given. + -p, --input-format string [auto|a|yaml|y|json|j|props|p|csv|c|tsv|t|xml|x|base64|uri|toml|lua|l] parse format for input. (default "auto") + --lua-globals output keys as top-level global variables + --lua-prefix string prefix (default "return ") + --lua-suffix string suffix (default ";\n") + --lua-unquoted output unquoted string keys (e.g. {foo="bar"}) + -M, --no-colors force print with no colors + -N, --no-doc Don't print document separators (---) + -0, --nul-output Use NUL char to separate values. If unwrap scalar is also set, fail if unwrapped scalar contains NUL char. + -n, --null-input Don't read input, simply evaluate the expression given. Useful for creating docs from scratch. + -o, --output-format string [auto|a|yaml|y|json|j|props|p|csv|c|tsv|t|xml|x|base64|uri|toml|shell|s|lua|l] output format type. (default "auto") + -P, --prettyPrint pretty print, shorthand for '... style = ""' + --properties-array-brackets use [x] in array paths (e.g. for SpringBoot) + --properties-separator string separator to use between keys and values (default " = ") + -s, --split-exp string print each result (or doc) into a file named (exp). [exp] argument must return a string. You can use $index in the expression as the result counter. + --split-exp-file string Use a file to specify the split-exp expression. + --string-interpolation Toggles strings interpolation of \(exp) (default true) + --tsv-auto-parse parse TSV YAML/JSON values (default true) + -r, --unwrapScalar unwrap scalar, print the value with no quotes, colors or comments. Defaults to true for yaml (default true) + -v, --verbose verbose mode + --xml-attribute-prefix string prefix for xml attributes (default "+@") + --xml-content-name string name for xml content (if no attribute name is present). (default "+content") + --xml-directive-name string name for xml directives (e.g. ) (default "+directive") + --xml-keep-namespace enables keeping namespace after parsing attributes (default true) + --xml-proc-inst-prefix string prefix for xml processing instructions (e.g. ) (default "+p_") + --xml-raw-token enables using RawToken method instead Token. Commonly disables namespace translations. See https://pkg.go.dev/encoding/xml#Decoder.RawToken for details. (default true) + --xml-skip-directives skip over directives (e.g. ) + --xml-skip-proc-inst skip over process instructions (e.g. ) + --xml-strict-mode enables strict parsing of XML. See https://pkg.go.dev/encoding/xml for more details. +``` + +### SEE ALSO + +* [zarf tools yq](/commands/zarf_tools_yq/) - yq is a lightweight and portable command-line data file processor. + From b200e226f035d5e6d8004f9d36d1296ce843fb9e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Aug 2024 07:30:37 +0200 Subject: [PATCH 52/68] chore(deps): bump codecov/codecov-action from 4.4.1 to 4.5.0 (#2808) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/test-unit.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-unit.yml b/.github/workflows/test-unit.yml index 8ea2cc7bdb..ddb513fcaf 100644 --- a/.github/workflows/test-unit.yml +++ b/.github/workflows/test-unit.yml @@ -47,6 +47,6 @@ jobs: run: make test-unit - name: Upload coverage reports to Codecov - uses: codecov/codecov-action@125fc84a9a348dbcf27191600683ec096ec9021c # v4.4.1 + uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # v4.5.0 with: token: ${{ secrets.CODECOV_TOKEN }} From 2b83a9373258c7952613d7957ac3c29bace112e3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Aug 2024 07:32:33 +0200 Subject: [PATCH 53/68] chore(deps): bump actions/create-github-app-token from 1.9.0 to 1.10.3 (#2809) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .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 b3460ed000..b6a50772e5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -167,7 +167,7 @@ jobs: - name: Get Brew tap repo token id: brew-tap-token - uses: actions/create-github-app-token@f2acddfb5195534d487896a656232b016a682f3c # v1.9.0 + uses: actions/create-github-app-token@31c86eb3b33c9b601a1f60f98dcbfd1d70f379b4 # v1.10.3 with: app-id: ${{ secrets.HOMEBREW_TAP_WORKFLOW_GITHUB_APP_ID }} private-key: ${{ secrets.HOMEBREW_TAP_WORKFLOW_GITHUB_APP_SECRET }} From 81c89651d7d5a8e6630b42ca14c89bb910800775 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Aug 2024 05:59:46 +0000 Subject: [PATCH 54/68] chore(deps): bump actions/download-artifact from 4.1.2 to 4.1.8 (#2810) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 4 ++-- .github/workflows/test-bigbang.yml | 2 +- .github/workflows/test-e2e.yml | 10 +++++----- .github/workflows/test-upgrade.yml | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b6a50772e5..b949f54cb3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -89,7 +89,7 @@ jobs: fetch-depth: 0 - name: Download build artifacts - uses: actions/download-artifact@eaceaf801fd36c7dee90939fad912460b18a1ffe # v4.1.2 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: name: build-artifacts path: build/ @@ -134,7 +134,7 @@ jobs: uses: ./.github/actions/install-tools - name: Download build artifacts - uses: actions/download-artifact@eaceaf801fd36c7dee90939fad912460b18a1ffe # v4.1.2 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: name: build-artifacts path: build/ diff --git a/.github/workflows/test-bigbang.yml b/.github/workflows/test-bigbang.yml index 1b5d47bb7f..8a8ffc22c0 100644 --- a/.github/workflows/test-bigbang.yml +++ b/.github/workflows/test-bigbang.yml @@ -77,7 +77,7 @@ jobs: uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Download build artifacts - uses: actions/download-artifact@eaceaf801fd36c7dee90939fad912460b18a1ffe # v4.1.2 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: name: build-artifacts path: build/ diff --git a/.github/workflows/test-e2e.yml b/.github/workflows/test-e2e.yml index e6026420b4..b8438f1ef5 100644 --- a/.github/workflows/test-e2e.yml +++ b/.github/workflows/test-e2e.yml @@ -61,7 +61,7 @@ jobs: uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Download build artifacts - uses: actions/download-artifact@eaceaf801fd36c7dee90939fad912460b18a1ffe # v4.1.2 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: name: build-artifacts path: build/ @@ -96,7 +96,7 @@ jobs: uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Download build artifacts - uses: actions/download-artifact@eaceaf801fd36c7dee90939fad912460b18a1ffe # v4.1.2 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: name: build-artifacts path: build/ @@ -134,7 +134,7 @@ jobs: uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Download build artifacts - uses: actions/download-artifact@eaceaf801fd36c7dee90939fad912460b18a1ffe # v4.1.2 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: name: build-artifacts path: build/ @@ -172,7 +172,7 @@ jobs: uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Download build artifacts - uses: actions/download-artifact@eaceaf801fd36c7dee90939fad912460b18a1ffe # v4.1.2 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: name: build-artifacts path: build/ @@ -212,7 +212,7 @@ jobs: uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Download build artifacts - uses: actions/download-artifact@eaceaf801fd36c7dee90939fad912460b18a1ffe # v4.1.2 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: name: build-artifacts path: build/ diff --git a/.github/workflows/test-upgrade.yml b/.github/workflows/test-upgrade.yml index 17179ff9ad..592b848dd9 100644 --- a/.github/workflows/test-upgrade.yml +++ b/.github/workflows/test-upgrade.yml @@ -60,7 +60,7 @@ jobs: uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Download build artifacts - uses: actions/download-artifact@eaceaf801fd36c7dee90939fad912460b18a1ffe # v4.1.2 + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: name: build-artifacts path: build/ From 6d86e48bd5de4b4cc961a32cbb4f64ba87a6168b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Aug 2024 07:41:12 +0000 Subject: [PATCH 55/68] chore(deps): bump actions/checkout from 4.1.1 to 4.1.7 (#2807) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-rust-injector.yml | 2 +- .github/workflows/commitlint.yml | 2 +- .github/workflows/dependency-review.yml | 2 +- .github/workflows/nightly-ecr.yml | 2 +- .github/workflows/nightly-eks.yml | 2 +- .github/workflows/publish-application-packages.yml | 2 +- .github/workflows/release.yml | 6 +++--- .github/workflows/scan-codeql.yml | 2 +- .github/workflows/scan-docs-and-schema.yml | 2 +- .github/workflows/scan-lint.yml | 2 +- .github/workflows/scorecard.yaml | 2 +- .github/workflows/test-bigbang.yml | 4 ++-- .github/workflows/test-e2e.yml | 12 ++++++------ .github/workflows/test-external.yml | 2 +- .github/workflows/test-site.yml | 2 +- .github/workflows/test-unit.yml | 2 +- .github/workflows/test-upgrade.yml | 4 ++-- .github/workflows/test-windows.yml | 4 ++-- 18 files changed, 28 insertions(+), 28 deletions(-) diff --git a/.github/workflows/build-rust-injector.yml b/.github/workflows/build-rust-injector.yml index eb41af52c7..b637a65261 100644 --- a/.github/workflows/build-rust-injector.yml +++ b/.github/workflows/build-rust-injector.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest steps: - name: "Checkout Repo" - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Install tools uses: ./.github/actions/install-tools diff --git a/.github/workflows/commitlint.yml b/.github/workflows/commitlint.yml index b83d5d3350..f6243f526e 100644 --- a/.github/workflows/commitlint.yml +++ b/.github/workflows/commitlint.yml @@ -16,7 +16,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 with: fetch-depth: 0 diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index 8e12c590e0..01843002e6 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -10,6 +10,6 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Dependency Review uses: actions/dependency-review-action@9129d7d40b8c12c1ed0f60400d00c92d437adcce # v4.1.3 diff --git a/.github/workflows/nightly-ecr.yml b/.github/workflows/nightly-ecr.yml index f922e89dba..cc05e5b358 100644 --- a/.github/workflows/nightly-ecr.yml +++ b/.github/workflows/nightly-ecr.yml @@ -19,7 +19,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Setup golang uses: ./.github/actions/golang diff --git a/.github/workflows/nightly-eks.yml b/.github/workflows/nightly-eks.yml index eee9191155..85ee03b7c5 100644 --- a/.github/workflows/nightly-eks.yml +++ b/.github/workflows/nightly-eks.yml @@ -27,7 +27,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Setup golang uses: ./.github/actions/golang diff --git a/.github/workflows/publish-application-packages.yml b/.github/workflows/publish-application-packages.yml index d075c7cecf..3944aa0abb 100644 --- a/.github/workflows/publish-application-packages.yml +++ b/.github/workflows/publish-application-packages.yml @@ -18,7 +18,7 @@ jobs: packages: write steps: - name: "Checkout Repo" - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 with: ref: ${{ github.event.inputs.branchName }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b949f54cb3..cc5d405a95 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -16,7 +16,7 @@ jobs: steps: # Checkout the repo and setup the tooling for this job - name: Checkout - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 with: fetch-depth: 0 @@ -84,7 +84,7 @@ jobs: steps: # Checkout the repo and setup the tooling for this job - name: Checkout - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 with: fetch-depth: 0 @@ -123,7 +123,7 @@ jobs: steps: # Checkout the repo and setup the tooling for this job - name: Checkout - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 with: fetch-depth: 0 diff --git a/.github/workflows/scan-codeql.yml b/.github/workflows/scan-codeql.yml index b410931356..4f651e704a 100644 --- a/.github/workflows/scan-codeql.yml +++ b/.github/workflows/scan-codeql.yml @@ -46,7 +46,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Setup golang uses: ./.github/actions/golang diff --git a/.github/workflows/scan-docs-and-schema.yml b/.github/workflows/scan-docs-and-schema.yml index 4d18ba393f..e614faa5a1 100644 --- a/.github/workflows/scan-docs-and-schema.yml +++ b/.github/workflows/scan-docs-and-schema.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Setup golang uses: ./.github/actions/golang diff --git a/.github/workflows/scan-lint.yml b/.github/workflows/scan-lint.yml index 66eab288a7..45421e95de 100644 --- a/.github/workflows/scan-lint.yml +++ b/.github/workflows/scan-lint.yml @@ -11,6 +11,6 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Run golangci-lint uses: golangci/golangci-lint-action@aaa42aa0628b4ae2578232a66b541047968fac86 # v6.1.0 diff --git a/.github/workflows/scorecard.yaml b/.github/workflows/scorecard.yaml index e53c293383..9b1a7e9f3a 100644 --- a/.github/workflows/scorecard.yaml +++ b/.github/workflows/scorecard.yaml @@ -22,7 +22,7 @@ jobs: steps: - name: "Checkout code" - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 with: persist-credentials: false diff --git a/.github/workflows/test-bigbang.yml b/.github/workflows/test-bigbang.yml index 8a8ffc22c0..34e7ac5ca5 100644 --- a/.github/workflows/test-bigbang.yml +++ b/.github/workflows/test-bigbang.yml @@ -34,7 +34,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Setup golang uses: ./.github/actions/golang @@ -74,7 +74,7 @@ jobs: needs: build steps: - name: Checkout - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Download build artifacts uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 diff --git a/.github/workflows/test-e2e.yml b/.github/workflows/test-e2e.yml index b8438f1ef5..91a5f160a4 100644 --- a/.github/workflows/test-e2e.yml +++ b/.github/workflows/test-e2e.yml @@ -35,7 +35,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Setup golang uses: ./.github/actions/golang @@ -58,7 +58,7 @@ jobs: needs: build steps: - name: Checkout - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Download build artifacts uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 @@ -93,7 +93,7 @@ jobs: needs: build steps: - name: Checkout - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Download build artifacts uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 @@ -131,7 +131,7 @@ jobs: needs: build steps: - name: Checkout - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Download build artifacts uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 @@ -169,7 +169,7 @@ jobs: needs: build steps: - name: Checkout - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Download build artifacts uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 @@ -209,7 +209,7 @@ jobs: needs: build steps: - name: Checkout - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Download build artifacts uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 diff --git a/.github/workflows/test-external.yml b/.github/workflows/test-external.yml index f288989c8f..081ac7c461 100644 --- a/.github/workflows/test-external.yml +++ b/.github/workflows/test-external.yml @@ -34,7 +34,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Setup golang uses: ./.github/actions/golang diff --git a/.github/workflows/test-site.yml b/.github/workflows/test-site.yml index af0a3baef9..1042f3a0b6 100644 --- a/.github/workflows/test-site.yml +++ b/.github/workflows/test-site.yml @@ -19,7 +19,7 @@ jobs: working-directory: ./site steps: - name: Checkout - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Setup Node.js uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 diff --git a/.github/workflows/test-unit.yml b/.github/workflows/test-unit.yml index ddb513fcaf..78b49b9c90 100644 --- a/.github/workflows/test-unit.yml +++ b/.github/workflows/test-unit.yml @@ -38,7 +38,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Setup golang uses: ./.github/actions/golang diff --git a/.github/workflows/test-upgrade.yml b/.github/workflows/test-upgrade.yml index 592b848dd9..3ffe41a13c 100644 --- a/.github/workflows/test-upgrade.yml +++ b/.github/workflows/test-upgrade.yml @@ -34,7 +34,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Setup golang uses: ./.github/actions/golang @@ -57,7 +57,7 @@ jobs: needs: build steps: - name: Checkout - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Download build artifacts uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 diff --git a/.github/workflows/test-windows.yml b/.github/workflows/test-windows.yml index 08b1a6e845..d9d9172a75 100644 --- a/.github/workflows/test-windows.yml +++ b/.github/workflows/test-windows.yml @@ -34,7 +34,7 @@ jobs: runs-on: windows-latest steps: - name: Checkout - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Run Windows unit tests run: make test-unit @@ -44,7 +44,7 @@ jobs: runs-on: windows-latest steps: - name: Checkout - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Build Windows binary and zarf packages uses: ./.github/actions/packages From 008c4fa905c5aded3ae8961d0dbce340f65857e5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Aug 2024 11:09:00 +0200 Subject: [PATCH 56/68] chore(deps): bump golang.org/x/crypto from 0.24.0 to 0.25.0 (#2813) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 6c345a7fe3..49f32cccf1 100644 --- a/go.mod +++ b/go.mod @@ -45,7 +45,7 @@ require ( github.com/spf13/viper v1.18.2 github.com/stretchr/testify v1.9.0 github.com/xeipuuv/gojsonschema v1.2.0 - golang.org/x/crypto v0.24.0 + golang.org/x/crypto v0.25.0 golang.org/x/sync v0.7.0 golang.org/x/term v0.22.0 helm.sh/helm/v3 v3.14.2 diff --git a/go.sum b/go.sum index 0e511de64e..0ffbde6fd0 100644 --- a/go.sum +++ b/go.sum @@ -1809,8 +1809,8 @@ golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58 golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= -golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= +golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= +golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= From 55ca6f58de46b0333b6e63cf892bc74c8690f5ff Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Aug 2024 11:09:20 +0200 Subject: [PATCH 57/68] chore(deps): bump github.com/goccy/go-yaml from 1.11.3 to 1.12.0 (#2811) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 49f32cccf1..223daea67b 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/fluxcd/pkg/apis/meta v1.5.0 github.com/fluxcd/source-controller/api v1.3.0 github.com/go-git/go-git/v5 v5.11.0 - github.com/goccy/go-yaml v1.11.3 + github.com/goccy/go-yaml v1.12.0 github.com/gofrs/flock v0.8.1 github.com/google/go-containerregistry v0.19.0 github.com/gosuri/uitable v0.0.4 diff --git a/go.sum b/go.sum index 0ffbde6fd0..a37a950db1 100644 --- a/go.sum +++ b/go.sum @@ -834,8 +834,8 @@ github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= -github.com/goccy/go-yaml v1.11.3 h1:B3W9IdWbvrUu2OYQGwvU1nZtvMQJPBKgBUuweJjLj6I= -github.com/goccy/go-yaml v1.11.3/go.mod h1:wKnAMd44+9JAAnGQpWVEgBzGt3YuTaQ4uXoHvE4m7WU= +github.com/goccy/go-yaml v1.12.0 h1:/1WHjnMsI1dlIBQutrvSMGZRQufVO3asrHfTwfACoPM= +github.com/goccy/go-yaml v1.12.0/go.mod h1:wKnAMd44+9JAAnGQpWVEgBzGt3YuTaQ4uXoHvE4m7WU= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= From aa3cd6a31255037cb5097a06c2ac4edb5ea99a2f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Aug 2024 17:13:19 +0200 Subject: [PATCH 58/68] chore(deps): bump aws-actions/configure-aws-credentials from 4.0.1 to 4.0.2 (#2806) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/build-rust-injector.yml | 2 +- .github/workflows/nightly-ecr.yml | 2 +- .github/workflows/nightly-eks.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-rust-injector.yml b/.github/workflows/build-rust-injector.yml index b637a65261..a302c1dfa0 100644 --- a/.github/workflows/build-rust-injector.yml +++ b/.github/workflows/build-rust-injector.yml @@ -34,7 +34,7 @@ jobs: shasum zarf-injector-arm64 >> checksums.txt - name: Auth with AWS - uses: aws-actions/configure-aws-credentials@010d0da01d0b5a38af31e9c3470dbfdabdecca3a # v4.0.1 + uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2 with: role-to-assume: ${{ secrets.AWS_WRITE_ROLE }} role-session-name: ${{ github.job || github.event.client_payload.pull_request.head.sha || github.sha }} diff --git a/.github/workflows/nightly-ecr.yml b/.github/workflows/nightly-ecr.yml index cc05e5b358..9ff144c4ff 100644 --- a/.github/workflows/nightly-ecr.yml +++ b/.github/workflows/nightly-ecr.yml @@ -28,7 +28,7 @@ jobs: run: make build-cli-linux-amd - name: Auth with AWS - uses: aws-actions/configure-aws-credentials@010d0da01d0b5a38af31e9c3470dbfdabdecca3a # v4.0.1 + uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2 with: role-to-assume: ${{ secrets.AWS_NIGHTLY_ROLE }} role-session-name: ${{ github.job || github.event.client_payload.pull_request.head.sha || github.sha }} diff --git a/.github/workflows/nightly-eks.yml b/.github/workflows/nightly-eks.yml index 85ee03b7c5..18b23bb1c6 100644 --- a/.github/workflows/nightly-eks.yml +++ b/.github/workflows/nightly-eks.yml @@ -36,7 +36,7 @@ jobs: uses: ./.github/actions/packages - name: Auth with AWS - uses: aws-actions/configure-aws-credentials@010d0da01d0b5a38af31e9c3470dbfdabdecca3a # v4.0.1 + uses: aws-actions/configure-aws-credentials@e3dd6a429d7300a6a4c196c26e071d42e0343502 # v4.0.2 with: role-to-assume: ${{ secrets.AWS_NIGHTLY_ROLE }} role-session-name: ${{ github.job || github.event.client_payload.pull_request.head.sha || github.sha }} From 296df54f21ce815b6fa863ae69e2e605d11d9af8 Mon Sep 17 00:00:00 2001 From: Austin Abro <37223396+AustinAbro321@users.noreply.github.com> Date: Thu, 1 Aug 2024 14:18:00 -0400 Subject: [PATCH 59/68] fix: resolve CVE-2024-41110 (#2815) Signed-off-by: Austin Abro --- go.mod | 20 +++++++++++--------- go.sum | 36 ++++++++++++++++++------------------ 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/go.mod b/go.mod index 223daea67b..2410520b5b 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,9 @@ go 1.22.4 // TODO (@AABRO): Pending merge into github.com/gojsonschema/gojsonschema (https://github.com/gojsonschema/gojsonschema/pull/5) replace github.com/xeipuuv/gojsonschema => github.com/defenseunicorns/gojsonschema v0.0.0-20231116163348-e00f069122d6 +// TODO once helm updates to use v25.0.6 we can delete this +replace github.com/docker/docker => github.com/docker/docker v25.0.6+incompatible + require ( github.com/AlecAivazis/survey/v2 v2.3.7 github.com/Masterminds/semver/v3 v3.2.1 @@ -48,13 +51,13 @@ require ( golang.org/x/crypto v0.25.0 golang.org/x/sync v0.7.0 golang.org/x/term v0.22.0 - helm.sh/helm/v3 v3.14.2 + helm.sh/helm/v3 v3.15.3 k8s.io/api v0.30.3 k8s.io/apimachinery v0.30.3 k8s.io/client-go v0.30.3 k8s.io/component-base v0.30.3 k8s.io/klog/v2 v2.120.1 - k8s.io/kubectl v0.29.1 + k8s.io/kubectl v0.30.0 oras.land/oras-go/v2 v2.5.0 sigs.k8s.io/cli-utils v0.36.0 sigs.k8s.io/kustomize/api v0.16.0 @@ -213,9 +216,9 @@ require ( github.com/dimchansky/utfbom v1.1.1 // indirect github.com/docker/cli v26.0.0+incompatible // indirect github.com/docker/distribution v2.8.3+incompatible // indirect - github.com/docker/docker v24.0.9+incompatible // indirect + github.com/docker/docker v25.0.6+incompatible // indirect github.com/docker/docker-credential-helpers v0.8.0 // indirect - github.com/docker/go-connections v0.4.0 // indirect + github.com/docker/go-connections v0.5.0 // indirect github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c // indirect github.com/docker/go-metrics v0.0.1 // indirect github.com/docker/go-units v0.5.0 // indirect @@ -366,7 +369,6 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect - github.com/morikuni/aec v1.0.0 // indirect github.com/mozillazg/docker-credential-acr-helper v0.3.0 // indirect github.com/mpvl/unique v0.0.0-20150818121801-cbe035fff7de // indirect github.com/muesli/ansi v0.0.0-20211031195517-c9f0611b6c70 // indirect @@ -505,16 +507,16 @@ require ( gorm.io/gorm v1.25.5 // indirect k8s.io/apiextensions-apiserver v0.30.0 // indirect k8s.io/apiserver v0.30.0 // indirect - k8s.io/cli-runtime v0.29.1 // indirect - k8s.io/component-helpers v0.29.1 // indirect + k8s.io/cli-runtime v0.30.0 // indirect + k8s.io/component-helpers v0.30.0 // indirect k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect - k8s.io/metrics v0.29.1 // indirect + k8s.io/metrics v0.30.0 // indirect k8s.io/utils v0.0.0-20231127182322-b307cd553661 // indirect modernc.org/libc v1.29.0 // indirect modernc.org/mathutil v1.6.0 // indirect modernc.org/memory v1.7.2 // indirect modernc.org/sqlite v1.28.0 // indirect - oras.land/oras-go v1.2.4 // indirect + oras.land/oras-go v1.2.5 // indirect sigs.k8s.io/controller-runtime v0.18.1 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/kustomize/kustomize/v5 v5.0.4-0.20230601165947-6ce0bf390ce3 // indirect diff --git a/go.sum b/go.sum index a37a950db1..798f2f8915 100644 --- a/go.sum +++ b/go.sum @@ -265,8 +265,8 @@ github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbi github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/CycloneDX/cyclonedx-go v0.8.0 h1:FyWVj6x6hoJrui5uRQdYZcSievw3Z32Z88uYzG/0D6M= github.com/CycloneDX/cyclonedx-go v0.8.0/go.mod h1:K2bA+324+Og0X84fA8HhN2X066K7Bxz4rpMQ4ZhjtSk= -github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= -github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= +github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU= +github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= @@ -639,12 +639,12 @@ github.com/docker/cli v26.0.0+incompatible h1:90BKrx1a1HKYpSnnBFR6AgDq/FqkHxwlUy github.com/docker/cli v26.0.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v24.0.9+incompatible h1:HPGzNmwfLZWdxHqK9/II92pyi1EpYKsAqcl4G0Of9v0= -github.com/docker/docker v24.0.9+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v25.0.6+incompatible h1:5cPwbwriIcsua2REJe8HqQV+6WlWc1byg2QSXzBxBGg= +github.com/docker/docker v25.0.6+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.8.0 h1:YQFtbBQb4VrpoPxhFuzEBPQ9E16qz5SpHLS+uswaCp8= github.com/docker/docker-credential-helpers v0.8.0/go.mod h1:UGFXcuoQ5TxPiB54nHOZ32AWRqQdECoh/Mg0AlEYb40= -github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= -github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= +github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= +github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8= github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8= @@ -2449,8 +2449,8 @@ gorm.io/gorm v1.25.5 h1:zR9lOiiYf09VNh5Q1gphfyia1JpiClIWG9hQaxB/mls= gorm.io/gorm v1.25.5/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= -helm.sh/helm/v3 v3.14.2 h1:V71fv+NGZv0icBlr+in1MJXuUIHCiPG1hW9gEBISTIA= -helm.sh/helm/v3 v3.14.2/go.mod h1:2itvvDv2WSZXTllknfQo6j7u3VVgMAvm8POCDgYH424= +helm.sh/helm/v3 v3.15.3 h1:HcZDaVFe9uHa6hpsR54mJjYyRy4uz/pc6csg27nxFOc= +helm.sh/helm/v3 v3.15.3/go.mod h1:FzSIP8jDQaa6WAVg9F+OkKz7J0ZmAga4MABtTbsb9WQ= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -2466,22 +2466,22 @@ k8s.io/apimachinery v0.30.3 h1:q1laaWCmrszyQuSQCfNB8cFgCuDAoPszKY4ucAjDwHc= k8s.io/apimachinery v0.30.3/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc= k8s.io/apiserver v0.30.0 h1:QCec+U72tMQ+9tR6A0sMBB5Vh6ImCEkoKkTDRABWq6M= k8s.io/apiserver v0.30.0/go.mod h1:smOIBq8t0MbKZi7O7SyIpjPsiKJ8qa+llcFCluKyqiY= -k8s.io/cli-runtime v0.29.1 h1:By3WVOlEWYfyxhGko0f/IuAOLQcbBSMzwSaDren2JUs= -k8s.io/cli-runtime v0.29.1/go.mod h1:vjEY9slFp8j8UoMhV5AlO8uulX9xk6ogfIesHobyBDU= +k8s.io/cli-runtime v0.30.0 h1:0vn6/XhOvn1RJ2KJOC6IRR2CGqrpT6QQF4+8pYpWQ48= +k8s.io/cli-runtime v0.30.0/go.mod h1:vATpDMATVTMA79sZ0YUCzlMelf6rUjoBzlp+RnoM+cg= k8s.io/client-go v0.30.3 h1:bHrJu3xQZNXIi8/MoxYtZBBWQQXwy16zqJwloXXfD3k= k8s.io/client-go v0.30.3/go.mod h1:8d4pf8vYu665/kUbsxWAQ/JDBNWqfFeZnvFiVdmx89U= k8s.io/component-base v0.30.3 h1:Ci0UqKWf4oiwy8hr1+E3dsnliKnkMLZMVbWzeorlk7s= k8s.io/component-base v0.30.3/go.mod h1:C1SshT3rGPCuNtBs14RmVD2xW0EhRSeLvBh7AGk1quA= -k8s.io/component-helpers v0.29.1 h1:54MMEDu6xeJmMtAKztsPwu0kJKr4+jCUzaEIn2UXRoc= -k8s.io/component-helpers v0.29.1/go.mod h1:+I7xz4kfUgxWAPJIVKrqe4ml4rb9UGpazlOmhXYo+cY= +k8s.io/component-helpers v0.30.0 h1:xbJtNCfSM4SB/Tz5JqCKDZv4eT5LVi/AWQ1VOxhmStU= +k8s.io/component-helpers v0.30.0/go.mod h1:68HlSwXIumMKmCx8cZe1PoafQEYh581/sEpxMrkhmX4= k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag= k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= -k8s.io/kubectl v0.29.1 h1:rWnW3hi/rEUvvg7jp4iYB68qW5un/urKbv7fu3Vj0/s= -k8s.io/kubectl v0.29.1/go.mod h1:SZzvLqtuOJYSvZzPZR9weSuP0wDQ+N37CENJf0FhDF4= -k8s.io/metrics v0.29.1 h1:qutc3aIPMCniMuEApuLaeYX47rdCn8eycVDx7R6wMlQ= -k8s.io/metrics v0.29.1/go.mod h1:JrbV2U71+v7d/9qb90UVKL8r0uJ6Z2Hy4V7mDm05cKs= +k8s.io/kubectl v0.30.0 h1:xbPvzagbJ6RNYVMVuiHArC1grrV5vSmmIcSZuCdzRyk= +k8s.io/kubectl v0.30.0/go.mod h1:zgolRw2MQXLPwmic2l/+iHs239L49fhSeICuMhQQXTI= +k8s.io/metrics v0.30.0 h1:tqB+T0GJY288KahaO3Eb41HaDVeLR18gBmyPo0R417s= +k8s.io/metrics v0.30.0/go.mod h1:nSDA8V19WHhCTBhRYuyzJT9yPJBxSpqbyrGCCQ4jPj4= k8s.io/utils v0.0.0-20231127182322-b307cd553661 h1:FepOBzJ0GXm8t0su67ln2wAZjbQ6RxQGZDnzuLcrUTI= k8s.io/utils v0.0.0-20231127182322-b307cd553661/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= modernc.org/libc v1.29.0 h1:tTFRFq69YKCF2QyGNuRUQxKBm1uZZLubf6Cjh/pVHXs= @@ -2492,8 +2492,8 @@ modernc.org/memory v1.7.2 h1:Klh90S215mmH8c9gO98QxQFsY+W451E8AnzjoE2ee1E= modernc.org/memory v1.7.2/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E= modernc.org/sqlite v1.28.0 h1:Zx+LyDDmXczNnEQdvPuEfcFVA2ZPyaD7UCZDjef3BHQ= modernc.org/sqlite v1.28.0/go.mod h1:Qxpazz0zH8Z1xCFyi5GSL3FzbtZ3fvbjmywNogldEW0= -oras.land/oras-go v1.2.4 h1:djpBY2/2Cs1PV87GSJlxv4voajVOMZxqqtq9AB8YNvY= -oras.land/oras-go v1.2.4/go.mod h1:DYcGfb3YF1nKjcezfX2SNlDAeQFKSXmf+qrFmrh4324= +oras.land/oras-go v1.2.5 h1:XpYuAwAb0DfQsunIyMfeET92emK8km3W4yEzZvUbsTo= +oras.land/oras-go v1.2.5/go.mod h1:PuAwRShRZCsZb7g8Ar3jKKQR/2A/qN+pkYxIOd/FAoo= oras.land/oras-go/v2 v2.5.0 h1:o8Me9kLY74Vp5uw07QXPiitjsw7qNXi8Twd+19Zf02c= oras.land/oras-go/v2 v2.5.0/go.mod h1:z4eisnLP530vwIOUOJeBIj0aGI0L1C3d53atvCBqZHg= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= From b903e262f16424307e056a6c85102e2294cabe1b Mon Sep 17 00:00:00 2001 From: Philip Laine Date: Thu, 1 Aug 2024 21:31:21 +0200 Subject: [PATCH 60/68] refactor: git package (#2790) Signed-off-by: Philip Laine Co-authored-by: Austin Abro <37223396+AustinAbro321@users.noreply.github.com> --- go.mod | 4 +- go.sum | 4 + src/extensions/bigbang/bigbang.go | 2 +- src/internal/git/fallback.go | 58 ++++++ src/internal/git/git.go | 26 +++ src/internal/git/git_test.go | 40 ++++ src/internal/git/repository.go | 271 ++++++++++++++++++++++++++ src/internal/git/repository_test.go | 85 ++++++++ src/internal/packager/git/checkout.go | 97 --------- src/internal/packager/git/clone.go | 126 ------------ src/internal/packager/git/common.go | 54 ----- src/internal/packager/git/pull.go | 81 -------- src/internal/packager/git/push.go | 143 -------------- src/internal/packager/helm/repo.go | 22 +-- src/pkg/packager/creator/normal.go | 6 +- src/pkg/packager/deploy.go | 20 +- src/pkg/packager/filters/diff.go | 2 +- 17 files changed, 514 insertions(+), 527 deletions(-) create mode 100644 src/internal/git/fallback.go create mode 100644 src/internal/git/git.go create mode 100644 src/internal/git/git_test.go create mode 100644 src/internal/git/repository.go create mode 100644 src/internal/git/repository_test.go delete mode 100644 src/internal/packager/git/checkout.go delete mode 100644 src/internal/packager/git/clone.go delete mode 100644 src/internal/packager/git/common.go delete mode 100644 src/internal/packager/git/pull.go delete mode 100644 src/internal/packager/git/push.go diff --git a/go.mod b/go.mod index 2410520b5b..5c299fc165 100644 --- a/go.mod +++ b/go.mod @@ -22,6 +22,7 @@ require ( github.com/distribution/reference v0.5.0 github.com/fairwindsops/pluto/v5 v5.18.4 github.com/fatih/color v1.17.0 + github.com/fluxcd/gitkit v0.6.0 github.com/fluxcd/helm-controller/api v1.0.1 github.com/fluxcd/pkg/apis/meta v1.5.0 github.com/fluxcd/source-controller/api v1.3.0 @@ -68,6 +69,7 @@ require ( require ( github.com/evanphx/json-patch/v5 v5.9.0 // indirect github.com/go-logr/logr v1.4.2 // indirect + github.com/gofrs/uuid v4.2.0+incompatible // indirect ) require ( @@ -247,7 +249,7 @@ require ( github.com/go-chi/chi v4.1.2+incompatible // indirect github.com/go-errors/errors v1.4.2 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect - github.com/go-git/go-billy/v5 v5.5.0 // indirect + github.com/go-git/go-billy/v5 v5.5.0 github.com/go-gorp/gorp/v3 v3.1.0 // indirect github.com/go-ini/ini v1.67.0 // indirect github.com/go-jose/go-jose/v3 v3.0.3 // indirect diff --git a/go.sum b/go.sum index 798f2f8915..b442e5c6a1 100644 --- a/go.sum +++ b/go.sum @@ -706,6 +706,8 @@ github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g= github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/fluxcd/gitkit v0.6.0 h1:iNg5LTx6ePo+Pl0ZwqHTAkhbUHxGVSY3YCxCdw7VIFg= +github.com/fluxcd/gitkit v0.6.0/go.mod h1:svOHuKi0fO9HoawdK4HfHAJJseZDHHjk7I3ihnCIqNo= github.com/fluxcd/helm-controller/api v1.0.1 h1:Gn9qEVuif6D5+gHmVwTEZkR4+nmLOcOhKx4Sw2gL2EA= github.com/fluxcd/helm-controller/api v1.0.1/go.mod h1:/6AD5a2qjo/ttxVM8GR33syLZwqigta60DCLdy8GrME= github.com/fluxcd/pkg/apis/acl v0.3.0 h1:UOrKkBTOJK+OlZX7n8rWt2rdBmDCoTK+f5TY2LcZi8A= @@ -841,6 +843,8 @@ github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= +github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0= +github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= diff --git a/src/extensions/bigbang/bigbang.go b/src/extensions/bigbang/bigbang.go index 951ae88ccf..31b71015cf 100644 --- a/src/extensions/bigbang/bigbang.go +++ b/src/extensions/bigbang/bigbang.go @@ -533,7 +533,7 @@ func findImagesforBBChartRepo(ctx context.Context, repo string, values chartutil spinner := message.NewProgressSpinner("Discovering images in %s", repo) defer spinner.Stop() - gitPath, err := helm.DownloadChartFromGitToTemp(ctx, repo, spinner) + gitPath, err := helm.DownloadChartFromGitToTemp(ctx, repo) if err != nil { return images, err } diff --git a/src/internal/git/fallback.go b/src/internal/git/fallback.go new file mode 100644 index 0000000000..960747413a --- /dev/null +++ b/src/internal/git/fallback.go @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2021-Present The Zarf Authors + +// Package git contains functions for interacting with git repositories. +package git + +import ( + "context" + "io" + + "github.com/go-git/go-git/v5/plumbing" + + "github.com/zarf-dev/zarf/src/pkg/utils/exec" +) + +// gitCloneFallback is a fallback if go-git fails to clone a repo. +func (r *Repository) gitCloneFallback(ctx context.Context, gitURL string, ref plumbing.ReferenceName, shallow bool) error { + // If we can't clone with go-git, fallback to the host clone + // Only support "all tags" due to the azure clone url format including a username + cloneArgs := []string{"clone", "--origin", onlineRemoteName, gitURL, r.path} + + // Don't clone all tags / refs if we're cloning a specific tag or branch. + if ref.IsTag() || ref.IsBranch() { + cloneArgs = append(cloneArgs, "--no-tags") + cloneArgs = append(cloneArgs, "-b", ref.Short()) + cloneArgs = append(cloneArgs, "--single-branch") + } + + // If this is a shallow clone set the depth to 1 + if shallow { + cloneArgs = append(cloneArgs, "--depth", "1") + } + + cloneExecConfig := exec.Config{ + Stdout: io.Discard, + Stderr: io.Discard, + } + _, _, err := exec.CmdWithContext(ctx, cloneExecConfig, "git", cloneArgs...) + if err != nil { + return err + } + + // If we're cloning the whole repo, we need to also fetch the other branches besides the default. + if ref == emptyRef { + fetchArgs := []string{"fetch", "--tags", "--update-head-ok", onlineRemoteName, "refs/*:refs/*"} + fetchExecConfig := exec.Config{ + Stdout: io.Discard, + Stderr: io.Discard, + Dir: r.path, + } + _, _, err := exec.CmdWithContext(ctx, fetchExecConfig, "git", fetchArgs...) + if err != nil { + return err + } + } + + return nil +} diff --git a/src/internal/git/git.go b/src/internal/git/git.go new file mode 100644 index 0000000000..506f2bea24 --- /dev/null +++ b/src/internal/git/git.go @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2021-Present The Zarf Authors + +// Package git contains functions for interacting with git repositories. +package git + +import ( + "fmt" + "strings" + + "github.com/go-git/go-git/v5/plumbing" +) + +const onlineRemoteName = "online-upstream" +const offlineRemoteName = "offline-downstream" +const emptyRef = "" + +// ParseRef parses the provided ref into a ReferenceName if it's not a hash. +func ParseRef(r string) plumbing.ReferenceName { + // If not a full ref, assume it's a tag at this point. + if !plumbing.IsHash(r) && !strings.HasPrefix(r, "refs/") { + r = fmt.Sprintf("refs/tags/%s", r) + } + // Set the reference name to the provided ref. + return plumbing.ReferenceName(r) +} diff --git a/src/internal/git/git_test.go b/src/internal/git/git_test.go new file mode 100644 index 0000000000..640d8a8b43 --- /dev/null +++ b/src/internal/git/git_test.go @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2021-Present The Zarf Authors + +package git + +import ( + "testing" + + "github.com/go-git/go-git/v5/plumbing" + "github.com/stretchr/testify/require" +) + +func TestParseRef(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + refPlain string + expectedRef plumbing.ReferenceName + }{ + { + name: "basic", + refPlain: "v1.0.0", + expectedRef: plumbing.ReferenceName("refs/tags/v1.0.0"), + }, + { + name: "basic", + refPlain: "refs/heads/branchname", + expectedRef: plumbing.ReferenceName("refs/heads/branchname"), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + ref := ParseRef(tt.refPlain) + require.Equal(t, tt.expectedRef, ref) + }) + } +} diff --git a/src/internal/git/repository.go b/src/internal/git/repository.go new file mode 100644 index 0000000000..9d2b2d4918 --- /dev/null +++ b/src/internal/git/repository.go @@ -0,0 +1,271 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2021-Present The Zarf Authors + +package git + +import ( + "context" + "errors" + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/go-git/go-git/v5" + "github.com/go-git/go-git/v5/config" + "github.com/go-git/go-git/v5/plumbing" + "github.com/go-git/go-git/v5/plumbing/object" + "github.com/go-git/go-git/v5/plumbing/transport" + "github.com/go-git/go-git/v5/plumbing/transport/http" + + "github.com/zarf-dev/zarf/src/pkg/message" + "github.com/zarf-dev/zarf/src/pkg/transform" + "github.com/zarf-dev/zarf/src/pkg/utils" +) + +// Open opens an existing local repository at the given path. +func Open(rootPath, address string) (*Repository, error) { + repoFolder, err := transform.GitURLtoFolderName(address) + if err != nil { + return nil, fmt.Errorf("unable to parse git url %s: %w", address, err) + } + repoPath := filepath.Join(rootPath, repoFolder) + + // Check that this package is using the new repo format (if not fallback to the format from <= 0.24.x) + _, err = os.Stat(repoPath) + if err != nil && !os.IsNotExist(err) { + return nil, err + } + if os.IsNotExist(err) { + repoFolder, err = transform.GitURLtoRepoName(address) + if err != nil { + return nil, fmt.Errorf("unable to parse git url %s: %w", address, err) + } + repoPath = filepath.Join(rootPath, repoFolder) + } + + return &Repository{ + path: repoPath, + }, nil +} + +// Clone clones a git repository to the given local path. +func Clone(ctx context.Context, rootPath, address string, shallow bool) (*Repository, error) { + // Split the remote url and the zarf reference + gitURLNoRef, refPlain, err := transform.GitURLSplitRef(address) + if err != nil { + return nil, err + } + + // Parse the ref from the git URL. + var ref plumbing.ReferenceName + if refPlain != emptyRef { + ref = ParseRef(refPlain) + } + + // Construct a path unique to this git repo + repoFolder, err := transform.GitURLtoFolderName(address) + if err != nil { + return nil, err + } + + r := &Repository{ + path: filepath.Join(rootPath, repoFolder), + } + + // Clone the repository + cloneOpts := &git.CloneOptions{ + URL: gitURLNoRef, + RemoteName: onlineRemoteName, + } + if ref.IsTag() || ref.IsBranch() { + cloneOpts.Tags = git.NoTags + cloneOpts.ReferenceName = ref + cloneOpts.SingleBranch = true + } + if shallow { + cloneOpts.Depth = 1 + } + gitCred, err := utils.FindAuthForHost(gitURLNoRef) + if err != nil { + return nil, err + } + if gitCred != nil { + cloneOpts.Auth = &gitCred.Auth + } + repo, err := git.PlainCloneContext(ctx, r.path, false, cloneOpts) + if err != nil { + message.Notef("Falling back to host 'git', failed to clone the repo %q with Zarf: %s", gitURLNoRef, err.Error()) + err := r.gitCloneFallback(ctx, gitURLNoRef, ref, shallow) + if err != nil { + return nil, err + } + } + + // If we're cloning the whole repo, we need to also fetch the other branches besides the default. + if ref == emptyRef { + fetchOpts := &git.FetchOptions{ + RemoteName: onlineRemoteName, + RefSpecs: []config.RefSpec{"refs/*:refs/*"}, + Tags: git.AllTags, + } + if gitCred != nil { + fetchOpts.Auth = &gitCred.Auth + } + if err := repo.FetchContext(ctx, fetchOpts); err != nil && !errors.Is(err, git.NoErrAlreadyUpToDate) { + return nil, err + } + } + + // Optionally checkout ref + if ref != emptyRef && !ref.IsBranch() { + // Remove the "refs/tags/" prefix from the ref. + stripped := strings.TrimPrefix(refPlain, "refs/tags/") + // Use the plain ref as part of the branch name so it is unique and doesn't conflict with other refs. + alias := fmt.Sprintf("zarf-ref-%s", stripped) + trunkBranchName := plumbing.NewBranchReferenceName(alias) + // Checkout the ref as a branch. + err := r.checkoutRefAsBranch(stripped, trunkBranchName) + if err != nil { + return nil, err + } + } + + return r, nil +} + +// Repository manages a local git repository. +type Repository struct { + path string +} + +// Path returns the local path the repository is stored at. +func (r *Repository) Path() string { + return r.path +} + +// Push pushes the repository to the remote git server. +func (r *Repository) Push(ctx context.Context, address, username, password string) error { + repo, err := git.PlainOpen(r.path) + if err != nil { + return fmt.Errorf("not a valid git repo or unable to open: %w", err) + } + + // Configure new remote + remote, err := repo.Remote(onlineRemoteName) + if err != nil { + return fmt.Errorf("unable to find the git remote: %w", err) + } + if len(remote.Config().URLs) == 0 { + return fmt.Errorf("repository has zero remotes configured") + } + targetURL, err := transform.GitURL(address, remote.Config().URLs[0], username) + if err != nil { + return fmt.Errorf("unable to transform the git url: %w", err) + } + // Remove any preexisting offlineRemotes (happens when a retry is triggered) + err = repo.DeleteRemote(offlineRemoteName) + if err != nil && !errors.Is(err, git.ErrRemoteNotFound) { + return err + } + _, err = repo.CreateRemote(&config.RemoteConfig{ + Name: offlineRemoteName, + URLs: []string{targetURL.String()}, + }) + if err != nil { + return fmt.Errorf("failed to create offline remote: %w", err) + } + + // Push to new remote + gitCred := http.BasicAuth{ + Username: username, + Password: password, + } + + // Fetch remote offline refs in case of old update or if multiple refs are specified in one package + // Attempt the fetch, if it fails, log a warning and continue trying to push (might as well try..) + fetchOptions := &git.FetchOptions{ + RemoteName: offlineRemoteName, + Auth: &gitCred, + RefSpecs: []config.RefSpec{ + "refs/heads/*:refs/heads/*", + "refs/tags/*:refs/tags/*", + }, + } + err = repo.FetchContext(ctx, fetchOptions) + if errors.Is(err, transport.ErrRepositoryNotFound) { + message.Debugf("Repo not yet available offline, skipping fetch...") + } else if errors.Is(err, git.ErrForceNeeded) { + message.Debugf("Repo fetch requires force, skipping fetch...") + } else if errors.Is(err, git.NoErrAlreadyUpToDate) { + message.Debugf("Repo already up-to-date, skipping fetch...") + } else if err != nil { + return fmt.Errorf("unable to fetch the git repo prior to push: %w", err) + } + + // Push all heads and tags to the offline remote + err = repo.PushContext(ctx, &git.PushOptions{ + RemoteName: offlineRemoteName, + Auth: &gitCred, + // TODO: (@JEFFMCCOY) add the parsing for the `+` force prefix (see https://github.com/zarf-dev/zarf/issues/1410) + //Force: isForce, + // If a provided refspec doesn't push anything, it is just ignored + RefSpecs: []config.RefSpec{ + "refs/heads/*:refs/heads/*", + "refs/tags/*:refs/tags/*", + }, + }) + if errors.Is(err, git.NoErrAlreadyUpToDate) { + message.Debug("Repo already up-to-date") + } else if errors.Is(err, plumbing.ErrObjectNotFound) { + return fmt.Errorf("unable to push repo due to likely shallow clone: %s", err.Error()) + } else if err != nil { + return fmt.Errorf("unable to push repo to the gitops service: %s", err.Error()) + } + + return nil +} +func (r *Repository) checkoutRefAsBranch(ref string, branch plumbing.ReferenceName) error { + repo, err := git.PlainOpen(r.path) + if err != nil { + return fmt.Errorf("not a valid git repo or unable to open: %w", err) + } + + var hash plumbing.Hash + if plumbing.IsHash(ref) { + hash = plumbing.NewHash(ref) + } else { + tagRef, err := repo.Tag(ref) + if err != nil { + return fmt.Errorf("failed to locate tag %s in repository: %w", ref, err) + } + hash = tagRef.Hash() + } + + objRef, err := repo.Object(plumbing.AnyObject, hash) + if err != nil { + return fmt.Errorf("an error occurred when getting the repo's object reference: %w", err) + } + + var commitHash plumbing.Hash + switch objRef := objRef.(type) { + case *object.Tag: + commitHash = objRef.Target + case *object.Commit: + commitHash = objRef.Hash + default: + return fmt.Errorf("hash type %s not supported", objRef.Type().String()) + } + + checkoutOpts := &git.CheckoutOptions{ + Hash: commitHash, + Branch: branch, + Create: true, + Force: true, + } + tree, err := repo.Worktree() + if err != nil { + return fmt.Errorf("unable to load the git repo: %w", err) + } + return tree.Checkout(checkoutOpts) +} diff --git a/src/internal/git/repository_test.go b/src/internal/git/repository_test.go new file mode 100644 index 0000000000..7e75319eee --- /dev/null +++ b/src/internal/git/repository_test.go @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2021-Present The Zarf Authors + +package git + +import ( + "fmt" + "net/http" + "net/http/httptest" + "path/filepath" + "testing" + + "github.com/fluxcd/gitkit" + "github.com/go-git/go-billy/v5/memfs" + "github.com/go-git/go-git/v5" + "github.com/go-git/go-git/v5/config" + "github.com/go-git/go-git/v5/plumbing/object" + "github.com/go-git/go-git/v5/storage/memory" + "github.com/stretchr/testify/require" + + "github.com/defenseunicorns/pkg/helpers/v2" + + "github.com/zarf-dev/zarf/src/test/testutil" +) + +func TestRepository(t *testing.T) { + t.Parallel() + ctx := testutil.TestContext(t) + + cfg := gitkit.Config{ + Dir: t.TempDir(), + AutoCreate: true, + } + gitSrv := gitkit.New(cfg) + err := gitSrv.Setup() + require.NoError(t, err) + srv := httptest.NewServer(http.HandlerFunc(gitSrv.ServeHTTP)) + t.Cleanup(func() { + srv.Close() + }) + + rootPath := t.TempDir() + repoName := "test" + repoAddress := fmt.Sprintf("%s/%s.git", srv.URL, repoName) + checksum := helpers.GetCRCHash(repoAddress) + expectedPath := fmt.Sprintf("%s-%d", repoName, checksum) + + storer := memory.NewStorage() + fs := memfs.New() + initRepo, err := git.Init(storer, fs) + require.NoError(t, err) + w, err := initRepo.Worktree() + require.NoError(t, err) + filePath := "test.txt" + newFile, err := fs.Create(filePath) + require.NoError(t, err) + _, err = newFile.Write([]byte("Hello World")) + require.NoError(t, err) + newFile.Close() + _, err = w.Add(filePath) + require.NoError(t, err) + _, err = w.Commit("Initial commit", &git.CommitOptions{ + Author: &object.Signature{ + Email: "example@example.com", + }, + }) + require.NoError(t, err) + _, err = initRepo.CreateRemote(&config.RemoteConfig{ + Name: "origin", + URLs: []string{repoAddress}, + }) + require.NoError(t, err) + err = initRepo.Push(&git.PushOptions{ + RemoteName: "origin", + }) + require.NoError(t, err) + + repo, err := Clone(ctx, rootPath, repoAddress, false) + require.NoError(t, err) + require.Equal(t, filepath.Join(rootPath, expectedPath), repo.Path()) + + repo, err = Open(rootPath, repoAddress) + require.NoError(t, err) + require.Equal(t, filepath.Join(rootPath, expectedPath), repo.Path()) +} diff --git a/src/internal/packager/git/checkout.go b/src/internal/packager/git/checkout.go deleted file mode 100644 index 5a9a960508..0000000000 --- a/src/internal/packager/git/checkout.go +++ /dev/null @@ -1,97 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2021-Present The Zarf Authors - -// Package git contains functions for interacting with git repositories. -package git - -import ( - "fmt" - - "github.com/go-git/go-git/v5" - "github.com/go-git/go-git/v5/plumbing" - "github.com/go-git/go-git/v5/plumbing/object" -) - -// CheckoutTag performs a `git checkout` of the provided tag to a detached HEAD. -func (g *Git) CheckoutTag(tag string) error { - options := &git.CheckoutOptions{ - Branch: ParseRef(tag), - } - return g.checkout(options) -} - -func (g *Git) checkoutRefAsBranch(ref string, branch plumbing.ReferenceName) error { - if plumbing.IsHash(ref) { - return g.checkoutHashAsBranch(plumbing.NewHash(ref), branch) - } - - return g.checkoutTagAsBranch(ref, branch) -} - -// checkoutTagAsBranch performs a `git checkout` of the provided tag but rather -// than checking out to a detached head, checks out to the provided branch ref -// It will delete the branch provided if it exists. -func (g *Git) checkoutTagAsBranch(tag string, branch plumbing.ReferenceName) error { - repo, err := git.PlainOpen(g.GitPath) - if err != nil { - return fmt.Errorf("not a valid git repo or unable to open: %w", err) - } - - tagRef, err := repo.Tag(tag) - if err != nil { - return fmt.Errorf("failed to locate tag (%s) in repository: %w", tag, err) - } - - return g.checkoutHashAsBranch(tagRef.Hash(), branch) -} - -// checkoutHashAsBranch performs a `git checkout` of the commit hash associated -// with the provided hash -// It will delete the branch provided if it exists. -func (g *Git) checkoutHashAsBranch(hash plumbing.Hash, branch plumbing.ReferenceName) error { - repo, err := git.PlainOpen(g.GitPath) - if err != nil { - return fmt.Errorf("not a valid git repo or unable to open: %w", err) - } - objRef, err := repo.Object(plumbing.AnyObject, hash) - if err != nil { - return fmt.Errorf("an error occurred when getting the repo's object reference: %w", err) - } - - var commitHash plumbing.Hash - switch objRef := objRef.(type) { - case *object.Tag: - commitHash = objRef.Target - case *object.Commit: - commitHash = objRef.Hash - default: - return fmt.Errorf("hash type %s not supported", objRef.Type().String()) - } - - options := &git.CheckoutOptions{ - Hash: commitHash, - Branch: branch, - Create: true, - Force: true, - } - return g.checkout(options) -} - -// checkout performs a `git checkout` on the path provided using the options provided -// It assumes the caller knows what to do and does not perform any safety checks. -func (g *Git) checkout(checkoutOptions *git.CheckoutOptions) error { - // Open the given repo - repo, err := git.PlainOpen(g.GitPath) - if err != nil { - return fmt.Errorf("not a valid git repo or unable to open: %w", err) - } - - // Get the working tree so we can change refs - tree, err := repo.Worktree() - if err != nil { - return fmt.Errorf("unable to load the git repo: %w", err) - } - - // Perform the checkout - return tree.Checkout(checkoutOptions) -} diff --git a/src/internal/packager/git/clone.go b/src/internal/packager/git/clone.go deleted file mode 100644 index 2f607670e7..0000000000 --- a/src/internal/packager/git/clone.go +++ /dev/null @@ -1,126 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2021-Present The Zarf Authors - -// Package git contains functions for interacting with git repositories. -package git - -import ( - "context" - "errors" - "strings" - - "github.com/go-git/go-git/v5" - goConfig "github.com/go-git/go-git/v5/config" - "github.com/go-git/go-git/v5/plumbing" - "github.com/zarf-dev/zarf/src/pkg/message" - "github.com/zarf-dev/zarf/src/pkg/utils" - "github.com/zarf-dev/zarf/src/pkg/utils/exec" -) - -// clone performs a `git clone` of a given repo. -func (g *Git) clone(ctx context.Context, gitURL string, ref plumbing.ReferenceName, shallow bool) error { - cloneOptions := &git.CloneOptions{ - URL: gitURL, - Progress: g.Spinner, - RemoteName: onlineRemoteName, - } - - // Don't clone all tags / refs if we're cloning a specific tag or branch. - if ref.IsTag() || ref.IsBranch() { - cloneOptions.Tags = git.NoTags - cloneOptions.ReferenceName = ref - cloneOptions.SingleBranch = true - } - - // If this is a shallow clone set the depth to 1 - if shallow { - cloneOptions.Depth = 1 - } - - // Setup git credentials if we have them, ignore if we don't. - gitCred, err := utils.FindAuthForHost(gitURL) - if err != nil { - return err - } - if gitCred != nil { - cloneOptions.Auth = &gitCred.Auth - } - - // Clone the given repo. - repo, err := git.PlainClone(g.GitPath, false, cloneOptions) - if err != nil { - message.Notef("Falling back to host 'git', failed to clone the repo %q with Zarf: %s", gitURL, err.Error()) - return g.gitCloneFallback(ctx, gitURL, ref, shallow) - } - - // If we're cloning the whole repo, we need to also fetch the other branches besides the default. - if ref == emptyRef { - fetchOpts := &git.FetchOptions{ - RemoteName: onlineRemoteName, - Progress: g.Spinner, - RefSpecs: []goConfig.RefSpec{"refs/*:refs/*"}, - Tags: git.AllTags, - } - - if gitCred != nil { - fetchOpts.Auth = &gitCred.Auth - } - - if err := repo.Fetch(fetchOpts); err != nil && !errors.Is(err, git.NoErrAlreadyUpToDate) { - return err - } - } - - return nil -} - -// gitCloneFallback is a fallback if go-git fails to clone a repo. -func (g *Git) gitCloneFallback(ctx context.Context, gitURL string, ref plumbing.ReferenceName, shallow bool) error { - // If we can't clone with go-git, fallback to the host clone - // Only support "all tags" due to the azure clone url format including a username - cloneArgs := []string{"clone", "--origin", onlineRemoteName, gitURL, g.GitPath} - - // Don't clone all tags / refs if we're cloning a specific tag or branch. - if ref.IsTag() || ref.IsBranch() { - cloneArgs = append(cloneArgs, "--no-tags") - cloneArgs = append(cloneArgs, "-b", ref.Short()) - cloneArgs = append(cloneArgs, "--single-branch") - } - - // If this is a shallow clone set the depth to 1 - if shallow { - cloneArgs = append(cloneArgs, "--depth", "1") - } - - cloneExecConfig := exec.Config{ - Stdout: g.Spinner, - Stderr: g.Spinner, - } - - message.Command("git %s", strings.Join(cloneArgs, " ")) - - _, _, err := exec.CmdWithContext(ctx, cloneExecConfig, "git", cloneArgs...) - if err != nil { - return err - } - - // If we're cloning the whole repo, we need to also fetch the other branches besides the default. - if ref == emptyRef { - fetchArgs := []string{"fetch", "--tags", "--update-head-ok", onlineRemoteName, "refs/*:refs/*"} - - fetchExecConfig := exec.Config{ - Stdout: g.Spinner, - Stderr: g.Spinner, - Dir: g.GitPath, - } - - message.Command("git %s", strings.Join(fetchArgs, " ")) - - _, _, err := exec.CmdWithContext(ctx, fetchExecConfig, "git", fetchArgs...) - if err != nil { - return err - } - } - - return nil -} diff --git a/src/internal/packager/git/common.go b/src/internal/packager/git/common.go deleted file mode 100644 index 6864d3dea5..0000000000 --- a/src/internal/packager/git/common.go +++ /dev/null @@ -1,54 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2021-Present The Zarf Authors - -// Package git contains functions for interacting with git repositories. -package git - -import ( - "fmt" - "strings" - - "github.com/go-git/go-git/v5/plumbing" - "github.com/zarf-dev/zarf/src/pkg/message" - "github.com/zarf-dev/zarf/src/types" -) - -// Git is the main struct for managing git repositories. -type Git struct { - // Server is the git server configuration. - Server types.GitServerInfo - // Spinner is an optional spinner to use for long running operations. - Spinner *message.Spinner - // Target working directory for the git repository. - GitPath string -} - -const onlineRemoteName = "online-upstream" -const offlineRemoteName = "offline-downstream" -const emptyRef = "" - -// New creates a new git instance with the provided server config. -func New(server types.GitServerInfo) *Git { - return &Git{ - Server: server, - } -} - -// NewWithSpinner creates a new git instance with the provided server config and spinner. -func NewWithSpinner(server types.GitServerInfo, spinner *message.Spinner) *Git { - return &Git{ - Server: server, - Spinner: spinner, - } -} - -// ParseRef parses the provided ref into a ReferenceName if it's not a hash. -func ParseRef(r string) plumbing.ReferenceName { - // If not a full ref, assume it's a tag at this point. - if !plumbing.IsHash(r) && !strings.HasPrefix(r, "refs/") { - r = fmt.Sprintf("refs/tags/%s", r) - } - - // Set the reference name to the provided ref. - return plumbing.ReferenceName(r) -} diff --git a/src/internal/packager/git/pull.go b/src/internal/packager/git/pull.go deleted file mode 100644 index 5d9e6f1006..0000000000 --- a/src/internal/packager/git/pull.go +++ /dev/null @@ -1,81 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2021-Present The Zarf Authors - -// Package git contains functions for interacting with git repositories. -package git - -import ( - "context" - "fmt" - "path" - "strings" - - "github.com/go-git/go-git/v5/plumbing" - "github.com/zarf-dev/zarf/src/config" - "github.com/zarf-dev/zarf/src/pkg/transform" - "github.com/zarf-dev/zarf/src/pkg/utils" -) - -// DownloadRepoToTemp clones or updates a repo into a temp folder to perform ephemeral actions (i.e. process chart repos). -func (g *Git) DownloadRepoToTemp(ctx context.Context, gitURL string) error { - g.Spinner.Updatef("g.DownloadRepoToTemp(%s)", gitURL) - - path, err := utils.MakeTempDir(config.CommonOptions.TempDirectory) - if err != nil { - return fmt.Errorf("unable to create tmpdir: %w", err) - } - - // If downloading to temp, set this as a shallow clone to only pull the exact - // gitURL w/ ref that was specified since we will throw away git history anyway - if err = g.Pull(ctx, gitURL, path, true); err != nil { - return fmt.Errorf("unable to pull the git repo at %s: %w", gitURL, err) - } - - return nil -} - -// Pull clones or updates a git repository into the target folder. -func (g *Git) Pull(ctx context.Context, gitURL, targetFolder string, shallow bool) error { - g.Spinner.Updatef("Processing git repo %s", gitURL) - - // Split the remote url and the zarf reference - gitURLNoRef, refPlain, err := transform.GitURLSplitRef(gitURL) - if err != nil { - return err - } - - var ref plumbing.ReferenceName - - // Parse the ref from the git URL. - if refPlain != emptyRef { - ref = ParseRef(refPlain) - } - - // Construct a path unique to this git repo - repoFolder, err := transform.GitURLtoFolderName(gitURL) - if err != nil { - return err - } - - g.GitPath = path.Join(targetFolder, repoFolder) - - // Clone the git repository. - err = g.clone(ctx, gitURLNoRef, ref, shallow) - if err != nil { - return fmt.Errorf("not a valid git repo or unable to clone (%s): %w", gitURL, err) - } - - if ref != emptyRef && !ref.IsBranch() { - // Remove the "refs/tags/" prefix from the ref. - stripped := strings.TrimPrefix(refPlain, "refs/tags/") - - // Use the plain ref as part of the branch name so it is unique and doesn't conflict with other refs. - alias := fmt.Sprintf("zarf-ref-%s", stripped) - trunkBranchName := plumbing.NewBranchReferenceName(alias) - - // Checkout the ref as a branch. - return g.checkoutRefAsBranch(stripped, trunkBranchName) - } - - return nil -} diff --git a/src/internal/packager/git/push.go b/src/internal/packager/git/push.go deleted file mode 100644 index 60b7b2bdf6..0000000000 --- a/src/internal/packager/git/push.go +++ /dev/null @@ -1,143 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: 2021-Present The Zarf Authors - -// Package git contains functions for interacting with git repositories. -package git - -import ( - "errors" - "fmt" - "os" - "path" - - "github.com/go-git/go-git/v5" - goConfig "github.com/go-git/go-git/v5/config" - "github.com/go-git/go-git/v5/plumbing" - "github.com/go-git/go-git/v5/plumbing/transport" - "github.com/go-git/go-git/v5/plumbing/transport/http" - "github.com/zarf-dev/zarf/src/pkg/message" - "github.com/zarf-dev/zarf/src/pkg/transform" -) - -// PushRepo pushes a git repository from the local path to the configured git server. -func (g *Git) PushRepo(srcURL, targetFolder string) error { - spinner := message.NewProgressSpinner("Processing git repo %s", srcURL) - defer spinner.Stop() - - // Setup git paths, including a unique name for the repo based on the hash of the git URL to avoid conflicts. - repoFolder, err := transform.GitURLtoFolderName(srcURL) - if err != nil { - return fmt.Errorf("unable to parse git url (%s): %w", srcURL, err) - } - repoPath := path.Join(targetFolder, repoFolder) - - // Check that this package is using the new repo format (if not fallback to the format from <= 0.24.x) - _, err = os.Stat(repoPath) - if os.IsNotExist(err) { - repoFolder, err = transform.GitURLtoRepoName(srcURL) - if err != nil { - return fmt.Errorf("unable to parse git url (%s): %w", srcURL, err) - } - repoPath = path.Join(targetFolder, repoFolder) - } - - g.GitPath = repoPath - - repo, err := g.prepRepoForPush() - if err != nil { - return fmt.Errorf("could not prepare the repo for push: %w", err) - } - - if err := g.push(repo, spinner); err != nil { - return fmt.Errorf("failed to push the git repo %q: %w", repoFolder, err) - } - - spinner.Success() - return nil -} - -func (g *Git) prepRepoForPush() (*git.Repository, error) { - // Open the given repo - repo, err := git.PlainOpen(g.GitPath) - if err != nil { - return nil, fmt.Errorf("not a valid git repo or unable to open: %w", err) - } - - // Get the upstream URL - remote, err := repo.Remote(onlineRemoteName) - if err != nil { - return nil, fmt.Errorf("unable to find the git remote: %w", err) - } - - remoteURL := remote.Config().URLs[0] - targetURL, err := transform.GitURL(g.Server.Address, remoteURL, g.Server.PushUsername) - if err != nil { - return nil, fmt.Errorf("unable to transform the git url: %w", err) - } - message.Debugf("Rewrite git URL: %s -> %s", remoteURL, targetURL.String()) - // Remove any preexisting offlineRemotes (happens when a retry is triggered) - _ = repo.DeleteRemote(offlineRemoteName) - - _, err = repo.CreateRemote(&goConfig.RemoteConfig{ - Name: offlineRemoteName, - URLs: []string{targetURL.String()}, - }) - if err != nil { - return nil, fmt.Errorf("failed to create offline remote: %w", err) - } - - return repo, nil -} - -func (g *Git) push(repo *git.Repository, spinner *message.Spinner) error { - gitCred := http.BasicAuth{ - Username: g.Server.PushUsername, - Password: g.Server.PushPassword, - } - - // Fetch remote offline refs in case of old update or if multiple refs are specified in one package - fetchOptions := &git.FetchOptions{ - RemoteName: offlineRemoteName, - Auth: &gitCred, - RefSpecs: []goConfig.RefSpec{ - "refs/heads/*:refs/heads/*", - "refs/tags/*:refs/tags/*", - }, - } - - // Attempt the fetch, if it fails, log a warning and continue trying to push (might as well try..) - err := repo.Fetch(fetchOptions) - if errors.Is(err, transport.ErrRepositoryNotFound) { - message.Debugf("Repo not yet available offline, skipping fetch...") - } else if errors.Is(err, git.ErrForceNeeded) { - message.Debugf("Repo fetch requires force, skipping fetch...") - } else if errors.Is(err, git.NoErrAlreadyUpToDate) { - message.Debugf("Repo already up-to-date, skipping fetch...") - } else if err != nil { - return fmt.Errorf("unable to fetch the git repo prior to push: %w", err) - } - - // Push all heads and tags to the offline remote - err = repo.Push(&git.PushOptions{ - RemoteName: offlineRemoteName, - Auth: &gitCred, - Progress: spinner, - // TODO: (@JEFFMCCOY) add the parsing for the `+` force prefix (see https://github.com/zarf-dev/zarf/issues/1410) - //Force: isForce, - // If a provided refspec doesn't push anything, it is just ignored - RefSpecs: []goConfig.RefSpec{ - "refs/heads/*:refs/heads/*", - "refs/tags/*:refs/tags/*", - }, - }) - - if errors.Is(err, git.NoErrAlreadyUpToDate) { - message.Debug("Repo already up-to-date") - } else if errors.Is(err, plumbing.ErrObjectNotFound) { - return fmt.Errorf("unable to push repo due to likely shallow clone: %s", err.Error()) - } else if err != nil { - return fmt.Errorf("unable to push repo to the gitops service: %s", err.Error()) - } - - return nil -} diff --git a/src/internal/packager/helm/repo.go b/src/internal/packager/helm/repo.go index dad0e59aab..24f3a7f4b0 100644 --- a/src/internal/packager/helm/repo.go +++ b/src/internal/packager/helm/repo.go @@ -15,11 +15,10 @@ import ( "github.com/defenseunicorns/pkg/helpers/v2" "github.com/zarf-dev/zarf/src/config" "github.com/zarf-dev/zarf/src/config/lang" - "github.com/zarf-dev/zarf/src/internal/packager/git" + "github.com/zarf-dev/zarf/src/internal/git" "github.com/zarf-dev/zarf/src/pkg/message" "github.com/zarf-dev/zarf/src/pkg/transform" "github.com/zarf-dev/zarf/src/pkg/utils" - "github.com/zarf-dev/zarf/src/types" "helm.sh/helm/v3/pkg/action" "helm.sh/helm/v3/pkg/chart" "helm.sh/helm/v3/pkg/cli" @@ -119,7 +118,7 @@ func (h *Helm) PackageChartFromGit(ctx context.Context, cosignKeyPath string) er defer spinner.Stop() // Retrieve the repo containing the chart - gitPath, err := DownloadChartFromGitToTemp(ctx, h.chart.URL, spinner) + gitPath, err := DownloadChartFromGitToTemp(ctx, h.chart.URL) if err != nil { return err } @@ -233,17 +232,16 @@ func (h *Helm) DownloadPublishedChart(ctx context.Context, cosignKeyPath string) } // DownloadChartFromGitToTemp downloads a chart from git into a temp directory -func DownloadChartFromGitToTemp(ctx context.Context, url string, spinner *message.Spinner) (string, error) { - // Create the Git configuration and download the repo - gitCfg := git.NewWithSpinner(types.GitServerInfo{}, spinner) - - // Download the git repo to a temporary directory - err := gitCfg.DownloadRepoToTemp(ctx, url) +func DownloadChartFromGitToTemp(ctx context.Context, url string) (string, error) { + path, err := utils.MakeTempDir(config.CommonOptions.TempDirectory) if err != nil { - return "", fmt.Errorf("unable to download the git repo %s: %w", url, err) + return "", fmt.Errorf("unable to create tmpdir: %w", err) } - - return gitCfg.GitPath, nil + repository, err := git.Clone(ctx, path, url, true) + if err != nil { + return "", err + } + return repository.Path(), nil } func (h *Helm) finalizeChartPackage(ctx context.Context, saved, cosignKeyPath string) error { diff --git a/src/pkg/packager/creator/normal.go b/src/pkg/packager/creator/normal.go index 99b0f572b4..2b32ac1ff1 100644 --- a/src/pkg/packager/creator/normal.go +++ b/src/pkg/packager/creator/normal.go @@ -21,7 +21,7 @@ import ( "github.com/zarf-dev/zarf/src/config" "github.com/zarf-dev/zarf/src/config/lang" "github.com/zarf-dev/zarf/src/extensions/bigbang" - "github.com/zarf-dev/zarf/src/internal/packager/git" + "github.com/zarf-dev/zarf/src/internal/git" "github.com/zarf-dev/zarf/src/internal/packager/helm" "github.com/zarf-dev/zarf/src/internal/packager/images" "github.com/zarf-dev/zarf/src/internal/packager/kustomize" @@ -513,8 +513,8 @@ func (pc *PackageCreator) addComponent(ctx context.Context, component types.Zarf for _, url := range component.Repos { // Pull all the references if there is no `@` in the string. - gitCfg := git.NewWithSpinner(types.GitServerInfo{}, spinner) - if err := gitCfg.Pull(ctx, url, componentPaths.Repos, false); err != nil { + _, err := git.Clone(ctx, componentPaths.Repos, url, false) + if err != nil { return fmt.Errorf("unable to pull git repo %s: %w", url, err) } } diff --git a/src/pkg/packager/deploy.go b/src/pkg/packager/deploy.go index 428f2e1726..0bc5fcfedb 100644 --- a/src/pkg/packager/deploy.go +++ b/src/pkg/packager/deploy.go @@ -25,8 +25,8 @@ import ( "github.com/defenseunicorns/pkg/helpers/v2" "github.com/zarf-dev/zarf/src/config" + "github.com/zarf-dev/zarf/src/internal/git" "github.com/zarf-dev/zarf/src/internal/gitea" - "github.com/zarf-dev/zarf/src/internal/packager/git" "github.com/zarf-dev/zarf/src/internal/packager/helm" "github.com/zarf-dev/zarf/src/internal/packager/images" "github.com/zarf-dev/zarf/src/internal/packager/template" @@ -545,6 +545,11 @@ func (p *Packager) pushImagesToRegistry(ctx context.Context, componentImages []s // Push all of the components git repos to the configured git server. func (p *Packager) pushReposToRepository(ctx context.Context, reposPath string, repos []string) error { for _, repoURL := range repos { + repository, err := git.Open(reposPath, repoURL) + if err != nil { + return err + } + // Create an anonymous function to push the repo to the Zarf git server tryPush := func() error { namespace, name, port, err := serviceInfoFromServiceURL(p.state.GitServer.Address) @@ -560,7 +565,6 @@ func (p *Packager) pushReposToRepository(ctx context.Context, reposPath string, return err } } - tunnel, err := p.cluster.NewTunnel(namespace, cluster.SvcResource, name, "", 0, port) if err != nil { return err @@ -570,18 +574,15 @@ func (p *Packager) pushReposToRepository(ctx context.Context, reposPath string, return err } defer tunnel.Close() - gitClient := git.New(p.state.GitServer) - gitClient.Server.Address = tunnel.HTTPEndpoint() giteaClient, err := gitea.NewClient(tunnel.HTTPEndpoint(), p.state.GitServer.PushUsername, p.state.GitServer.PushPassword) if err != nil { return err } return tunnel.Wrap(func() error { - err = gitClient.PushRepo(repoURL, reposPath) + err = repository.Push(ctx, tunnel.HTTPEndpoint(), p.state.GitServer.PushUsername, p.state.GitServer.PushPassword) if err != nil { return err } - // Add the read-only user to this repo repoName, err := transform.GitURLtoRepoName(repoURL) if err != nil { @@ -595,8 +596,11 @@ func (p *Packager) pushReposToRepository(ctx context.Context, reposPath string, }) } - gitClient := git.New(p.state.GitServer) - return gitClient.PushRepo(repoURL, reposPath) + err = repository.Push(ctx, p.state.GitServer.Address, p.state.GitServer.PushUsername, p.state.GitServer.PushPassword) + if err != nil { + return err + } + return nil } // Try repo push up to retry limit diff --git a/src/pkg/packager/filters/diff.go b/src/pkg/packager/filters/diff.go index bbba9ab789..7b65f6f576 100644 --- a/src/pkg/packager/filters/diff.go +++ b/src/pkg/packager/filters/diff.go @@ -7,7 +7,7 @@ import ( "fmt" "github.com/go-git/go-git/v5/plumbing" - "github.com/zarf-dev/zarf/src/internal/packager/git" + "github.com/zarf-dev/zarf/src/internal/git" "github.com/zarf-dev/zarf/src/pkg/transform" "github.com/zarf-dev/zarf/src/types" ) From 8d663aa4965dcc766d6da8eff8edd2450842f3e1 Mon Sep 17 00:00:00 2001 From: Austin Abro <37223396+AustinAbro321@users.noreply.github.com> Date: Thu, 1 Aug 2024 18:20:21 -0400 Subject: [PATCH 61/68] ci: better named gh jobs (#2816) Signed-off-by: Austin Abro --- .github/workflows/dependency-review.yml | 2 +- .github/workflows/nightly-ecr.yml | 2 +- .github/workflows/nightly-eks.yml | 2 +- .github/workflows/release.yml | 10 +++++----- .github/workflows/scan-codeql.yml | 2 +- .github/workflows/scan-docs-and-schema.yml | 2 +- .github/workflows/scan-lint.yml | 2 +- .github/workflows/test-bigbang.yml | 6 +++--- .github/workflows/test-e2e.yml | 12 ++++++------ .github/workflows/test-external.yml | 2 +- .github/workflows/test-site.yml | 2 +- .github/workflows/test-unit.yml | 2 +- .github/workflows/test-upgrade.yml | 6 +++--- 13 files changed, 26 insertions(+), 26 deletions(-) diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index 01843002e6..fec97b77c3 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -6,7 +6,7 @@ permissions: contents: read jobs: - validate: + dependency-review: runs-on: ubuntu-latest steps: - name: Checkout diff --git a/.github/workflows/nightly-ecr.yml b/.github/workflows/nightly-ecr.yml index 9ff144c4ff..ca9bf97ca4 100644 --- a/.github/workflows/nightly-ecr.yml +++ b/.github/workflows/nightly-ecr.yml @@ -15,7 +15,7 @@ permissions: contents: read jobs: - validate: + ecr-nightly-test: runs-on: ubuntu-latest steps: - name: Checkout diff --git a/.github/workflows/nightly-eks.yml b/.github/workflows/nightly-eks.yml index 18b23bb1c6..3ea9aae5a9 100644 --- a/.github/workflows/nightly-eks.yml +++ b/.github/workflows/nightly-eks.yml @@ -23,7 +23,7 @@ concurrency: cancel-in-progress: true jobs: - validate: + eks-nightly-test: runs-on: ubuntu-latest steps: - name: Checkout diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index cc5d405a95..8da6cbc22b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,7 +9,7 @@ on: - "v*" jobs: - build: + build-release: runs-on: ubuntu-latest permissions: packages: write @@ -78,9 +78,9 @@ jobs: path: build/ retention-days: 1 - validate: + validate-release: runs-on: ubuntu-latest - needs: build + needs: build-release steps: # Checkout the repo and setup the tooling for this job - name: Checkout @@ -114,9 +114,9 @@ jobs: if: always() uses: ./.github/actions/save-logs - push: + create-release: runs-on: ubuntu-latest - needs: validate + needs: validate-release environment: release permissions: contents: write diff --git a/.github/workflows/scan-codeql.yml b/.github/workflows/scan-codeql.yml index 4f651e704a..e5ab9bd6d8 100644 --- a/.github/workflows/scan-codeql.yml +++ b/.github/workflows/scan-codeql.yml @@ -30,7 +30,7 @@ on: - cron: "32 2 * * 5" jobs: - validate: + codeql-scan: runs-on: ubuntu-latest permissions: actions: read diff --git a/.github/workflows/scan-docs-and-schema.yml b/.github/workflows/scan-docs-and-schema.yml index e614faa5a1..c4819b6525 100644 --- a/.github/workflows/scan-docs-and-schema.yml +++ b/.github/workflows/scan-docs-and-schema.yml @@ -7,7 +7,7 @@ permissions: contents: read jobs: - validate: + validate-docs-and-schema: runs-on: ubuntu-latest steps: - name: Checkout diff --git a/.github/workflows/scan-lint.yml b/.github/workflows/scan-lint.yml index 45421e95de..95642fe5cc 100644 --- a/.github/workflows/scan-lint.yml +++ b/.github/workflows/scan-lint.yml @@ -7,7 +7,7 @@ permissions: contents: read jobs: - validate: + lint: runs-on: ubuntu-latest steps: - name: Checkout diff --git a/.github/workflows/test-bigbang.yml b/.github/workflows/test-bigbang.yml index 34e7ac5ca5..451a2082a9 100644 --- a/.github/workflows/test-bigbang.yml +++ b/.github/workflows/test-bigbang.yml @@ -30,7 +30,7 @@ concurrency: cancel-in-progress: true jobs: - build: + build-bigbang: runs-on: ubuntu-latest steps: - name: Checkout @@ -69,9 +69,9 @@ jobs: path: build/ retention-days: 1 - validate: + validate-bigbang: runs-on: ubuntu-latest - needs: build + needs: build-bigbang steps: - name: Checkout uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 diff --git a/.github/workflows/test-e2e.yml b/.github/workflows/test-e2e.yml index 91a5f160a4..b3fee07a16 100644 --- a/.github/workflows/test-e2e.yml +++ b/.github/workflows/test-e2e.yml @@ -31,7 +31,7 @@ concurrency: jobs: # Build the binary and init package - build: + build-e2e: runs-on: ubuntu-latest steps: - name: Checkout @@ -55,7 +55,7 @@ jobs: validate-without-cluster: runs-on: ubuntu-latest - needs: build + needs: build-e2e steps: - name: Checkout uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 @@ -90,7 +90,7 @@ jobs: # Run the tests on k3d validate-k3d: runs-on: ubuntu-latest - needs: build + needs: build-e2e steps: - name: Checkout uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 @@ -128,7 +128,7 @@ jobs: # Run the tests on k3s validate-k3s: runs-on: ubuntu-latest - needs: build + needs: build-e2e steps: - name: Checkout uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 @@ -166,7 +166,7 @@ jobs: # Run the tests on kind validate-kind: runs-on: ubuntu-latest - needs: build + needs: build-e2e steps: - name: Checkout uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 @@ -206,7 +206,7 @@ jobs: # Run the tests on minikube validate-minikube: runs-on: ubuntu-latest - needs: build + needs: build-e2e steps: - name: Checkout uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 diff --git a/.github/workflows/test-external.yml b/.github/workflows/test-external.yml index 081ac7c461..2db9dcbcd3 100644 --- a/.github/workflows/test-external.yml +++ b/.github/workflows/test-external.yml @@ -30,7 +30,7 @@ concurrency: cancel-in-progress: true jobs: - validate: + validate-external: runs-on: ubuntu-latest steps: - name: Checkout diff --git a/.github/workflows/test-site.yml b/.github/workflows/test-site.yml index 1042f3a0b6..fcacbfee38 100644 --- a/.github/workflows/test-site.yml +++ b/.github/workflows/test-site.yml @@ -12,7 +12,7 @@ concurrency: cancel-in-progress: true jobs: - validate: + validate-site: runs-on: ubuntu-latest defaults: run: diff --git a/.github/workflows/test-unit.yml b/.github/workflows/test-unit.yml index 78b49b9c90..4690674604 100644 --- a/.github/workflows/test-unit.yml +++ b/.github/workflows/test-unit.yml @@ -34,7 +34,7 @@ concurrency: cancel-in-progress: true jobs: - validate: + validate-unit: runs-on: ubuntu-latest steps: - name: Checkout diff --git a/.github/workflows/test-upgrade.yml b/.github/workflows/test-upgrade.yml index 3ffe41a13c..a86c02e5cc 100644 --- a/.github/workflows/test-upgrade.yml +++ b/.github/workflows/test-upgrade.yml @@ -30,7 +30,7 @@ concurrency: cancel-in-progress: true jobs: - build: + build-upgrade: runs-on: ubuntu-latest steps: - name: Checkout @@ -52,9 +52,9 @@ jobs: path: build/ retention-days: 1 - validate: + validate-upgrade: runs-on: ubuntu-latest - needs: build + needs: build-upgrade steps: - name: Checkout uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 From cb88e4cd88894d2b1120e613708d5984263cf4c2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Aug 2024 21:23:11 -0600 Subject: [PATCH 62/68] chore(deps): bump actions/dependency-review-action from 4.1.3 to 4.3.4 (#2822) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/dependency-review.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index fec97b77c3..ed74def218 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -12,4 +12,4 @@ jobs: - name: Checkout uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Dependency Review - uses: actions/dependency-review-action@9129d7d40b8c12c1ed0f60400d00c92d437adcce # v4.1.3 + uses: actions/dependency-review-action@5a2ce3f5b92ee19cbb1541a4984c76d921601d7c # v4.3.4 From 03a8a078c4a098076f58097542fb2cfd94462bb9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Aug 2024 21:50:18 -0600 Subject: [PATCH 63/68] chore(deps): bump actions/setup-node from 4.0.2 to 4.0.3 (#2821) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/commitlint.yml | 2 +- .github/workflows/test-site.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/commitlint.yml b/.github/workflows/commitlint.yml index f6243f526e..a03541314d 100644 --- a/.github/workflows/commitlint.yml +++ b/.github/workflows/commitlint.yml @@ -21,7 +21,7 @@ jobs: fetch-depth: 0 - name: Setup Node.js - uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 + uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 - name: Install commitlint run: npm install --save-dev @commitlint/{config-conventional,cli} diff --git a/.github/workflows/test-site.yml b/.github/workflows/test-site.yml index fcacbfee38..f581379037 100644 --- a/.github/workflows/test-site.yml +++ b/.github/workflows/test-site.yml @@ -22,7 +22,7 @@ jobs: uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - name: Setup Node.js - uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2 + uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3 - name: npm ci run: npm ci From 8e7c9c738ffda393639617ff84c53d69660db8c7 Mon Sep 17 00:00:00 2001 From: schristoff <28318173+schristoff@users.noreply.github.com> Date: Fri, 2 Aug 2024 02:00:21 -0600 Subject: [PATCH 64/68] chore: move context.TODO to context.Background() (4) (#2749) Signed-off-by: schristoff <28318173+schristoff@users.noreply.github.com> --- src/pkg/packager/actions/actions.go | 25 ++++++++++++------------- src/pkg/packager/creator/normal.go | 8 ++++---- src/pkg/packager/deploy.go | 8 ++++---- src/pkg/packager/remove.go | 8 ++++---- src/pkg/packager/sources/oci.go | 4 ++-- src/pkg/packager/sources/tarball.go | 8 ++++---- src/pkg/packager/sources/validate.go | 5 +++-- src/pkg/utils/cosign.go | 4 ++-- src/pkg/utils/exec/exec.go | 4 ++-- 9 files changed, 37 insertions(+), 37 deletions(-) diff --git a/src/pkg/packager/actions/actions.go b/src/pkg/packager/actions/actions.go index ee66b84c39..3d979ffcac 100644 --- a/src/pkg/packager/actions/actions.go +++ b/src/pkg/packager/actions/actions.go @@ -22,13 +22,13 @@ import ( ) // Run runs all provided actions. -func Run(defaultCfg types.ZarfComponentActionDefaults, actions []types.ZarfComponentAction, variableConfig *variables.VariableConfig) error { +func Run(ctx context.Context, defaultCfg types.ZarfComponentActionDefaults, actions []types.ZarfComponentAction, variableConfig *variables.VariableConfig) error { if variableConfig == nil { variableConfig = template.GetZarfVariableConfig() } for _, a := range actions { - if err := runAction(defaultCfg, a, variableConfig); err != nil { + if err := runAction(ctx, defaultCfg, a, variableConfig); err != nil { return err } } @@ -36,10 +36,8 @@ func Run(defaultCfg types.ZarfComponentActionDefaults, actions []types.ZarfCompo } // Run commands that a component has provided. -func runAction(defaultCfg types.ZarfComponentActionDefaults, action types.ZarfComponentAction, variableConfig *variables.VariableConfig) error { +func runAction(ctx context.Context, defaultCfg types.ZarfComponentActionDefaults, action types.ZarfComponentAction, variableConfig *variables.VariableConfig) error { var ( - ctx context.Context - cancel context.CancelFunc cmdEscaped string out string err error @@ -56,7 +54,7 @@ func runAction(defaultCfg types.ZarfComponentActionDefaults, action types.ZarfCo } // Convert the wait to a command. - if cmd, err = convertWaitToCmd(*action.Wait, action.MaxTotalSeconds); err != nil { + if cmd, err = convertWaitToCmd(ctx, *action.Wait, action.MaxTotalSeconds); err != nil { return err } @@ -85,9 +83,9 @@ func runAction(defaultCfg types.ZarfComponentActionDefaults, action types.ZarfCo // Persist the spinner output so it doesn't get overwritten by the command output. spinner.EnablePreserveWrites() - actionDefaults := actionGetCfg(defaultCfg, action, variableConfig.GetAllTemplates()) + actionDefaults := actionGetCfg(ctx, defaultCfg, action, variableConfig.GetAllTemplates()) - if cmd, err = actionCmdMutation(cmd, actionDefaults.Shell); err != nil { + if cmd, err = actionCmdMutation(ctx, cmd, actionDefaults.Shell); err != nil { spinner.Errorf(err, "Error mutating command: %s", cmdEscaped) } @@ -128,7 +126,8 @@ retryCmd: // If no timeout is set, run the command and return or continue retrying. if actionDefaults.MaxTotalSeconds < 1 { spinner.Updatef("Waiting for \"%s\" (no timeout)", cmdEscaped) - if err := tryCmd(context.TODO()); err != nil { + //TODO (schristoff): Make it so tryCmd can take a normal ctx + if err := tryCmd(context.Background()); err != nil { continue retryCmd } @@ -144,7 +143,7 @@ retryCmd: // Otherwise, try running the command. default: - ctx, cancel = context.WithTimeout(context.Background(), duration) + ctx, cancel := context.WithTimeout(ctx, duration) defer cancel() if err := tryCmd(ctx); err != nil { continue retryCmd @@ -169,7 +168,7 @@ retryCmd: } // convertWaitToCmd will return the wait command if it exists, otherwise it will return the original command. -func convertWaitToCmd(wait types.ZarfComponentActionWait, timeout *int) (string, error) { +func convertWaitToCmd(_ context.Context, wait types.ZarfComponentActionWait, timeout *int) (string, error) { // Build the timeout string. timeoutString := fmt.Sprintf("--timeout %ds", *timeout) @@ -205,7 +204,7 @@ func convertWaitToCmd(wait types.ZarfComponentActionWait, timeout *int) (string, } // Perform some basic string mutations to make commands more useful. -func actionCmdMutation(cmd string, shellPref exec.Shell) (string, error) { +func actionCmdMutation(_ context.Context, cmd string, shellPref exec.Shell) (string, error) { zarfCommand, err := utils.GetFinalExecutableCommand() if err != nil { return cmd, err @@ -236,7 +235,7 @@ func actionCmdMutation(cmd string, shellPref exec.Shell) (string, error) { } // Merge the ActionSet defaults with the action config. -func actionGetCfg(cfg types.ZarfComponentActionDefaults, a types.ZarfComponentAction, vars map[string]*variables.TextTemplate) types.ZarfComponentActionDefaults { +func actionGetCfg(_ context.Context, cfg types.ZarfComponentActionDefaults, a types.ZarfComponentAction, vars map[string]*variables.TextTemplate) types.ZarfComponentActionDefaults { if a.Mute != nil { cfg.Mute = *a.Mute } diff --git a/src/pkg/packager/creator/normal.go b/src/pkg/packager/creator/normal.go index 2b32ac1ff1..ea9f6d24c9 100644 --- a/src/pkg/packager/creator/normal.go +++ b/src/pkg/packager/creator/normal.go @@ -136,7 +136,7 @@ func (pc *PackageCreator) Assemble(ctx context.Context, dst *layout.PackagePaths onCreate := component.Actions.OnCreate onFailure := func() { - if err := actions.Run(onCreate.Defaults, onCreate.OnFailure, nil); err != nil { + if err := actions.Run(ctx, onCreate.Defaults, onCreate.OnFailure, nil); err != nil { message.Debugf("unable to run component failure action: %s", err.Error()) } } @@ -146,7 +146,7 @@ func (pc *PackageCreator) Assemble(ctx context.Context, dst *layout.PackagePaths return fmt.Errorf("unable to add component %q: %w", component.Name, err) } - if err := actions.Run(onCreate.Defaults, onCreate.OnSuccess, nil); err != nil { + if err := actions.Run(ctx, onCreate.Defaults, onCreate.OnSuccess, nil); err != nil { onFailure() return fmt.Errorf("unable to run component success action: %w", err) } @@ -359,7 +359,7 @@ func (pc *PackageCreator) addComponent(ctx context.Context, component types.Zarf } onCreate := component.Actions.OnCreate - if err := actions.Run(onCreate.Defaults, onCreate.Before, nil); err != nil { + if err := actions.Run(ctx, onCreate.Defaults, onCreate.Before, nil); err != nil { return fmt.Errorf("unable to run component before action: %w", err) } @@ -521,7 +521,7 @@ func (pc *PackageCreator) addComponent(ctx context.Context, component types.Zarf spinner.Success() } - if err := actions.Run(onCreate.Defaults, onCreate.After, nil); err != nil { + if err := actions.Run(ctx, onCreate.Defaults, onCreate.After, nil); err != nil { return fmt.Errorf("unable to run component after action: %w", err) } diff --git a/src/pkg/packager/deploy.go b/src/pkg/packager/deploy.go index 0bc5fcfedb..5f2f2f4ab3 100644 --- a/src/pkg/packager/deploy.go +++ b/src/pkg/packager/deploy.go @@ -194,7 +194,7 @@ func (p *Packager) deployComponents(ctx context.Context) (deployedComponents []t onDeploy := component.Actions.OnDeploy onFailure := func() { - if err := actions.Run(onDeploy.Defaults, onDeploy.OnFailure, p.variableConfig); err != nil { + if err := actions.Run(ctx, onDeploy.Defaults, onDeploy.OnFailure, p.variableConfig); err != nil { message.Debugf("unable to run component failure action: %s", err.Error()) } } @@ -222,7 +222,7 @@ func (p *Packager) deployComponents(ctx context.Context) (deployedComponents []t } } - if err := actions.Run(onDeploy.Defaults, onDeploy.OnSuccess, p.variableConfig); err != nil { + if err := actions.Run(ctx, onDeploy.Defaults, onDeploy.OnSuccess, p.variableConfig); err != nil { onFailure() return deployedComponents, fmt.Errorf("unable to run component success action: %w", err) } @@ -324,7 +324,7 @@ func (p *Packager) deployComponent(ctx context.Context, component types.ZarfComp return charts, err } - if err = actions.Run(onDeploy.Defaults, onDeploy.Before, p.variableConfig); err != nil { + if err = actions.Run(ctx, onDeploy.Defaults, onDeploy.Before, p.variableConfig); err != nil { return charts, fmt.Errorf("unable to run component before action: %w", err) } @@ -359,7 +359,7 @@ func (p *Packager) deployComponent(ctx context.Context, component types.ZarfComp } } - if err = actions.Run(onDeploy.Defaults, onDeploy.After, p.variableConfig); err != nil { + if err = actions.Run(ctx, onDeploy.Defaults, onDeploy.After, p.variableConfig); err != nil { return charts, fmt.Errorf("unable to run component after action: %w", err) } diff --git a/src/pkg/packager/remove.go b/src/pkg/packager/remove.go index dbfbf7d690..59583cee28 100644 --- a/src/pkg/packager/remove.go +++ b/src/pkg/packager/remove.go @@ -169,12 +169,12 @@ func (p *Packager) removeComponent(ctx context.Context, deployedPackage *types.D onRemove := c.Actions.OnRemove onFailure := func() { - if err := actions.Run(onRemove.Defaults, onRemove.OnFailure, nil); err != nil { + if err := actions.Run(ctx, onRemove.Defaults, onRemove.OnFailure, nil); err != nil { message.Debugf("Unable to run the failure action: %s", err) } } - if err := actions.Run(onRemove.Defaults, onRemove.Before, nil); err != nil { + if err := actions.Run(ctx, onRemove.Defaults, onRemove.Before, nil); err != nil { onFailure() return nil, fmt.Errorf("unable to run the before action for component (%s): %w", c.Name, err) } @@ -206,12 +206,12 @@ func (p *Packager) removeComponent(ctx context.Context, deployedPackage *types.D } } - if err := actions.Run(onRemove.Defaults, onRemove.After, nil); err != nil { + if err := actions.Run(ctx, onRemove.Defaults, onRemove.After, nil); err != nil { onFailure() return deployedPackage, fmt.Errorf("unable to run the after action: %w", err) } - if err := actions.Run(onRemove.Defaults, onRemove.OnSuccess, nil); err != nil { + if err := actions.Run(ctx, onRemove.Defaults, onRemove.OnSuccess, nil); err != nil { onFailure() return deployedPackage, fmt.Errorf("unable to run the success action: %w", err) } diff --git a/src/pkg/packager/sources/oci.go b/src/pkg/packager/sources/oci.go index f22547d520..78276d33af 100644 --- a/src/pkg/packager/sources/oci.go +++ b/src/pkg/packager/sources/oci.go @@ -78,7 +78,7 @@ func (s *OCISource) LoadPackage(ctx context.Context, dst *layout.PackagePaths, f spinner.Success() - if err := ValidatePackageSignature(dst, s.PublicKeyPath); err != nil { + if err := ValidatePackageSignature(ctx, dst, s.PublicKeyPath); err != nil { return pkg, nil, err } } @@ -140,7 +140,7 @@ func (s *OCISource) LoadPackageMetadata(ctx context.Context, dst *layout.Package spinner.Success() } - if err := ValidatePackageSignature(dst, s.PublicKeyPath); err != nil { + if err := ValidatePackageSignature(ctx, dst, s.PublicKeyPath); err != nil { if errors.Is(err, ErrPkgSigButNoKey) && skipValidation { message.Warn("The package was signed but no public key was provided, skipping signature validation") } else { diff --git a/src/pkg/packager/sources/tarball.go b/src/pkg/packager/sources/tarball.go index 9cbbf1b071..822dbd330e 100644 --- a/src/pkg/packager/sources/tarball.go +++ b/src/pkg/packager/sources/tarball.go @@ -33,7 +33,7 @@ type TarballSource struct { } // LoadPackage loads a package from a tarball. -func (s *TarballSource) LoadPackage(_ context.Context, dst *layout.PackagePaths, filter filters.ComponentFilterStrategy, unarchiveAll bool) (pkg types.ZarfPackage, warnings []string, err error) { +func (s *TarballSource) LoadPackage(ctx context.Context, dst *layout.PackagePaths, filter filters.ComponentFilterStrategy, unarchiveAll bool) (pkg types.ZarfPackage, warnings []string, err error) { spinner := message.NewProgressSpinner("Loading package from %q", s.PackageSource) defer spinner.Stop() @@ -106,7 +106,7 @@ func (s *TarballSource) LoadPackage(_ context.Context, dst *layout.PackagePaths, spinner.Success() - if err := ValidatePackageSignature(dst, s.PublicKeyPath); err != nil { + if err := ValidatePackageSignature(ctx, dst, s.PublicKeyPath); err != nil { return pkg, nil, err } } @@ -138,7 +138,7 @@ func (s *TarballSource) LoadPackage(_ context.Context, dst *layout.PackagePaths, } // LoadPackageMetadata loads a package's metadata from a tarball. -func (s *TarballSource) LoadPackageMetadata(_ context.Context, dst *layout.PackagePaths, wantSBOM bool, skipValidation bool) (pkg types.ZarfPackage, warnings []string, err error) { +func (s *TarballSource) LoadPackageMetadata(ctx context.Context, dst *layout.PackagePaths, wantSBOM bool, skipValidation bool) (pkg types.ZarfPackage, warnings []string, err error) { if s.Shasum != "" { if err := helpers.SHAsMatch(s.PackageSource, s.Shasum); err != nil { return pkg, nil, err @@ -184,7 +184,7 @@ func (s *TarballSource) LoadPackageMetadata(_ context.Context, dst *layout.Packa spinner.Success() } - if err := ValidatePackageSignature(dst, s.PublicKeyPath); err != nil { + if err := ValidatePackageSignature(ctx, dst, s.PublicKeyPath); err != nil { if errors.Is(err, ErrPkgSigButNoKey) && skipValidation { message.Warn("The package was signed but no public key was provided, skipping signature validation") } else { diff --git a/src/pkg/packager/sources/validate.go b/src/pkg/packager/sources/validate.go index 427d05708a..1c7914ea69 100644 --- a/src/pkg/packager/sources/validate.go +++ b/src/pkg/packager/sources/validate.go @@ -6,6 +6,7 @@ package sources import ( "bufio" + "context" "errors" "fmt" "io/fs" @@ -28,7 +29,7 @@ var ( ) // ValidatePackageSignature validates the signature of a package -func ValidatePackageSignature(paths *layout.PackagePaths, publicKeyPath string) error { +func ValidatePackageSignature(ctx context.Context, paths *layout.PackagePaths, publicKeyPath string) error { // If the insecure flag was provided ignore the signature validation if config.CommonOptions.Insecure { return nil @@ -52,7 +53,7 @@ func ValidatePackageSignature(paths *layout.PackagePaths, publicKeyPath string) } // Validate the signature with the key we were provided - if err := utils.CosignVerifyBlob(paths.ZarfYAML, paths.Signature, publicKeyPath); err != nil { + if err := utils.CosignVerifyBlob(ctx, paths.ZarfYAML, paths.Signature, publicKeyPath); err != nil { return fmt.Errorf("package signature did not match the provided key: %w", err) } diff --git a/src/pkg/utils/cosign.go b/src/pkg/utils/cosign.go index ae8e553cda..eb16d6159f 100644 --- a/src/pkg/utils/cosign.go +++ b/src/pkg/utils/cosign.go @@ -179,7 +179,7 @@ func Sget(ctx context.Context, image, key string, out io.Writer) error { } // CosignVerifyBlob verifies the zarf.yaml.sig was signed with the key provided by the flag -func CosignVerifyBlob(blobRef string, sigRef string, keyPath string) error { +func CosignVerifyBlob(ctx context.Context, blobRef string, sigRef string, keyPath string) error { keyOptions := options.KeyOpts{KeyRef: keyPath} cmd := &verify.VerifyBlobCmd{ KeyOpts: keyOptions, @@ -188,7 +188,7 @@ func CosignVerifyBlob(blobRef string, sigRef string, keyPath string) error { Offline: true, IgnoreTlog: true, } - err := cmd.Exec(context.TODO(), blobRef) + err := cmd.Exec(ctx, blobRef) if err == nil { message.Successf("Package signature validated!") } diff --git a/src/pkg/utils/exec/exec.go b/src/pkg/utils/exec/exec.go index a3957edd31..4ac90b6a92 100644 --- a/src/pkg/utils/exec/exec.go +++ b/src/pkg/utils/exec/exec.go @@ -42,12 +42,12 @@ func PrintCfg() Config { // Cmd executes a given command with given config. func Cmd(command string, args ...string) (string, string, error) { - return CmdWithContext(context.TODO(), Config{}, command, args...) + return CmdWithContext(context.Background(), Config{}, command, args...) } // CmdWithPrint executes a given command with given config and prints the command. func CmdWithPrint(command string, args ...string) error { - _, _, err := CmdWithContext(context.TODO(), PrintCfg(), command, args...) + _, _, err := CmdWithContext(context.Background(), PrintCfg(), command, args...) return err } From dc08529020d2fa739454a7c73fd9c7db30d9ac24 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 2 Aug 2024 08:00:56 +0000 Subject: [PATCH 65/68] chore(deps): bump github.com/sigstore/sigstore/pkg/signature/kms/hashivault from 1.8.1 to 1.8.7 (#2800) Signed-off-by: dependabot[bot] Signed-off-by: schristoff <28318173+schristoff@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: schristoff <28318173+schristoff@users.noreply.github.com> --- go.mod | 52 +++---- go.sum | 135 +++++++++--------- .../docs/commands/zarf_tools_registry_ls.md | 2 +- 3 files changed, 95 insertions(+), 94 deletions(-) diff --git a/go.mod b/go.mod index 5c299fc165..ba2b2f6cd0 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( github.com/go-git/go-git/v5 v5.11.0 github.com/goccy/go-yaml v1.12.0 github.com/gofrs/flock v0.8.1 - github.com/google/go-containerregistry v0.19.0 + github.com/google/go-containerregistry v0.20.1 github.com/gosuri/uitable v0.0.4 github.com/invopop/jsonschema v0.12.0 github.com/mholt/archiver/v3 v3.5.1 @@ -43,7 +43,7 @@ require ( github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.1 github.com/sigstore/sigstore/pkg/signature/kms/azure v1.8.1 github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.8.1 - github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.8.1 + github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.8.7 github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.18.2 @@ -68,6 +68,7 @@ require ( require ( github.com/evanphx/json-patch/v5 v5.9.0 // indirect + github.com/go-jose/go-jose/v4 v4.0.2 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/gofrs/uuid v4.2.0+incompatible // indirect ) @@ -151,22 +152,22 @@ require ( github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/atotto/clipboard v0.1.4 // indirect github.com/aws/aws-sdk-go v1.54.9 // indirect - github.com/aws/aws-sdk-go-v2 v1.24.1 // indirect - github.com/aws/aws-sdk-go-v2/config v1.26.6 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.16.16 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.7.3 // indirect + github.com/aws/aws-sdk-go-v2 v1.27.2 // indirect + github.com/aws/aws-sdk-go-v2/config v1.27.18 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.17.18 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.5 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.9 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.9 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect github.com/aws/aws-sdk-go-v2/service/ecr v1.20.2 // indirect github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.18.2 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.11 // indirect github.com/aws/aws-sdk-go-v2/service/kms v1.27.9 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.18.7 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.26.7 // indirect - github.com/aws/smithy-go v1.19.0 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.20.11 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.5 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.28.12 // indirect + github.com/aws/smithy-go v1.20.2 // indirect github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20231024185945-8841054dbdb8 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/bahlo/generic-list-go v0.2.0 // indirect @@ -182,7 +183,7 @@ require ( github.com/buildkite/go-pipeline v0.3.2 // indirect github.com/buildkite/interpolate v0.0.0-20200526001904-07f35b4ae251 // indirect github.com/cenkalti/backoff/v3 v3.2.2 // indirect - github.com/cenkalti/backoff/v4 v4.2.1 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/chai2010/gettext-go v1.0.2 // indirect github.com/charmbracelet/bubbles v0.16.1 // indirect @@ -203,7 +204,7 @@ require ( github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect github.com/containerd/ttrpc v1.2.2 // indirect github.com/containerd/typeurl/v2 v2.1.1 // indirect - github.com/coreos/go-oidc/v3 v3.9.0 // indirect + github.com/coreos/go-oidc/v3 v3.11.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect github.com/cyberphone/json-canonicalization v0.0.0-20231011164504-785e29786b46 // indirect github.com/cyphar/filepath-securejoin v0.2.4 // indirect @@ -266,7 +267,7 @@ require ( github.com/go-openapi/validate v0.22.4 // indirect github.com/go-piv/piv-go v1.11.0 // indirect github.com/go-restruct/restruct v1.2.0-alpha // indirect - github.com/go-test/deep v1.1.0 // indirect + github.com/go-test/deep v1.1.1 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/goccy/go-json v0.10.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect @@ -306,7 +307,7 @@ require ( github.com/hashicorp/go-sockaddr v1.0.5 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/hashicorp/hcl v1.0.1-vault-5 // indirect - github.com/hashicorp/vault/api v1.10.0 // indirect + github.com/hashicorp/vault/api v1.14.0 // indirect github.com/huandu/xstrings v1.4.0 // indirect github.com/iancoleman/strcase v0.3.0 // indirect github.com/imdario/mergo v0.3.16 // indirect @@ -314,7 +315,7 @@ require ( github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267 // indirect - github.com/jellydator/ttlcache/v3 v3.1.1 // indirect + github.com/jellydator/ttlcache/v3 v3.2.0 // indirect github.com/jinzhu/copier v0.4.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect @@ -335,7 +336,7 @@ require ( github.com/kylelemons/godebug v1.1.0 // indirect github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect - github.com/letsencrypt/boulder v0.0.0-20231026200631-000cd05d5491 // indirect + github.com/letsencrypt/boulder v0.0.0-20240620165639-de9c06129bec // indirect github.com/lib/pq v1.10.9 // indirect github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect github.com/lithammer/dedent v1.1.0 // indirect @@ -429,7 +430,7 @@ require ( github.com/shopspring/decimal v1.3.1 // indirect github.com/sigstore/fulcio v1.4.3 // indirect github.com/sigstore/rekor v1.3.4 // indirect - github.com/sigstore/sigstore v1.8.1 // indirect + github.com/sigstore/sigstore v1.8.7 // indirect github.com/sigstore/timestamp-authority v1.2.1 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/skeema/knownhosts v1.2.1 // indirect @@ -477,15 +478,15 @@ require ( go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.52.0 // indirect go.opentelemetry.io/otel v1.27.0 // indirect go.opentelemetry.io/otel/metric v1.27.0 // indirect - go.opentelemetry.io/otel/sdk v1.26.0 // indirect + go.opentelemetry.io/otel/sdk v1.27.0 // indirect go.opentelemetry.io/otel/trace v1.27.0 // indirect go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect go.step.sm/crypto v0.42.1 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.26.0 // indirect - golang.org/x/exp v0.0.0-20231108232855-2478ac86f678 // indirect + golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 // indirect golang.org/x/mod v0.17.0 // indirect - golang.org/x/net v0.26.0 // indirect + golang.org/x/net v0.27.0 // indirect golang.org/x/oauth2 v0.21.0 // indirect golang.org/x/sys v0.22.0 // indirect golang.org/x/text v0.16.0 // indirect @@ -499,7 +500,6 @@ require ( google.golang.org/grpc v1.64.0 // indirect google.golang.org/protobuf v1.34.2 // indirect gopkg.in/evanphx/json-patch.v5 v5.6.0 // indirect - gopkg.in/go-jose/go-jose.v2 v2.6.3 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473 // indirect diff --git a/go.sum b/go.sum index b442e5c6a1..1cc270facf 100644 --- a/go.sum +++ b/go.sum @@ -425,41 +425,41 @@ github.com/aws/aws-sdk-go v1.44.122/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX github.com/aws/aws-sdk-go v1.54.9 h1:e0Czh9AhrCVPuyaIUnibYmih3cYexJKlqlHSJ2eMKbI= github.com/aws/aws-sdk-go v1.54.9/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= github.com/aws/aws-sdk-go-v2 v1.21.2/go.mod h1:ErQhvNuEMhJjweavOYhxVkn2RUx7kQXVATHrjKtxIpM= -github.com/aws/aws-sdk-go-v2 v1.24.1 h1:xAojnj+ktS95YZlDf0zxWBkbFtymPeDP+rvUQIH3uAU= -github.com/aws/aws-sdk-go-v2 v1.24.1/go.mod h1:LNh45Br1YAkEKaAqvmE1m8FUx6a5b/V0oAKV7of29b4= -github.com/aws/aws-sdk-go-v2/config v1.26.6 h1:Z/7w9bUqlRI0FFQpetVuFYEsjzE3h7fpU6HuGmfPL/o= -github.com/aws/aws-sdk-go-v2/config v1.26.6/go.mod h1:uKU6cnDmYCvJ+pxO9S4cWDb2yWWIH5hra+32hVh1MI4= -github.com/aws/aws-sdk-go-v2/credentials v1.16.16 h1:8q6Rliyv0aUFAVtzaldUEcS+T5gbadPbWdV1WcAddK8= -github.com/aws/aws-sdk-go-v2/credentials v1.16.16/go.mod h1:UHVZrdUsv63hPXFo1H7c5fEneoVo9UXiz36QG1GEPi0= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11 h1:c5I5iH+DZcH3xOIMlz3/tCKJDaHFwYEmxvlh2fAcFo8= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.11/go.mod h1:cRrYDYAMUohBJUtUnOhydaMHtiK/1NZ0Otc9lIb6O0Y= +github.com/aws/aws-sdk-go-v2 v1.27.2 h1:pLsTXqX93rimAOZG2FIYraDQstZaaGVVN4tNw65v0h8= +github.com/aws/aws-sdk-go-v2 v1.27.2/go.mod h1:ffIFB97e2yNsv4aTSGkqtHnppsIJzw7G7BReUZ3jCXM= +github.com/aws/aws-sdk-go-v2/config v1.27.18 h1:wFvAnwOKKe7QAyIxziwSKjmer9JBMH1vzIL6W+fYuKk= +github.com/aws/aws-sdk-go-v2/config v1.27.18/go.mod h1:0xz6cgdX55+kmppvPm2IaKzIXOheGJhAufacPJaXZ7c= +github.com/aws/aws-sdk-go-v2/credentials v1.17.18 h1:D/ALDWqK4JdY3OFgA2thcPO1c9aYTT5STS/CvnkqY1c= +github.com/aws/aws-sdk-go-v2/credentials v1.17.18/go.mod h1:JuitCWq+F5QGUrmMPsk945rop6bB57jdscu+Glozdnc= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.5 h1:dDgptDO9dxeFkXy+tEgVkzSClHZje/6JkPW5aZyEvrQ= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.5/go.mod h1:gjvE2KBUgUQhcv89jqxrIxH9GaKs1JbZzWejj/DaHGA= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.43/go.mod h1:auo+PiyLl0n1l8A0e8RIeR8tOzYPfZZH/JNlrJ8igTQ= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10 h1:vF+Zgd9s+H4vOXd5BMaPWykta2a6Ih0AKLq/X6NYKn4= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10/go.mod h1:6BkRjejp/GR4411UGqkX8+wFMbFbqsUIimfK4XjOKR4= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.9 h1:cy8ahBJuhtM8GTTSyOkfy6WVPV1IE+SS5/wfXUYuulw= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.9/go.mod h1:CZBXGLaJnEZI6EVNcPd7a6B5IC5cA/GkRWtu9fp3S6Y= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.37/go.mod h1:Qe+2KtKml+FEsQF/DHmDV+xjtche/hwoF75EG4UlHW8= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10 h1:nYPe006ktcqUji8S2mqXf9c/7NdiKriOwMvWQHgYztw= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10/go.mod h1:6UV4SZkVvmODfXKql4LCbaZUpF7HO2BX38FgBf9ZOLw= -github.com/aws/aws-sdk-go-v2/internal/ini v1.7.3 h1:n3GDfwqF2tzEkXlv5cuy4iy7LpKDtqDMcNLfZDu9rls= -github.com/aws/aws-sdk-go-v2/internal/ini v1.7.3/go.mod h1:6fQQgfuGmw8Al/3M2IgIllycxV7ZW7WCdVSqfBeUiCY= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.9 h1:A4SYk07ef04+vxZToz9LWvAXl9LW0NClpPpMsi31cz0= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.9/go.mod h1:5jJcHuwDagxN+ErjQ3PU3ocf6Ylc/p9x+BLO/+X4iXw= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY= github.com/aws/aws-sdk-go-v2/service/ecr v1.20.2 h1:y6LX9GUoEA3mO0qpFl1ZQHj1rFyPWVphlzebiSt2tKE= github.com/aws/aws-sdk-go-v2/service/ecr v1.20.2/go.mod h1:Q0LcmaN/Qr8+4aSBrdrXXePqoX0eOuYpJLbYpilmWnA= github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.18.2 h1:PpbXaecV3sLAS6rjQiaKw4/jyq3Z8gNzmoJupHAoBp0= github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.18.2/go.mod h1:fUHpGXr4DrXkEDpGAjClPsviWf+Bszeb0daKE0blxv8= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4 h1:/b31bi3YVNlkzkBrm9LfpaKoaYZUxIAj4sHfOTmLfqw= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.10.4/go.mod h1:2aGXHFmbInwgP9ZfpmdIfOELL79zhdNYNmReK8qDfdQ= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10 h1:DBYTXwIGQSGs9w4jKm60F5dmCQ3EEruxdc0MFh+3EY4= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.10.10/go.mod h1:wohMUQiFdzo0NtxbBg0mSRGZ4vL3n0dKjLTINdcIino= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 h1:Ji0DY1xUsUr3I8cHps0G+XM3WWU16lP6yG8qu1GAZAs= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2/go.mod h1:5CsjAbs3NlGQyZNFACh+zztPDI7fU6eW9QsxjfnuBKg= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.11 h1:o4T+fKxA3gTMcluBNZZXE9DNaMkJuUL1O3mffCUjoJo= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.11/go.mod h1:84oZdJ+VjuJKs9v1UTC9NaodRZRseOXCTgku+vQJWR8= github.com/aws/aws-sdk-go-v2/service/kms v1.27.9 h1:W9PbZAZAEcelhhjb7KuwUtf+Lbc+i7ByYJRuWLlnxyQ= github.com/aws/aws-sdk-go-v2/service/kms v1.27.9/go.mod h1:2tFmR7fQnOdQlM2ZCEPpFnBIQD1U8wmXmduBgZbOag0= -github.com/aws/aws-sdk-go-v2/service/sso v1.18.7 h1:eajuO3nykDPdYicLlP3AGgOyVN3MOlFmZv7WGTuJPow= -github.com/aws/aws-sdk-go-v2/service/sso v1.18.7/go.mod h1:+mJNDdF+qiUlNKNC3fxn74WWNN+sOiGOEImje+3ScPM= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7 h1:QPMJf+Jw8E1l7zqhZmMlFw6w1NmfkfiSK8mS4zOx3BA= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.7/go.mod h1:ykf3COxYI0UJmxcfcxcVuz7b6uADi1FkiUz6Eb7AgM8= -github.com/aws/aws-sdk-go-v2/service/sts v1.26.7 h1:NzO4Vrau795RkUdSHKEwiR01FaGzGOH1EETJ+5QHnm0= -github.com/aws/aws-sdk-go-v2/service/sts v1.26.7/go.mod h1:6h2YuIoxaMSCFf5fi1EgZAwdfkGMgDY+DVfa61uLe4U= +github.com/aws/aws-sdk-go-v2/service/sso v1.20.11 h1:gEYM2GSpr4YNWc6hCd5nod4+d4kd9vWIAWrmGuLdlMw= +github.com/aws/aws-sdk-go-v2/service/sso v1.20.11/go.mod h1:gVvwPdPNYehHSP9Rs7q27U1EU+3Or2ZpXvzAYJNh63w= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.5 h1:iXjh3uaH3vsVcnyZX7MqCoCfcyxIrVE9iOQruRaWPrQ= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.24.5/go.mod h1:5ZXesEuy/QcO0WUnt+4sDkxhdXRHTu2yG0uCSH8B6os= +github.com/aws/aws-sdk-go-v2/service/sts v1.28.12 h1:M/1u4HBpwLuMtjlxuI2y6HoVLzF5e2mfxHCg7ZVMYmk= +github.com/aws/aws-sdk-go-v2/service/sts v1.28.12/go.mod h1:kcfd+eTdEi/40FIbLq4Hif3XMXnl5b/+t/KTfLt9xIk= github.com/aws/smithy-go v1.15.0/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= -github.com/aws/smithy-go v1.19.0 h1:KWFKQV80DpP3vJrrA9sVAHQ5gc2z8i4EzrLhLlWXcBM= -github.com/aws/smithy-go v1.19.0/go.mod h1:NukqUGpCZIILqqiV0NIjeFh24kd/FAa4beRb6nbIUPE= +github.com/aws/smithy-go v1.20.2 h1:tbp628ireGtzcHDDmLT/6ADHidqnwgF57XOXZe6tp4Q= +github.com/aws/smithy-go v1.20.2/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E= github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20231024185945-8841054dbdb8 h1:SoFYaT9UyGkR0+nogNyD/Lj+bsixB+SNuAS4ABlEs6M= github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20231024185945-8841054dbdb8/go.mod h1:2JF49jcDOrLStIXN/j/K1EKRq8a8R2qRnlZA6/o/c7c= github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= @@ -500,8 +500,8 @@ github.com/bytecodealliance/wasmtime-go/v3 v3.0.2 h1:3uZCA/BLTIu+DqCfguByNMJa2HV github.com/bytecodealliance/wasmtime-go/v3 v3.0.2/go.mod h1:RnUjnIXxEJcL6BgCvNyzCCRzZcxCgsZCi+RNlvYor5Q= github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M= github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= -github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= -github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= @@ -570,8 +570,8 @@ github.com/containerd/ttrpc v1.2.2 h1:9vqZr0pxwOF5koz6N0N3kJ0zDHokrcPxIR/ZR2YFtO github.com/containerd/ttrpc v1.2.2/go.mod h1:sIT6l32Ph/H9cvnJsfXM5drIVzTr5A2flTf1G5tYZak= github.com/containerd/typeurl/v2 v2.1.1 h1:3Q4Pt7i8nYwy2KmQWIw2+1hTvwTE/6w9FqcttATPO/4= github.com/containerd/typeurl/v2 v2.1.1/go.mod h1:IDp2JFvbwZ31H8dQbEIY7sDl2L3o3HZj1hsSQlywkQ0= -github.com/coreos/go-oidc/v3 v3.9.0 h1:0J/ogVOd4y8P0f0xUh8l9t07xRP/d8tccvjHl2dcsSo= -github.com/coreos/go-oidc/v3 v3.9.0/go.mod h1:rTKz2PYwftcrtoCzV5g5kvfJoWcm0Mk8AF8y1iAQro4= +github.com/coreos/go-oidc/v3 v3.11.0 h1:Ia3MxdwpSw702YW0xgfmP1GVCMA9aEFWu12XUZ3/OtI= +github.com/coreos/go-oidc/v3 v3.11.0/go.mod h1:gE3LgjOgFoHi9a4ce4/tJczr0Ai2/BoDhf0r5lltWI0= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= @@ -772,6 +772,8 @@ github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A= github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k= github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= +github.com/go-jose/go-jose/v4 v4.0.2 h1:R3l3kkBds16bO7ZFAEEcofK0MkrAJt3jlJznWZG0nvk= +github.com/go-jose/go-jose/v4 v4.0.2/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= @@ -815,8 +817,8 @@ github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7 github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow= github.com/go-restruct/restruct v1.2.0-alpha h1:2Lp474S/9660+SJjpVxoKuWX09JsXHSrdV7Nv3/gkvc= github.com/go-restruct/restruct v1.2.0-alpha/go.mod h1:KqrpKpn4M8OLznErihXTGLlsXFGeLxHUrLRRI/1YjGk= -github.com/go-rod/rod v0.114.5 h1:1x6oqnslwFVuXJbJifgxspJUd3O4ntaGhRLHt+4Er9c= -github.com/go-rod/rod v0.114.5/go.mod h1:aiedSEFg5DwG/fnNbUOTPMTTWX3MRj6vIs/a684Mthw= +github.com/go-rod/rod v0.116.1 h1:BDMZY3qm/14SmvHBV7DoFUhXeJ2MbUYgumQ88b+v2WE= +github.com/go-rod/rod v0.116.1/go.mod h1:3Ash9fYwznqz9S1uLQgQRStur4fCXjoxxGW+ym6TYjU= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= @@ -824,8 +826,8 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= -github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= -github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= +github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U= +github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/gobuffalo/logger v1.0.6 h1:nnZNpxYo0zx+Aj9RfMPBm+x9zAU2OayFh/xrAWi34HU= github.com/gobuffalo/logger v1.0.6/go.mod h1:J31TBEHR1QLV2683OXTAItYIg8pv2JMHnF/quuAbMjs= github.com/gobuffalo/packd v1.0.1 h1:U2wXfRr4E9DH8IdsDLlRFwTZTK7hLfq9qT/QHXGVe/0= @@ -927,8 +929,8 @@ github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-containerregistry v0.19.0 h1:uIsMRBV7m/HDkDxE/nXMnv1q+lOOSPlQ/ywc5JbB8Ic= -github.com/google/go-containerregistry v0.19.0/go.mod h1:u0qB2l7mvtWVR5kNcbFIhFY1hLbf8eeGapA+vbFDCtQ= +github.com/google/go-containerregistry v0.20.1 h1:eTgx9QNYugV4DN5mz4U8hiAGTi1ybXn0TPi4Smd8du0= +github.com/google/go-containerregistry v0.20.1/go.mod h1:YCMFNQeeXeLF+dnhhWkqDItx/JSkH01j1Kis4PsjzFI= github.com/google/go-github/v55 v55.0.0 h1:4pp/1tNMB9X/LuAhs5i0KQAE40NmiR/y6prLNb9x9cg= github.com/google/go-github/v55 v55.0.0/go.mod h1:JLahOTA1DnXzhxEymmFF5PP2tSS9JVNj68mSZNDwskA= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= @@ -1015,8 +1017,8 @@ github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWet github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0 h1:RtRsiaGvWxcwd8y3BiRZxsylPT8hLWZ5SPcfI+3IDNk= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0/go.mod h1:TzP6duP4Py2pHLVPPQp42aoYI92+PCrVotyR5e8Vqlk= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= github.com/hako/durafmt v0.0.0-20210608085754-5c1018a4e16b h1:wDUNC2eKiL35DbLvsDhiblTUXHxcOPwQSCzi7xpQUN4= github.com/hako/durafmt v0.0.0-20210608085754-5c1018a4e16b/go.mod h1:VzxiSdG6j1pi7rwGm/xYI5RbtpBgM8sARDXlvEvxlu0= github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= @@ -1081,8 +1083,8 @@ github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOn github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= -github.com/hashicorp/vault/api v1.10.0 h1:/US7sIjWN6Imp4o/Rj1Ce2Nr5bki/AXi9vAW3p2tOJQ= -github.com/hashicorp/vault/api v1.10.0/go.mod h1:jo5Y/ET+hNyz+JnKDt8XLAdKs+AM0G5W0Vp1IrFI8N8= +github.com/hashicorp/vault/api v1.14.0 h1:Ah3CFLixD5jmjusOgm8grfN9M0d+Y8fVR2SW0K6pJLU= +github.com/hashicorp/vault/api v1.14.0/go.mod h1:pV9YLxBGSz+cItFDd8Ii4G17waWOQ32zVjMWHe/cOqk= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog= @@ -1113,8 +1115,8 @@ github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOl github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267 h1:TMtDYDHKYY15rFihtRfck/bfFqNfvcabqvXAFQfAUpY= github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267/go.mod h1:h1nSAbGFqGVzn6Jyl1R/iCcBUHN4g+gW1u9CoBTrb9E= -github.com/jellydator/ttlcache/v3 v3.1.1 h1:RCgYJqo3jgvhl+fEWvjNW8thxGWsgxi+TPhRir1Y9y8= -github.com/jellydator/ttlcache/v3 v3.1.1/go.mod h1:hi7MGFdMAwZna5n2tuvh63DvFLzVKySzCVW6+0gA2n4= +github.com/jellydator/ttlcache/v3 v3.2.0 h1:6lqVJ8X3ZaUwvzENqPAobDsXNExfUJd61u++uW8a3LE= +github.com/jellydator/ttlcache/v3 v3.2.0/go.mod h1:hi7MGFdMAwZna5n2tuvh63DvFLzVKySzCVW6+0gA2n4= github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8= github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= @@ -1195,8 +1197,8 @@ github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhR github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw= github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= -github.com/letsencrypt/boulder v0.0.0-20231026200631-000cd05d5491 h1:WGrKdjHtWC67RX96eTkYD2f53NDHhrq/7robWTAfk4s= -github.com/letsencrypt/boulder v0.0.0-20231026200631-000cd05d5491/go.mod h1:o158RFmdEbYyIZmXAbrvmJWesbyxlLKee6X64VPVuOc= +github.com/letsencrypt/boulder v0.0.0-20240620165639-de9c06129bec h1:2tTW6cDth2TSgRbAhD7yjZzTQmcN25sDRPEeinR51yQ= +github.com/letsencrypt/boulder v0.0.0-20240620165639-de9c06129bec/go.mod h1:TmwEoGCwIti7BCeJ9hescZgRtatxRE+A72pCoPfmcfk= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= @@ -1269,8 +1271,8 @@ github.com/microsoft/go-rustaudit v0.0.0-20220730194248-4b17361d90a5/go.mod h1:v github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= -github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo= -github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= +github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4= +github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY= github.com/miekg/pkcs11 v1.0.3-0.20190429190417-a667d056470f/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU= github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= @@ -1351,8 +1353,9 @@ github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481/go.mod h1:yKZQO8Q github.com/nwaples/rardecode v1.1.0 h1:vSxaY8vQhOcVr4mm5e8XllHWTiM4JF507A0Katqw7MQ= github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY= +github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc= github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/oleiade/reflections v1.0.1 h1:D1XO3LVEYroYskEsoSiGItp9RUxG6jWnCVvrqH0HHQM= @@ -1546,16 +1549,16 @@ github.com/sigstore/fulcio v1.4.3 h1:9JcUCZjjVhRF9fmhVuz6i1RyhCc/EGCD7MOl+iqCJLQ github.com/sigstore/fulcio v1.4.3/go.mod h1:BQPWo7cfxmJwgaHlphUHUpFkp5+YxeJes82oo39m5og= github.com/sigstore/rekor v1.3.4 h1:RGIia1iOZU7fOiiP2UY/WFYhhp50S5aUm7YrM8aiA6E= github.com/sigstore/rekor v1.3.4/go.mod h1:1GubPVO2yO+K0m0wt/3SHFqnilr/hWbsjSOe7Vzxrlg= -github.com/sigstore/sigstore v1.8.1 h1:mAVposMb14oplk2h/bayPmIVdzbq2IhCgy4g6R0ZSjo= -github.com/sigstore/sigstore v1.8.1/go.mod h1:02SL1158BSj15bZyOFz7m+/nJzLZfFd9A8ab3Kz7w/E= +github.com/sigstore/sigstore v1.8.7 h1:L7/zKauHTg0d0Hukx7qlR4nifh6T6O6UIt9JBwAmTIg= +github.com/sigstore/sigstore v1.8.7/go.mod h1:MPiQ/NIV034Fc3Kk2IX9/XmBQdK60wfmpvgK9Z1UjRA= github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.1 h1:rEDdUefulkIQaMJyzLwtgPDLNXBIltBABiFYfb0YmgQ= github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.1/go.mod h1:RCdYCc1IxCYWzh2IdzdA6Yf7JIY0cMRqH08fpQYechw= github.com/sigstore/sigstore/pkg/signature/kms/azure v1.8.1 h1:DvRWG99QGWZC5mp42SEde2Xke/Q384Idnj2da7yB+Mk= github.com/sigstore/sigstore/pkg/signature/kms/azure v1.8.1/go.mod h1:s13mo3a0UCQS3+PAUUZfvKe48sMDMsHk2GE1b2YfPcU= github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.8.1 h1:lwdRsJv1UbBemuk7w5YfXAQilQxMoFevrzamdPbG0wY= github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.8.1/go.mod h1:2OaSQ80EcdyVRSQ3T4d1lsc6Scopblsiq8U2AEk5K1A= -github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.8.1 h1:9Ki0qudKpc1FQdef7xHO2bkLyTuw+qNUpWRzjBEmF4c= -github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.8.1/go.mod h1:nhIgyu4YwwNgalIwTGsoAzam16jjAn3ADRSWKbWPwGI= +github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.8.7 h1:dbcB9VEddYrvK+y4rHeES5OZ/pMQuucfJ0qCNWQmnp0= +github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.8.7/go.mod h1:96MrPJBkHiAvqFyqviuYbwPAdbPCj8CR3V0RJ9bKjrE= github.com/sigstore/timestamp-authority v1.2.1 h1:j9RmqSAdvKgSofeltPO4x7d+1M3AXaROBzUJ+AA7L5Q= github.com/sigstore/timestamp-authority v1.2.1/go.mod h1:Ce+vWWEf0QaKLY2u6mpwEJbmYXEVeOfUk4fQ69kE6ck= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= @@ -1701,8 +1704,8 @@ github.com/ysmood/fetchup v0.2.3 h1:ulX+SonA0Vma5zUFXtv52Kzip/xe7aj4vqT5AJwQ+ZQ= github.com/ysmood/fetchup v0.2.3/go.mod h1:xhibcRKziSvol0H1/pj33dnKrYyI2ebIvz5cOOkYGns= github.com/ysmood/goob v0.4.0 h1:HsxXhyLBeGzWXnqVKtmT9qM7EuVs/XOgkX7T6r1o1AQ= github.com/ysmood/goob v0.4.0/go.mod h1:u6yx7ZhS4Exf2MwciFr6nIM8knHQIE22lFpWHnfql18= -github.com/ysmood/got v0.34.1 h1:IrV2uWLs45VXNvZqhJ6g2nIhY+pgIG1CUoOcqfXFl1s= -github.com/ysmood/got v0.34.1/go.mod h1:yddyjq/PmAf08RMLSwDjPyCvHvYed+WjHnQxpH851LM= +github.com/ysmood/got v0.40.0 h1:ZQk1B55zIvS7zflRrkGfPDrPG3d7+JOza1ZkNxcc74Q= +github.com/ysmood/got v0.40.0/go.mod h1:W7DdpuX6skL3NszLmAsC5hT7JAhuLZhByVzHTq874Qg= github.com/ysmood/gson v0.7.3 h1:QFkWbTH8MxyUTKPkVWAENJhxqdBa4lYTQWqZCiLG6kE= github.com/ysmood/gson v0.7.3/go.mod h1:3Kzs5zDl21g5F/BlLTNcuAGAYLKt2lV5G8D1zF3RNmg= github.com/ysmood/leakless v0.8.0 h1:BzLrVoiwxikpgEQR0Lk8NyBN5Cit2b1z+u0mgL4ZJak= @@ -1752,10 +1755,10 @@ go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.44.0 h1:jd0 go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.44.0/go.mod h1:U707O40ee1FpQGyhvqnzmCJm1Wh6OX6GGBVn0E6Uyyk= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.44.0 h1:bflGWrfYyuulcdxf14V6n9+CoQcu5SAAdHmDPAJnlps= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v0.44.0/go.mod h1:qcTO4xHAxZLaLxPd60TdE88rxtItPHgHWqOhOGRr0as= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.22.0 h1:9M3+rhx7kZCIQQhQRYaZCdNu1V73tm4TvXs2ntl98C4= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.22.0/go.mod h1:noq80iT8rrHP1SfybmPiRGc9dc5M8RPmGvtwo7Oo7tc= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.22.0 h1:H2JFgRcGiyHg7H7bwcwaQJYrNFqCqrbTQ8K4p1OvDu8= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.22.0/go.mod h1:WfCWp1bGoYK8MeULtI15MmQVczfR+bFkk0DF3h06QmQ= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.0 h1:R9DE4kQ4k+YtfLI2ULwX82VtNQ2J8yZmA7ZIF/D+7Mc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.0/go.mod h1:OQFyQVrDlbe+R7xrEyDr/2Wr67Ol0hRUgsfA+V5A95s= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 h1:qFffATk0X+HD+f1Z8lswGiOQYKHRlzfmdJm0wEaVrFA= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0/go.mod h1:MOiCmryaYtc+V0Ei+Tx9o5S1ZjA7kzLucuVuyzBZloQ= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0 h1:digkEZCJWobwBqMwC0cwCq8/wkkRy/OowZg5OArWZrM= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0/go.mod h1:/OpE/y70qVkndM0TrxT4KBoN3RsFZP0QaofcfYrj76I= go.opentelemetry.io/otel/exporters/prometheus v0.44.0 h1:08qeJgaPC0YEBu2PQMbqU3rogTlyzpjhCI2b58Yn00w= @@ -1766,15 +1769,15 @@ go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.21.0 h1:VhlEQAPp9R1ktYf go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.21.0/go.mod h1:kB3ufRbfU+CQ4MlUcqtW8Z7YEOBeK2DJ6CmR5rYYF3E= go.opentelemetry.io/otel/metric v1.27.0 h1:hvj3vdEKyeCi4YaYfNjv2NUje8FqKqUY8IlF0FxV/ik= go.opentelemetry.io/otel/metric v1.27.0/go.mod h1:mVFgmRlhljgBiuk/MP/oKylr4hs85GZAylncepAX/ak= -go.opentelemetry.io/otel/sdk v1.26.0 h1:Y7bumHf5tAiDlRYFmGqetNcLaVUZmh4iYfmGxtmz7F8= -go.opentelemetry.io/otel/sdk v1.26.0/go.mod h1:0p8MXpqLeJ0pzcszQQN4F0S5FVjBLgypeGSngLsmirs= +go.opentelemetry.io/otel/sdk v1.27.0 h1:mlk+/Y1gLPLn84U4tI8d3GNJmGT/eXe3ZuOXN9kTWmI= +go.opentelemetry.io/otel/sdk v1.27.0/go.mod h1:Ha9vbLwJE6W86YstIywK2xFfPjbWlCuwPtMkKdz/Y4A= go.opentelemetry.io/otel/sdk/metric v1.21.0 h1:smhI5oD714d6jHE6Tie36fPx4WDFIg+Y6RfAY4ICcR0= go.opentelemetry.io/otel/sdk/metric v1.21.0/go.mod h1:FJ8RAsoPGv/wYMgBdUJXOm+6pzFY3YdljnXtv1SBE8Q= go.opentelemetry.io/otel/trace v1.27.0 h1:IqYb813p7cmbHk0a5y6pD5JPakbVfftRXABGt5/Rscw= go.opentelemetry.io/otel/trace v1.27.0/go.mod h1:6RiD1hkAprV4/q+yd2ln1HG9GoPx39SuvvstaLBl+l4= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= -go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= +go.opentelemetry.io/proto/otlp v1.2.0 h1:pVeZGk7nXDC9O2hncA6nHldxEjm6LByfA2aN8IOkz94= +go.opentelemetry.io/proto/otlp v1.2.0/go.mod h1:gGpR8txAl5M03pDhMC79G6SdqNV26naRm/KDsgaHD8A= go.starlark.net v0.0.0-20230525235612-a134d8f9ddca h1:VdD38733bfYv5tUZwEIskMM93VanwNIi5bIKnDrJdEY= go.starlark.net v0.0.0-20230525235612-a134d8f9ddca/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds= go.step.sm/crypto v0.42.1 h1:OmwHm3GJO8S4VGWL3k4+I+Q4P/F2s+j8msvTyGnh1Vg= @@ -1825,8 +1828,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20231108232855-2478ac86f678 h1:mchzmB1XO2pMaKFRqk/+MV3mgGG96aqaPXaMifQU47w= -golang.org/x/exp v0.0.0-20231108232855-2478ac86f678/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= +golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 h1:hNQpMuAJe5CtcUqCXaWga3FHu+kQvCqcsoVaQgSV60o= +golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -1922,8 +1925,8 @@ golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= -golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= -golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= +golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= +golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -2422,8 +2425,6 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/evanphx/json-patch.v5 v5.6.0 h1:BMT6KIwBD9CaU91PJCZIe46bDmBWa9ynTQgJIOpfQBk= gopkg.in/evanphx/json-patch.v5 v5.6.0/go.mod h1:/kvTRh1TVm5wuM6OkHxqXtE/1nUZZpihg29RtuIyfvk= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/go-jose/go-jose.v2 v2.6.3 h1:nt80fvSDlhKWQgSWyHyy5CfmlQr+asih51R8PTWNKKs= -gopkg.in/go-jose/go-jose.v2 v2.6.3/go.mod h1:zzZDPkNNw/c9IE7Z9jr11mBZQhKQTMzoEEIoEdZlFBI= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.56.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= diff --git a/site/src/content/docs/commands/zarf_tools_registry_ls.md b/site/src/content/docs/commands/zarf_tools_registry_ls.md index 262a676377..f7754e813f 100644 --- a/site/src/content/docs/commands/zarf_tools_registry_ls.md +++ b/site/src/content/docs/commands/zarf_tools_registry_ls.md @@ -31,7 +31,7 @@ $ zarf tools registry ls reg.example.com/stefanprodan/podinfo ``` --full-ref (Optional) if true, print the full image reference -h, --help help for ls - --omit-digest-tags (Optional), if true, omit digest tags (e.g., ':sha256-...') + -O, --omit-digest-tags (Optional), if true, omit digest tags (e.g., ':sha256-...') ``` ### Options inherited from parent commands From 198a26c1055d6b58bbea670b8fcd2fa47c2feb61 Mon Sep 17 00:00:00 2001 From: schristoff <28318173+schristoff@users.noreply.github.com> Date: Fri, 2 Aug 2024 02:11:45 -0600 Subject: [PATCH 66/68] chore: turn down codecov (#2823) Signed-off-by: schristoff <28318173+schristoff@users.noreply.github.com> --- .github/.codecov.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 .github/.codecov.yml diff --git a/.github/.codecov.yml b/.github/.codecov.yml new file mode 100644 index 0000000000..c17bea84b0 --- /dev/null +++ b/.github/.codecov.yml @@ -0,0 +1,20 @@ +# To validate: +# cat codecov.yml | curl --data-binary @- https://codecov.io/validate + +codecov: + notify: + require_ci_to_pass: yes + +coverage: + status: + patch: false + + status: + project: + default: + target: auto + threshold: 1% + patch: + default: + enabled: no # disable patch since it is noisy and not correct + if_not_found: success \ No newline at end of file From 5e77e3816051973c3b5ec3d48be30865b40db5e1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 2 Aug 2024 08:34:15 +0000 Subject: [PATCH 67/68] chore(deps): bump github.com/sigstore/sigstore/pkg/signature/kms/gcp from 1.8.1 to 1.8.7 (#2812) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 10 +++++----- go.sum | 20 ++++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/go.mod b/go.mod index ba2b2f6cd0..a5196222e6 100644 --- a/go.mod +++ b/go.mod @@ -42,7 +42,7 @@ require ( github.com/sigstore/cosign/v2 v2.2.3 github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.1 github.com/sigstore/sigstore/pkg/signature/kms/azure v1.8.1 - github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.8.1 + github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.8.7 github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.8.7 github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 @@ -78,11 +78,11 @@ require ( atomicgo.dev/keyboard v0.2.9 // indirect atomicgo.dev/schedule v0.1.0 // indirect cloud.google.com/go v0.115.0 // indirect - cloud.google.com/go/auth v0.6.0 // indirect + cloud.google.com/go/auth v0.6.1 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.2 // indirect cloud.google.com/go/compute/metadata v0.3.0 // indirect cloud.google.com/go/iam v1.1.9 // indirect - cloud.google.com/go/kms v1.18.0 // indirect + cloud.google.com/go/kms v1.18.2 // indirect cloud.google.com/go/longrunning v0.5.7 // indirect cloud.google.com/go/storage v1.42.0 // indirect cuelabs.dev/go/oci/ociregistry v0.0.0-20231103182354-93e78c079a13 // indirect @@ -493,11 +493,11 @@ require ( golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect - google.golang.org/api v0.186.0 // indirect + google.golang.org/api v0.187.0 // indirect google.golang.org/genproto v0.0.0-20240624140628-dc46fd24d27d // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240624140628-dc46fd24d27d // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240624140628-dc46fd24d27d // indirect - google.golang.org/grpc v1.64.0 // indirect + google.golang.org/grpc v1.64.1 // indirect google.golang.org/protobuf v1.34.2 // indirect gopkg.in/evanphx/json-patch.v5 v5.6.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect diff --git a/go.sum b/go.sum index 1cc270facf..4d6331b57f 100644 --- a/go.sum +++ b/go.sum @@ -55,8 +55,8 @@ cloud.google.com/go/asset v1.8.0/go.mod h1:mUNGKhiqIdbr8X7KNayoYvyc4HbbFO9URsjby cloud.google.com/go/assuredworkloads v1.5.0/go.mod h1:n8HOZ6pff6re5KYfBXcFvSViQjDwxFkAkmUFffJRbbY= cloud.google.com/go/assuredworkloads v1.6.0/go.mod h1:yo2YOk37Yc89Rsd5QMVECvjaMKymF9OP+QXWlKXUkXw= cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVoYoxeLBoj4XkKYscNI= -cloud.google.com/go/auth v0.6.0 h1:5x+d6b5zdezZ7gmLWD1m/xNjnaQ2YDhmIz/HH3doy1g= -cloud.google.com/go/auth v0.6.0/go.mod h1:b4acV+jLQDyjwm4OXHYjNvRi4jvGBzHWJRtJcy+2P4g= +cloud.google.com/go/auth v0.6.1 h1:T0Zw1XM5c1GlpN2HYr2s+m3vr1p2wy+8VN+Z1FKxW38= +cloud.google.com/go/auth v0.6.1/go.mod h1:eFHG7zDzbXHKmjJddFG/rBlcGp6t25SwRUiEQSlO4x4= cloud.google.com/go/auth/oauth2adapt v0.2.2 h1:+TTV8aXpjeChS9M+aTtN/TjdQnzJvmzKFt//oWu7HX4= cloud.google.com/go/auth/oauth2adapt v0.2.2/go.mod h1:wcYjgpZI9+Yu7LyYBg4pqSiaRkfEK3GQcpb7C/uyF1Q= cloud.google.com/go/automl v1.5.0/go.mod h1:34EjfoFGMZ5sgJ9EoLsRtdPSNZLcfflJR39VbVNS2M0= @@ -123,8 +123,8 @@ cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp cloud.google.com/go/iam v0.5.0/go.mod h1:wPU9Vt0P4UmCux7mqtRu6jcpPAb74cP1fh50J3QpkUc= cloud.google.com/go/iam v1.1.9 h1:oSkYLVtVme29uGYrOcKcvJRht7cHJpYD09GM9JaR0TE= cloud.google.com/go/iam v1.1.9/go.mod h1:Nt1eDWNYH9nGQg3d/mY7U1hvfGmsaG9o/kLGoLoLXjQ= -cloud.google.com/go/kms v1.18.0 h1:pqNdaVmZJFP+i8OVLocjfpdTWETTYa20FWOegSCdrRo= -cloud.google.com/go/kms v1.18.0/go.mod h1:DyRBeWD/pYBMeyiaXFa/DGNyxMDL3TslIKb8o/JkLkw= +cloud.google.com/go/kms v1.18.2 h1:EGgD0B9k9tOOkbPhYW1PHo2W0teamAUYMOUIcDRMfPk= +cloud.google.com/go/kms v1.18.2/go.mod h1:YFz1LYrnGsXARuRePL729oINmN5J/5e7nYijgvfiIeY= cloud.google.com/go/language v1.4.0/go.mod h1:F9dRpNFQmJbkaop6g0JhSBXCNlO90e1KWx5iDdxbWic= cloud.google.com/go/language v1.6.0/go.mod h1:6dJ8t3B+lUYfStgls25GusK04NLh3eDLQnWM3mdEbhI= cloud.google.com/go/lifesciences v0.5.0/go.mod h1:3oIKy8ycWGPUyZDR/8RNnTOYevhaMLqh5vLUXs9zvT8= @@ -1555,8 +1555,8 @@ github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.1 h1:rEDdUefulkIQaMJyzLw github.com/sigstore/sigstore/pkg/signature/kms/aws v1.8.1/go.mod h1:RCdYCc1IxCYWzh2IdzdA6Yf7JIY0cMRqH08fpQYechw= github.com/sigstore/sigstore/pkg/signature/kms/azure v1.8.1 h1:DvRWG99QGWZC5mp42SEde2Xke/Q384Idnj2da7yB+Mk= github.com/sigstore/sigstore/pkg/signature/kms/azure v1.8.1/go.mod h1:s13mo3a0UCQS3+PAUUZfvKe48sMDMsHk2GE1b2YfPcU= -github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.8.1 h1:lwdRsJv1UbBemuk7w5YfXAQilQxMoFevrzamdPbG0wY= -github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.8.1/go.mod h1:2OaSQ80EcdyVRSQ3T4d1lsc6Scopblsiq8U2AEk5K1A= +github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.8.7 h1:zYg1XlbKpQkmE7FpWTkLuUn7RttLAq4FcZ1G9JcqhoY= +github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.8.7/go.mod h1:VmUsO1R4OHuyHBEgI4bbSUn0z2nojszrDMvlDxyX/dE= github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.8.7 h1:dbcB9VEddYrvK+y4rHeES5OZ/pMQuucfJ0qCNWQmnp0= github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.8.7/go.mod h1:96MrPJBkHiAvqFyqviuYbwPAdbPCj8CR3V0RJ9bKjrE= github.com/sigstore/timestamp-authority v1.2.1 h1:j9RmqSAdvKgSofeltPO4x7d+1M3AXaROBzUJ+AA7L5Q= @@ -2237,8 +2237,8 @@ google.golang.org/api v0.96.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ google.golang.org/api v0.97.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= google.golang.org/api v0.98.0/go.mod h1:w7wJQLTM+wvQpNf5JyEcBoxK0RH7EDrh/L4qfsuJ13s= google.golang.org/api v0.100.0/go.mod h1:ZE3Z2+ZOr87Rx7dqFsdRQkRBk36kDtp/h+QpHbB7a70= -google.golang.org/api v0.186.0 h1:n2OPp+PPXX0Axh4GuSsL5QL8xQCTb2oDwyzPnQvqUug= -google.golang.org/api v0.186.0/go.mod h1:hvRbBmgoje49RV3xqVXrmP6w93n6ehGgIVPYrGtBFFc= +google.golang.org/api v0.187.0 h1:Mxs7VATVC2v7CY+7Xwm4ndkX71hpElcvx0D1Ji/p1eo= +google.golang.org/api v0.187.0/go.mod h1:KIHlTc4x7N7gKKuVsdmfBXN13yEEWXWFURWY6SBp2gk= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -2393,8 +2393,8 @@ google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACu google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= -google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= +google.golang.org/grpc v1.64.1 h1:LKtvyfbX3UGVPFcGqJ9ItpVWW6oN/2XqTxfAnwRRXiA= +google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= From 36f1df6de73c28b8dda8ea4a61bb38bcafe389d0 Mon Sep 17 00:00:00 2001 From: Philip Laine Date: Fri, 2 Aug 2024 15:07:31 +0200 Subject: [PATCH 68/68] refactor: move and test HasImages (#2831) Signed-off-by: Philip Laine --- src/pkg/packager/common.go | 12 +---- src/types/package.go | 10 ++++ src/types/package_test.go | 101 +++++++++++++++++++++++++++++++++++++ 3 files changed, 112 insertions(+), 11 deletions(-) create mode 100644 src/types/package_test.go diff --git a/src/pkg/packager/common.go b/src/pkg/packager/common.go index a753ec29d4..dd4588a193 100644 --- a/src/pkg/packager/common.go +++ b/src/pkg/packager/common.go @@ -149,16 +149,6 @@ func (p *Packager) isConnectedToCluster() bool { return p.cluster != nil } -// hasImages returns whether the current package contains images -func (p *Packager) hasImages() bool { - for _, component := range p.cfg.Pkg.Components { - if len(component.Images) > 0 { - return true - } - } - return false -} - // attemptClusterChecks attempts to connect to the cluster and check for useful metadata and config mismatches. // NOTE: attemptClusterChecks should only return an error if there is a problem significant enough to halt a deployment, otherwise it should return nil and print a warning message. func (p *Packager) attemptClusterChecks(ctx context.Context) (err error) { @@ -197,7 +187,7 @@ func (p *Packager) attemptClusterChecks(ctx context.Context) (err error) { // validatePackageArchitecture validates that the package architecture matches the target cluster architecture. func (p *Packager) validatePackageArchitecture(ctx context.Context) error { // Ignore this check if we don't have a cluster connection, or the package contains no images - if !p.isConnectedToCluster() || !p.hasImages() { + if !p.isConnectedToCluster() || !p.cfg.Pkg.HasImages() { return nil } diff --git a/src/types/package.go b/src/types/package.go index bb4b0edc0a..fa3f8e5819 100644 --- a/src/types/package.go +++ b/src/types/package.go @@ -37,6 +37,16 @@ func (pkg ZarfPackage) IsInitConfig() bool { return pkg.Kind == ZarfInitConfig } +// HasImages returns true if one of the components contains an image. +func (pkg ZarfPackage) HasImages() bool { + for _, component := range pkg.Components { + if len(component.Images) > 0 { + return true + } + } + return false +} + // IsSBOMAble checks if a package has contents that an SBOM can be created on (i.e. images, files, or data injections). func (pkg ZarfPackage) IsSBOMAble() bool { for _, c := range pkg.Components { diff --git a/src/types/package_test.go b/src/types/package_test.go new file mode 100644 index 0000000000..7dca85bd1f --- /dev/null +++ b/src/types/package_test.go @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2021-Present The Zarf Authors + +package types + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestZarfPackageIsInitPackage(t *testing.T) { + t.Parallel() + + pkg := ZarfPackage{ + Kind: ZarfInitConfig, + } + require.True(t, pkg.IsInitConfig()) + pkg = ZarfPackage{ + Kind: ZarfPackageConfig, + } + require.False(t, pkg.IsInitConfig()) +} + +func TestZarfPackageHasImages(t *testing.T) { + t.Parallel() + + pkg := ZarfPackage{ + Components: []ZarfComponent{ + { + Name: "without images", + }, + }, + } + require.False(t, pkg.HasImages()) + pkg = ZarfPackage{ + Components: []ZarfComponent{ + { + Name: "with images", + Images: []string{"docker.io/library/alpine:latest"}, + }, + }, + } + require.True(t, pkg.HasImages()) +} + +func TestZarfPackageIsSBOMable(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + images []string + files []ZarfFile + dataInjections []ZarfDataInjection + expected bool + }{ + { + name: "empty component", + expected: false, + }, + { + name: "only images", + images: []string{""}, + expected: true, + }, + { + name: "only files", + files: []ZarfFile{{}}, + expected: true, + }, + { + name: "only data injections", + dataInjections: []ZarfDataInjection{{}}, + expected: true, + }, + { + name: "all three set", + images: []string{""}, + files: []ZarfFile{{}}, + dataInjections: []ZarfDataInjection{{}}, + expected: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + pkg := ZarfPackage{ + Components: []ZarfComponent{ + { + Name: "without images", + Images: tt.images, + Files: tt.files, + DataInjections: tt.dataInjections, + }, + }, + } + require.Equal(t, tt.expected, pkg.IsSBOMAble()) + }) + } +}