diff --git a/.github/ISSUE_TEMPLATE/release.md b/.github/ISSUE_TEMPLATE/release.md index dd24ed32aee77..b43b91a0e05ce 100644 --- a/.github/ISSUE_TEMPLATE/release.md +++ b/.github/ISSUE_TEMPLATE/release.md @@ -9,12 +9,6 @@ assignees: '' Target RC1 date: ___. __, ____ Target GA date: ___. __, ____ - - [ ] Create new section in the [Release Planning doc](https://docs.google.com/document/d/1trJIomcgXcfvLw0aYnERrFWfPjQOfYMDJOCh1S8nMBc/edit?usp=sharing) - - [ ] Schedule a Release Planning meeting roughly two weeks before the scheduled Release freeze date by adding it to the community calendar (or delegate this task to someone with write access to the community calendar) - - [ ] Include Zoom link in the invite - - [ ] Post in #argo-cd and #argo-contributors one week before the meeting - - [ ] Post again one hour before the meeting - - [ ] At the meeting, remove issues/PRs from the project's column for that release which have not been “claimed” by at least one Approver (add it to the next column if Approver requests that) - [ ] 1wk before feature freeze post in #argo-contributors that PRs must be merged by DD-MM-YYYY to be included in the release - ask approvers to drop items from milestone they can’t merge - [ ] At least two days before RC1 date, draft RC blog post and submit it for review (or delegate this task) - [ ] Cut RC1 (or delegate this task to an Approver and coordinate timing) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 406306bbeca2e..c1a3f42508aaa 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -13,11 +13,12 @@ Checklist: * [ ] I've updated both the CLI and UI to expose my feature, or I plan to submit a second PR with them. * [ ] Does this PR require documentation updates? * [ ] I've updated documentation as required by this PR. -* [ ] Optional. My organization is added to USERS.md. * [ ] I have signed off all my commits as required by [DCO](https://github.com/argoproj/argoproj/blob/master/community/CONTRIBUTING.md#legal) * [ ] I have written unit and/or e2e tests for my change. PRs without these are unlikely to be merged. * [ ] My build is green ([troubleshooting builds](https://argo-cd.readthedocs.io/en/latest/developer-guide/ci/)). * [ ] My new feature complies with the [feature status](https://github.com/argoproj/argoproj/blob/master/community/feature-status.md) guidelines. * [ ] I have added a brief description of why this PR is necessary and/or what this PR solves. +* [ ] Optional. My organization is added to USERS.md. +* [ ] Optional. For bug fixes, I've indicated what older releases this fix should be cherry-picked into (this may or may not happen depending on risk/complexity). diff --git a/.github/workflows/ci-build.yaml b/.github/workflows/ci-build.yaml index adffe526da728..c8a522fbf7198 100644 --- a/.github/workflows/ci-build.yaml +++ b/.github/workflows/ci-build.yaml @@ -1,5 +1,5 @@ name: Integration tests -on: +on: push: branches: - 'master' @@ -23,9 +23,28 @@ permissions: contents: read jobs: + changes: + runs-on: ubuntu-latest + outputs: + backend: ${{ steps.filter.outputs.backend }} + frontend: ${{ steps.filter.outputs.frontend }} + steps: + - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + - uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2 + id: filter + with: + # Any file which is not under docs/, ui/ or is not a markdown file is counted as a backend file + filters: | + backend: + - '!(ui/**|docs/**|**.md|**/*.md)' + frontend: + - 'ui/**' check-go: name: Ensure Go modules synchronicity + if: ${{ needs.changes.outputs.backend == 'true' }} runs-on: ubuntu-22.04 + needs: + - changes steps: - name: Checkout code uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 @@ -43,7 +62,10 @@ jobs: build-go: name: Build & cache Go code + if: ${{ needs.changes.outputs.backend == 'true' }} runs-on: ubuntu-22.04 + needs: + - changes steps: - name: Checkout code uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 @@ -67,7 +89,10 @@ jobs: contents: read # for actions/checkout to fetch code pull-requests: read # for golangci/golangci-lint-action to fetch pull requests name: Lint Go code + if: ${{ needs.changes.outputs.backend == 'true' }} runs-on: ubuntu-22.04 + needs: + - changes steps: - name: Checkout code uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 @@ -83,12 +108,14 @@ jobs: test-go: name: Run unit tests for Go packages + if: ${{ needs.changes.outputs.backend == 'true' }} runs-on: ubuntu-22.04 needs: - build-go + - changes env: GITHUB_TOKEN: ${{ secrets.E2E_TEST_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - GITLAB_TOKEN: ${{ secrets.E2E_TEST_GITLAB_TOKEN }} + GITLAB_TOKEN: ${{ secrets.E2E_TEST_GITLAB_TOKEN }} steps: - name: Create checkout directory run: mkdir -p ~/go/src/github.com/argoproj @@ -150,12 +177,14 @@ jobs: test-go-race: name: Run unit tests with -race for Go packages + if: ${{ needs.changes.outputs.backend == 'true' }} runs-on: ubuntu-22.04 needs: - build-go + - changes env: GITHUB_TOKEN: ${{ secrets.E2E_TEST_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - GITLAB_TOKEN: ${{ secrets.E2E_TEST_GITLAB_TOKEN }} + GITLAB_TOKEN: ${{ secrets.E2E_TEST_GITLAB_TOKEN }} steps: - name: Create checkout directory run: mkdir -p ~/go/src/github.com/argoproj @@ -212,7 +241,10 @@ jobs: codegen: name: Check changes to generated code + if: ${{ needs.changes.outputs.backend == 'true' }} runs-on: ubuntu-22.04 + needs: + - changes steps: - name: Checkout code uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 @@ -260,14 +292,17 @@ jobs: build-ui: name: Build, test & lint UI code + if: ${{ needs.changes.outputs.frontend == 'true' }} runs-on: ubuntu-22.04 + needs: + - changes steps: - name: Checkout code uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 - name: Setup NodeJS uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1 with: - node-version: '20.7.0' + node-version: '21.6.1' - name: Restore node dependency cache id: cache-dependencies uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 @@ -292,10 +327,12 @@ jobs: analyze: name: Process & analyze test artifacts + if: ${{ needs.changes.outputs.backend == 'true' || needs.changes.outputs.frontend == 'true' }} runs-on: ubuntu-22.04 needs: - test-go - build-ui + - changes env: sonar_secret: ${{ secrets.SONAR_TOKEN }} steps: @@ -315,7 +352,7 @@ jobs: - name: Create test-results directory run: | mkdir -p test-results - - name: Get code coverage artifiact + - name: Get code coverage artifact uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a # v3.0.2 with: name: code-coverage @@ -336,35 +373,37 @@ jobs: SCANNER_PATH: /tmp/cache/scanner OS: linux run: | - # We do not use the provided action, because it does contain an old - # version of the scanner, and also takes time to build. - set -e - mkdir -p ${SCANNER_PATH} - export SONAR_USER_HOME=${SCANNER_PATH}/.sonar - if [[ ! -x "${SCANNER_PATH}/sonar-scanner-${SCANNER_VERSION}-${OS}/bin/sonar-scanner" ]]; then - curl -Ol https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-${SCANNER_VERSION}-${OS}.zip - unzip -qq -o sonar-scanner-cli-${SCANNER_VERSION}-${OS}.zip -d ${SCANNER_PATH} - fi - - chmod +x ${SCANNER_PATH}/sonar-scanner-${SCANNER_VERSION}-${OS}/bin/sonar-scanner - chmod +x ${SCANNER_PATH}/sonar-scanner-${SCANNER_VERSION}-${OS}/jre/bin/java - - # Explicitly set NODE_MODULES - export NODE_MODULES=${PWD}/ui/node_modules - export NODE_PATH=${PWD}/ui/node_modules - - ${SCANNER_PATH}/sonar-scanner-${SCANNER_VERSION}-${OS}/bin/sonar-scanner + # We do not use the provided action, because it does contain an old + # version of the scanner, and also takes time to build. + set -e + mkdir -p ${SCANNER_PATH} + export SONAR_USER_HOME=${SCANNER_PATH}/.sonar + if [[ ! -x "${SCANNER_PATH}/sonar-scanner-${SCANNER_VERSION}-${OS}/bin/sonar-scanner" ]]; then + curl -Ol https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-${SCANNER_VERSION}-${OS}.zip + unzip -qq -o sonar-scanner-cli-${SCANNER_VERSION}-${OS}.zip -d ${SCANNER_PATH} + fi + + chmod +x ${SCANNER_PATH}/sonar-scanner-${SCANNER_VERSION}-${OS}/bin/sonar-scanner + chmod +x ${SCANNER_PATH}/sonar-scanner-${SCANNER_VERSION}-${OS}/jre/bin/java + + # Explicitly set NODE_MODULES + export NODE_MODULES=${PWD}/ui/node_modules + export NODE_PATH=${PWD}/ui/node_modules + + ${SCANNER_PATH}/sonar-scanner-${SCANNER_VERSION}-${OS}/bin/sonar-scanner if: env.sonar_secret != '' test-e2e: name: Run end-to-end tests + if: ${{ needs.changes.outputs.backend == 'true' }} runs-on: ubuntu-22.04 strategy: fail-fast: false matrix: - k3s-version: [v1.28.2, v1.27.6, v1.26.9, v1.25.14] - needs: + k3s-version: [v1.29.1, v1.28.6, v1.27.10, v1.26.13, v1.25.16] + needs: - build-go + - changes env: GOPATH: /home/runner/go ARGOCD_FAKE_IN_CLUSTER: "true" @@ -374,10 +413,10 @@ jobs: ARGOCD_E2E_K3S: "true" ARGOCD_IN_CI: "true" ARGOCD_E2E_APISERVER_PORT: "8088" - ARGOCD_APPLICATION_NAMESPACES: "argocd-e2e-external" + ARGOCD_APPLICATION_NAMESPACES: "argocd-e2e-external,argocd-e2e-external-2" ARGOCD_SERVER: "127.0.0.1:8088" GITHUB_TOKEN: ${{ secrets.E2E_TEST_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} - GITLAB_TOKEN: ${{ secrets.E2E_TEST_GITLAB_TOKEN }} + GITLAB_TOKEN: ${{ secrets.E2E_TEST_GITLAB_TOKEN }} steps: - name: Checkout code uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 @@ -427,9 +466,9 @@ jobs: git config --global user.email "john.doe@example.com" - name: Pull Docker image required for tests run: | - docker pull ghcr.io/dexidp/dex:v2.37.0 + docker pull ghcr.io/dexidp/dex:v2.38.0 docker pull argoproj/argo-cd-ci-builder:v1.0.0 - docker pull redis:7.0.11-alpine + docker pull redis:7.0.14-alpine - name: Create target directory for binaries in the build-process run: | mkdir -p dist @@ -462,3 +501,26 @@ jobs: name: e2e-server-k8s${{ matrix.k3s-version }}.log path: /tmp/e2e-server.log if: ${{ failure() }} + + # workaround for status checks -- check this one job instead of each individual E2E job in the matrix + # this allows us to skip the entire matrix when it doesn't need to run while still having accurate status checks + # see: + # https://github.com/argoproj/argo-workflows/pull/12006 + # https://github.com/orgs/community/discussions/9141#discussioncomment-2296809 + # https://github.com/orgs/community/discussions/26822#discussioncomment-3305794 + test-e2e-composite-result: + name: E2E Tests - Composite result + if: ${{ always() }} + needs: + - test-e2e + - changes + runs-on: ubuntu-22.04 + steps: + - run: | + result="${{ needs.test-e2e.result }}" + # mark as successful even if skipped + if [[ $result == "success" || $result == "skipped" ]]; then + exit 0 + else + exit 1 + fi \ No newline at end of file diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 58426890abcbf..2311d43925bb7 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -27,10 +27,15 @@ jobs: # CodeQL runs on ubuntu-latest and windows-latest runs-on: ubuntu-22.04 - steps: - name: Checkout repository uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0 + + # Use correct go version. https://github.com/github/codeql-action/issues/1842#issuecomment-1704398087 + - name: Setup Golang + uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.0.0 + with: + go-version-file: go.mod # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/image-reuse.yaml b/.github/workflows/image-reuse.yaml index 55d3bc309294a..0838f38e4230d 100644 --- a/.github/workflows/image-reuse.yaml +++ b/.github/workflows/image-reuse.yaml @@ -74,9 +74,9 @@ jobs: go-version: ${{ inputs.go-version }} - name: Install cosign - uses: sigstore/cosign-installer@11086d25041f77fe8fe7b9ea4e48e3b9192b8f19 # v3.1.2 + uses: sigstore/cosign-installer@1fc5bd396d372bee37d608f955b336615edf79c8 # v3.2.0 with: - cosign-release: 'v2.0.0' + cosign-release: 'v2.2.1' - uses: docker/setup-qemu-action@2b82ce82d56a2a04d2637cd93a637ae1b359c0a7 # v2.2.0 - uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0 @@ -145,7 +145,7 @@ jobs: - name: Build and push container image id: image - uses: docker/build-push-action@2eb1c1961a95fc15694676618e422e8ba1d63825 #v4.1.1 + uses: docker/build-push-action@4a13e500e55cf31b7a5d59a38ab2040ab0f42f56 #v5.1.0 with: context: . platforms: ${{ inputs.platforms }} diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 7e9303f288ae4..ae5174659cf40 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -38,7 +38,7 @@ jobs: packages: write # for uploading attestations. (https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#known-issues) # Must be refernced by a tag. https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#referencing-the-slsa-generator if: github.repository == 'argoproj/argo-cd' - uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v1.7.0 + uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v1.9.0 with: image: quay.io/argoproj/argocd digest: ${{ needs.argocd-image.outputs.image-digest }} @@ -120,7 +120,7 @@ jobs: contents: write # Needed for release uploads if: github.repository == 'argoproj/argo-cd' # Must be refernced by a tag. https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#referencing-the-slsa-generator - uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v1.7.0 + uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v1.9.0 with: base64-subjects: "${{ needs.goreleaser.outputs.hashes }}" provenance-name: "argocd-cli.intoto.jsonl" @@ -204,7 +204,7 @@ jobs: contents: write # Needed for release uploads if: github.repository == 'argoproj/argo-cd' # Must be refernced by a tag. https://github.com/slsa-framework/slsa-github-generator/blob/main/internal/builders/container/README.md#referencing-the-slsa-generator - uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v1.7.0 + uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v1.9.0 with: base64-subjects: "${{ needs.generate-sbom.outputs.hashes }}" provenance-name: "argocd-sbom.intoto.jsonl" @@ -265,11 +265,13 @@ jobs: set -xue SOURCE_TAG=${{ github.ref_name }} VERSION_REF="${SOURCE_TAG#*v}" + COMMIT_HASH=$(git rev-parse HEAD) if echo "$VERSION_REF" | grep -E -- '^[0-9]+\.[0-9]+\.0-rc1';then VERSION=$(awk 'BEGIN {FS=OFS="."} {$2++; print}' <<< "${VERSION_REF%-rc1}") echo "Updating VERSION to: $VERSION" echo "UPDATE_VERSION=true" >> $GITHUB_ENV echo "NEW_VERSION=$VERSION" >> $GITHUB_ENV + echo "COMMIT_HASH=$COMMIT_HASH" >> $GITHUB_ENV else echo "Not updating VERSION" echo "UPDATE_VERSION=false" >> $GITHUB_ENV @@ -278,6 +280,10 @@ jobs: - name: Update VERSION on master branch run: | echo ${{ env.NEW_VERSION }} > VERSION + # Replace the 'project-release: vX.X.X-rcX' line in SECURITY-INSIGHTS.yml + sed -i "s/project-release: v.*$/project-release: v${{ env.NEW_VERSION }}/" SECURITY-INSIGHTS.yml + # Update the 'commit-hash: XXXXXXX' line in SECURITY-INSIGHTS.yml + sed -i "s/commit-hash: .*/commit-hash: ${{ env.NEW_VERSION }}/" SECURITY-INSIGHTS.yml if: ${{ env.UPDATE_VERSION == 'true' }} - name: Create PR to update VERSION on master branch diff --git a/CODEOWNERS b/CODEOWNERS index 507193dad5611..83bb38871d96d 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -2,8 +2,10 @@ ** @argoproj/argocd-approvers # Docs -/docs/** @argoproj/argocd-approvers @argoproj/argocd-approvers-docs -/USERS.md @argoproj/argocd-approvers @argoproj/argocd-approvers-docs +/docs/** @argoproj/argocd-approvers @argoproj/argocd-approvers-docs +/USERS.md @argoproj/argocd-approvers @argoproj/argocd-approvers-docs +/README.md @argoproj/argocd-approvers @argoproj/argocd-approvers-docs +/mkdocs.yml @argoproj/argocd-approvers @argoproj/argocd-approvers-docs # CI /.github/** @argoproj/argocd-approvers @argoproj/argocd-approvers-ci diff --git a/Dockerfile b/Dockerfile index 2c31b5077f67e..511fa7cceef96 100644 --- a/Dockerfile +++ b/Dockerfile @@ -51,7 +51,7 @@ RUN groupadd -g $ARGOCD_USER_ID argocd && \ apt-get update && \ apt-get dist-upgrade -y && \ apt-get install -y \ - git git-lfs tini gpg tzdata && \ + git git-lfs tini gpg tzdata connect-proxy && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* @@ -83,7 +83,7 @@ WORKDIR /home/argocd #################################################################################################### # Argo CD UI stage #################################################################################################### -FROM --platform=$BUILDPLATFORM docker.io/library/node:20.6.1@sha256:14bd39208dbc0eb171cbfb26ccb9ac09fa1b2eba04ccd528ab5d12983fd9ee24 AS argocd-ui +FROM --platform=$BUILDPLATFORM docker.io/library/node:21.6.1@sha256:abc4a25c8b5a2b460f3144aabfc8941ecd7e4fb721e0b14b635e70394c1899fb AS argocd-ui WORKDIR /src COPY ["ui/package.json", "ui/yarn.lock", "./"] diff --git a/Makefile b/Makefile index 4d245b9bf15b5..a4d6bd5264624 100644 --- a/Makefile +++ b/Makefile @@ -49,7 +49,7 @@ ARGOCD_E2E_DEX_PORT?=5556 ARGOCD_E2E_YARN_HOST?=localhost ARGOCD_E2E_DISABLE_AUTH?= -ARGOCD_E2E_TEST_TIMEOUT?=60m +ARGOCD_E2E_TEST_TIMEOUT?=90m ARGOCD_IN_CI?=false ARGOCD_TEST_E2E?=true @@ -175,29 +175,21 @@ endif .PHONY: all all: cli image -# We have some legacy requirements for being checked out within $GOPATH. -# The ensure-gopath target can be used as dependency to ensure we are running -# within these boundaries. -.PHONY: ensure-gopath -ensure-gopath: -ifneq ("$(PWD)","$(LEGACY_PATH)") - @echo "Due to legacy requirements for codegen, repository needs to be checked out within \$$GOPATH" - @echo "Location of this repo should be '$(LEGACY_PATH)' but is '$(PWD)'" - @exit 1 -endif - .PHONY: gogen -gogen: ensure-gopath +gogen: export GO111MODULE=off go generate ./util/argo/... .PHONY: protogen -protogen: ensure-gopath mod-vendor-local +protogen: mod-vendor-local protogen-fast + +.PHONY: protogen-fast +protogen-fast: export GO111MODULE=off ./hack/generate-proto.sh .PHONY: openapigen -openapigen: ensure-gopath +openapigen: export GO111MODULE=off ./hack/update-openapi.sh @@ -212,19 +204,22 @@ notification-docs: .PHONY: clientgen -clientgen: ensure-gopath +clientgen: export GO111MODULE=off ./hack/update-codegen.sh .PHONY: clidocsgen -clidocsgen: ensure-gopath +clidocsgen: go run tools/cmd-docs/main.go .PHONY: codegen-local -codegen-local: ensure-gopath mod-vendor-local gogen protogen clientgen openapigen clidocsgen manifests-local notification-docs notification-catalog +codegen-local: mod-vendor-local gogen protogen clientgen openapigen clidocsgen manifests-local notification-docs notification-catalog rm -rf vendor/ +.PHONY: codegen-local-fast +codegen-local-fast: gogen protogen-fast clientgen openapigen clidocsgen manifests-local notification-docs notification-catalog + .PHONY: codegen codegen: test-tools-image $(call run-in-test-client,make codegen-local) @@ -438,6 +433,7 @@ start-e2e: test-tools-image start-e2e-local: mod-vendor-local dep-ui-local cli-local kubectl create ns argocd-e2e || true kubectl create ns argocd-e2e-external || true + kubectl create ns argocd-e2e-external-2 || true kubectl config set-context --current --namespace=argocd-e2e kustomize build test/manifests/base | kubectl apply -f - kubectl apply -f https://raw.githubusercontent.com/open-cluster-management/api/a6845f2ebcb186ec26b832f60c988537a58f3859/cluster/v1alpha1/0000_04_clusters.open-cluster-management.io_placementdecisions.crd.yaml @@ -458,8 +454,8 @@ start-e2e-local: mod-vendor-local dep-ui-local cli-local ARGOCD_ZJWT_FEATURE_FLAG=always \ ARGOCD_IN_CI=$(ARGOCD_IN_CI) \ BIN_MODE=$(ARGOCD_BIN_MODE) \ - ARGOCD_APPLICATION_NAMESPACES=argocd-e2e-external \ - ARGOCD_APPLICATIONSET_CONTROLLER_NAMESPACES=argocd-e2e-external \ + ARGOCD_APPLICATION_NAMESPACES=argocd-e2e-external,argocd-e2e-external-2 \ + ARGOCD_APPLICATIONSET_CONTROLLER_NAMESPACES=argocd-e2e-external,argocd-e2e-external-2 \ ARGOCD_APPLICATIONSET_CONTROLLER_ALLOWED_SCM_PROVIDERS=http://127.0.0.1:8341,http://127.0.0.1:8342,http://127.0.0.1:8343,http://127.0.0.1:8344 \ ARGOCD_E2E_TEST=true \ goreman -f $(ARGOCD_PROCFILE) start ${ARGOCD_START} @@ -491,6 +487,7 @@ start-local: mod-vendor-local dep-ui-local cli-local ARGOCD_ZJWT_FEATURE_FLAG=always \ ARGOCD_IN_CI=false \ ARGOCD_GPG_ENABLED=$(ARGOCD_GPG_ENABLED) \ + BIN_MODE=$(ARGOCD_BIN_MODE) \ ARGOCD_E2E_TEST=false \ ARGOCD_APPLICATION_NAMESPACES=$(ARGOCD_APPLICATION_NAMESPACES) \ goreman -f $(ARGOCD_PROCFILE) start ${ARGOCD_START} diff --git a/OWNERS b/OWNERS index d8532c550005a..56e037e282a0a 100644 --- a/OWNERS +++ b/OWNERS @@ -5,6 +5,7 @@ owners: approvers: - alexec - alexmt +- gdsoumya - jannfis - jessesuen - jgwest @@ -30,4 +31,3 @@ reviewers: - zachaller - 34fathombelow - alexef -- gdsoumya diff --git a/Procfile b/Procfile index 2bb26a086fb1d..4862b0230062f 100644 --- a/Procfile +++ b/Procfile @@ -1,4 +1,4 @@ -controller: [ "$BIN_MODE" = 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} ARGOCD_BINARY_NAME=argocd-application-controller $COMMAND --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081} --otlp-address=${ARGOCD_OTLP_ADDRESS} --application-namespaces=${ARGOCD_APPLICATION_NAMESPACES:-''}" +controller: [ "$BIN_MODE" = 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "HOSTNAME=testappcontroller-1 FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} ARGOCD_BINARY_NAME=argocd-application-controller $COMMAND --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081} --otlp-address=${ARGOCD_OTLP_ADDRESS} --application-namespaces=${ARGOCD_APPLICATION_NAMESPACES:-''} --server-side-diff-enabled=${ARGOCD_APPLICATION_CONTROLLER_SERVER_SIDE_DIFF:-'false'}" api-server: [ "$BIN_MODE" = 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} ARGOCD_BINARY_NAME=argocd-server $COMMAND --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --disable-auth=${ARGOCD_E2E_DISABLE_AUTH:-'true'} --insecure --dex-server http://localhost:${ARGOCD_E2E_DEX_PORT:-5556} --repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081} --port ${ARGOCD_E2E_APISERVER_PORT:-8080} --otlp-address=${ARGOCD_OTLP_ADDRESS} --application-namespaces=${ARGOCD_APPLICATION_NAMESPACES:-''}" dex: sh -c "ARGOCD_BINARY_NAME=argocd-dex go run github.com/argoproj/argo-cd/v2/cmd gendexcfg -o `pwd`/dist/dex.yaml && (test -f dist/dex.yaml || { echo 'Failed to generate dex configuration'; exit 1; }) && docker run --rm -p ${ARGOCD_E2E_DEX_PORT:-5556}:${ARGOCD_E2E_DEX_PORT:-5556} -v `pwd`/dist/dex.yaml:/dex.yaml ghcr.io/dexidp/dex:$(grep "image: ghcr.io/dexidp/dex" manifests/base/dex/argocd-dex-server-deployment.yaml | cut -d':' -f3) dex serve /dex.yaml" redis: bash -c "if [ \"$ARGOCD_REDIS_LOCAL\" = 'true' ]; then redis-server --save '' --appendonly no --port ${ARGOCD_E2E_REDIS_PORT:-6379}; else docker run --rm --name argocd-redis -i -p ${ARGOCD_E2E_REDIS_PORT:-6379}:${ARGOCD_E2E_REDIS_PORT:-6379} docker.io/library/redis:$(grep "image: redis" manifests/base/redis/argocd-redis-deployment.yaml | cut -d':' -f3) --save '' --appendonly no --port ${ARGOCD_E2E_REDIS_PORT:-6379}; fi" @@ -9,4 +9,5 @@ git-server: test/fixture/testrepos/start-git.sh helm-registry: test/fixture/testrepos/start-helm-registry.sh dev-mounter: [[ "$ARGOCD_E2E_TEST" != "true" ]] && go run hack/dev-mounter/main.go --configmap argocd-ssh-known-hosts-cm=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} --configmap argocd-tls-certs-cm=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} --configmap argocd-gpg-keys-cm=${ARGOCD_GPG_DATA_PATH:-/tmp/argocd-local/gpg/source} applicationset-controller: [ "$BIN_MODE" = 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "FORCE_LOG_COLORS=4 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} ARGOCD_BINARY_NAME=argocd-applicationset-controller $COMMAND --loglevel debug --metrics-addr localhost:12345 --probe-addr localhost:12346 --argocd-repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081}" -notification: [ "$BIN_MODE" = 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "FORCE_LOG_COLORS=4 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_BINARY_NAME=argocd-notifications $COMMAND --loglevel debug" +notification: [ "$BIN_MODE" = 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "FORCE_LOG_COLORS=4 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_BINARY_NAME=argocd-notifications $COMMAND --loglevel debug --application-namespaces=${ARGOCD_APPLICATION_NAMESPACES:-''} --self-service-notification-enabled=${ARGOCD_NOTIFICATION_CONTROLLER_SELF_SERVICE_NOTIFICATION_ENABLED:-'false'}" + diff --git a/README.md b/README.md index ef5664de5b5b7..707848191c830 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ **Social:** [![Twitter Follow](https://img.shields.io/twitter/follow/argoproj?style=social)](https://twitter.com/argoproj) [![Slack](https://img.shields.io/badge/slack-argoproj-brightgreen.svg?logo=slack)](https://argoproj.github.io/community/join-slack) +[![LinkedIn](https://img.shields.io/badge/LinkedIn-argoproj-blue.svg?logo=linkedin)](https://www.linkedin.com/company/argoproj/) # Argo CD - Declarative Continuous Delivery for Kubernetes @@ -85,4 +86,5 @@ Participation in the Argo CD project is governed by the [CNCF Code of Conduct](h 1. [Getting Started with ArgoCD for GitOps Deployments](https://youtu.be/AvLuplh1skA) 1. [Using Argo CD & Datree for Stable Kubernetes CI/CD Deployments](https://youtu.be/17894DTru2Y) 1. [How to create Argo CD Applications Automatically using ApplicationSet? "Automation of GitOps"](https://amralaayassen.medium.com/how-to-create-argocd-applications-automatically-using-applicationset-automation-of-the-gitops-59455eaf4f72) +1. [Progressive Delivery with Service Mesh – Argo Rollouts with Istio](https://www.cncf.io/blog/2022/12/16/progressive-delivery-with-service-mesh-argo-rollouts-with-istio/) diff --git a/SECURITY-INSIGHTS.yml b/SECURITY-INSIGHTS.yml new file mode 100644 index 0000000000000..8ac4bc36b04ae --- /dev/null +++ b/SECURITY-INSIGHTS.yml @@ -0,0 +1,128 @@ +header: + schema-version: 1.0.0 + expiration-date: '2024-10-31T00:00:00.000Z' # One year from initial release. + last-updated: '2023-10-27' + last-reviewed: '2023-10-27' + commit-hash: b71277c6beb949d0199d647a582bc25822b88838 + project-url: https://github.com/argoproj/argo-cd + project-release: v2.9.0-rc3 + changelog: https://github.com/argoproj/argo-cd/releases + license: https://github.com/argoproj/argo-cd/blob/master/LICENSE +project-lifecycle: + status: active + roadmap: https://github.com/orgs/argoproj/projects/25 + bug-fixes-only: false + core-maintainers: + - https://github.com/argoproj/argoproj/blob/master/MAINTAINERS.md + release-cycle: https://argo-cd.readthedocs.io/en/stable/developer-guide/release-process-and-cadence/ + release-process: https://argo-cd.readthedocs.io/en/stable/developer-guide/release-process-and-cadence/#release-process +contribution-policy: + accepts-pull-requests: true + accepts-automated-pull-requests: true + automated-tools-list: + - automated-tool: dependabot + action: allowed + path: + - / + - automated-tool: snyk-report + action: allowed + path: + - docs/snyk + comment: | + This tool runs Snyk and generates a report of vulnerabilities in the project's dependencies. The report is + placed in the project's documentation. The workflow is defined here: + https://github.com/argoproj/argo-cd/blob/master/.github/workflows/update-snyk.yaml + contributing-policy: https://argo-cd.readthedocs.io/en/stable/developer-guide/code-contributions/ + code-of-conduct: https://github.com/cncf/foundation/blob/master/code-of-conduct.md +documentation: + - https://argo-cd.readthedocs.io/ +distribution-points: + - https://github.com/argoproj/argo-cd/releases + - https://quay.io/repository/argoproj/argocd +security-artifacts: + threat-model: + threat-model-created: true + evidence-url: + - https://github.com/argoproj/argoproj/blob/master/docs/argo_threat_model.pdf + - https://github.com/argoproj/argoproj/blob/master/docs/end_user_threat_model.pdf + self-assessment: + self-assessment-created: false + comment: | + An extensive self-assessment was performed for CNCF graduation. Because the self-assessment process was evolving + at the time, no standardized document has been published. +security-testing: + - tool-type: sca + tool-name: Dependabot + tool-version: "2" + tool-url: https://github.com/dependabot + integration: + ad-hoc: false + ci: false + before-release: false + tool-rulesets: + - https://github.com/argoproj/argo-cd/blob/master/.github/dependabot.yml + - tool-type: sca + tool-name: Snyk + tool-version: latest + tool-url: https://snyk.io/ + integration: + ad-hoc: true + ci: true + before-release: false + - tool-type: sast + tool-name: CodeQL + tool-version: latest + tool-url: https://codeql.github.com/ + integration: + ad-hoc: false + ci: true + before-release: false + comment: | + We use the default configuration with the latest version. +security-assessments: + - auditor-name: Trail of Bits + auditor-url: https://trailofbits.com + auditor-report: https://github.com/argoproj/argoproj/blob/master/docs/argo_security_final_report.pdf + report-year: 2021 + - auditor-name: Ada Logics + auditor-url: https://adalogics.com + auditor-report: https://github.com/argoproj/argoproj/blob/master/docs/argo_security_audit_2022.pdf + report-year: 2022 + - auditor-name: Ada Logics + auditor-url: https://adalogics.com + auditor-report: https://github.com/argoproj/argoproj/blob/master/docs/audit_fuzzer_adalogics_2022.pdf + report-year: 2022 + comment: | + Part of the audit was performed by Ada Logics, focussed on fuzzing. + - auditor-name: Chainguard + auditor-url: https://chainguard.dev + auditor-report: https://github.com/argoproj/argoproj/blob/master/docs/software_supply_chain_slsa_assessment_chainguard_2023.pdf + report-year: 2023 + comment: | + Confirmed the project's release process as achieving SLSA (v0.1) level 3. +security-contacts: + - type: email + value: cncf-argo-security@lists.cncf.io + primary: true +vulnerability-reporting: + accepts-vulnerability-reports: true + email-contact: cncf-argo-security@lists.cncf.io + security-policy: https://github.com/argoproj/argo-cd/security/policy + bug-bounty-available: true + bug-bounty-url: https://hackerone.com/ibb/policy_scopes + out-scope: + - vulnerable and outdated components # See https://github.com/argoproj/argo-cd/blob/master/SECURITY.md#a-word-about-security-scanners + - security logging and monitoring failures +dependencies: + third-party-packages: true + dependencies-lists: + - https://github.com/argoproj/argo-cd/blob/master/go.mod + - https://github.com/argoproj/argo-cd/blob/master/Dockerfile + - https://github.com/argoproj/argo-cd/blob/master/ui/package.json + sbom: + - sbom-file: https://github.com/argoproj/argo-cd/releases # Every release's assets include SBOMs. + sbom-format: SPDX + dependencies-lifecycle: + policy-url: https://argo-cd.readthedocs.io/en/stable/developer-guide/release-process-and-cadence/#dependencies-lifecycle-policy + env-dependencies-policy: + policy-url: https://argo-cd.readthedocs.io/en/stable/developer-guide/release-process-and-cadence/#dependencies-lifecycle-policy diff --git a/USERS.md b/USERS.md index 652a68c6e679f..3f164796d099f 100644 --- a/USERS.md +++ b/USERS.md @@ -25,7 +25,8 @@ Currently, the following organizations are **officially** using Argo CD: 1. [AppDirect](https://www.appdirect.com) 1. [Arctiq Inc.](https://www.arctiq.ca) 1. [ARZ Allgemeines Rechenzentrum GmbH](https://www.arz.at/) -2. [Autodesk](https://www.autodesk.com) +1. [Autodesk](https://www.autodesk.com) +1. [Axians ACSP](https://www.axians.fr) 1. [Axual B.V.](https://axual.com) 1. [Back Market](https://www.backmarket.com) 1. [Baloise](https://www.baloise.com) @@ -39,6 +40,7 @@ Currently, the following organizations are **officially** using Argo CD: 1. [Boozt](https://www.booztgroup.com/) 1. [Boticario](https://www.boticario.com.br/) 1. [Bulder Bank](https://bulderbank.no) +1. [CAM](https://cam-inc.co.jp) 1. [Camptocamp](https://camptocamp.com) 1. [Candis](https://www.candis.io) 1. [Capital One](https://www.capitalone.com) @@ -92,7 +94,9 @@ Currently, the following organizations are **officially** using Argo CD: 1. [Fave](https://myfave.com) 1. [Flexport](https://www.flexport.com/) 1. [Flip](https://flip.id) +1. [Fly Security](https://www.flysecurity.com.br/) 1. [Fonoa](https://www.fonoa.com/) +1. [Fortra](https://www.fortra.com) 1. [freee](https://corp.freee.co.jp/en/company/) 1. [Freshop, Inc](https://www.freshop.com/) 1. [Future PLC](https://www.futureplc.com/) @@ -126,6 +130,7 @@ Currently, the following organizations are **officially** using Argo CD: 1. [IBM](https://www.ibm.com/) 1. [Ibotta](https://home.ibotta.com) 1. [IITS-Consulting](https://iits-consulting.de) +1. [IllumiDesk](https://www.illumidesk.com) 1. [imaware](https://imaware.health) 1. [Indeed](https://indeed.com) 1. [Index Exchange](https://www.indexexchange.com/) @@ -146,6 +151,7 @@ Currently, the following organizations are **officially** using Argo CD: 1. [Kinguin](https://www.kinguin.net/) 1. [KintoHub](https://www.kintohub.com/) 1. [KompiTech GmbH](https://www.kompitech.com/) +1. [Kong Inc.](https://konghq.com/) 1. [KPMG](https://kpmg.com/uk) 1. [KubeSphere](https://github.com/kubesphere) 1. [Kurly](https://www.kurly.com/) @@ -210,10 +216,12 @@ Currently, the following organizations are **officially** using Argo CD: 1. [Patreon](https://www.patreon.com/) 1. [PayPay](https://paypay.ne.jp/) 1. [Peloton Interactive](https://www.onepeloton.com/) +1. [Percona](https://percona.com/) 1. [PGS](https://www.pgs.com) 1. [Pigment](https://www.gopigment.com/) 1. [Pipefy](https://www.pipefy.com/) 1. [Pismo](https://pismo.io/) +1. [PITS Globale Datenrettungsdienste](https://www.pitsdatenrettung.de/) 1. [Platform9 Systems](https://platform9.com/) 1. [Polarpoint.io](https://polarpoint.io) 1. [PostFinance](https://github.com/postfinance) @@ -240,12 +248,14 @@ Currently, the following organizations are **officially** using Argo CD: 1. [Robotinfra](https://www.robotinfra.com) 1. [Rubin Observatory](https://www.lsst.org) 1. [Saildrone](https://www.saildrone.com/) +1. [Salad Technologies](https://salad.com/) 1. [Saloodo! GmbH](https://www.saloodo.com) 1. [Sap Labs](http://sap.com) 1. [Sauce Labs](https://saucelabs.com/) 1. [Schwarz IT](https://jobs.schwarz/it-mission) 1. [SCRM Lidl International Hub](https://scrm.lidl) 1. [SEEK](https://seek.com.au) +1. [Semgrep](https://semgrep.com) 1. [SI Analytics](https://si-analytics.ai) 1. [Skit](https://skit.ai/) 1. [Skyscanner](https://www.skyscanner.net/) @@ -260,6 +270,7 @@ Currently, the following organizations are **officially** using Argo CD: 1. [Spendesk](https://spendesk.com/) 1. [Splunk](https://splunk.com/) 1. [Spores Labs](https://spores.app) +1. [Statsig](https://statsig.com) 1. [StreamNative](https://streamnative.io) 1. [Stuart](https://stuart.com/) 1. [Sumo Logic](https://sumologic.com/) @@ -273,6 +284,7 @@ Currently, the following organizations are **officially** using Argo CD: 1. [Tamkeen Technologies](https://tamkeentech.sa/) 1. [Techcombank](https://www.techcombank.com.vn/trang-chu) 1. [Technacy](https://www.technacy.it/) +1. [Telavita](https://www.telavita.com.br/) 1. [Tesla](https://tesla.com/) 1. [The Scale Factory](https://www.scalefactory.com/) 1. [ThousandEyes](https://www.thousandeyes.com/) diff --git a/applicationset/controllers/applicationset_controller.go b/applicationset/controllers/applicationset_controller.go index 60bab2564d92c..4f5ac66fc016d 100644 --- a/applicationset/controllers/applicationset_controller.go +++ b/applicationset/controllers/applicationset_controller.go @@ -16,7 +16,6 @@ package controllers import ( "context" - "encoding/json" "fmt" "reflect" "time" @@ -25,7 +24,6 @@ import ( corev1 "k8s.io/api/core/v1" apierr "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/intstr" @@ -46,7 +44,6 @@ import ( "github.com/argoproj/argo-cd/v2/applicationset/generators" "github.com/argoproj/argo-cd/v2/applicationset/utils" "github.com/argoproj/argo-cd/v2/common" - argodiff "github.com/argoproj/argo-cd/v2/util/argo/diff" "github.com/argoproj/argo-cd/v2/util/db" "github.com/argoproj/argo-cd/v2/util/glob" @@ -111,13 +108,23 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque // Do not attempt to further reconcile the ApplicationSet if it is being deleted. if applicationSetInfo.ObjectMeta.DeletionTimestamp != nil { + deleteAllowed := utils.DefaultPolicy(applicationSetInfo.Spec.SyncPolicy, r.Policy, r.EnablePolicyOverride).AllowDelete() + if !deleteAllowed { + if err := r.removeOwnerReferencesOnDeleteAppSet(ctx, applicationSetInfo); err != nil { + return ctrl.Result{}, err + } + controllerutil.RemoveFinalizer(&applicationSetInfo, argov1alpha1.ResourcesFinalizerName) + if err := r.Update(ctx, &applicationSetInfo); err != nil { + return ctrl.Result{}, err + } + } return ctrl.Result{}, nil } // Log a warning if there are unrecognized generators _ = utils.CheckInvalidGenerators(&applicationSetInfo) // desiredApplications is the main list of all expected Applications from all generators in this appset. - desiredApplications, applicationSetReason, err := r.generateApplications(applicationSetInfo) + desiredApplications, applicationSetReason, err := r.generateApplications(logCtx, applicationSetInfo) if err != nil { _ = r.setApplicationSetStatusCondition(ctx, &applicationSetInfo, @@ -163,13 +170,15 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque if r.EnableProgressiveSyncs { if applicationSetInfo.Spec.Strategy == nil && len(applicationSetInfo.Status.ApplicationStatus) > 0 { - log.Infof("Removing %v unnecessary AppStatus entries from ApplicationSet %v", len(applicationSetInfo.Status.ApplicationStatus), applicationSetInfo.Name) + // If appset used progressive sync but stopped, clean up the progressive sync application statuses + logCtx.Infof("Removing %v unnecessary AppStatus entries from ApplicationSet %v", len(applicationSetInfo.Status.ApplicationStatus), applicationSetInfo.Name) - err := r.setAppSetApplicationStatus(ctx, &applicationSetInfo, []argov1alpha1.ApplicationSetApplicationStatus{}) + err := r.setAppSetApplicationStatus(ctx, logCtx, &applicationSetInfo, []argov1alpha1.ApplicationSetApplicationStatus{}) if err != nil { return ctrl.Result{}, fmt.Errorf("failed to clear previous AppSet application statuses for %v: %w", applicationSetInfo.Name, err) } - } else { + } else if applicationSetInfo.Spec.Strategy != nil { + // appset uses progressive sync applications, err := r.getCurrentApplications(ctx, applicationSetInfo) if err != nil { return ctrl.Result{}, fmt.Errorf("failed to get current applications for application set: %w", err) @@ -179,7 +188,7 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque appMap[app.Name] = app } - appSyncMap, err = r.performProgressiveSyncs(ctx, applicationSetInfo, applications, desiredApplications, appMap) + appSyncMap, err = r.performProgressiveSyncs(ctx, logCtx, applicationSetInfo, applications, desiredApplications, appMap) if err != nil { return ctrl.Result{}, fmt.Errorf("failed to perform progressive sync reconciliation for application set: %w", err) } @@ -217,7 +226,7 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque if r.EnableProgressiveSyncs { // trigger appropriate application syncs if RollingSync strategy is enabled if progressiveSyncsStrategyEnabled(&applicationSetInfo, "RollingSync") { - validApps, err = r.syncValidApplications(ctx, &applicationSetInfo, appSyncMap, appMap, validApps) + validApps, err = r.syncValidApplications(logCtx, &applicationSetInfo, appSyncMap, appMap, validApps) if err != nil { _ = r.setApplicationSetStatusCondition(ctx, @@ -235,7 +244,7 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque } if utils.DefaultPolicy(applicationSetInfo.Spec.SyncPolicy, r.Policy, r.EnablePolicyOverride).AllowUpdate() { - err = r.createOrUpdateInCluster(ctx, applicationSetInfo, validApps) + err = r.createOrUpdateInCluster(ctx, logCtx, applicationSetInfo, validApps) if err != nil { _ = r.setApplicationSetStatusCondition(ctx, &applicationSetInfo, @@ -249,7 +258,7 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque return ctrl.Result{}, err } } else { - err = r.createInCluster(ctx, applicationSetInfo, validApps) + err = r.createInCluster(ctx, logCtx, applicationSetInfo, validApps) if err != nil { _ = r.setApplicationSetStatusCondition(ctx, &applicationSetInfo, @@ -265,7 +274,7 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque } if utils.DefaultPolicy(applicationSetInfo.Spec.SyncPolicy, r.Policy, r.EnablePolicyOverride).AllowDelete() { - err = r.deleteInCluster(ctx, applicationSetInfo, desiredApplications) + err = r.deleteInCluster(ctx, logCtx, applicationSetInfo, desiredApplications) if err != nil { _ = r.setApplicationSetStatusCondition(ctx, &applicationSetInfo, @@ -490,7 +499,7 @@ func getTempApplication(applicationSetTemplate argov1alpha1.ApplicationSetTempla return &tmplApplication } -func (r *ApplicationSetReconciler) generateApplications(applicationSetInfo argov1alpha1.ApplicationSet) ([]argov1alpha1.Application, argov1alpha1.ApplicationSetReasonType, error) { +func (r *ApplicationSetReconciler) generateApplications(logCtx *log.Entry, applicationSetInfo argov1alpha1.ApplicationSet) ([]argov1alpha1.Application, argov1alpha1.ApplicationSetReasonType, error) { var res []argov1alpha1.Application var firstError error @@ -499,7 +508,7 @@ func (r *ApplicationSetReconciler) generateApplications(applicationSetInfo argov for _, requestedGenerator := range applicationSetInfo.Spec.Generators { t, err := generators.Transform(requestedGenerator, r.Generators, applicationSetInfo.Spec.Template, &applicationSetInfo, map[string]interface{}{}) if err != nil { - log.WithError(err).WithField("generator", requestedGenerator). + logCtx.WithError(err).WithField("generator", requestedGenerator). Error("error generating application from params") if firstError == nil { firstError = err @@ -513,8 +522,9 @@ func (r *ApplicationSetReconciler) generateApplications(applicationSetInfo argov for _, p := range a.Params { app, err := r.Renderer.RenderTemplateParams(tmplApplication, applicationSetInfo.Spec.SyncPolicy, p, applicationSetInfo.Spec.GoTemplate, applicationSetInfo.Spec.GoTemplateOptions) + if err != nil { - log.WithError(err).WithField("params", a.Params).WithField("generator", requestedGenerator). + logCtx.WithError(err).WithField("params", a.Params).WithField("generator", requestedGenerator). Error("error generating application from params") if firstError == nil { @@ -523,17 +533,45 @@ func (r *ApplicationSetReconciler) generateApplications(applicationSetInfo argov } continue } + + if applicationSetInfo.Spec.TemplatePatch != nil { + patchedApplication, err := r.applyTemplatePatch(app, applicationSetInfo, p) + + if err != nil { + log.WithError(err).WithField("params", a.Params).WithField("generator", requestedGenerator). + Error("error generating application from params") + + if firstError == nil { + firstError = err + applicationSetReason = argov1alpha1.ApplicationSetReasonRenderTemplateParamsError + } + continue + } + + app = patchedApplication + } + res = append(res, *app) } } - log.WithField("generator", requestedGenerator).Infof("generated %d applications", len(res)) - log.WithField("generator", requestedGenerator).Debugf("apps from generator: %+v", res) + logCtx.WithField("generator", requestedGenerator).Infof("generated %d applications", len(res)) + logCtx.WithField("generator", requestedGenerator).Debugf("apps from generator: %+v", res) } return res, applicationSetReason, firstError } +func (r *ApplicationSetReconciler) applyTemplatePatch(app *argov1alpha1.Application, applicationSetInfo argov1alpha1.ApplicationSet, params map[string]interface{}) (*argov1alpha1.Application, error) { + replacedTemplate, err := r.Renderer.Replace(*applicationSetInfo.Spec.TemplatePatch, params, applicationSetInfo.Spec.GoTemplate, applicationSetInfo.Spec.GoTemplateOptions) + + if err != nil { + return nil, fmt.Errorf("error replacing values in templatePatch: %w", err) + } + + return applyTemplatePatch(app, replacedTemplate) +} + func ignoreNotAllowedNamespaces(namespaces []string) predicate.Predicate { return predicate.Funcs{ CreateFunc: func(e event.CreateEvent) bool { @@ -542,22 +580,24 @@ func ignoreNotAllowedNamespaces(namespaces []string) predicate.Predicate { } } -func (r *ApplicationSetReconciler) SetupWithManager(mgr ctrl.Manager, enableProgressiveSyncs bool, maxConcurrentReconciliations int) error { - if err := mgr.GetFieldIndexer().IndexField(context.TODO(), &argov1alpha1.Application{}, ".metadata.controller", func(rawObj client.Object) []string { - // grab the job object, extract the owner... - app := rawObj.(*argov1alpha1.Application) - owner := metav1.GetControllerOf(app) - if owner == nil { - return nil - } - // ...make sure it's a application set... - if owner.APIVersion != argov1alpha1.SchemeGroupVersion.String() || owner.Kind != "ApplicationSet" { - return nil - } +func appControllerIndexer(rawObj client.Object) []string { + // grab the job object, extract the owner... + app := rawObj.(*argov1alpha1.Application) + owner := metav1.GetControllerOf(app) + if owner == nil { + return nil + } + // ...make sure it's a application set... + if owner.APIVersion != argov1alpha1.SchemeGroupVersion.String() || owner.Kind != "ApplicationSet" { + return nil + } + + // ...and if so, return it + return []string{owner.Name} +} - // ...and if so, return it - return []string{owner.Name} - }); err != nil { +func (r *ApplicationSetReconciler) SetupWithManager(mgr ctrl.Manager, enableProgressiveSyncs bool, maxConcurrentReconciliations int) error { + if err := mgr.GetFieldIndexer().IndexField(context.TODO(), &argov1alpha1.Application{}, ".metadata.controller", appControllerIndexer); err != nil { return fmt.Errorf("error setting up with manager: %w", err) } @@ -601,15 +641,17 @@ func (r *ApplicationSetReconciler) updateCache(ctx context.Context, obj client.O // - For new applications, it will call create // - For existing application, it will call update // The function also adds owner reference to all applications, and uses it to delete them. -func (r *ApplicationSetReconciler) createOrUpdateInCluster(ctx context.Context, applicationSet argov1alpha1.ApplicationSet, desiredApplications []argov1alpha1.Application) error { +func (r *ApplicationSetReconciler) createOrUpdateInCluster(ctx context.Context, logCtx *log.Entry, applicationSet argov1alpha1.ApplicationSet, desiredApplications []argov1alpha1.Application) error { var firstError error // Creates or updates the application in appList for _, generatedApp := range desiredApplications { - - appLog := log.WithFields(log.Fields{"app": generatedApp.Name, "appSet": applicationSet.Name}) + // The app's namespace must be the same as the AppSet's namespace to preserve the appsets-in-any-namespace + // security boundary. generatedApp.Namespace = applicationSet.Namespace + appLog := logCtx.WithFields(log.Fields{"app": generatedApp.QualifiedName()}) + // Normalize to avoid fighting with the application controller. generatedApp.Spec = *argoutil.NormalizeApplicationSpec(&generatedApp.Spec) @@ -624,7 +666,7 @@ func (r *ApplicationSetReconciler) createOrUpdateInCluster(ctx context.Context, }, } - action, err := utils.CreateOrUpdate(ctx, r.Client, found, func() error { + action, err := utils.CreateOrUpdate(ctx, appLog, r.Client, applicationSet.Spec.IgnoreApplicationDifferences, found, func() error { // Copy only the Application/ObjectMeta fields that are significant, from the generatedApp found.Spec = generatedApp.Spec @@ -677,13 +719,6 @@ func (r *ApplicationSetReconciler) createOrUpdateInCluster(ctx context.Context, found.ObjectMeta.Finalizers = generatedApp.Finalizers found.ObjectMeta.Labels = generatedApp.Labels - if found != nil && len(found.Spec.IgnoreDifferences) > 0 { - err := applyIgnoreDifferences(applicationSet.Spec.IgnoreApplicationDifferences, found, generatedApp) - if err != nil { - return fmt.Errorf("failed to apply ignore differences: %w", err) - } - } - return controllerutil.SetControllerReference(&applicationSet, found, r.Scheme) }) @@ -709,57 +744,9 @@ func (r *ApplicationSetReconciler) createOrUpdateInCluster(ctx context.Context, return firstError } -// applyIgnoreDifferences applies the ignore differences rules to the found application. It modifies the found application in place. -func applyIgnoreDifferences(applicationSetIgnoreDifferences argov1alpha1.ApplicationSetIgnoreDifferences, found *argov1alpha1.Application, generatedApp argov1alpha1.Application) error { - diffConfig, err := argodiff.NewDiffConfigBuilder(). - WithDiffSettings(applicationSetIgnoreDifferences.ToApplicationIgnoreDifferences(), nil, false). - WithNoCache(). - Build() - if err != nil { - return fmt.Errorf("failed to build diff config: %w", err) - } - unstructuredFound, err := appToUnstructured(found) - if err != nil { - return fmt.Errorf("failed to convert found application to unstructured: %w", err) - } - unstructuredGenerated, err := appToUnstructured(&generatedApp) - if err != nil { - return fmt.Errorf("failed to convert found application to unstructured: %w", err) - } - result, err := argodiff.Normalize([]*unstructured.Unstructured{unstructuredFound}, []*unstructured.Unstructured{unstructuredGenerated}, diffConfig) - if err != nil { - return fmt.Errorf("failed to normalize application spec: %w", err) - } - if len(result.Targets) != 1 { - return fmt.Errorf("expected 1 normalized application, got %d", len(result.Targets)) - } - jsonNormalized, err := json.Marshal(result.Targets[0].Object) - if err != nil { - return fmt.Errorf("failed to marshal normalized app to json: %w", err) - } - err = json.Unmarshal(jsonNormalized, &found) - if err != nil { - return fmt.Errorf("failed to unmarshal normalized app json to structured app: %w", err) - } - // Prohibit jq queries from mutating silly things. - found.TypeMeta = generatedApp.TypeMeta - found.Name = generatedApp.Name - found.Namespace = generatedApp.Namespace - found.Operation = generatedApp.Operation - return nil -} - -func appToUnstructured(app *argov1alpha1.Application) (*unstructured.Unstructured, error) { - u, err := runtime.DefaultUnstructuredConverter.ToUnstructured(app) - if err != nil { - return nil, fmt.Errorf("failed to convert app object to unstructured: %w", err) - } - return &unstructured.Unstructured{Object: u}, nil -} - // createInCluster will filter from the desiredApplications only the application that needs to be created // Then it will call createOrUpdateInCluster to do the actual create -func (r *ApplicationSetReconciler) createInCluster(ctx context.Context, applicationSet argov1alpha1.ApplicationSet, desiredApplications []argov1alpha1.Application) error { +func (r *ApplicationSetReconciler) createInCluster(ctx context.Context, logCtx *log.Entry, applicationSet argov1alpha1.ApplicationSet, desiredApplications []argov1alpha1.Application) error { var createApps []argov1alpha1.Application current, err := r.getCurrentApplications(ctx, applicationSet) @@ -782,13 +769,12 @@ func (r *ApplicationSetReconciler) createInCluster(ctx context.Context, applicat } } - return r.createOrUpdateInCluster(ctx, applicationSet, createApps) + return r.createOrUpdateInCluster(ctx, logCtx, applicationSet, createApps) } -func (r *ApplicationSetReconciler) getCurrentApplications(_ context.Context, applicationSet argov1alpha1.ApplicationSet) ([]argov1alpha1.Application, error) { - // TODO: Should this use the context param? +func (r *ApplicationSetReconciler) getCurrentApplications(ctx context.Context, applicationSet argov1alpha1.ApplicationSet) ([]argov1alpha1.Application, error) { var current argov1alpha1.ApplicationList - err := r.Client.List(context.Background(), ¤t, client.MatchingFields{".metadata.controller": applicationSet.Name}) + err := r.Client.List(ctx, ¤t, client.MatchingFields{".metadata.controller": applicationSet.Name}, client.InNamespace(applicationSet.Namespace)) if err != nil { return nil, fmt.Errorf("error retrieving applications: %w", err) @@ -799,7 +785,7 @@ func (r *ApplicationSetReconciler) getCurrentApplications(_ context.Context, app // deleteInCluster will delete Applications that are currently on the cluster, but not in appList. // The function must be called after all generators had been called and generated applications -func (r *ApplicationSetReconciler) deleteInCluster(ctx context.Context, applicationSet argov1alpha1.ApplicationSet, desiredApplications []argov1alpha1.Application) error { +func (r *ApplicationSetReconciler) deleteInCluster(ctx context.Context, logCtx *log.Entry, applicationSet argov1alpha1.ApplicationSet, desiredApplications []argov1alpha1.Application) error { // settingsMgr := settings.NewSettingsManager(context.TODO(), r.KubeClientset, applicationSet.Namespace) // argoDB := db.NewDB(applicationSet.Namespace, settingsMgr, r.KubeClientset) // clusterList, err := argoDB.ListClusters(ctx) @@ -823,15 +809,15 @@ func (r *ApplicationSetReconciler) deleteInCluster(ctx context.Context, applicat // Delete apps that are not in m[string]bool var firstError error for _, app := range current { - appLog := log.WithFields(log.Fields{"app": app.Name, "appSet": applicationSet.Name}) + logCtx = logCtx.WithField("app", app.QualifiedName()) _, exists := m[app.Name] if !exists { // Removes the Argo CD resources finalizer if the application contains an invalid target (eg missing cluster) - err := r.removeFinalizerOnInvalidDestination(ctx, applicationSet, &app, clusterList, appLog) + err := r.removeFinalizerOnInvalidDestination(ctx, applicationSet, &app, clusterList, logCtx) if err != nil { - appLog.WithError(err).Error("failed to update Application") + logCtx.WithError(err).Error("failed to update Application") if firstError != nil { firstError = err } @@ -840,14 +826,14 @@ func (r *ApplicationSetReconciler) deleteInCluster(ctx context.Context, applicat err = r.Client.Delete(ctx, &app) if err != nil { - appLog.WithError(err).Error("failed to delete Application") + logCtx.WithError(err).Error("failed to delete Application") if firstError != nil { firstError = err } continue } r.Recorder.Eventf(&applicationSet, corev1.EventTypeNormal, "Deleted", "Deleted Application %q", app.Name) - appLog.Log(log.InfoLevel, "Deleted application") + logCtx.Log(log.InfoLevel, "Deleted application") } } return firstError @@ -910,7 +896,11 @@ func (r *ApplicationSetReconciler) removeFinalizerOnInvalidDestination(ctx conte if len(newFinalizers) != len(app.Finalizers) { updated := app.DeepCopy() updated.Finalizers = newFinalizers - if err := r.Client.Patch(ctx, updated, client.MergeFrom(app)); err != nil { + patch := client.MergeFrom(app) + if log.IsLevelEnabled(log.DebugLevel) { + utils.LogPatch(appLog, patch, updated) + } + if err := r.Client.Patch(ctx, updated, patch); err != nil { return fmt.Errorf("error updating finalizers: %w", err) } r.updateCache(ctx, updated, appLog) @@ -925,21 +915,38 @@ func (r *ApplicationSetReconciler) removeFinalizerOnInvalidDestination(ctx conte return nil } -func (r *ApplicationSetReconciler) performProgressiveSyncs(ctx context.Context, appset argov1alpha1.ApplicationSet, applications []argov1alpha1.Application, desiredApplications []argov1alpha1.Application, appMap map[string]argov1alpha1.Application) (map[string]bool, error) { +func (r *ApplicationSetReconciler) removeOwnerReferencesOnDeleteAppSet(ctx context.Context, applicationSet argov1alpha1.ApplicationSet) error { + applications, err := r.getCurrentApplications(ctx, applicationSet) + if err != nil { + return err + } + + for _, app := range applications { + app.SetOwnerReferences([]metav1.OwnerReference{}) + err := r.Client.Update(ctx, &app) + if err != nil { + return err + } + } + + return nil +} + +func (r *ApplicationSetReconciler) performProgressiveSyncs(ctx context.Context, logCtx *log.Entry, appset argov1alpha1.ApplicationSet, applications []argov1alpha1.Application, desiredApplications []argov1alpha1.Application, appMap map[string]argov1alpha1.Application) (map[string]bool, error) { - appDependencyList, appStepMap, err := r.buildAppDependencyList(ctx, appset, desiredApplications) + appDependencyList, appStepMap, err := r.buildAppDependencyList(logCtx, appset, desiredApplications) if err != nil { return nil, fmt.Errorf("failed to build app dependency list: %w", err) } - _, err = r.updateApplicationSetApplicationStatus(ctx, &appset, applications, appStepMap) + _, err = r.updateApplicationSetApplicationStatus(ctx, logCtx, &appset, applications, appStepMap) if err != nil { return nil, fmt.Errorf("failed to update applicationset app status: %w", err) } - log.Infof("ApplicationSet %v step list:", appset.Name) + logCtx.Infof("ApplicationSet %v step list:", appset.Name) for i, step := range appDependencyList { - log.Infof("step %v: %+v", i+1, step) + logCtx.Infof("step %v: %+v", i+1, step) } appSyncMap, err := r.buildAppSyncMap(ctx, appset, appDependencyList, appMap) @@ -947,9 +954,9 @@ func (r *ApplicationSetReconciler) performProgressiveSyncs(ctx context.Context, return nil, fmt.Errorf("failed to build app sync map: %w", err) } - log.Infof("Application allowed to sync before maxUpdate?: %+v", appSyncMap) + logCtx.Infof("Application allowed to sync before maxUpdate?: %+v", appSyncMap) - _, err = r.updateApplicationSetApplicationStatusProgress(ctx, &appset, appSyncMap, appStepMap, appMap) + _, err = r.updateApplicationSetApplicationStatusProgress(ctx, logCtx, &appset, appSyncMap, appStepMap, appMap) if err != nil { return nil, fmt.Errorf("failed to update applicationset application status progress: %w", err) } @@ -963,7 +970,7 @@ func (r *ApplicationSetReconciler) performProgressiveSyncs(ctx context.Context, } // this list tracks which Applications belong to each RollingUpdate step -func (r *ApplicationSetReconciler) buildAppDependencyList(ctx context.Context, applicationSet argov1alpha1.ApplicationSet, applications []argov1alpha1.Application) ([][]string, map[string]int, error) { +func (r *ApplicationSetReconciler) buildAppDependencyList(logCtx *log.Entry, applicationSet argov1alpha1.ApplicationSet, applications []argov1alpha1.Application) ([][]string, map[string]int, error) { if applicationSet.Spec.Strategy == nil || applicationSet.Spec.Strategy.Type == "" || applicationSet.Spec.Strategy.Type == "AllAtOnce" { return [][]string{}, map[string]int{}, nil @@ -990,9 +997,9 @@ func (r *ApplicationSetReconciler) buildAppDependencyList(ctx context.Context, a for _, matchExpression := range step.MatchExpressions { if val, ok := app.Labels[matchExpression.Key]; ok { - valueMatched := labelMatchedExpression(val, matchExpression) + valueMatched := labelMatchedExpression(logCtx, val, matchExpression) - if !valueMatched { // none of the matchExpression values was a match with the Application'ss labels + if !valueMatched { // none of the matchExpression values was a match with the Application's labels selected = false break } @@ -1005,7 +1012,7 @@ func (r *ApplicationSetReconciler) buildAppDependencyList(ctx context.Context, a if selected { appDependencyList[i] = append(appDependencyList[i], app.Name) if val, ok := appStepMap[app.Name]; ok { - log.Warnf("AppSet '%v' has a invalid matchExpression that selects Application '%v' label twice, in steps %v and %v", applicationSet.Name, app.Name, val+1, i+1) + logCtx.Warnf("AppSet '%v' has a invalid matchExpression that selects Application '%v' label twice, in steps %v and %v", applicationSet.Name, app.Name, val+1, i+1) } else { appStepMap[app.Name] = i } @@ -1016,9 +1023,9 @@ func (r *ApplicationSetReconciler) buildAppDependencyList(ctx context.Context, a return appDependencyList, appStepMap, nil } -func labelMatchedExpression(val string, matchExpression argov1alpha1.ApplicationMatchExpression) bool { +func labelMatchedExpression(logCtx *log.Entry, val string, matchExpression argov1alpha1.ApplicationMatchExpression) bool { if matchExpression.Operator != "In" && matchExpression.Operator != "NotIn" { - log.Errorf("skipping AppSet rollingUpdate step Application selection, invalid matchExpression operator provided: %q ", matchExpression.Operator) + logCtx.Errorf("skipping AppSet rollingUpdate step Application selection, invalid matchExpression operator provided: %q ", matchExpression.Operator) return false } @@ -1122,7 +1129,7 @@ func statusStrings(app argov1alpha1.Application) (string, string, string) { } // check the status of each Application's status and promote Applications to the next status if needed -func (r *ApplicationSetReconciler) updateApplicationSetApplicationStatus(ctx context.Context, applicationSet *argov1alpha1.ApplicationSet, applications []argov1alpha1.Application, appStepMap map[string]int) ([]argov1alpha1.ApplicationSetApplicationStatus, error) { +func (r *ApplicationSetReconciler) updateApplicationSetApplicationStatus(ctx context.Context, logCtx *log.Entry, applicationSet *argov1alpha1.ApplicationSet, applications []argov1alpha1.Application, appStepMap map[string]int) ([]argov1alpha1.ApplicationSetApplicationStatus, error) { now := metav1.Now() appStatuses := make([]argov1alpha1.ApplicationSetApplicationStatus, 0, len(applications)) @@ -1155,7 +1162,7 @@ func (r *ApplicationSetReconciler) updateApplicationSetApplicationStatus(ctx con } if appOutdated && currentAppStatus.Status != "Waiting" && currentAppStatus.Status != "Pending" { - log.Infof("Application %v is outdated, updating its ApplicationSet status to Waiting", app.Name) + logCtx.Infof("Application %v is outdated, updating its ApplicationSet status to Waiting", app.Name) currentAppStatus.LastTransitionTime = &now currentAppStatus.Status = "Waiting" currentAppStatus.Message = "Application has pending changes, setting status to Waiting." @@ -1167,15 +1174,15 @@ func (r *ApplicationSetReconciler) updateApplicationSetApplicationStatus(ctx con // this covers race conditions where syncs initiated by RollingSync miraculously have a sync time before the transition to Pending state occurred (could be a few seconds) if operationPhaseString == "Succeeded" && app.Status.OperationState.StartedAt.Add(time.Duration(10)*time.Second).After(currentAppStatus.LastTransitionTime.Time) { if !app.Status.OperationState.StartedAt.After(currentAppStatus.LastTransitionTime.Time) { - log.Warnf("Application %v was synced less than 10s prior to entering Pending status, we'll assume the AppSet controller triggered this sync and update its status to Progressing", app.Name) + logCtx.Warnf("Application %v was synced less than 10s prior to entering Pending status, we'll assume the AppSet controller triggered this sync and update its status to Progressing", app.Name) } - log.Infof("Application %v has completed a sync successfully, updating its ApplicationSet status to Progressing", app.Name) + logCtx.Infof("Application %v has completed a sync successfully, updating its ApplicationSet status to Progressing", app.Name) currentAppStatus.LastTransitionTime = &now currentAppStatus.Status = "Progressing" currentAppStatus.Message = "Application resource completed a sync successfully, updating status from Pending to Progressing." currentAppStatus.Step = fmt.Sprint(appStepMap[currentAppStatus.Application] + 1) } else if operationPhaseString == "Running" || healthStatusString == "Progressing" { - log.Infof("Application %v has entered Progressing status, updating its ApplicationSet status to Progressing", app.Name) + logCtx.Infof("Application %v has entered Progressing status, updating its ApplicationSet status to Progressing", app.Name) currentAppStatus.LastTransitionTime = &now currentAppStatus.Status = "Progressing" currentAppStatus.Message = "Application resource became Progressing, updating status from Pending to Progressing." @@ -1184,7 +1191,7 @@ func (r *ApplicationSetReconciler) updateApplicationSetApplicationStatus(ctx con } if currentAppStatus.Status == "Waiting" && isApplicationHealthy(app) { - log.Infof("Application %v is already synced and healthy, updating its ApplicationSet status to Healthy", app.Name) + logCtx.Infof("Application %v is already synced and healthy, updating its ApplicationSet status to Healthy", app.Name) currentAppStatus.LastTransitionTime = &now currentAppStatus.Status = healthStatusString currentAppStatus.Message = "Application resource is already Healthy, updating status from Waiting to Healthy." @@ -1192,7 +1199,7 @@ func (r *ApplicationSetReconciler) updateApplicationSetApplicationStatus(ctx con } if currentAppStatus.Status == "Progressing" && isApplicationHealthy(app) { - log.Infof("Application %v has completed Progressing status, updating its ApplicationSet status to Healthy", app.Name) + logCtx.Infof("Application %v has completed Progressing status, updating its ApplicationSet status to Healthy", app.Name) currentAppStatus.LastTransitionTime = &now currentAppStatus.Status = healthStatusString currentAppStatus.Message = "Application resource became Healthy, updating status from Progressing to Healthy." @@ -1202,7 +1209,7 @@ func (r *ApplicationSetReconciler) updateApplicationSetApplicationStatus(ctx con appStatuses = append(appStatuses, currentAppStatus) } - err := r.setAppSetApplicationStatus(ctx, applicationSet, appStatuses) + err := r.setAppSetApplicationStatus(ctx, logCtx, applicationSet, appStatuses) if err != nil { return nil, fmt.Errorf("failed to set AppSet application statuses: %w", err) } @@ -1211,7 +1218,7 @@ func (r *ApplicationSetReconciler) updateApplicationSetApplicationStatus(ctx con } // check Applications that are in Waiting status and promote them to Pending if needed -func (r *ApplicationSetReconciler) updateApplicationSetApplicationStatusProgress(ctx context.Context, applicationSet *argov1alpha1.ApplicationSet, appSyncMap map[string]bool, appStepMap map[string]int, appMap map[string]argov1alpha1.Application) ([]argov1alpha1.ApplicationSetApplicationStatus, error) { +func (r *ApplicationSetReconciler) updateApplicationSetApplicationStatusProgress(ctx context.Context, logCtx *log.Entry, applicationSet *argov1alpha1.ApplicationSet, appSyncMap map[string]bool, appStepMap map[string]int, appMap map[string]argov1alpha1.Application) ([]argov1alpha1.ApplicationSetApplicationStatus, error) { now := metav1.Now() appStatuses := make([]argov1alpha1.ApplicationSetApplicationStatus, 0, len(applicationSet.Status.ApplicationStatus)) @@ -1253,7 +1260,7 @@ func (r *ApplicationSetReconciler) updateApplicationSetApplicationStatusProgress if maxUpdate != nil { maxUpdateVal, err := intstr.GetScaledValueFromIntOrPercent(maxUpdate, totalCountMap[appStepMap[appStatus.Application]], false) if err != nil { - log.Warnf("AppSet '%v' has a invalid maxUpdate value '%+v', ignoring maxUpdate logic for this step: %v", applicationSet.Name, maxUpdate, err) + logCtx.Warnf("AppSet '%v' has a invalid maxUpdate value '%+v', ignoring maxUpdate logic for this step: %v", applicationSet.Name, maxUpdate, err) } // ensure that percentage values greater than 0% always result in at least 1 Application being selected @@ -1263,13 +1270,13 @@ func (r *ApplicationSetReconciler) updateApplicationSetApplicationStatusProgress if updateCountMap[appStepMap[appStatus.Application]] >= maxUpdateVal { maxUpdateAllowed = false - log.Infof("Application %v is not allowed to update yet, %v/%v Applications already updating in step %v in AppSet %v", appStatus.Application, updateCountMap[appStepMap[appStatus.Application]], maxUpdateVal, appStepMap[appStatus.Application]+1, applicationSet.Name) + logCtx.Infof("Application %v is not allowed to update yet, %v/%v Applications already updating in step %v in AppSet %v", appStatus.Application, updateCountMap[appStepMap[appStatus.Application]], maxUpdateVal, appStepMap[appStatus.Application]+1, applicationSet.Name) } } if appStatus.Status == "Waiting" && appSyncMap[appStatus.Application] && maxUpdateAllowed { - log.Infof("Application %v moved to Pending status, watching for the Application to start Progressing", appStatus.Application) + logCtx.Infof("Application %v moved to Pending status, watching for the Application to start Progressing", appStatus.Application) appStatus.LastTransitionTime = &now appStatus.Status = "Pending" appStatus.Message = "Application moved to Pending status, watching for the Application resource to start Progressing." @@ -1282,7 +1289,7 @@ func (r *ApplicationSetReconciler) updateApplicationSetApplicationStatusProgress } } - err := r.setAppSetApplicationStatus(ctx, applicationSet, appStatuses) + err := r.setAppSetApplicationStatus(ctx, logCtx, applicationSet, appStatuses) if err != nil { return nil, fmt.Errorf("failed to set AppSet app status: %w", err) } @@ -1344,7 +1351,7 @@ func findApplicationStatusIndex(appStatuses []argov1alpha1.ApplicationSetApplica // setApplicationSetApplicationStatus updates the ApplicatonSet's status field // with any new/changed Application statuses. -func (r *ApplicationSetReconciler) setAppSetApplicationStatus(ctx context.Context, applicationSet *argov1alpha1.ApplicationSet, applicationStatuses []argov1alpha1.ApplicationSetApplicationStatus) error { +func (r *ApplicationSetReconciler) setAppSetApplicationStatus(ctx context.Context, logCtx *log.Entry, applicationSet *argov1alpha1.ApplicationSet, applicationStatuses []argov1alpha1.ApplicationSetApplicationStatus) error { needToUpdateStatus := false if len(applicationStatuses) != len(applicationSet.Status.ApplicationStatus) { @@ -1378,7 +1385,7 @@ func (r *ApplicationSetReconciler) setAppSetApplicationStatus(ctx context.Contex err := r.Client.Status().Update(ctx, applicationSet) if err != nil { - log.Errorf("unable to set application set status: %v", err) + logCtx.Errorf("unable to set application set status: %v", err) return fmt.Errorf("unable to set application set status: %v", err) } @@ -1393,7 +1400,7 @@ func (r *ApplicationSetReconciler) setAppSetApplicationStatus(ctx context.Contex return nil } -func (r *ApplicationSetReconciler) syncValidApplications(ctx context.Context, applicationSet *argov1alpha1.ApplicationSet, appSyncMap map[string]bool, appMap map[string]argov1alpha1.Application, validApps []argov1alpha1.Application) ([]argov1alpha1.Application, error) { +func (r *ApplicationSetReconciler) syncValidApplications(logCtx *log.Entry, applicationSet *argov1alpha1.ApplicationSet, appSyncMap map[string]bool, appMap map[string]argov1alpha1.Application, validApps []argov1alpha1.Application) ([]argov1alpha1.Application, error) { rolloutApps := []argov1alpha1.Application{} for i := range validApps { pruneEnabled := false @@ -1413,7 +1420,7 @@ func (r *ApplicationSetReconciler) syncValidApplications(ctx context.Context, ap // check appSyncMap to determine which Applications are ready to be updated and which should be skipped if appSyncMap[validApps[i].Name] && appMap[validApps[i].Name].Status.Sync.Status == "OutOfSync" && appSetStatusPending { - log.Infof("triggering sync for application: %v, prune enabled: %v", validApps[i].Name, pruneEnabled) + logCtx.Infof("triggering sync for application: %v, prune enabled: %v", validApps[i].Name, pruneEnabled) validApps[i], _ = syncApplication(validApps[i], pruneEnabled) } rolloutApps = append(rolloutApps, validApps[i]) @@ -1457,29 +1464,51 @@ func getOwnsHandlerPredicates(enableProgressiveSyncs bool) predicate.Funcs { CreateFunc: func(e event.CreateEvent) bool { // if we are the owner and there is a create event, we most likely created it and do not need to // re-reconcile - log.Debugln("received create event from owning an application") + if log.IsLevelEnabled(log.DebugLevel) { + var appName string + app, isApp := e.Object.(*argov1alpha1.Application) + if isApp { + appName = app.QualifiedName() + } + log.WithField("app", appName).Debugln("received create event from owning an application") + } return false }, DeleteFunc: func(e event.DeleteEvent) bool { - log.Debugln("received delete event from owning an application") + if log.IsLevelEnabled(log.DebugLevel) { + var appName string + app, isApp := e.Object.(*argov1alpha1.Application) + if isApp { + appName = app.QualifiedName() + } + log.WithField("app", appName).Debugln("received delete event from owning an application") + } return true }, UpdateFunc: func(e event.UpdateEvent) bool { - log.Debugln("received update event from owning an application") appOld, isApp := e.ObjectOld.(*argov1alpha1.Application) if !isApp { return false } + logCtx := log.WithField("app", appOld.QualifiedName()) + logCtx.Debugln("received update event from owning an application") appNew, isApp := e.ObjectNew.(*argov1alpha1.Application) if !isApp { return false } requeue := shouldRequeueApplicationSet(appOld, appNew, enableProgressiveSyncs) - log.Debugf("requeue: %t caused by application %s\n", requeue, appNew.Name) + logCtx.WithField("requeue", requeue).Debugf("requeue: %t caused by application %s\n", requeue, appNew.Name) return requeue }, GenericFunc: func(e event.GenericEvent) bool { - log.Debugln("received generic event from owning an application") + if log.IsLevelEnabled(log.DebugLevel) { + var appName string + app, isApp := e.Object.(*argov1alpha1.Application) + if isApp { + appName = app.QualifiedName() + } + log.WithField("app", appName).Debugln("received generic event from owning an application") + } return true }, } diff --git a/applicationset/controllers/applicationset_controller_test.go b/applicationset/controllers/applicationset_controller_test.go index 7c3721e2ee6ed..81fbad95ac50b 100644 --- a/applicationset/controllers/applicationset_controller_test.go +++ b/applicationset/controllers/applicationset_controller_test.go @@ -12,8 +12,6 @@ import ( log "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - "gopkg.in/yaml.v2" corev1 "k8s.io/api/core/v1" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -88,6 +86,12 @@ func (g *generatorMock) GenerateParams(appSetGenerator *v1alpha1.ApplicationSetG return args.Get(0).([]map[string]interface{}), args.Error(1) } +func (g *generatorMock) Replace(tmpl string, replaceMap map[string]interface{}, useGoTemplate bool, goTemplateOptions []string) (string, error) { + args := g.Called(tmpl, replaceMap, useGoTemplate, goTemplateOptions) + + return args.Get(0).(string), args.Error(1) +} + type rendererMock struct { mock.Mock } @@ -109,6 +113,12 @@ func (r *rendererMock) RenderTemplateParams(tmpl *v1alpha1.Application, syncPoli } +func (r *rendererMock) Replace(tmpl string, replaceMap map[string]interface{}, useGoTemplate bool, goTemplateOptions []string) (string, error) { + args := r.Called(tmpl, replaceMap, useGoTemplate, goTemplateOptions) + + return args.Get(0).(string), args.Error(1) +} + func TestExtractApplications(t *testing.T) { scheme := runtime.NewScheme() err := v1alpha1.AddToScheme(scheme) @@ -220,7 +230,7 @@ func TestExtractApplications(t *testing.T) { Cache: &fakeCache{}, } - got, reason, err := r.generateApplications(v1alpha1.ApplicationSet{ + got, reason, err := r.generateApplications(log.NewEntry(log.StandardLogger()), v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "namespace", @@ -333,7 +343,7 @@ func TestMergeTemplateApplications(t *testing.T) { KubeClientset: kubefake.NewSimpleClientset(), } - got, _, _ := r.generateApplications(v1alpha1.ApplicationSet{ + got, _, _ := r.generateApplications(log.NewEntry(log.StandardLogger()), v1alpha1.ApplicationSet{ ObjectMeta: metav1.ObjectMeta{ Name: "name", Namespace: "namespace", @@ -981,6 +991,296 @@ func TestCreateOrUpdateInCluster(t *testing.T) { }, }, }, + }, { + // For this use case: https://github.com/argoproj/argo-cd/issues/9101#issuecomment-1191138278 + name: "Ensure that ignored targetRevision difference doesn't cause an update, even if another field changes", + appSet: v1alpha1.ApplicationSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "name", + Namespace: "namespace", + }, + Spec: v1alpha1.ApplicationSetSpec{ + IgnoreApplicationDifferences: v1alpha1.ApplicationSetIgnoreDifferences{ + {JQPathExpressions: []string{".spec.source.targetRevision"}}, + }, + Template: v1alpha1.ApplicationSetTemplate{ + Spec: v1alpha1.ApplicationSpec{ + Project: "project", + Source: &v1alpha1.ApplicationSource{ + RepoURL: "https://git.example.com/test-org/test-repo.git", + TargetRevision: "foo", + }, + }, + }, + }, + }, + existingApps: []v1alpha1.Application{ + { + TypeMeta: metav1.TypeMeta{ + Kind: "Application", + APIVersion: "argoproj.io/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "app1", + Namespace: "namespace", + ResourceVersion: "2", + }, + Spec: v1alpha1.ApplicationSpec{ + Project: "project", + Source: &v1alpha1.ApplicationSource{ + RepoURL: "https://git.example.com/test-org/test-repo.git", + TargetRevision: "bar", + }, + }, + }, + }, + desiredApps: []v1alpha1.Application{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "app1", + }, + Spec: v1alpha1.ApplicationSpec{ + Project: "project", + Source: &v1alpha1.ApplicationSource{ + RepoURL: "https://git.example.com/test-org/test-repo.git", + // The targetRevision is ignored, so this should not be updated. + TargetRevision: "foo", + // This should be updated. + Helm: &v1alpha1.ApplicationSourceHelm{ + Parameters: []v1alpha1.HelmParameter{ + {Name: "hi", Value: "there"}, + }, + }, + }, + }, + }, + }, + expected: []v1alpha1.Application{ + { + TypeMeta: metav1.TypeMeta{ + Kind: "Application", + APIVersion: "argoproj.io/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "app1", + Namespace: "namespace", + ResourceVersion: "3", + }, + Spec: v1alpha1.ApplicationSpec{ + Project: "project", + Source: &v1alpha1.ApplicationSource{ + RepoURL: "https://git.example.com/test-org/test-repo.git", + // This is the existing value from the cluster, which should not be updated because the field is ignored. + TargetRevision: "bar", + // This was missing on the cluster, so it should be added. + Helm: &v1alpha1.ApplicationSourceHelm{ + Parameters: []v1alpha1.HelmParameter{ + {Name: "hi", Value: "there"}, + }, + }, + }, + }, + }, + }, + }, { + // For this use case: https://github.com/argoproj/argo-cd/pull/14743#issuecomment-1761954799 + name: "ignore parameters added to a multi-source app in the cluster", + appSet: v1alpha1.ApplicationSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "name", + Namespace: "namespace", + }, + Spec: v1alpha1.ApplicationSetSpec{ + IgnoreApplicationDifferences: v1alpha1.ApplicationSetIgnoreDifferences{ + {JQPathExpressions: []string{`.spec.sources[] | select(.repoURL | contains("test-repo")).helm.parameters`}}, + }, + Template: v1alpha1.ApplicationSetTemplate{ + Spec: v1alpha1.ApplicationSpec{ + Project: "project", + Sources: []v1alpha1.ApplicationSource{ + { + RepoURL: "https://git.example.com/test-org/test-repo.git", + Helm: &v1alpha1.ApplicationSourceHelm{ + Values: "foo: bar", + }, + }, + }, + }, + }, + }, + }, + existingApps: []v1alpha1.Application{ + { + TypeMeta: metav1.TypeMeta{ + Kind: "Application", + APIVersion: "argoproj.io/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "app1", + Namespace: "namespace", + ResourceVersion: "2", + }, + Spec: v1alpha1.ApplicationSpec{ + Project: "project", + Sources: []v1alpha1.ApplicationSource{ + { + RepoURL: "https://git.example.com/test-org/test-repo.git", + Helm: &v1alpha1.ApplicationSourceHelm{ + Values: "foo: bar", + Parameters: []v1alpha1.HelmParameter{ + {Name: "hi", Value: "there"}, + }, + }, + }, + }, + }, + }, + }, + desiredApps: []v1alpha1.Application{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "app1", + }, + Spec: v1alpha1.ApplicationSpec{ + Project: "project", + Sources: []v1alpha1.ApplicationSource{ + { + RepoURL: "https://git.example.com/test-org/test-repo.git", + Helm: &v1alpha1.ApplicationSourceHelm{ + Values: "foo: bar", + }, + }, + }, + }, + }, + }, + expected: []v1alpha1.Application{ + { + TypeMeta: metav1.TypeMeta{ + Kind: "Application", + APIVersion: "argoproj.io/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "app1", + Namespace: "namespace", + // This should not be updated, because reconciliation shouldn't modify the App. + ResourceVersion: "2", + }, + Spec: v1alpha1.ApplicationSpec{ + Project: "project", + Sources: []v1alpha1.ApplicationSource{ + { + RepoURL: "https://git.example.com/test-org/test-repo.git", + Helm: &v1alpha1.ApplicationSourceHelm{ + Values: "foo: bar", + Parameters: []v1alpha1.HelmParameter{ + // This existed only in the cluster, but it shouldn't be removed, because the field is ignored. + {Name: "hi", Value: "there"}, + }, + }, + }, + }, + }, + }, + }, + }, { + name: "Demonstrate limitation of MergePatch", // Maybe we can fix this in Argo CD 3.0: https://github.com/argoproj/argo-cd/issues/15975 + appSet: v1alpha1.ApplicationSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "name", + Namespace: "namespace", + }, + Spec: v1alpha1.ApplicationSetSpec{ + IgnoreApplicationDifferences: v1alpha1.ApplicationSetIgnoreDifferences{ + {JQPathExpressions: []string{`.spec.sources[] | select(.repoURL | contains("test-repo")).helm.parameters`}}, + }, + Template: v1alpha1.ApplicationSetTemplate{ + Spec: v1alpha1.ApplicationSpec{ + Project: "project", + Sources: []v1alpha1.ApplicationSource{ + { + RepoURL: "https://git.example.com/test-org/test-repo.git", + Helm: &v1alpha1.ApplicationSourceHelm{ + Values: "new: values", + }, + }, + }, + }, + }, + }, + }, + existingApps: []v1alpha1.Application{ + { + TypeMeta: metav1.TypeMeta{ + Kind: "Application", + APIVersion: "argoproj.io/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "app1", + Namespace: "namespace", + ResourceVersion: "2", + }, + Spec: v1alpha1.ApplicationSpec{ + Project: "project", + Sources: []v1alpha1.ApplicationSource{ + { + RepoURL: "https://git.example.com/test-org/test-repo.git", + Helm: &v1alpha1.ApplicationSourceHelm{ + Values: "foo: bar", + Parameters: []v1alpha1.HelmParameter{ + {Name: "hi", Value: "there"}, + }, + }, + }, + }, + }, + }, + }, + desiredApps: []v1alpha1.Application{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "app1", + }, + Spec: v1alpha1.ApplicationSpec{ + Project: "project", + Sources: []v1alpha1.ApplicationSource{ + { + RepoURL: "https://git.example.com/test-org/test-repo.git", + Helm: &v1alpha1.ApplicationSourceHelm{ + Values: "new: values", + }, + }, + }, + }, + }, + }, + expected: []v1alpha1.Application{ + { + TypeMeta: metav1.TypeMeta{ + Kind: "Application", + APIVersion: "argoproj.io/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "app1", + Namespace: "namespace", + ResourceVersion: "3", + }, + Spec: v1alpha1.ApplicationSpec{ + Project: "project", + Sources: []v1alpha1.ApplicationSource{ + { + RepoURL: "https://git.example.com/test-org/test-repo.git", + Helm: &v1alpha1.ApplicationSourceHelm{ + Values: "new: values", + // The Parameters field got blown away, because the values field changed. MergePatch + // doesn't merge list items, it replaces the whole list if an item changes. + // If we eventually add a `name` field to Sources, we can use StrategicMergePatch. + }, + }, + }, + }, + }, + }, }, } { @@ -994,7 +1294,7 @@ func TestCreateOrUpdateInCluster(t *testing.T) { initObjs = append(initObjs, &a) } - client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(initObjs...).Build() + client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(initObjs...).WithIndex(&v1alpha1.Application{}, ".metadata.controller", appControllerIndexer).Build() r := ApplicationSetReconciler{ Client: client, @@ -1003,8 +1303,8 @@ func TestCreateOrUpdateInCluster(t *testing.T) { Cache: &fakeCache{}, } - err = r.createOrUpdateInCluster(context.TODO(), c.appSet, c.desiredApps) - assert.Nil(t, err) + err = r.createOrUpdateInCluster(context.TODO(), log.NewEntry(log.StandardLogger()), c.appSet, c.desiredApps) + assert.NoError(t, err) for _, obj := range c.expected { got := &v1alpha1.Application{} @@ -1014,7 +1314,6 @@ func TestCreateOrUpdateInCluster(t *testing.T) { }, got) err = controllerutil.SetControllerReference(&c.appSet, &obj, r.Scheme) - assert.Nil(t, err) assert.Equal(t, obj, *got) } }) @@ -1088,7 +1387,7 @@ func TestRemoveFinalizerOnInvalidDestination_FinalizerTypes(t *testing.T) { initObjs := []crtclient.Object{&app, &appSet} - client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(initObjs...).Build() + client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(initObjs...).WithIndex(&v1alpha1.Application{}, ".metadata.controller", appControllerIndexer).Build() secret := &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ Name: "my-secret", @@ -1250,7 +1549,7 @@ func TestRemoveFinalizerOnInvalidDestination_DestinationTypes(t *testing.T) { initObjs := []crtclient.Object{&app, &appSet} - client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(initObjs...).Build() + client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(initObjs...).WithIndex(&v1alpha1.Application{}, ".metadata.controller", appControllerIndexer).Build() secret := &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ Name: "my-secret", @@ -1306,6 +1605,81 @@ func TestRemoveFinalizerOnInvalidDestination_DestinationTypes(t *testing.T) { } } +func TestRemoveOwnerReferencesOnDeleteAppSet(t *testing.T) { + scheme := runtime.NewScheme() + err := v1alpha1.AddToScheme(scheme) + assert.Nil(t, err) + + err = v1alpha1.AddToScheme(scheme) + assert.Nil(t, err) + + for _, c := range []struct { + // name is human-readable test name + name string + }{ + { + name: "ownerReferences cleared", + }, + } { + t.Run(c.name, func(t *testing.T) { + appSet := v1alpha1.ApplicationSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "name", + Namespace: "namespace", + Finalizers: []string{v1alpha1.ResourcesFinalizerName}, + }, + Spec: v1alpha1.ApplicationSetSpec{ + Template: v1alpha1.ApplicationSetTemplate{ + Spec: v1alpha1.ApplicationSpec{ + Project: "project", + }, + }, + }, + } + + app := v1alpha1.Application{ + ObjectMeta: metav1.ObjectMeta{ + Name: "app1", + Namespace: "namespace", + }, + Spec: v1alpha1.ApplicationSpec{ + Project: "project", + Source: &v1alpha1.ApplicationSource{Path: "path", TargetRevision: "revision", RepoURL: "repoURL"}, + Destination: v1alpha1.ApplicationDestination{ + Namespace: "namespace", + Server: "https://kubernetes.default.svc", + }, + }, + } + + err := controllerutil.SetControllerReference(&appSet, &app, scheme) + assert.NoError(t, err, "Unexpected error") + + initObjs := []crtclient.Object{&app, &appSet} + + client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(initObjs...).WithIndex(&v1alpha1.Application{}, ".metadata.controller", appControllerIndexer).Build() + + r := ApplicationSetReconciler{ + Client: client, + Scheme: scheme, + Recorder: record.NewFakeRecorder(10), + KubeClientset: nil, + Cache: &fakeCache{}, + } + + err = r.removeOwnerReferencesOnDeleteAppSet(context.Background(), appSet) + assert.NoError(t, err, "Unexpected error") + + retrievedApp := v1alpha1.Application{} + err = client.Get(context.Background(), crtclient.ObjectKeyFromObject(&app), &retrievedApp) + assert.NoError(t, err, "Unexpected error") + + ownerReferencesRemoved := len(retrievedApp.OwnerReferences) == 0 + assert.True(t, ownerReferencesRemoved) + }) + } +} + func TestCreateApplications(t *testing.T) { scheme := runtime.NewScheme() @@ -1482,7 +1856,7 @@ func TestCreateApplications(t *testing.T) { initObjs = append(initObjs, &a) } - client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(initObjs...).Build() + client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(initObjs...).WithIndex(&v1alpha1.Application{}, ".metadata.controller", appControllerIndexer).Build() r := ApplicationSetReconciler{ Client: client, @@ -1491,7 +1865,7 @@ func TestCreateApplications(t *testing.T) { Cache: &fakeCache{}, } - err = r.createInCluster(context.TODO(), c.appSet, c.apps) + err = r.createInCluster(context.TODO(), log.NewEntry(log.StandardLogger()), c.appSet, c.apps) assert.Nil(t, err) for _, obj := range c.expected { @@ -1626,7 +2000,7 @@ func TestDeleteInCluster(t *testing.T) { initObjs = append(initObjs, &temp) } - client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(initObjs...).Build() + client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(initObjs...).WithIndex(&v1alpha1.Application{}, ".metadata.controller", appControllerIndexer).Build() r := ApplicationSetReconciler{ Client: client, @@ -1635,7 +2009,7 @@ func TestDeleteInCluster(t *testing.T) { KubeClientset: kubefake.NewSimpleClientset(), } - err = r.deleteInCluster(context.TODO(), c.appSet, c.desiredApps) + err = r.deleteInCluster(context.TODO(), log.NewEntry(log.StandardLogger()), c.appSet, c.desiredApps) assert.Nil(t, err) // For each of the expected objects, verify they exist on the cluster @@ -2000,7 +2374,15 @@ func TestReconcilerValidationProjectErrorBehaviour(t *testing.T) { argoDBMock := dbmocks.ArgoDB{} argoObjs := []runtime.Object{&project} - client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&appSet).Build() + client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&appSet).WithIndex(&v1alpha1.Application{}, ".metadata.controller", appControllerIndexer).Build() + goodCluster := v1alpha1.Cluster{Server: "https://good-cluster", Name: "good-cluster"} + badCluster := v1alpha1.Cluster{Server: "https://bad-cluster", Name: "bad-cluster"} + argoDBMock.On("GetCluster", mock.Anything, "https://good-cluster").Return(&goodCluster, nil) + argoDBMock.On("GetCluster", mock.Anything, "https://bad-cluster").Return(&badCluster, nil) + argoDBMock.On("ListClusters", mock.Anything).Return(&v1alpha1.ClusterList{Items: []v1alpha1.Cluster{ + goodCluster, + }}, nil) + r := ApplicationSetReconciler{ Client: client, Scheme: scheme, @@ -2076,7 +2458,7 @@ func TestSetApplicationSetStatusCondition(t *testing.T) { argoDBMock := dbmocks.ArgoDB{} argoObjs := []runtime.Object{} - client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&appSet).Build() + client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&appSet).WithIndex(&v1alpha1.Application{}, ".metadata.controller", appControllerIndexer).Build() r := ApplicationSetReconciler{ Client: client, @@ -2146,7 +2528,7 @@ func applicationsUpdateSyncPolicyTest(t *testing.T, applicationsSyncPolicy v1alp argoDBMock := dbmocks.ArgoDB{} argoObjs := []runtime.Object{&defaultProject} - client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&appSet).Build() + client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&appSet).WithIndex(&v1alpha1.Application{}, ".metadata.controller", appControllerIndexer).Build() goodCluster := v1alpha1.Cluster{Server: "https://good-cluster", Name: "good-cluster"} argoDBMock.On("GetCluster", mock.Anything, "https://good-cluster").Return(&goodCluster, nil) argoDBMock.On("ListClusters", mock.Anything).Return(&v1alpha1.ClusterList{Items: []v1alpha1.Cluster{ @@ -2316,7 +2698,7 @@ func applicationsDeleteSyncPolicyTest(t *testing.T, applicationsSyncPolicy v1alp argoDBMock := dbmocks.ArgoDB{} argoObjs := []runtime.Object{&defaultProject} - client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&appSet).Build() + client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&appSet).WithIndex(&v1alpha1.Application{}, ".metadata.controller", appControllerIndexer).Build() goodCluster := v1alpha1.Cluster{Server: "https://good-cluster", Name: "good-cluster"} argoDBMock.On("GetCluster", mock.Anything, "https://good-cluster").Return(&goodCluster, nil) argoDBMock.On("ListClusters", mock.Anything).Return(&v1alpha1.ClusterList{Items: []v1alpha1.Cluster{ @@ -2445,17 +2827,24 @@ func TestGenerateAppsUsingPullRequestGenerator(t *testing.T) { { name: "Generate an application from a go template application set manifest using a pull request generator", params: []map[string]interface{}{{ - "number": "1", - "branch": "branch1", - "branch_slug": "branchSlug1", - "head_sha": "089d92cbf9ff857a39e6feccd32798ca700fb958", - "head_short_sha": "089d92cb", - "labels": []string{"label1"}}}, + "number": "1", + "branch": "branch1", + "branch_slug": "branchSlug1", + "head_sha": "089d92cbf9ff857a39e6feccd32798ca700fb958", + "head_short_sha": "089d92cb", + "branch_slugify_default": "feat/a_really+long_pull_request_name_to_test_argo_slugification_and_branch_name_shortening_feature", + "branch_slugify_smarttruncate_disabled": "feat/areallylongpullrequestnametotestargoslugificationandbranchnameshorteningfeature", + "branch_slugify_smarttruncate_enabled": "feat/testwithsmarttruncateenabledramdomlonglistofcharacters", + "labels": []string{"label1"}}, + }, template: v1alpha1.ApplicationSetTemplate{ ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{ Name: "AppSet-{{.branch}}-{{.number}}", Labels: map[string]string{ - "app1": "{{index .labels 0}}", + "app1": "{{index .labels 0}}", + "branch-test1": "AppSet-{{.branch_slugify_default | slugify }}", + "branch-test2": "AppSet-{{.branch_slugify_smarttruncate_disabled | slugify 49 false }}", + "branch-test3": "AppSet-{{.branch_slugify_smarttruncate_enabled | slugify 50 true }}", }, }, Spec: v1alpha1.ApplicationSpec{ @@ -2474,7 +2863,10 @@ func TestGenerateAppsUsingPullRequestGenerator(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "AppSet-branch1-1", Labels: map[string]string{ - "app1": "label1", + "app1": "label1", + "branch-test1": "AppSet-feat-a-really-long-pull-request-name-to-test-argo", + "branch-test2": "AppSet-feat-areallylongpullrequestnametotestargoslugific", + "branch-test3": "AppSet-feat", }, }, Spec: v1alpha1.ApplicationSpec{ @@ -2517,7 +2909,7 @@ func TestGenerateAppsUsingPullRequestGenerator(t *testing.T) { KubeClientset: kubefake.NewSimpleClientset(), } - gotApp, _, _ := appSetReconciler.generateApplications(v1alpha1.ApplicationSet{ + gotApp, _, _ := appSetReconciler.generateApplications(log.NewEntry(log.StandardLogger()), v1alpha1.ApplicationSet{ Spec: v1alpha1.ApplicationSetSpec{ GoTemplate: true, Generators: []v1alpha1.ApplicationSetGenerator{{ @@ -2627,7 +3019,7 @@ func TestPolicies(t *testing.T) { }, } - client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&appSet).Build() + client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&appSet).WithIndex(&v1alpha1.Application{}, ".metadata.controller", appControllerIndexer).Build() r := ApplicationSetReconciler{ Client: client, @@ -2806,7 +3198,7 @@ func TestSetApplicationSetApplicationStatus(t *testing.T) { KubeClientset: kubeclientset, } - err = r.setAppSetApplicationStatus(context.TODO(), &cc.appSet, cc.appStatuses) + err = r.setAppSetApplicationStatus(context.TODO(), log.NewEntry(log.StandardLogger()), &cc.appSet, cc.appStatuses) assert.Nil(t, err) assert.Equal(t, cc.expectedAppStatuses, cc.appSet.Status.ApplicationStatus) @@ -3569,7 +3961,7 @@ func TestBuildAppDependencyList(t *testing.T) { KubeClientset: kubeclientset, } - appDependencyList, appStepMap, err := r.buildAppDependencyList(context.TODO(), cc.appSet, cc.apps) + appDependencyList, appStepMap, err := r.buildAppDependencyList(log.NewEntry(log.StandardLogger()), cc.appSet, cc.apps) assert.Equal(t, err, nil, "expected no errors, but errors occured") assert.Equal(t, cc.expectedList, appDependencyList, "expected appDependencyList did not match actual") assert.Equal(t, cc.expectedStepMap, appStepMap, "expected appStepMap did not match actual") @@ -4823,7 +5215,7 @@ func TestUpdateApplicationSetApplicationStatus(t *testing.T) { KubeClientset: kubeclientset, } - appStatuses, err := r.updateApplicationSetApplicationStatus(context.TODO(), &cc.appSet, cc.apps, cc.appStepMap) + appStatuses, err := r.updateApplicationSetApplicationStatus(context.TODO(), log.NewEntry(log.StandardLogger()), &cc.appSet, cc.apps, cc.appStepMap) // opt out of testing the LastTransitionTime is accurate for i := range appStatuses { @@ -5577,7 +5969,7 @@ func TestUpdateApplicationSetApplicationStatusProgress(t *testing.T) { KubeClientset: kubeclientset, } - appStatuses, err := r.updateApplicationSetApplicationStatusProgress(context.TODO(), &cc.appSet, cc.appSyncMap, cc.appStepMap, cc.appMap) + appStatuses, err := r.updateApplicationSetApplicationStatusProgress(context.TODO(), log.NewEntry(log.StandardLogger()), &cc.appSet, cc.appSyncMap, cc.appStepMap, cc.appMap) // opt out of testing the LastTransitionTime is accurate for i := range appStatuses { @@ -5719,173 +6111,3 @@ func TestOwnsHandler(t *testing.T) { }) } } - -func Test_applyIgnoreDifferences(t *testing.T) { - appMeta := metav1.TypeMeta{ - APIVersion: v1alpha1.ApplicationSchemaGroupVersionKind.GroupVersion().String(), - Kind: v1alpha1.ApplicationSchemaGroupVersionKind.Kind, - } - testCases := []struct { - name string - ignoreDifferences v1alpha1.ApplicationSetIgnoreDifferences - foundApp string - generatedApp string - expectedApp string - }{ - { - name: "empty ignoreDifferences", - foundApp: ` -spec: {}`, - generatedApp: ` -spec: {}`, - expectedApp: ` -spec: {}`, - }, - { - // For this use case: https://github.com/argoproj/argo-cd/issues/9101#issuecomment-1191138278 - name: "ignore target revision with jq", - ignoreDifferences: v1alpha1.ApplicationSetIgnoreDifferences{ - {JQPathExpressions: []string{".spec.source.targetRevision"}}, - }, - foundApp: ` -spec: - source: - targetRevision: foo`, - generatedApp: ` -spec: - source: - targetRevision: bar`, - expectedApp: ` -spec: - source: - targetRevision: foo`, - }, - { - // For this use case: https://github.com/argoproj/argo-cd/issues/9101#issuecomment-1103593714 - name: "ignore helm parameter with jq", - ignoreDifferences: v1alpha1.ApplicationSetIgnoreDifferences{ - {JQPathExpressions: []string{`.spec.source.helm.parameters | select(.name == "image.tag")`}}, - }, - foundApp: ` -spec: - source: - helm: - parameters: - - name: image.tag - value: test - - name: another - value: value`, - generatedApp: ` -spec: - source: - helm: - parameters: - - name: image.tag - value: v1.0.0 - - name: another - value: value`, - expectedApp: ` -spec: - source: - helm: - parameters: - - name: image.tag - value: test - - name: another - value: value`, - }, - { - // For this use case: https://github.com/argoproj/argo-cd/issues/9101#issuecomment-1191138278 - name: "ignore auto-sync with jq", - ignoreDifferences: v1alpha1.ApplicationSetIgnoreDifferences{ - {JQPathExpressions: []string{".spec.syncPolicy.automated"}}, - }, - foundApp: ` -spec: - syncPolicy: - retry: - limit: 5`, - generatedApp: ` -spec: - syncPolicy: - automated: - selfHeal: true - retry: - limit: 5`, - expectedApp: ` -spec: - syncPolicy: - retry: - limit: 5`, - }, - { - // For this use case: https://github.com/argoproj/argo-cd/issues/9101#issuecomment-1420656537 - name: "ignore a one-off annotation with jq", - ignoreDifferences: v1alpha1.ApplicationSetIgnoreDifferences{ - {JQPathExpressions: []string{`.metadata.annotations | select(.["foo.bar"] == "baz")`}}, - }, - foundApp: ` -metadata: - annotations: - foo.bar: baz - some.other: annotation`, - generatedApp: ` -metadata: - annotations: - some.other: annotation`, - expectedApp: ` -metadata: - annotations: - foo.bar: baz - some.other: annotation`, - }, - { - // For this use case: https://github.com/argoproj/argo-cd/issues/9101#issuecomment-1515672638 - name: "ignore the source.plugin field with a json pointer", - ignoreDifferences: v1alpha1.ApplicationSetIgnoreDifferences{ - {JSONPointers: []string{"/spec/source/plugin"}}, - }, - foundApp: ` -spec: - source: - plugin: - parameters: - - name: url - string: https://example.com`, - generatedApp: ` -spec: - source: - plugin: - parameters: - - name: url - string: https://example.com/wrong`, - expectedApp: ` -spec: - source: - plugin: - parameters: - - name: url - string: https://example.com`, - }, - } - - for _, tc := range testCases { - tc := tc - t.Run(tc.name, func(t *testing.T) { - t.Parallel() - foundApp := v1alpha1.Application{TypeMeta: appMeta} - err := yaml.Unmarshal([]byte(tc.foundApp), &foundApp) - require.NoError(t, err, tc.foundApp) - generatedApp := v1alpha1.Application{TypeMeta: appMeta} - err = yaml.Unmarshal([]byte(tc.generatedApp), &generatedApp) - require.NoError(t, err, tc.generatedApp) - err = applyIgnoreDifferences(tc.ignoreDifferences, &foundApp, generatedApp) - require.NoError(t, err) - jsonFound, err := json.Marshal(tc.foundApp) - require.NoError(t, err) - jsonExpected, err := json.Marshal(tc.expectedApp) - require.NoError(t, err) - assert.Equal(t, string(jsonExpected), string(jsonFound)) - }) - } -} diff --git a/applicationset/controllers/templatePatch.go b/applicationset/controllers/templatePatch.go new file mode 100644 index 0000000000000..f8efd9f376996 --- /dev/null +++ b/applicationset/controllers/templatePatch.go @@ -0,0 +1,46 @@ +package controllers + +import ( + "encoding/json" + "fmt" + + "k8s.io/apimachinery/pkg/util/strategicpatch" + + "github.com/argoproj/argo-cd/v2/applicationset/utils" + appv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" +) + +func applyTemplatePatch(app *appv1.Application, templatePatch string) (*appv1.Application, error) { + + appString, err := json.Marshal(app) + if err != nil { + return nil, fmt.Errorf("error while marhsalling Application %w", err) + } + + convertedTemplatePatch, err := utils.ConvertYAMLToJSON(templatePatch) + + if err != nil { + return nil, fmt.Errorf("error while converting template to json %q: %w", convertedTemplatePatch, err) + } + + if err := json.Unmarshal([]byte(convertedTemplatePatch), &appv1.Application{}); err != nil { + return nil, fmt.Errorf("invalid templatePatch %q: %w", convertedTemplatePatch, err) + } + + data, err := strategicpatch.StrategicMergePatch(appString, []byte(convertedTemplatePatch), appv1.Application{}) + + if err != nil { + return nil, fmt.Errorf("error while applying templatePatch template to json %q: %w", convertedTemplatePatch, err) + } + + finalApp := appv1.Application{} + err = json.Unmarshal(data, &finalApp) + if err != nil { + return nil, fmt.Errorf("error while unmarhsalling patched application: %w", err) + } + + // Prevent changes to the `project` field. This helps prevent malicious template patches + finalApp.Spec.Project = app.Spec.Project + + return &finalApp, nil +} diff --git a/applicationset/controllers/templatePatch_test.go b/applicationset/controllers/templatePatch_test.go new file mode 100644 index 0000000000000..c1a794077c8ee --- /dev/null +++ b/applicationset/controllers/templatePatch_test.go @@ -0,0 +1,249 @@ +package controllers + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + appv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" +) + +func Test_ApplyTemplatePatch(t *testing.T) { + testCases := []struct { + name string + appTemplate *appv1.Application + templatePatch string + expectedApp *appv1.Application + }{ + { + name: "patch with JSON", + appTemplate: &appv1.Application{ + TypeMeta: metav1.TypeMeta{ + Kind: "Application", + APIVersion: "argoproj.io/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "my-cluster-guestbook", + Namespace: "namespace", + Finalizers: []string{"resources-finalizer.argocd.argoproj.io"}, + }, + Spec: appv1.ApplicationSpec{ + Project: "default", + Source: &appv1.ApplicationSource{ + RepoURL: "https://github.com/argoproj/argocd-example-apps.git", + TargetRevision: "HEAD", + Path: "guestbook", + }, + Destination: appv1.ApplicationDestination{ + Server: "https://kubernetes.default.svc", + Namespace: "guestbook", + }, + }, + }, + templatePatch: `{ + "metadata": { + "annotations": { + "annotation-some-key": "annotation-some-value" + } + }, + "spec": { + "source": { + "helm": { + "valueFiles": [ + "values.test.yaml", + "values.big.yaml" + ] + } + }, + "syncPolicy": { + "automated": { + "prune": true + } + } + } + }`, + expectedApp: &appv1.Application{ + TypeMeta: metav1.TypeMeta{ + Kind: "Application", + APIVersion: "argoproj.io/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "my-cluster-guestbook", + Namespace: "namespace", + Finalizers: []string{"resources-finalizer.argocd.argoproj.io"}, + Annotations: map[string]string{ + "annotation-some-key": "annotation-some-value", + }, + }, + Spec: appv1.ApplicationSpec{ + Project: "default", + Source: &appv1.ApplicationSource{ + RepoURL: "https://github.com/argoproj/argocd-example-apps.git", + TargetRevision: "HEAD", + Path: "guestbook", + Helm: &appv1.ApplicationSourceHelm{ + ValueFiles: []string{ + "values.test.yaml", + "values.big.yaml", + }, + }, + }, + Destination: appv1.ApplicationDestination{ + Server: "https://kubernetes.default.svc", + Namespace: "guestbook", + }, + SyncPolicy: &appv1.SyncPolicy{ + Automated: &appv1.SyncPolicyAutomated{ + Prune: true, + }, + }, + }, + }, + }, + { + name: "patch with YAML", + appTemplate: &appv1.Application{ + TypeMeta: metav1.TypeMeta{ + Kind: "Application", + APIVersion: "argoproj.io/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "my-cluster-guestbook", + Namespace: "namespace", + Finalizers: []string{"resources-finalizer.argocd.argoproj.io"}, + }, + Spec: appv1.ApplicationSpec{ + Project: "default", + Source: &appv1.ApplicationSource{ + RepoURL: "https://github.com/argoproj/argocd-example-apps.git", + TargetRevision: "HEAD", + Path: "guestbook", + }, + Destination: appv1.ApplicationDestination{ + Server: "https://kubernetes.default.svc", + Namespace: "guestbook", + }, + }, + }, + templatePatch: ` +metadata: + annotations: + annotation-some-key: annotation-some-value +spec: + source: + helm: + valueFiles: + - values.test.yaml + - values.big.yaml + syncPolicy: + automated: + prune: true`, + expectedApp: &appv1.Application{ + TypeMeta: metav1.TypeMeta{ + Kind: "Application", + APIVersion: "argoproj.io/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "my-cluster-guestbook", + Namespace: "namespace", + Finalizers: []string{"resources-finalizer.argocd.argoproj.io"}, + Annotations: map[string]string{ + "annotation-some-key": "annotation-some-value", + }, + }, + Spec: appv1.ApplicationSpec{ + Project: "default", + Source: &appv1.ApplicationSource{ + RepoURL: "https://github.com/argoproj/argocd-example-apps.git", + TargetRevision: "HEAD", + Path: "guestbook", + Helm: &appv1.ApplicationSourceHelm{ + ValueFiles: []string{ + "values.test.yaml", + "values.big.yaml", + }, + }, + }, + Destination: appv1.ApplicationDestination{ + Server: "https://kubernetes.default.svc", + Namespace: "guestbook", + }, + SyncPolicy: &appv1.SyncPolicy{ + Automated: &appv1.SyncPolicyAutomated{ + Prune: true, + }, + }, + }, + }, + }, + { + name: "project field isn't overwritten", + appTemplate: &appv1.Application{ + TypeMeta: metav1.TypeMeta{ + Kind: "Application", + APIVersion: "argoproj.io/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "my-cluster-guestbook", + Namespace: "namespace", + }, + Spec: appv1.ApplicationSpec{ + Project: "default", + Source: &appv1.ApplicationSource{ + RepoURL: "https://github.com/argoproj/argocd-example-apps.git", + TargetRevision: "HEAD", + Path: "guestbook", + }, + Destination: appv1.ApplicationDestination{ + Server: "https://kubernetes.default.svc", + Namespace: "guestbook", + }, + }, + }, + templatePatch: ` +spec: + project: my-project`, + expectedApp: &appv1.Application{ + TypeMeta: metav1.TypeMeta{ + Kind: "Application", + APIVersion: "argoproj.io/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "my-cluster-guestbook", + Namespace: "namespace", + }, + Spec: appv1.ApplicationSpec{ + Project: "default", + Source: &appv1.ApplicationSource{ + RepoURL: "https://github.com/argoproj/argocd-example-apps.git", + TargetRevision: "HEAD", + Path: "guestbook", + }, + Destination: appv1.ApplicationDestination{ + Server: "https://kubernetes.default.svc", + Namespace: "guestbook", + }, + }, + }, + }, + } + + for _, tc := range testCases { + tcc := tc + t.Run(tcc.name, func(t *testing.T) { + result, err := applyTemplatePatch(tcc.appTemplate, tcc.templatePatch) + require.NoError(t, err) + assert.Equal(t, *tcc.expectedApp, *result) + }) + } +} + +func TestError(t *testing.T) { + app := &appv1.Application{} + + result, err := applyTemplatePatch(app, "hello world") + require.Error(t, err) + require.Nil(t, result) +} diff --git a/applicationset/generators/git.go b/applicationset/generators/git.go index 07c1b11849cd0..57fe2835b8df0 100644 --- a/applicationset/generators/git.go +++ b/applicationset/generators/git.go @@ -56,12 +56,14 @@ func (g *GitGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.Applic return nil, EmptyAppSetGeneratorError } + noRevisionCache := appSet.RefreshRequired() + var err error var res []map[string]interface{} if len(appSetGenerator.Git.Directories) != 0 { - res, err = g.generateParamsForGitDirectories(appSetGenerator, appSet.Spec.GoTemplate, appSet.Spec.GoTemplateOptions) + res, err = g.generateParamsForGitDirectories(appSetGenerator, noRevisionCache, appSet.Spec.GoTemplate, appSet.Spec.GoTemplateOptions) } else if len(appSetGenerator.Git.Files) != 0 { - res, err = g.generateParamsForGitFiles(appSetGenerator, appSet.Spec.GoTemplate, appSet.Spec.GoTemplateOptions) + res, err = g.generateParamsForGitFiles(appSetGenerator, noRevisionCache, appSet.Spec.GoTemplate, appSet.Spec.GoTemplateOptions) } else { return nil, EmptyAppSetGeneratorError } @@ -72,10 +74,10 @@ func (g *GitGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.Applic return res, nil } -func (g *GitGenerator) generateParamsForGitDirectories(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, useGoTemplate bool, goTemplateOptions []string) ([]map[string]interface{}, error) { +func (g *GitGenerator) generateParamsForGitDirectories(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, noRevisionCache bool, useGoTemplate bool, goTemplateOptions []string) ([]map[string]interface{}, error) { // Directories, not files - allPaths, err := g.repos.GetDirectories(context.TODO(), appSetGenerator.Git.RepoURL, appSetGenerator.Git.Revision) + allPaths, err := g.repos.GetDirectories(context.TODO(), appSetGenerator.Git.RepoURL, appSetGenerator.Git.Revision, noRevisionCache) if err != nil { return nil, fmt.Errorf("error getting directories from repo: %w", err) } @@ -98,12 +100,12 @@ func (g *GitGenerator) generateParamsForGitDirectories(appSetGenerator *argoproj return res, nil } -func (g *GitGenerator) generateParamsForGitFiles(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, useGoTemplate bool, goTemplateOptions []string) ([]map[string]interface{}, error) { +func (g *GitGenerator) generateParamsForGitFiles(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, noRevisionCache bool, useGoTemplate bool, goTemplateOptions []string) ([]map[string]interface{}, error) { // Get all files that match the requested path string, removing duplicates allFiles := make(map[string][]byte) for _, requestedPath := range appSetGenerator.Git.Files { - files, err := g.repos.GetFiles(context.TODO(), appSetGenerator.Git.RepoURL, appSetGenerator.Git.Revision, requestedPath.Path) + files, err := g.repos.GetFiles(context.TODO(), appSetGenerator.Git.RepoURL, appSetGenerator.Git.Revision, requestedPath.Path, noRevisionCache) if err != nil { return nil, err } diff --git a/applicationset/generators/git_test.go b/applicationset/generators/git_test.go index f0d1d29bca6ec..d3fd4965057f8 100644 --- a/applicationset/generators/git_test.go +++ b/applicationset/generators/git_test.go @@ -317,7 +317,7 @@ func TestGitGenerateParamsFromDirectories(t *testing.T) { argoCDServiceMock := mocks.Repos{} - argoCDServiceMock.On("GetDirectories", mock.Anything, mock.Anything, mock.Anything).Return(testCaseCopy.repoApps, testCaseCopy.repoError) + argoCDServiceMock.On("GetDirectories", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(testCaseCopy.repoApps, testCaseCopy.repoError) var gitGenerator = NewGitGenerator(&argoCDServiceMock) applicationSetInfo := argoprojiov1alpha1.ApplicationSet{ @@ -613,7 +613,7 @@ func TestGitGenerateParamsFromDirectoriesGoTemplate(t *testing.T) { argoCDServiceMock := mocks.Repos{} - argoCDServiceMock.On("GetDirectories", mock.Anything, mock.Anything, mock.Anything).Return(testCaseCopy.repoApps, testCaseCopy.repoError) + argoCDServiceMock.On("GetDirectories", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(testCaseCopy.repoApps, testCaseCopy.repoError) var gitGenerator = NewGitGenerator(&argoCDServiceMock) applicationSetInfo := argoprojiov1alpha1.ApplicationSet{ @@ -972,7 +972,7 @@ cluster: t.Parallel() argoCDServiceMock := mocks.Repos{} - argoCDServiceMock.On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything). + argoCDServiceMock.On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything). Return(testCaseCopy.repoFileContents, testCaseCopy.repoPathsError) var gitGenerator = NewGitGenerator(&argoCDServiceMock) @@ -1322,7 +1322,7 @@ cluster: t.Parallel() argoCDServiceMock := mocks.Repos{} - argoCDServiceMock.On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything). + argoCDServiceMock.On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything). Return(testCaseCopy.repoFileContents, testCaseCopy.repoPathsError) var gitGenerator = NewGitGenerator(&argoCDServiceMock) diff --git a/applicationset/generators/matrix_test.go b/applicationset/generators/matrix_test.go index 35748b98bcf19..21e88710ae618 100644 --- a/applicationset/generators/matrix_test.go +++ b/applicationset/generators/matrix_test.go @@ -1108,7 +1108,7 @@ func TestGitGenerator_GenerateParams_list_x_git_matrix_generator(t *testing.T) { } repoServiceMock := &mocks.Repos{} - repoServiceMock.On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(map[string][]byte{ + repoServiceMock.On("GetFiles", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(map[string][]byte{ "some/path.json": []byte("test: content"), }, nil) gitGenerator := NewGitGenerator(repoServiceMock) diff --git a/applicationset/services/mocks/Repos.go b/applicationset/services/mocks/Repos.go index 776b104cae284..b7620b22f08bb 100644 --- a/applicationset/services/mocks/Repos.go +++ b/applicationset/services/mocks/Repos.go @@ -13,25 +13,25 @@ type Repos struct { mock.Mock } -// GetDirectories provides a mock function with given fields: ctx, repoURL, revision -func (_m *Repos) GetDirectories(ctx context.Context, repoURL string, revision string) ([]string, error) { - ret := _m.Called(ctx, repoURL, revision) +// GetDirectories provides a mock function with given fields: ctx, repoURL, revision, noRevisionCache +func (_m *Repos) GetDirectories(ctx context.Context, repoURL string, revision string, noRevisionCache bool) ([]string, error) { + ret := _m.Called(ctx, repoURL, revision, noRevisionCache) var r0 []string var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string, string) ([]string, error)); ok { - return rf(ctx, repoURL, revision) + if rf, ok := ret.Get(0).(func(context.Context, string, string, bool) ([]string, error)); ok { + return rf(ctx, repoURL, revision, noRevisionCache) } - if rf, ok := ret.Get(0).(func(context.Context, string, string) []string); ok { - r0 = rf(ctx, repoURL, revision) + if rf, ok := ret.Get(0).(func(context.Context, string, string, bool) []string); ok { + r0 = rf(ctx, repoURL, revision, noRevisionCache) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]string) } } - if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok { - r1 = rf(ctx, repoURL, revision) + if rf, ok := ret.Get(1).(func(context.Context, string, string, bool) error); ok { + r1 = rf(ctx, repoURL, revision, noRevisionCache) } else { r1 = ret.Error(1) } @@ -39,25 +39,25 @@ func (_m *Repos) GetDirectories(ctx context.Context, repoURL string, revision st return r0, r1 } -// GetFiles provides a mock function with given fields: ctx, repoURL, revision, pattern -func (_m *Repos) GetFiles(ctx context.Context, repoURL string, revision string, pattern string) (map[string][]byte, error) { - ret := _m.Called(ctx, repoURL, revision, pattern) +// GetFiles provides a mock function with given fields: ctx, repoURL, revision, pattern, noRevisionCache +func (_m *Repos) GetFiles(ctx context.Context, repoURL string, revision string, pattern string, noRevisionCache bool) (map[string][]byte, error) { + ret := _m.Called(ctx, repoURL, revision, pattern, noRevisionCache) var r0 map[string][]byte var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string, string, string) (map[string][]byte, error)); ok { - return rf(ctx, repoURL, revision, pattern) + if rf, ok := ret.Get(0).(func(context.Context, string, string, string, bool) (map[string][]byte, error)); ok { + return rf(ctx, repoURL, revision, pattern, noRevisionCache) } - if rf, ok := ret.Get(0).(func(context.Context, string, string, string) map[string][]byte); ok { - r0 = rf(ctx, repoURL, revision, pattern) + if rf, ok := ret.Get(0).(func(context.Context, string, string, string, bool) map[string][]byte); ok { + r0 = rf(ctx, repoURL, revision, pattern, noRevisionCache) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(map[string][]byte) } } - if rf, ok := ret.Get(1).(func(context.Context, string, string, string) error); ok { - r1 = rf(ctx, repoURL, revision, pattern) + if rf, ok := ret.Get(1).(func(context.Context, string, string, string, bool) error); ok { + r1 = rf(ctx, repoURL, revision, pattern, noRevisionCache) } else { r1 = ret.Error(1) } diff --git a/applicationset/services/pull_request/azure_devops_test.go b/applicationset/services/pull_request/azure_devops_test.go index 15ac1c8233d89..5ed8f4de78b9d 100644 --- a/applicationset/services/pull_request/azure_devops_test.go +++ b/applicationset/services/pull_request/azure_devops_test.go @@ -206,9 +206,9 @@ func TestBuildURL(t *testing.T) { }, { name: "Provided custom URL and organization", - url: "https://azuredevops.mycompany.com/", + url: "https://azuredevops.example.com/", organization: "myorganization", - expected: "https://azuredevops.mycompany.com/myorganization", + expected: "https://azuredevops.example.com/myorganization", }, } diff --git a/applicationset/services/repo_service.go b/applicationset/services/repo_service.go index 8ad261fda11cd..64fedc34390b8 100644 --- a/applicationset/services/repo_service.go +++ b/applicationset/services/repo_service.go @@ -11,6 +11,8 @@ import ( "github.com/argoproj/argo-cd/v2/util/io" ) +//go:generate go run github.com/vektra/mockery/v2@v2.25.1 --name=RepositoryDB + // RepositoryDB Is a lean facade for ArgoDB, // Using a lean interface makes it easier to test the functionality of the git generator type RepositoryDB interface { @@ -25,13 +27,15 @@ type argoCDService struct { newFileGlobbingEnabled bool } +//go:generate go run github.com/vektra/mockery/v2@v2.25.1 --name=Repos + type Repos interface { // GetFiles returns content of files (not directories) within the target repo - GetFiles(ctx context.Context, repoURL string, revision string, pattern string) (map[string][]byte, error) + GetFiles(ctx context.Context, repoURL string, revision string, pattern string, noRevisionCache bool) (map[string][]byte, error) // GetDirectories returns a list of directories (not files) within the target repo - GetDirectories(ctx context.Context, repoURL string, revision string) ([]string, error) + GetDirectories(ctx context.Context, repoURL string, revision string, noRevisionCache bool) ([]string, error) } func NewArgoCDService(db db.ArgoDB, submoduleEnabled bool, repoClientset apiclient.Clientset, newFileGlobbingEnabled bool) (Repos, error) { @@ -43,7 +47,7 @@ func NewArgoCDService(db db.ArgoDB, submoduleEnabled bool, repoClientset apiclie }, nil } -func (a *argoCDService) GetFiles(ctx context.Context, repoURL string, revision string, pattern string) (map[string][]byte, error) { +func (a *argoCDService) GetFiles(ctx context.Context, repoURL string, revision string, pattern string, noRevisionCache bool) (map[string][]byte, error) { repo, err := a.repositoriesDB.GetRepository(ctx, repoURL) if err != nil { return nil, fmt.Errorf("error in GetRepository: %w", err) @@ -55,6 +59,7 @@ func (a *argoCDService) GetFiles(ctx context.Context, repoURL string, revision s Revision: revision, Path: pattern, NewGitFileGlobbingEnabled: a.newFileGlobbingEnabled, + NoRevisionCache: noRevisionCache, } closer, client, err := a.repoServerClientSet.NewRepoServerClient() if err != nil { @@ -69,7 +74,7 @@ func (a *argoCDService) GetFiles(ctx context.Context, repoURL string, revision s return fileResponse.GetMap(), nil } -func (a *argoCDService) GetDirectories(ctx context.Context, repoURL string, revision string) ([]string, error) { +func (a *argoCDService) GetDirectories(ctx context.Context, repoURL string, revision string, noRevisionCache bool) ([]string, error) { repo, err := a.repositoriesDB.GetRepository(ctx, repoURL) if err != nil { return nil, fmt.Errorf("error in GetRepository: %w", err) @@ -79,6 +84,7 @@ func (a *argoCDService) GetDirectories(ctx context.Context, repoURL string, revi Repo: repo, SubmoduleEnabled: a.submoduleEnabled, Revision: revision, + NoRevisionCache: noRevisionCache, } closer, client, err := a.repoServerClientSet.NewRepoServerClient() diff --git a/applicationset/services/repo_service_test.go b/applicationset/services/repo_service_test.go index 62f8c11c172d0..040fe57f96958 100644 --- a/applicationset/services/repo_service_test.go +++ b/applicationset/services/repo_service_test.go @@ -25,9 +25,10 @@ func TestGetDirectories(t *testing.T) { repoServerClientFuncs []func(*repo_mocks.RepoServerServiceClient) } type args struct { - ctx context.Context - repoURL string - revision string + ctx context.Context + repoURL string + revision string + noRevisionCache bool } tests := []struct { name string @@ -88,11 +89,11 @@ func TestGetDirectories(t *testing.T) { submoduleEnabled: tt.fields.submoduleEnabled, repoServerClientSet: &repo_mocks.Clientset{RepoServerServiceClient: mockRepoClient}, } - got, err := a.GetDirectories(tt.args.ctx, tt.args.repoURL, tt.args.revision) - if !tt.wantErr(t, err, fmt.Sprintf("GetDirectories(%v, %v, %v)", tt.args.ctx, tt.args.repoURL, tt.args.revision)) { + got, err := a.GetDirectories(tt.args.ctx, tt.args.repoURL, tt.args.revision, tt.args.noRevisionCache) + if !tt.wantErr(t, err, fmt.Sprintf("GetDirectories(%v, %v, %v, %v)", tt.args.ctx, tt.args.repoURL, tt.args.revision, tt.args.noRevisionCache)) { return } - assert.Equalf(t, tt.want, got, "GetDirectories(%v, %v, %v)", tt.args.ctx, tt.args.repoURL, tt.args.revision) + assert.Equalf(t, tt.want, got, "GetDirectories(%v, %v, %v, %v)", tt.args.ctx, tt.args.repoURL, tt.args.revision, tt.args.noRevisionCache) }) } } @@ -105,10 +106,11 @@ func TestGetFiles(t *testing.T) { repoServerClientFuncs []func(*repo_mocks.RepoServerServiceClient) } type args struct { - ctx context.Context - repoURL string - revision string - pattern string + ctx context.Context + repoURL string + revision string + pattern string + noRevisionCache bool } tests := []struct { name string @@ -175,11 +177,11 @@ func TestGetFiles(t *testing.T) { submoduleEnabled: tt.fields.submoduleEnabled, repoServerClientSet: &repo_mocks.Clientset{RepoServerServiceClient: mockRepoClient}, } - got, err := a.GetFiles(tt.args.ctx, tt.args.repoURL, tt.args.revision, tt.args.pattern) - if !tt.wantErr(t, err, fmt.Sprintf("GetFiles(%v, %v, %v, %v)", tt.args.ctx, tt.args.repoURL, tt.args.revision, tt.args.pattern)) { + got, err := a.GetFiles(tt.args.ctx, tt.args.repoURL, tt.args.revision, tt.args.pattern, tt.args.noRevisionCache) + if !tt.wantErr(t, err, fmt.Sprintf("GetFiles(%v, %v, %v, %v, %v)", tt.args.ctx, tt.args.repoURL, tt.args.revision, tt.args.pattern, tt.args.noRevisionCache)) { return } - assert.Equalf(t, tt.want, got, "GetFiles(%v, %v, %v, %v)", tt.args.ctx, tt.args.repoURL, tt.args.revision, tt.args.pattern) + assert.Equalf(t, tt.want, got, "GetFiles(%v, %v, %v, %v, %v)", tt.args.ctx, tt.args.repoURL, tt.args.revision, tt.args.pattern, tt.args.noRevisionCache) }) } } diff --git a/applicationset/services/scm_provider/gitlab.go b/applicationset/services/scm_provider/gitlab.go index f4b92b3ed9e5f..ca174de540887 100644 --- a/applicationset/services/scm_provider/gitlab.go +++ b/applicationset/services/scm_provider/gitlab.go @@ -100,12 +100,20 @@ func (g *GitlabProvider) ListRepos(ctx context.Context, cloneProtocol string) ([ return nil, fmt.Errorf("unknown clone protocol for Gitlab %v", cloneProtocol) } + var repoLabels []string + if len(gitlabRepo.Topics) == 0 { + // fallback to for gitlab prior to 14.5 + repoLabels = gitlabRepo.TagList + } else { + repoLabels = gitlabRepo.Topics + } + repos = append(repos, &Repository{ Organization: gitlabRepo.Namespace.FullPath, Repository: gitlabRepo.Path, URL: url, Branch: gitlabRepo.DefaultBranch, - Labels: gitlabRepo.TagList, + Labels: repoLabels, RepositoryId: gitlabRepo.ID, }) } diff --git a/applicationset/services/scm_provider/gitlab_test.go b/applicationset/services/scm_provider/gitlab_test.go index 11b21cb6da6d4..b93616fa8367f 100644 --- a/applicationset/services/scm_provider/gitlab_test.go +++ b/applicationset/services/scm_provider/gitlab_test.go @@ -1063,6 +1063,16 @@ func TestGitlabListRepos(t *testing.T) { proto: "ssh", url: "git@gitlab.com:test-argocd-proton/argocd.git", }, + { + name: "labelmatch", + proto: "ssh", + url: "git@gitlab.com:test-argocd-proton/argocd.git", + filters: []v1alpha1.SCMProviderGeneratorFilter{ + { + LabelMatch: strp("test-topic"), + }, + }, + }, { name: "https protocol", proto: "https", diff --git a/applicationset/utils/clusterUtils.go b/applicationset/utils/clusterUtils.go index ee9832f533e5e..3b34a5a863dbd 100644 --- a/applicationset/utils/clusterUtils.go +++ b/applicationset/utils/clusterUtils.go @@ -180,7 +180,7 @@ func secretToCluster(s *corev1.Secret) (*appv1.Cluster, error) { if val, err := strconv.Atoi(string(shardStr)); err != nil { log.Warnf("Error while parsing shard in cluster secret '%s': %v", s.Name, err) } else { - shard = pointer.Int64Ptr(int64(val)) + shard = pointer.Int64(int64(val)) } } cluster := appv1.Cluster{ diff --git a/applicationset/utils/createOrUpdate.go b/applicationset/utils/createOrUpdate.go index 096be5a9a97d3..1f2a8a9c4a54c 100644 --- a/applicationset/utils/createOrUpdate.go +++ b/applicationset/utils/createOrUpdate.go @@ -2,18 +2,24 @@ package utils import ( "context" + "encoding/json" "fmt" + log "github.com/sirupsen/logrus" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/conversion" "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" argov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + "github.com/argoproj/argo-cd/v2/util/argo" + argodiff "github.com/argoproj/argo-cd/v2/util/argo/diff" ) // CreateOrUpdate overrides "sigs.k8s.io/controller-runtime" function @@ -29,7 +35,7 @@ import ( // The MutateFn is called regardless of creating or updating an object. // // It returns the executed operation and an error. -func CreateOrUpdate(ctx context.Context, c client.Client, obj client.Object, f controllerutil.MutateFn) (controllerutil.OperationResult, error) { +func CreateOrUpdate(ctx context.Context, logCtx *log.Entry, c client.Client, ignoreAppDifferences argov1alpha1.ApplicationSetIgnoreDifferences, obj *argov1alpha1.Application, f controllerutil.MutateFn) (controllerutil.OperationResult, error) { key := client.ObjectKeyFromObject(obj) if err := c.Get(ctx, key, obj); err != nil { @@ -45,15 +51,24 @@ func CreateOrUpdate(ctx context.Context, c client.Client, obj client.Object, f c return controllerutil.OperationResultCreated, nil } - existingObj := obj.DeepCopyObject() - existing, ok := existingObj.(client.Object) - if !ok { - panic(fmt.Errorf("existing object is not a client.Object")) - } + normalizedLive := obj.DeepCopy() + + // Mutate the live object to match the desired state. if err := mutate(f, key, obj); err != nil { return controllerutil.OperationResultNone, err } + // Apply ignoreApplicationDifferences rules to remove ignored fields from both the live and the desired state. This + // prevents those differences from appearing in the diff and therefore in the patch. + err := applyIgnoreDifferences(ignoreAppDifferences, normalizedLive, obj) + if err != nil { + return controllerutil.OperationResultNone, fmt.Errorf("failed to apply ignore differences: %w", err) + } + + // Normalize to avoid diffing on unimportant differences. + normalizedLive.Spec = *argo.NormalizeApplicationSpec(&normalizedLive.Spec) + obj.Spec = *argo.NormalizeApplicationSpec(&obj.Spec) + equality := conversion.EqualitiesOrDie( func(a, b resource.Quantity) bool { // Ignore formatting, only care that numeric value stayed the same. @@ -79,16 +94,34 @@ func CreateOrUpdate(ctx context.Context, c client.Client, obj client.Object, f c }, ) - if equality.DeepEqual(existing, obj) { + if equality.DeepEqual(normalizedLive, obj) { return controllerutil.OperationResultNone, nil } - if err := c.Patch(ctx, obj, client.MergeFrom(existing)); err != nil { + patch := client.MergeFrom(normalizedLive) + if log.IsLevelEnabled(log.DebugLevel) { + LogPatch(logCtx, patch, obj) + } + if err := c.Patch(ctx, obj, patch); err != nil { return controllerutil.OperationResultNone, err } return controllerutil.OperationResultUpdated, nil } +func LogPatch(logCtx *log.Entry, patch client.Patch, obj *argov1alpha1.Application) { + patchBytes, err := patch.Data(obj) + if err != nil { + logCtx.Errorf("failed to generate patch: %v", err) + } + // Get the patch as a plain object so it is easier to work with in json logs. + var patchObj map[string]interface{} + err = json.Unmarshal(patchBytes, &patchObj) + if err != nil { + logCtx.Errorf("failed to unmarshal patch: %v", err) + } + logCtx.WithField("patch", patchObj).Debug("patching application") +} + // mutate wraps a MutateFn and applies validation to its result func mutate(f controllerutil.MutateFn, key client.ObjectKey, obj client.Object) error { if err := f(); err != nil { @@ -99,3 +132,71 @@ func mutate(f controllerutil.MutateFn, key client.ObjectKey, obj client.Object) } return nil } + +// applyIgnoreDifferences applies the ignore differences rules to the found application. It modifies the applications in place. +func applyIgnoreDifferences(applicationSetIgnoreDifferences argov1alpha1.ApplicationSetIgnoreDifferences, found *argov1alpha1.Application, generatedApp *argov1alpha1.Application) error { + if len(applicationSetIgnoreDifferences) == 0 { + return nil + } + + generatedAppCopy := generatedApp.DeepCopy() + diffConfig, err := argodiff.NewDiffConfigBuilder(). + WithDiffSettings(applicationSetIgnoreDifferences.ToApplicationIgnoreDifferences(), nil, false). + WithNoCache(). + Build() + if err != nil { + return fmt.Errorf("failed to build diff config: %w", err) + } + unstructuredFound, err := appToUnstructured(found) + if err != nil { + return fmt.Errorf("failed to convert found application to unstructured: %w", err) + } + unstructuredGenerated, err := appToUnstructured(generatedApp) + if err != nil { + return fmt.Errorf("failed to convert found application to unstructured: %w", err) + } + result, err := argodiff.Normalize([]*unstructured.Unstructured{unstructuredFound}, []*unstructured.Unstructured{unstructuredGenerated}, diffConfig) + if err != nil { + return fmt.Errorf("failed to normalize application spec: %w", err) + } + if len(result.Lives) != 1 { + return fmt.Errorf("expected 1 normalized application, got %d", len(result.Lives)) + } + foundJsonNormalized, err := json.Marshal(result.Lives[0].Object) + if err != nil { + return fmt.Errorf("failed to marshal normalized app to json: %w", err) + } + foundNormalized := &argov1alpha1.Application{} + err = json.Unmarshal(foundJsonNormalized, &foundNormalized) + if err != nil { + return fmt.Errorf("failed to unmarshal normalized app to json: %w", err) + } + if len(result.Targets) != 1 { + return fmt.Errorf("expected 1 normalized application, got %d", len(result.Targets)) + } + foundNormalized.DeepCopyInto(found) + generatedJsonNormalized, err := json.Marshal(result.Targets[0].Object) + if err != nil { + return fmt.Errorf("failed to marshal normalized app to json: %w", err) + } + generatedAppNormalized := &argov1alpha1.Application{} + err = json.Unmarshal(generatedJsonNormalized, &generatedAppNormalized) + if err != nil { + return fmt.Errorf("failed to unmarshal normalized app json to structured app: %w", err) + } + generatedAppNormalized.DeepCopyInto(generatedApp) + // Prohibit jq queries from mutating silly things. + generatedApp.TypeMeta = generatedAppCopy.TypeMeta + generatedApp.Name = generatedAppCopy.Name + generatedApp.Namespace = generatedAppCopy.Namespace + generatedApp.Operation = generatedAppCopy.Operation + return nil +} + +func appToUnstructured(app client.Object) (*unstructured.Unstructured, error) { + u, err := runtime.DefaultUnstructuredConverter.ToUnstructured(app) + if err != nil { + return nil, fmt.Errorf("failed to convert app object to unstructured: %w", err) + } + return &unstructured.Unstructured{Object: u}, nil +} diff --git a/applicationset/utils/createOrUpdate_test.go b/applicationset/utils/createOrUpdate_test.go new file mode 100644 index 0000000000000..a294e89281974 --- /dev/null +++ b/applicationset/utils/createOrUpdate_test.go @@ -0,0 +1,234 @@ +package utils + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "gopkg.in/yaml.v3" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" +) + +func Test_applyIgnoreDifferences(t *testing.T) { + appMeta := metav1.TypeMeta{ + APIVersion: v1alpha1.ApplicationSchemaGroupVersionKind.GroupVersion().String(), + Kind: v1alpha1.ApplicationSchemaGroupVersionKind.Kind, + } + testCases := []struct { + name string + ignoreDifferences v1alpha1.ApplicationSetIgnoreDifferences + foundApp string + generatedApp string + expectedApp string + }{ + { + name: "empty ignoreDifferences", + foundApp: ` +spec: {}`, + generatedApp: ` +spec: {}`, + expectedApp: ` +spec: {}`, + }, + { + // For this use case: https://github.com/argoproj/argo-cd/issues/9101#issuecomment-1191138278 + name: "ignore target revision with jq", + ignoreDifferences: v1alpha1.ApplicationSetIgnoreDifferences{ + {JQPathExpressions: []string{".spec.source.targetRevision"}}, + }, + foundApp: ` +spec: + source: + targetRevision: foo`, + generatedApp: ` +spec: + source: + targetRevision: bar`, + expectedApp: ` +spec: + source: + targetRevision: foo`, + }, + { + // For this use case: https://github.com/argoproj/argo-cd/issues/9101#issuecomment-1103593714 + name: "ignore helm parameter with jq", + ignoreDifferences: v1alpha1.ApplicationSetIgnoreDifferences{ + {JQPathExpressions: []string{`.spec.source.helm.parameters | select(.name == "image.tag")`}}, + }, + foundApp: ` +spec: + source: + helm: + parameters: + - name: image.tag + value: test + - name: another + value: value`, + generatedApp: ` +spec: + source: + helm: + parameters: + - name: image.tag + value: v1.0.0 + - name: another + value: value`, + expectedApp: ` +spec: + source: + helm: + parameters: + - name: image.tag + value: test + - name: another + value: value`, + }, + { + // For this use case: https://github.com/argoproj/argo-cd/issues/9101#issuecomment-1191138278 + name: "ignore auto-sync in appset when it's not in the cluster with jq", + ignoreDifferences: v1alpha1.ApplicationSetIgnoreDifferences{ + {JQPathExpressions: []string{".spec.syncPolicy.automated"}}, + }, + foundApp: ` +spec: + syncPolicy: + retry: + limit: 5`, + generatedApp: ` +spec: + syncPolicy: + automated: + selfHeal: true + retry: + limit: 5`, + expectedApp: ` +spec: + syncPolicy: + retry: + limit: 5`, + }, + { + name: "ignore auto-sync in the cluster when it's not in the appset with jq", + ignoreDifferences: v1alpha1.ApplicationSetIgnoreDifferences{ + {JQPathExpressions: []string{".spec.syncPolicy.automated"}}, + }, + foundApp: ` +spec: + syncPolicy: + automated: + selfHeal: true + retry: + limit: 5`, + generatedApp: ` +spec: + syncPolicy: + retry: + limit: 5`, + expectedApp: ` +spec: + syncPolicy: + automated: + selfHeal: true + retry: + limit: 5`, + }, + { + // For this use case: https://github.com/argoproj/argo-cd/issues/9101#issuecomment-1420656537 + name: "ignore a one-off annotation with jq", + ignoreDifferences: v1alpha1.ApplicationSetIgnoreDifferences{ + {JQPathExpressions: []string{`.metadata.annotations | select(.["foo.bar"] == "baz")`}}, + }, + foundApp: ` +metadata: + annotations: + foo.bar: baz + some.other: annotation`, + generatedApp: ` +metadata: + annotations: + some.other: annotation`, + expectedApp: ` +metadata: + annotations: + foo.bar: baz + some.other: annotation`, + }, + { + // For this use case: https://github.com/argoproj/argo-cd/issues/9101#issuecomment-1515672638 + name: "ignore the source.plugin field with a json pointer", + ignoreDifferences: v1alpha1.ApplicationSetIgnoreDifferences{ + {JSONPointers: []string{"/spec/source/plugin"}}, + }, + foundApp: ` +spec: + source: + plugin: + parameters: + - name: url + string: https://example.com`, + generatedApp: ` +spec: + source: + plugin: + parameters: + - name: url + string: https://example.com/wrong`, + expectedApp: ` +spec: + source: + plugin: + parameters: + - name: url + string: https://example.com`, + }, + { + // For this use case: https://github.com/argoproj/argo-cd/pull/14743#issuecomment-1761954799 + name: "ignore parameters added to a multi-source app in the cluster", + ignoreDifferences: v1alpha1.ApplicationSetIgnoreDifferences{ + {JQPathExpressions: []string{`.spec.sources[] | select(.repoURL | contains("test-repo")).helm.parameters`}}, + }, + foundApp: ` +spec: + sources: + - repoURL: https://git.example.com/test-org/test-repo + helm: + parameters: + - name: test + value: hi`, + generatedApp: ` +spec: + sources: + - repoURL: https://git.example.com/test-org/test-repo`, + expectedApp: ` +spec: + sources: + - repoURL: https://git.example.com/test-org/test-repo + helm: + parameters: + - name: test + value: hi`, + }, + } + + for _, tc := range testCases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + foundApp := v1alpha1.Application{TypeMeta: appMeta} + err := yaml.Unmarshal([]byte(tc.foundApp), &foundApp) + require.NoError(t, err, tc.foundApp) + generatedApp := v1alpha1.Application{TypeMeta: appMeta} + err = yaml.Unmarshal([]byte(tc.generatedApp), &generatedApp) + require.NoError(t, err, tc.generatedApp) + err = applyIgnoreDifferences(tc.ignoreDifferences, &foundApp, &generatedApp) + require.NoError(t, err) + yamlFound, err := yaml.Marshal(tc.foundApp) + require.NoError(t, err) + yamlExpected, err := yaml.Marshal(tc.expectedApp) + require.NoError(t, err) + assert.Equal(t, string(yamlExpected), string(yamlFound)) + }) + } +} diff --git a/applicationset/utils/utils.go b/applicationset/utils/utils.go index 089a6ff103100..2d128eb81a16c 100644 --- a/applicationset/utils/utils.go +++ b/applicationset/utils/utils.go @@ -16,6 +16,7 @@ import ( "unsafe" "github.com/Masterminds/sprig/v3" + "github.com/gosimple/slug" "github.com/valyala/fasttemplate" "sigs.k8s.io/yaml" @@ -32,6 +33,7 @@ func init() { delete(sprigFuncMap, "expandenv") delete(sprigFuncMap, "getHostByName") sprigFuncMap["normalize"] = SanitizeName + sprigFuncMap["slugify"] = SlugifyName sprigFuncMap["toYaml"] = toYAML sprigFuncMap["fromYaml"] = fromYAML sprigFuncMap["fromYamlArray"] = fromYAMLArray @@ -39,6 +41,7 @@ func init() { type Renderer interface { RenderTemplateParams(tmpl *argoappsv1.Application, syncPolicy *argoappsv1.ApplicationSetSyncPolicy, params map[string]interface{}, useGoTemplate bool, goTemplateOptions []string) (*argoappsv1.Application, error) + Replace(tmpl string, replaceMap map[string]interface{}, useGoTemplate bool, goTemplateOptions []string) (string, error) } type Render struct { @@ -434,6 +437,54 @@ func NormalizeBitbucketBasePath(basePath string) string { return basePath } +// SlugifyName generates a URL-friendly slug from the provided name and additional options. +// The slug is generated in accordance with the following rules: +// 1. The generated slug will be URL-safe and suitable for use in URLs. +// 2. The maximum length of the slug can be specified using the `maxSize` argument. +// 3. Smart truncation can be enabled or disabled using the `EnableSmartTruncate` argument. +// 4. The input name can be any string value that needs to be converted into a slug. +// +// Args: +// - args: A variadic number of arguments where: +// - The first argument (if provided) is an integer specifying the maximum length of the slug. +// - The second argument (if provided) is a boolean indicating whether smart truncation is enabled. +// - The last argument (if provided) is the input name that needs to be slugified. +// If no name is provided, an empty string will be used. +// +// Returns: +// - string: The generated URL-friendly slug based on the input name and options. +func SlugifyName(args ...interface{}) string { + // Default values for arguments + maxSize := 50 + EnableSmartTruncate := true + name := "" + + // Process the arguments + for idx, arg := range args { + switch idx { + case len(args) - 1: + name = arg.(string) + case 0: + maxSize = arg.(int) + case 1: + EnableSmartTruncate = arg.(bool) + default: + log.Errorf("Bad 'slugify' arguments.") + } + } + + sanitizedName := SanitizeName(name) + + // Configure slug generation options + slug.EnableSmartTruncate = EnableSmartTruncate + slug.MaxLength = maxSize + + // Generate the slug from the input name + urlSlug := slug.Make(sanitizedName) + + return urlSlug +} + func getTlsConfigWithCACert(scmRootCAPath string) *tls.Config { tlsConfig := &tls.Config{} diff --git a/applicationset/utils/utils_test.go b/applicationset/utils/utils_test.go index a1c58769160cc..3b4702bc35c3f 100644 --- a/applicationset/utils/utils_test.go +++ b/applicationset/utils/utils_test.go @@ -1243,6 +1243,43 @@ func TestNormalizeBitbucketBasePath(t *testing.T) { } } +func TestSlugify(t *testing.T) { + for _, c := range []struct { + branch string + smartTruncate bool + length int + expectedBasePath string + }{ + { + branch: "feat/a_really+long_pull_request_name_to_test_argo_slugification_and_branch_name_shortening_feature", + smartTruncate: false, + length: 50, + expectedBasePath: "feat-a-really-long-pull-request-name-to-test-argo", + }, + { + branch: "feat/a_really+long_pull_request_name_to_test_argo_slugification_and_branch_name_shortening_feature", + smartTruncate: true, + length: 53, + expectedBasePath: "feat-a-really-long-pull-request-name-to-test-argo", + }, + { + branch: "feat/areallylongpullrequestnametotestargoslugificationandbranchnameshorteningfeature", + smartTruncate: true, + length: 50, + expectedBasePath: "feat", + }, + { + branch: "feat/areallylongpullrequestnametotestargoslugificationandbranchnameshorteningfeature", + smartTruncate: false, + length: 50, + expectedBasePath: "feat-areallylongpullrequestnametotestargoslugifica", + }, + } { + result := SlugifyName(c.length, c.smartTruncate, c.branch) + assert.Equal(t, c.expectedBasePath, result, c.branch) + } +} + func TestGetTLSConfig(t *testing.T) { // certParsed, err := tls.X509KeyPair(test.Cert, test.PrivateKey) // require.NoError(t, err) diff --git a/applicationset/webhook/testdata/github-pull-request-labeled-event.json b/applicationset/webhook/testdata/github-pull-request-labeled-event.json new file mode 100644 index 0000000000000..f912a2fdb4a97 --- /dev/null +++ b/applicationset/webhook/testdata/github-pull-request-labeled-event.json @@ -0,0 +1,473 @@ +{ + "action": "labeled", + "number": 2, + "label": { + "id": 6129306173, + "node_id": "LA_kwDOIqudU88AAAABbVXKPQ", + "url": "https://api.github.com/repos/SG60/backstage/labels/deploy-preview", + "name": "deploy-preview", + "color": "bfd4f2", + "default": false, + "description": "" + }, + "pull_request": { + "url": "https://api.github.com/repos/Codertocat/Hello-World/pulls/2", + "id": 279147437, + "node_id": "MDExOlB1bGxSZXF1ZXN0Mjc5MTQ3NDM3", + "html_url": "https://github.com/Codertocat/Hello-World/pull/2", + "diff_url": "https://github.com/Codertocat/Hello-World/pull/2.diff", + "patch_url": "https://github.com/Codertocat/Hello-World/pull/2.patch", + "issue_url": "https://api.github.com/repos/Codertocat/Hello-World/issues/2", + "number": 2, + "state": "open", + "locked": false, + "title": "Update the README with new information.", + "user": { + "login": "Codertocat", + "id": 21031067, + "node_id": "MDQ6VXNlcjIxMDMxMDY3", + "avatar_url": "https://avatars1.githubusercontent.com/u/21031067?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/Codertocat", + "html_url": "https://github.com/Codertocat", + "followers_url": "https://api.github.com/users/Codertocat/followers", + "following_url": "https://api.github.com/users/Codertocat/following{/other_user}", + "gists_url": "https://api.github.com/users/Codertocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/Codertocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/Codertocat/subscriptions", + "organizations_url": "https://api.github.com/users/Codertocat/orgs", + "repos_url": "https://api.github.com/users/Codertocat/repos", + "events_url": "https://api.github.com/users/Codertocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/Codertocat/received_events", + "type": "User", + "site_admin": false + }, + "body": "This is a pretty simple change that we need to pull into master.", + "created_at": "2019-05-15T15:20:33Z", + "updated_at": "2019-05-15T15:20:33Z", + "closed_at": null, + "merged_at": null, + "merge_commit_sha": null, + "assignee": null, + "assignees": [], + "requested_reviewers": [], + "requested_teams": [], + "labels": [ + { + "id": 6129306173, + "node_id": "LA_kwDOIqudU88AAAABbVXKPQ", + "url": "https://api.github.com/repos/Codertocat/Hello-World/labels/deploy-preview", + "name": "deploy-preview", + "color": "bfd4f2", + "default": false, + "description": "" + } + ], + "milestone": null, + "commits_url": "https://api.github.com/repos/Codertocat/Hello-World/pulls/2/commits", + "review_comments_url": "https://api.github.com/repos/Codertocat/Hello-World/pulls/2/comments", + "review_comment_url": "https://api.github.com/repos/Codertocat/Hello-World/pulls/comments{/number}", + "comments_url": "https://api.github.com/repos/Codertocat/Hello-World/issues/2/comments", + "statuses_url": "https://api.github.com/repos/Codertocat/Hello-World/statuses/ec26c3e57ca3a959ca5aad62de7213c562f8c821", + "head": { + "label": "Codertocat:changes", + "ref": "changes", + "sha": "ec26c3e57ca3a959ca5aad62de7213c562f8c821", + "user": { + "login": "Codertocat", + "id": 21031067, + "node_id": "MDQ6VXNlcjIxMDMxMDY3", + "avatar_url": "https://avatars1.githubusercontent.com/u/21031067?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/Codertocat", + "html_url": "https://github.com/Codertocat", + "followers_url": "https://api.github.com/users/Codertocat/followers", + "following_url": "https://api.github.com/users/Codertocat/following{/other_user}", + "gists_url": "https://api.github.com/users/Codertocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/Codertocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/Codertocat/subscriptions", + "organizations_url": "https://api.github.com/users/Codertocat/orgs", + "repos_url": "https://api.github.com/users/Codertocat/repos", + "events_url": "https://api.github.com/users/Codertocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/Codertocat/received_events", + "type": "User", + "site_admin": false + }, + "repo": { + "id": 186853002, + "node_id": "MDEwOlJlcG9zaXRvcnkxODY4NTMwMDI=", + "name": "Hello-World", + "full_name": "Codertocat/Hello-World", + "private": false, + "owner": { + "login": "Codertocat", + "id": 21031067, + "node_id": "MDQ6VXNlcjIxMDMxMDY3", + "avatar_url": "https://avatars1.githubusercontent.com/u/21031067?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/Codertocat", + "html_url": "https://github.com/Codertocat", + "followers_url": "https://api.github.com/users/Codertocat/followers", + "following_url": "https://api.github.com/users/Codertocat/following{/other_user}", + "gists_url": "https://api.github.com/users/Codertocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/Codertocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/Codertocat/subscriptions", + "organizations_url": "https://api.github.com/users/Codertocat/orgs", + "repos_url": "https://api.github.com/users/Codertocat/repos", + "events_url": "https://api.github.com/users/Codertocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/Codertocat/received_events", + "type": "User", + "site_admin": false + }, + "html_url": "https://github.com/Codertocat/Hello-World", + "description": null, + "fork": false, + "url": "https://api.github.com/repos/Codertocat/Hello-World", + "forks_url": "https://api.github.com/repos/Codertocat/Hello-World/forks", + "keys_url": "https://api.github.com/repos/Codertocat/Hello-World/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/Codertocat/Hello-World/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/Codertocat/Hello-World/teams", + "hooks_url": "https://api.github.com/repos/Codertocat/Hello-World/hooks", + "issue_events_url": "https://api.github.com/repos/Codertocat/Hello-World/issues/events{/number}", + "events_url": "https://api.github.com/repos/Codertocat/Hello-World/events", + "assignees_url": "https://api.github.com/repos/Codertocat/Hello-World/assignees{/user}", + "branches_url": "https://api.github.com/repos/Codertocat/Hello-World/branches{/branch}", + "tags_url": "https://api.github.com/repos/Codertocat/Hello-World/tags", + "blobs_url": "https://api.github.com/repos/Codertocat/Hello-World/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/Codertocat/Hello-World/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/Codertocat/Hello-World/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/Codertocat/Hello-World/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/Codertocat/Hello-World/statuses/{sha}", + "languages_url": "https://api.github.com/repos/Codertocat/Hello-World/languages", + "stargazers_url": "https://api.github.com/repos/Codertocat/Hello-World/stargazers", + "contributors_url": "https://api.github.com/repos/Codertocat/Hello-World/contributors", + "subscribers_url": "https://api.github.com/repos/Codertocat/Hello-World/subscribers", + "subscription_url": "https://api.github.com/repos/Codertocat/Hello-World/subscription", + "commits_url": "https://api.github.com/repos/Codertocat/Hello-World/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/Codertocat/Hello-World/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/Codertocat/Hello-World/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/Codertocat/Hello-World/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/Codertocat/Hello-World/contents/{+path}", + "compare_url": "https://api.github.com/repos/Codertocat/Hello-World/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/Codertocat/Hello-World/merges", + "archive_url": "https://api.github.com/repos/Codertocat/Hello-World/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/Codertocat/Hello-World/downloads", + "issues_url": "https://api.github.com/repos/Codertocat/Hello-World/issues{/number}", + "pulls_url": "https://api.github.com/repos/Codertocat/Hello-World/pulls{/number}", + "milestones_url": "https://api.github.com/repos/Codertocat/Hello-World/milestones{/number}", + "notifications_url": "https://api.github.com/repos/Codertocat/Hello-World/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/Codertocat/Hello-World/labels{/name}", + "releases_url": "https://api.github.com/repos/Codertocat/Hello-World/releases{/id}", + "deployments_url": "https://api.github.com/repos/Codertocat/Hello-World/deployments", + "created_at": "2019-05-15T15:19:25Z", + "updated_at": "2019-05-15T15:19:27Z", + "pushed_at": "2019-05-15T15:20:32Z", + "git_url": "git://github.com/Codertocat/Hello-World.git", + "ssh_url": "git@github.com:Codertocat/Hello-World.git", + "clone_url": "https://github.com/Codertocat/Hello-World.git", + "svn_url": "https://github.com/Codertocat/Hello-World", + "homepage": null, + "size": 0, + "stargazers_count": 0, + "watchers_count": 0, + "language": null, + "has_issues": true, + "has_projects": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": true, + "forks_count": 0, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 2, + "license": null, + "forks": 0, + "open_issues": 2, + "watchers": 0, + "default_branch": "master", + "allow_squash_merge": true, + "allow_merge_commit": true, + "allow_rebase_merge": true, + "delete_branch_on_merge": false + } + }, + "base": { + "label": "Codertocat:master", + "ref": "master", + "sha": "f95f852bd8fca8fcc58a9a2d6c842781e32a215e", + "user": { + "login": "Codertocat", + "id": 21031067, + "node_id": "MDQ6VXNlcjIxMDMxMDY3", + "avatar_url": "https://avatars1.githubusercontent.com/u/21031067?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/Codertocat", + "html_url": "https://github.com/Codertocat", + "followers_url": "https://api.github.com/users/Codertocat/followers", + "following_url": "https://api.github.com/users/Codertocat/following{/other_user}", + "gists_url": "https://api.github.com/users/Codertocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/Codertocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/Codertocat/subscriptions", + "organizations_url": "https://api.github.com/users/Codertocat/orgs", + "repos_url": "https://api.github.com/users/Codertocat/repos", + "events_url": "https://api.github.com/users/Codertocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/Codertocat/received_events", + "type": "User", + "site_admin": false + }, + "repo": { + "id": 186853002, + "node_id": "MDEwOlJlcG9zaXRvcnkxODY4NTMwMDI=", + "name": "Hello-World", + "full_name": "Codertocat/Hello-World", + "private": false, + "owner": { + "login": "Codertocat", + "id": 21031067, + "node_id": "MDQ6VXNlcjIxMDMxMDY3", + "avatar_url": "https://avatars1.githubusercontent.com/u/21031067?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/Codertocat", + "html_url": "https://github.com/Codertocat", + "followers_url": "https://api.github.com/users/Codertocat/followers", + "following_url": "https://api.github.com/users/Codertocat/following{/other_user}", + "gists_url": "https://api.github.com/users/Codertocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/Codertocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/Codertocat/subscriptions", + "organizations_url": "https://api.github.com/users/Codertocat/orgs", + "repos_url": "https://api.github.com/users/Codertocat/repos", + "events_url": "https://api.github.com/users/Codertocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/Codertocat/received_events", + "type": "User", + "site_admin": false + }, + "html_url": "https://github.com/Codertocat/Hello-World", + "description": null, + "fork": false, + "url": "https://api.github.com/repos/Codertocat/Hello-World", + "forks_url": "https://api.github.com/repos/Codertocat/Hello-World/forks", + "keys_url": "https://api.github.com/repos/Codertocat/Hello-World/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/Codertocat/Hello-World/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/Codertocat/Hello-World/teams", + "hooks_url": "https://api.github.com/repos/Codertocat/Hello-World/hooks", + "issue_events_url": "https://api.github.com/repos/Codertocat/Hello-World/issues/events{/number}", + "events_url": "https://api.github.com/repos/Codertocat/Hello-World/events", + "assignees_url": "https://api.github.com/repos/Codertocat/Hello-World/assignees{/user}", + "branches_url": "https://api.github.com/repos/Codertocat/Hello-World/branches{/branch}", + "tags_url": "https://api.github.com/repos/Codertocat/Hello-World/tags", + "blobs_url": "https://api.github.com/repos/Codertocat/Hello-World/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/Codertocat/Hello-World/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/Codertocat/Hello-World/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/Codertocat/Hello-World/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/Codertocat/Hello-World/statuses/{sha}", + "languages_url": "https://api.github.com/repos/Codertocat/Hello-World/languages", + "stargazers_url": "https://api.github.com/repos/Codertocat/Hello-World/stargazers", + "contributors_url": "https://api.github.com/repos/Codertocat/Hello-World/contributors", + "subscribers_url": "https://api.github.com/repos/Codertocat/Hello-World/subscribers", + "subscription_url": "https://api.github.com/repos/Codertocat/Hello-World/subscription", + "commits_url": "https://api.github.com/repos/Codertocat/Hello-World/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/Codertocat/Hello-World/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/Codertocat/Hello-World/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/Codertocat/Hello-World/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/Codertocat/Hello-World/contents/{+path}", + "compare_url": "https://api.github.com/repos/Codertocat/Hello-World/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/Codertocat/Hello-World/merges", + "archive_url": "https://api.github.com/repos/Codertocat/Hello-World/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/Codertocat/Hello-World/downloads", + "issues_url": "https://api.github.com/repos/Codertocat/Hello-World/issues{/number}", + "pulls_url": "https://api.github.com/repos/Codertocat/Hello-World/pulls{/number}", + "milestones_url": "https://api.github.com/repos/Codertocat/Hello-World/milestones{/number}", + "notifications_url": "https://api.github.com/repos/Codertocat/Hello-World/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/Codertocat/Hello-World/labels{/name}", + "releases_url": "https://api.github.com/repos/Codertocat/Hello-World/releases{/id}", + "deployments_url": "https://api.github.com/repos/Codertocat/Hello-World/deployments", + "created_at": "2019-05-15T15:19:25Z", + "updated_at": "2019-05-15T15:19:27Z", + "pushed_at": "2019-05-15T15:20:32Z", + "git_url": "git://github.com/Codertocat/Hello-World.git", + "ssh_url": "git@github.com:Codertocat/Hello-World.git", + "clone_url": "https://github.com/Codertocat/Hello-World.git", + "svn_url": "https://github.com/Codertocat/Hello-World", + "homepage": null, + "size": 0, + "stargazers_count": 0, + "watchers_count": 0, + "language": null, + "has_issues": true, + "has_projects": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": true, + "forks_count": 0, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 2, + "license": null, + "forks": 0, + "open_issues": 2, + "watchers": 0, + "default_branch": "master", + "allow_squash_merge": true, + "allow_merge_commit": true, + "allow_rebase_merge": true, + "delete_branch_on_merge": false + } + }, + "_links": { + "self": { + "href": "https://api.github.com/repos/Codertocat/Hello-World/pulls/2" + }, + "html": { + "href": "https://github.com/Codertocat/Hello-World/pull/2" + }, + "issue": { + "href": "https://api.github.com/repos/Codertocat/Hello-World/issues/2" + }, + "comments": { + "href": "https://api.github.com/repos/Codertocat/Hello-World/issues/2/comments" + }, + "review_comments": { + "href": "https://api.github.com/repos/Codertocat/Hello-World/pulls/2/comments" + }, + "review_comment": { + "href": "https://api.github.com/repos/Codertocat/Hello-World/pulls/comments{/number}" + }, + "commits": { + "href": "https://api.github.com/repos/Codertocat/Hello-World/pulls/2/commits" + }, + "statuses": { + "href": "https://api.github.com/repos/Codertocat/Hello-World/statuses/ec26c3e57ca3a959ca5aad62de7213c562f8c821" + } + }, + "author_association": "OWNER", + "draft": false, + "merged": false, + "mergeable": null, + "rebaseable": null, + "mergeable_state": "unknown", + "merged_by": null, + "comments": 0, + "review_comments": 0, + "maintainer_can_modify": false, + "commits": 1, + "additions": 1, + "deletions": 1, + "changed_files": 1 + }, + "repository": { + "id": 186853002, + "node_id": "MDEwOlJlcG9zaXRvcnkxODY4NTMwMDI=", + "name": "Hello-World", + "full_name": "Codertocat/Hello-World", + "private": false, + "owner": { + "login": "Codertocat", + "id": 21031067, + "node_id": "MDQ6VXNlcjIxMDMxMDY3", + "avatar_url": "https://avatars1.githubusercontent.com/u/21031067?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/Codertocat", + "html_url": "https://github.com/Codertocat", + "followers_url": "https://api.github.com/users/Codertocat/followers", + "following_url": "https://api.github.com/users/Codertocat/following{/other_user}", + "gists_url": "https://api.github.com/users/Codertocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/Codertocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/Codertocat/subscriptions", + "organizations_url": "https://api.github.com/users/Codertocat/orgs", + "repos_url": "https://api.github.com/users/Codertocat/repos", + "events_url": "https://api.github.com/users/Codertocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/Codertocat/received_events", + "type": "User", + "site_admin": false + }, + "html_url": "https://github.com/Codertocat/Hello-World", + "description": null, + "fork": false, + "url": "https://api.github.com/repos/Codertocat/Hello-World", + "forks_url": "https://api.github.com/repos/Codertocat/Hello-World/forks", + "keys_url": "https://api.github.com/repos/Codertocat/Hello-World/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/Codertocat/Hello-World/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/Codertocat/Hello-World/teams", + "hooks_url": "https://api.github.com/repos/Codertocat/Hello-World/hooks", + "issue_events_url": "https://api.github.com/repos/Codertocat/Hello-World/issues/events{/number}", + "events_url": "https://api.github.com/repos/Codertocat/Hello-World/events", + "assignees_url": "https://api.github.com/repos/Codertocat/Hello-World/assignees{/user}", + "branches_url": "https://api.github.com/repos/Codertocat/Hello-World/branches{/branch}", + "tags_url": "https://api.github.com/repos/Codertocat/Hello-World/tags", + "blobs_url": "https://api.github.com/repos/Codertocat/Hello-World/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/Codertocat/Hello-World/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/Codertocat/Hello-World/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/Codertocat/Hello-World/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/Codertocat/Hello-World/statuses/{sha}", + "languages_url": "https://api.github.com/repos/Codertocat/Hello-World/languages", + "stargazers_url": "https://api.github.com/repos/Codertocat/Hello-World/stargazers", + "contributors_url": "https://api.github.com/repos/Codertocat/Hello-World/contributors", + "subscribers_url": "https://api.github.com/repos/Codertocat/Hello-World/subscribers", + "subscription_url": "https://api.github.com/repos/Codertocat/Hello-World/subscription", + "commits_url": "https://api.github.com/repos/Codertocat/Hello-World/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/Codertocat/Hello-World/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/Codertocat/Hello-World/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/Codertocat/Hello-World/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/Codertocat/Hello-World/contents/{+path}", + "compare_url": "https://api.github.com/repos/Codertocat/Hello-World/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/Codertocat/Hello-World/merges", + "archive_url": "https://api.github.com/repos/Codertocat/Hello-World/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/Codertocat/Hello-World/downloads", + "issues_url": "https://api.github.com/repos/Codertocat/Hello-World/issues{/number}", + "pulls_url": "https://api.github.com/repos/Codertocat/Hello-World/pulls{/number}", + "milestones_url": "https://api.github.com/repos/Codertocat/Hello-World/milestones{/number}", + "notifications_url": "https://api.github.com/repos/Codertocat/Hello-World/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/Codertocat/Hello-World/labels{/name}", + "releases_url": "https://api.github.com/repos/Codertocat/Hello-World/releases{/id}", + "deployments_url": "https://api.github.com/repos/Codertocat/Hello-World/deployments", + "created_at": "2019-05-15T15:19:25Z", + "updated_at": "2019-05-15T15:19:27Z", + "pushed_at": "2019-05-15T15:20:32Z", + "git_url": "git://github.com/Codertocat/Hello-World.git", + "ssh_url": "git@github.com:Codertocat/Hello-World.git", + "clone_url": "https://github.com/Codertocat/Hello-World.git", + "svn_url": "https://github.com/Codertocat/Hello-World", + "homepage": null, + "size": 0, + "stargazers_count": 0, + "watchers_count": 0, + "language": null, + "has_issues": true, + "has_projects": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": true, + "forks_count": 0, + "mirror_url": null, + "archived": false, + "disabled": false, + "open_issues_count": 2, + "license": null, + "forks": 0, + "open_issues": 2, + "watchers": 0, + "default_branch": "master" + }, + "sender": { + "login": "Codertocat", + "id": 21031067, + "node_id": "MDQ6VXNlcjIxMDMxMDY3", + "avatar_url": "https://avatars1.githubusercontent.com/u/21031067?v=4", + "gravatar_id": "", + "url": "https://api.github.com/users/Codertocat", + "html_url": "https://github.com/Codertocat", + "followers_url": "https://api.github.com/users/Codertocat/followers", + "following_url": "https://api.github.com/users/Codertocat/following{/other_user}", + "gists_url": "https://api.github.com/users/Codertocat/gists{/gist_id}", + "starred_url": "https://api.github.com/users/Codertocat/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/Codertocat/subscriptions", + "organizations_url": "https://api.github.com/users/Codertocat/orgs", + "repos_url": "https://api.github.com/users/Codertocat/repos", + "events_url": "https://api.github.com/users/Codertocat/events{/privacy}", + "received_events_url": "https://api.github.com/users/Codertocat/received_events", + "type": "User", + "site_admin": false + } +} diff --git a/applicationset/webhook/webhook.go b/applicationset/webhook/webhook.go index ce099df35ea35..d55e63e064f5a 100644 --- a/applicationset/webhook/webhook.go +++ b/applicationset/webhook/webhook.go @@ -412,10 +412,12 @@ func shouldRefreshPRGenerator(gen *v1alpha1.PullRequestGenerator, info *prGenera } if gen.Github != nil && info.Github != nil { - if gen.Github.Owner != info.Github.Owner { + // repository owner and name are case-insensitive + // See https://docs.github.com/en/rest/pulls/pulls?apiVersion=2022-11-28#list-pull-requests + if !strings.EqualFold(gen.Github.Owner, info.Github.Owner) { return false } - if gen.Github.Repo != info.Github.Repo { + if !strings.EqualFold(gen.Github.Repo, info.Github.Repo) { return false } api := gen.Github.API diff --git a/applicationset/webhook/webhook_test.go b/applicationset/webhook/webhook_test.go index 349d275948aee..d22b1a07ca6f2 100644 --- a/applicationset/webhook/webhook_test.go +++ b/applicationset/webhook/webhook_test.go @@ -111,7 +111,7 @@ func TestWebhookHandler(t *testing.T) { expectedRefresh: false, }, { - desc: "WebHook from a GitHub repository via pull_reqeuest opened event", + desc: "WebHook from a GitHub repository via pull_request opened event", headerKey: "X-GitHub-Event", headerValue: "pull_request", payloadFile: "github-pull-request-opened-event.json", @@ -120,7 +120,7 @@ func TestWebhookHandler(t *testing.T) { expectedRefresh: true, }, { - desc: "WebHook from a GitHub repository via pull_reqeuest assigned event", + desc: "WebHook from a GitHub repository via pull_request assigned event", headerKey: "X-GitHub-Event", headerValue: "pull_request", payloadFile: "github-pull-request-assigned-event.json", @@ -128,6 +128,15 @@ func TestWebhookHandler(t *testing.T) { expectedStatusCode: http.StatusOK, expectedRefresh: false, }, + { + desc: "WebHook from a GitHub repository via pull_request labeled event", + headerKey: "X-GitHub-Event", + headerValue: "pull_request", + payloadFile: "github-pull-request-labeled-event.json", + effectedAppSets: []string{"pull-request-github", "matrix-pull-request-github", "matrix-scm-pull-request-github", "merge-pull-request-github", "plugin", "matrix-pull-request-github-plugin"}, + expectedStatusCode: http.StatusOK, + expectedRefresh: true, + }, { desc: "WebHook from a GitLab repository via open merge request event", headerKey: "X-Gitlab-Event", @@ -180,7 +189,7 @@ func TestWebhookHandler(t *testing.T) { fakeAppWithGitGenerator("git-github", namespace, "https://github.com/org/repo"), fakeAppWithGitGenerator("git-gitlab", namespace, "https://gitlab/group/name"), fakeAppWithGitGenerator("git-azure-devops", namespace, "https://dev.azure.com/fabrikam-fiber-inc/DefaultCollection/_git/Fabrikam-Fiber-Git"), - fakeAppWithGithubPullRequestGenerator("pull-request-github", namespace, "Codertocat", "Hello-World"), + fakeAppWithGithubPullRequestGenerator("pull-request-github", namespace, "CodErTOcat", "Hello-World"), fakeAppWithGitlabPullRequestGenerator("pull-request-gitlab", namespace, "100500"), fakeAppWithAzureDevOpsPullRequestGenerator("pull-request-azure-devops", namespace, "DefaultCollection", "Fabrikam"), fakeAppWithPluginGenerator("plugin", namespace), @@ -189,7 +198,7 @@ func TestWebhookHandler(t *testing.T) { fakeAppWithMatrixAndScmWithGitGenerator("matrix-scm-git-github", namespace, "org"), fakeAppWithMatrixAndScmWithPullRequestGenerator("matrix-scm-pull-request-github", namespace, "Codertocat"), fakeAppWithMatrixAndNestedGitGenerator("matrix-nested-git-github", namespace, "https://github.com/org/repo"), - fakeAppWithMatrixAndPullRequestGeneratorWithPluginGenerator("matrix-pull-request-github-plugin", namespace, "Codertocat", "Hello-World", "plugin-cm"), + fakeAppWithMatrixAndPullRequestGeneratorWithPluginGenerator("matrix-pull-request-github-plugin", namespace, "coDErtoCat", "HeLLO-WorLD", "plugin-cm"), fakeAppWithMergeAndGitGenerator("merge-git-github", namespace, "https://github.com/org/repo"), fakeAppWithMergeAndPullRequestGenerator("merge-pull-request-github", namespace, "Codertocat", "Hello-World"), fakeAppWithMergeAndNestedGitGenerator("merge-nested-git-github", namespace, "https://github.com/org/repo"), diff --git a/assets/swagger.json b/assets/swagger.json index c97e0a3c78239..91e815203eee0 100644 --- a/assets/swagger.json +++ b/assets/swagger.json @@ -234,7 +234,7 @@ }, { "type": "string", - "description": "forces application reconciliation if set to true.", + "description": "forces application reconciliation if set to 'hard'.", "name": "refresh", "in": "query" }, @@ -573,7 +573,7 @@ }, { "type": "string", - "description": "forces application reconciliation if set to true.", + "description": "forces application reconciliation if set to 'hard'.", "name": "refresh", "in": "query" }, @@ -3816,7 +3816,7 @@ }, { "type": "string", - "description": "forces application reconciliation if set to true.", + "description": "forces application reconciliation if set to 'hard'.", "name": "refresh", "in": "query" }, @@ -4462,6 +4462,9 @@ "clientID": { "type": "string" }, + "enablePKCEAuthentication": { + "type": "boolean" + }, "idTokenClaims": { "type": "object", "additionalProperties": { @@ -5089,7 +5092,7 @@ } }, "runtimeRawExtension": { - "description": "RawExtension is used to hold extensions in external versions.\n\nTo use this, make a field which has RawExtension as its type in your external, versioned\nstruct, and Object in your internal struct. You also need to register your\nvarious plugin types.\n\n// Internal package:\ntype MyAPIObject struct {\n\truntime.TypeMeta `json:\",inline\"`\n\tMyPlugin runtime.Object `json:\"myPlugin\"`\n}\ntype PluginA struct {\n\tAOption string `json:\"aOption\"`\n}\n\n// External package:\ntype MyAPIObject struct {\n\truntime.TypeMeta `json:\",inline\"`\n\tMyPlugin runtime.RawExtension `json:\"myPlugin\"`\n}\ntype PluginA struct {\n\tAOption string `json:\"aOption\"`\n}\n\n// On the wire, the JSON will look something like this:\n{\n\t\"kind\":\"MyAPIObject\",\n\t\"apiVersion\":\"v1\",\n\t\"myPlugin\": {\n\t\t\"kind\":\"PluginA\",\n\t\t\"aOption\":\"foo\",\n\t},\n}\n\nSo what happens? Decode first uses json or yaml to unmarshal the serialized data into\nyour external MyAPIObject. That causes the raw JSON to be stored, but not unpacked.\nThe next step is to copy (using pkg/conversion) into the internal struct. The runtime\npackage's DefaultScheme has conversion functions installed which will unpack the\nJSON stored in RawExtension, turning it into the correct object type, and storing it\nin the Object. (TODO: In the case where the object is of an unknown type, a\nruntime.Unknown object will be created and stored.)\n\n+k8s:deepcopy-gen=true\n+protobuf=true\n+k8s:openapi-gen=true", + "description": "RawExtension is used to hold extensions in external versions.\n\nTo use this, make a field which has RawExtension as its type in your external, versioned\nstruct, and Object in your internal struct. You also need to register your\nvarious plugin types.\n\n// Internal package:\n\n\ttype MyAPIObject struct {\n\t\truntime.TypeMeta `json:\",inline\"`\n\t\tMyPlugin runtime.Object `json:\"myPlugin\"`\n\t}\n\n\ttype PluginA struct {\n\t\tAOption string `json:\"aOption\"`\n\t}\n\n// External package:\n\n\ttype MyAPIObject struct {\n\t\truntime.TypeMeta `json:\",inline\"`\n\t\tMyPlugin runtime.RawExtension `json:\"myPlugin\"`\n\t}\n\n\ttype PluginA struct {\n\t\tAOption string `json:\"aOption\"`\n\t}\n\n// On the wire, the JSON will look something like this:\n\n\t{\n\t\t\"kind\":\"MyAPIObject\",\n\t\t\"apiVersion\":\"v1\",\n\t\t\"myPlugin\": {\n\t\t\t\"kind\":\"PluginA\",\n\t\t\t\"aOption\":\"foo\",\n\t\t},\n\t}\n\nSo what happens? Decode first uses json or yaml to unmarshal the serialized data into\nyour external MyAPIObject. That causes the raw JSON to be stored, but not unpacked.\nThe next step is to copy (using pkg/conversion) into the internal struct. The runtime\npackage's DefaultScheme has conversion functions installed which will unpack the\nJSON stored in RawExtension, turning it into the correct object type, and storing it\nin the Object. (TODO: In the case where the object is of an unknown type, a\nruntime.Unknown object will be created and stored.)\n\n+k8s:deepcopy-gen=true\n+protobuf=true\n+k8s:openapi-gen=true", "type": "object", "properties": { "raw": { @@ -5496,10 +5499,6 @@ "type": "string" } }, - "clusterName": { - "description": "Deprecated: ClusterName is a legacy field that was always cleared by\nthe system and never used; it will be removed completely in 1.25.\n\nThe name in the go struct is changed to help clients detect\naccidental use.\n\n+optional", - "type": "string" - }, "creationTimestamp": { "$ref": "#/definitions/v1Time" }, @@ -5571,8 +5570,8 @@ } }, "v1ObjectReference": { + "description": "ObjectReference contains enough information to let you inspect or modify the referred object.\n---\nNew uses of this type are discouraged because of difficulty describing its usage when embedded in APIs.\n 1. Ignored fields. It includes many fields which are not generally honored. For instance, ResourceVersion and FieldPath are both very rarely valid in actual usage.\n 2. Invalid usage help. It is impossible to add specific help for individual usage. In most embedded usages, there are particular\n restrictions like, \"must refer only to types A and B\" or \"UID not honored\" or \"name must be restricted\".\n Those cannot be well described when embedded.\n 3. Inconsistent validation. Because the usages are different, the validation rules are different by usage, which makes it hard for users to predict what will happen.\n 4. The fields are both imprecise and overly precise. Kind is not a precise mapping to a URL. This can produce ambiguity\n during interpretation and require a REST mapping. In most cases, the dependency is on the group,resource tuple\n and the version of the actual struct is irrelevant.\n 5. We cannot easily change it. Because this type is embedded in many locations, updates to this type\n will affect numerous schemas. Don't make new APIs embed an underspecified API type they do not control.\n\nInstead of using this type, create a locally provided and used type that is well-focused on your reference.\nFor example, ServiceReferences for admission registration: https://github.com/kubernetes/api/blob/release-1.17/admissionregistration/v1/types.go#L533 .\n+k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object\n+structType=atomic", "type": "object", - "title": "ObjectReference contains enough information to let you inspect or modify the referred object.\n---\nNew uses of this type are discouraged because of difficulty describing its usage when embedded in APIs.\n 1. Ignored fields. It includes many fields which are not generally honored. For instance, ResourceVersion and FieldPath are both very rarely valid in actual usage.\n 2. Invalid usage help. It is impossible to add specific help for individual usage. In most embedded usages, there are particular\n restrictions like, \"must refer only to types A and B\" or \"UID not honored\" or \"name must be restricted\".\n Those cannot be well described when embedded.\n 3. Inconsistent validation. Because the usages are different, the validation rules are different by usage, which makes it hard for users to predict what will happen.\n 4. The fields are both imprecise and overly precise. Kind is not a precise mapping to a URL. This can produce ambiguity\n during interpretation and require a REST mapping. In most cases, the dependency is on the group,resource tuple\n and the version of the actual struct is irrelevant.\n 5. We cannot easily change it. Because this type is embedded in many locations, updates to this type\n will affect numerous schemas. Don't make new APIs embed an underspecified API type they do not control.\nInstead of using this type, create a locally provided and used type that is well-focused on your reference.\nFor example, ServiceReferences for admission registration: https://github.com/kubernetes/api/blob/release-1.17/admissionregistration/v1/types.go#L533 .\n+k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object\n+structType=atomic", "properties": { "apiVersion": { "type": "string", @@ -5665,6 +5664,10 @@ "type": "string", "title": "ClusterName contains AWS cluster name" }, + "profile": { + "description": "Profile contains optional role ARN. If set then AWS IAM Authenticator uses the profile to perform cluster operations instead of the default AWS credential provider chain.", + "type": "string" + }, "roleARN": { "description": "RoleARN contains optional role ARN. If set then AWS IAM Authenticator assume a role to perform cluster operations instead of the default AWS credential provider chain.", "type": "string" @@ -6144,6 +6147,9 @@ }, "template": { "$ref": "#/definitions/v1alpha1ApplicationSetTemplate" + }, + "templatePatch": { + "type": "string" } } }, @@ -6396,6 +6402,13 @@ "type": "string" } }, + "components": { + "type": "array", + "title": "Components specifies a list of kustomize components to add to the kustomization before building", + "items": { + "type": "string" + } + }, "forceCommonAnnotations": { "type": "boolean", "title": "ForceCommonAnnotations specifies whether to force applying common annotations to resources for Kustomize apps" @@ -8490,6 +8503,9 @@ "format": "int64", "title": "ID is an auto incrementing identifier of the RevisionHistory" }, + "initiatedBy": { + "$ref": "#/definitions/v1alpha1OperationInitiator" + }, "revision": { "type": "string", "title": "Revision holds the revision the sync was performed against" diff --git a/cmd/argocd-application-controller/commands/argocd_application_controller.go b/cmd/argocd-application-controller/commands/argocd_application_controller.go index a43174633b02a..c38a2113e2b34 100644 --- a/cmd/argocd-application-controller/commands/argocd_application_controller.go +++ b/cmd/argocd-application-controller/commands/argocd_application_controller.go @@ -10,6 +10,8 @@ import ( "github.com/redis/go-redis/v9" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" + kubeerrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/clientcmd" @@ -19,6 +21,7 @@ import ( "github.com/argoproj/argo-cd/v2/controller/sharding" "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" appclientset "github.com/argoproj/argo-cd/v2/pkg/client/clientset/versioned" + "github.com/argoproj/argo-cd/v2/pkg/ratelimiter" "github.com/argoproj/argo-cd/v2/reposerver/apiclient" cacheutil "github.com/argoproj/argo-cd/v2/util/cache" appstatecache "github.com/argoproj/argo-cd/v2/util/cache/appstate" @@ -30,8 +33,6 @@ import ( "github.com/argoproj/argo-cd/v2/util/settings" "github.com/argoproj/argo-cd/v2/util/tls" "github.com/argoproj/argo-cd/v2/util/trace" - kubeerrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) const ( @@ -45,9 +46,12 @@ const ( func NewCommand() *cobra.Command { var ( + workqueueRateLimit ratelimiter.AppControllerRateLimiterConfig clientConfig clientcmd.ClientConfig appResyncPeriod int64 appHardResyncPeriod int64 + appResyncJitter int64 + repoErrorGracePeriod int64 repoServerAddress string repoServerTimeoutSeconds int selfHealTimeoutSeconds int @@ -63,11 +67,14 @@ func NewCommand() *cobra.Command { repoServerPlaintext bool repoServerStrictTLS bool otlpAddress string + otlpInsecure bool + otlpHeaders map[string]string otlpAttrs []string applicationNamespaces []string persistResourceHealth bool shardingAlgorithm string enableDynamicClusterDistribution bool + serverSideDiff bool ) var command = cobra.Command{ Use: cliName, @@ -140,7 +147,7 @@ func NewCommand() *cobra.Command { appController.InvalidateProjectsCache() })) kubectl := kubeutil.NewKubectl() - clusterFilter := getClusterFilter(kubeClient, settingsMgr, shardingAlgorithm, enableDynamicClusterDistribution) + clusterSharding, err := getClusterSharding(kubeClient, settingsMgr, shardingAlgorithm, enableDynamicClusterDistribution) errors.CheckError(err) appController, err = controller.NewApplicationController( namespace, @@ -152,14 +159,19 @@ func NewCommand() *cobra.Command { kubectl, resyncDuration, hardResyncDuration, + time.Duration(appResyncJitter)*time.Second, time.Duration(selfHealTimeoutSeconds)*time.Second, + time.Duration(repoErrorGracePeriod)*time.Second, metricsPort, metricsCacheExpiration, metricsAplicationLabels, kubectlParallelismLimit, persistResourceHealth, - clusterFilter, + clusterSharding, applicationNamespaces, + &workqueueRateLimit, + serverSideDiff, + enableDynamicClusterDistribution, ) errors.CheckError(err) cacheutil.CollectMetrics(redisClient, appController.GetMetricsServer()) @@ -169,7 +181,7 @@ func NewCommand() *cobra.Command { stats.RegisterHeapDumper("memprofile") if otlpAddress != "" { - closeTracer, err := trace.InitTracer(ctx, "argocd-controller", otlpAddress, otlpAttrs) + closeTracer, err := trace.InitTracer(ctx, "argocd-controller", otlpAddress, otlpInsecure, otlpHeaders, otlpAttrs) if err != nil { log.Fatalf("failed to initialize tracing: %v", err) } @@ -186,6 +198,8 @@ func NewCommand() *cobra.Command { clientConfig = cli.AddKubectlFlagsToCmd(&command) command.Flags().Int64Var(&appResyncPeriod, "app-resync", int64(env.ParseDurationFromEnv("ARGOCD_RECONCILIATION_TIMEOUT", defaultAppResyncPeriod*time.Second, 0, math.MaxInt64).Seconds()), "Time period in seconds for application resync.") command.Flags().Int64Var(&appHardResyncPeriod, "app-hard-resync", int64(env.ParseDurationFromEnv("ARGOCD_HARD_RECONCILIATION_TIMEOUT", defaultAppHardResyncPeriod*time.Second, 0, math.MaxInt64).Seconds()), "Time period in seconds for application hard resync.") + command.Flags().Int64Var(&appResyncJitter, "app-resync-jitter", int64(env.ParseDurationFromEnv("ARGOCD_RECONCILIATION_JITTER", 0*time.Second, 0, math.MaxInt64).Seconds()), "Maximum time period in seconds to add as a delay jitter for application resync.") + command.Flags().Int64Var(&repoErrorGracePeriod, "repo-error-grace-period-seconds", int64(env.ParseDurationFromEnv("ARGOCD_REPO_ERROR_GRACE_PERIOD_SECONDS", defaultAppResyncPeriod*time.Second, 0, math.MaxInt64).Seconds()), "Grace period in seconds for ignoring consecutive errors while communicating with repo server.") command.Flags().StringVar(&repoServerAddress, "repo-server", env.StringFromEnv("ARGOCD_APPLICATION_CONTROLLER_REPO_SERVER", common.DefaultRepoServerAddr), "Repo server address.") command.Flags().IntVar(&repoServerTimeoutSeconds, "repo-server-timeout-seconds", env.ParseNumFromEnv("ARGOCD_APPLICATION_CONTROLLER_REPO_SERVER_TIMEOUT_SECONDS", 60, 0, math.MaxInt64), "Repo server RPC call timeout seconds.") command.Flags().IntVar(&statusProcessors, "status-processors", env.ParseNumFromEnv("ARGOCD_APPLICATION_CONTROLLER_STATUS_PROCESSORS", 20, 0, math.MaxInt32), "Number of application status processors") @@ -201,48 +215,68 @@ func NewCommand() *cobra.Command { command.Flags().BoolVar(&repoServerStrictTLS, "repo-server-strict-tls", env.ParseBoolFromEnv("ARGOCD_APPLICATION_CONTROLLER_REPO_SERVER_STRICT_TLS", false), "Whether to use strict validation of the TLS cert presented by the repo server") command.Flags().StringSliceVar(&metricsAplicationLabels, "metrics-application-labels", []string{}, "List of Application labels that will be added to the argocd_application_labels metric") command.Flags().StringVar(&otlpAddress, "otlp-address", env.StringFromEnv("ARGOCD_APPLICATION_CONTROLLER_OTLP_ADDRESS", ""), "OpenTelemetry collector address to send traces to") + command.Flags().BoolVar(&otlpInsecure, "otlp-insecure", env.ParseBoolFromEnv("ARGOCD_APPLICATION_CONTROLLER_OTLP_INSECURE", true), "OpenTelemetry collector insecure mode") + command.Flags().StringToStringVar(&otlpHeaders, "otlp-headers", env.ParseStringToStringFromEnv("ARGOCD_APPLICATION_CONTROLLER_OTLP_HEADERS", map[string]string{}, ","), "List of OpenTelemetry collector extra headers sent with traces, headers are comma-separated key-value pairs(e.g. key1=value1,key2=value2)") command.Flags().StringSliceVar(&otlpAttrs, "otlp-attrs", env.StringsFromEnv("ARGOCD_APPLICATION_CONTROLLER_OTLP_ATTRS", []string{}, ","), "List of OpenTelemetry collector extra attrs when send traces, each attribute is separated by a colon(e.g. key:value)") command.Flags().StringSliceVar(&applicationNamespaces, "application-namespaces", env.StringsFromEnv("ARGOCD_APPLICATION_NAMESPACES", []string{}, ","), "List of additional namespaces that applications are allowed to be reconciled from") command.Flags().BoolVar(&persistResourceHealth, "persist-resource-health", env.ParseBoolFromEnv("ARGOCD_APPLICATION_CONTROLLER_PERSIST_RESOURCE_HEALTH", true), "Enables storing the managed resources health in the Application CRD") command.Flags().StringVar(&shardingAlgorithm, "sharding-method", env.StringFromEnv(common.EnvControllerShardingAlgorithm, common.DefaultShardingAlgorithm), "Enables choice of sharding method. Supported sharding methods are : [legacy, round-robin] ") + // global queue rate limit config + command.Flags().Int64Var(&workqueueRateLimit.BucketSize, "wq-bucket-size", env.ParseInt64FromEnv("WORKQUEUE_BUCKET_SIZE", 500, 1, math.MaxInt64), "Set Workqueue Rate Limiter Bucket Size, default 500") + command.Flags().Int64Var(&workqueueRateLimit.BucketQPS, "wq-bucket-qps", env.ParseInt64FromEnv("WORKQUEUE_BUCKET_QPS", 50, 1, math.MaxInt64), "Set Workqueue Rate Limiter Bucket QPS, default 50") + // individual item rate limit config + // when WORKQUEUE_FAILURE_COOLDOWN is 0 per item rate limiting is disabled(default) + command.Flags().DurationVar(&workqueueRateLimit.FailureCoolDown, "wq-cooldown-ns", time.Duration(env.ParseInt64FromEnv("WORKQUEUE_FAILURE_COOLDOWN_NS", 0, 0, (24*time.Hour).Nanoseconds())), "Set Workqueue Per Item Rate Limiter Cooldown duration in ns, default 0(per item rate limiter disabled)") + command.Flags().DurationVar(&workqueueRateLimit.BaseDelay, "wq-basedelay-ns", time.Duration(env.ParseInt64FromEnv("WORKQUEUE_BASE_DELAY_NS", time.Millisecond.Nanoseconds(), time.Nanosecond.Nanoseconds(), (24*time.Hour).Nanoseconds())), "Set Workqueue Per Item Rate Limiter Base Delay duration in nanoseconds, default 1000000 (1ms)") + command.Flags().DurationVar(&workqueueRateLimit.MaxDelay, "wq-maxdelay-ns", time.Duration(env.ParseInt64FromEnv("WORKQUEUE_MAX_DELAY_NS", time.Second.Nanoseconds(), 1*time.Millisecond.Nanoseconds(), (24*time.Hour).Nanoseconds())), "Set Workqueue Per Item Rate Limiter Max Delay duration in nanoseconds, default 1000000000 (1s)") + command.Flags().Float64Var(&workqueueRateLimit.BackoffFactor, "wq-backoff-factor", env.ParseFloat64FromEnv("WORKQUEUE_BACKOFF_FACTOR", 1.5, 0, math.MaxFloat64), "Set Workqueue Per Item Rate Limiter Backoff Factor, default is 1.5") command.Flags().BoolVar(&enableDynamicClusterDistribution, "dynamic-cluster-distribution-enabled", env.ParseBoolFromEnv(common.EnvEnableDynamicClusterDistribution, false), "Enables dynamic cluster distribution.") - cacheSource = appstatecache.AddCacheFlagsToCmd(&command, func(client *redis.Client) { - redisClient = client + command.Flags().BoolVar(&serverSideDiff, "server-side-diff-enabled", env.ParseBoolFromEnv(common.EnvServerSideDiff, false), "Feature flag to enable ServerSide diff. Default (\"false\")") + cacheSource = appstatecache.AddCacheFlagsToCmd(&command, cacheutil.Options{ + OnClientCreated: func(client *redis.Client) { + redisClient = client + }, }) return &command } -func getClusterFilter(kubeClient *kubernetes.Clientset, settingsMgr *settings.SettingsManager, shardingAlgorithm string, enableDynamicClusterDistribution bool) sharding.ClusterFilterFunction { +func getClusterSharding(kubeClient *kubernetes.Clientset, settingsMgr *settings.SettingsManager, shardingAlgorithm string, enableDynamicClusterDistribution bool) (sharding.ClusterShardingCache, error) { + var ( + replicasCount int + ) + // StatefulSet mode and Deployment mode uses different default values for shard number. + defaultShardNumberValue := 0 - var replicas int - shard := env.ParseNumFromEnv(common.EnvControllerShard, -1, -math.MaxInt32, math.MaxInt32) + if enableDynamicClusterDistribution { + applicationControllerName := env.StringFromEnv(common.EnvAppControllerName, common.DefaultApplicationControllerName) + appControllerDeployment, err := kubeClient.AppsV1().Deployments(settingsMgr.GetNamespace()).Get(context.Background(), applicationControllerName, metav1.GetOptions{}) - applicationControllerName := env.StringFromEnv(common.EnvAppControllerName, common.DefaultApplicationControllerName) - appControllerDeployment, err := kubeClient.AppsV1().Deployments(settingsMgr.GetNamespace()).Get(context.Background(), applicationControllerName, metav1.GetOptions{}) + // if app controller deployment is not found when dynamic cluster distribution is enabled error out + if err != nil { + return nil, fmt.Errorf("(dymanic cluster distribution) failed to get app controller deployment: %v", err) + } - // if the application controller deployment was not found, the Get() call returns an empty Deployment object. So, set the variable to nil explicitly - if err != nil && kubeerrors.IsNotFound(err) { - appControllerDeployment = nil - } + if appControllerDeployment != nil && appControllerDeployment.Spec.Replicas != nil { + replicasCount = int(*appControllerDeployment.Spec.Replicas) + defaultShardNumberValue = -1 + } else { + return nil, fmt.Errorf("(dymanic cluster distribution) failed to get app controller deployment replica count") + } - if enableDynamicClusterDistribution && appControllerDeployment != nil && appControllerDeployment.Spec.Replicas != nil { - replicas = int(*appControllerDeployment.Spec.Replicas) } else { - replicas = env.ParseNumFromEnv(common.EnvControllerReplicas, 0, 0, math.MaxInt32) + replicasCount = env.ParseNumFromEnv(common.EnvControllerReplicas, 0, 0, math.MaxInt32) } - - var clusterFilter func(cluster *v1alpha1.Cluster) bool - if replicas > 1 { + shardNumber := env.ParseNumFromEnv(common.EnvControllerShard, defaultShardNumberValue, -math.MaxInt32, math.MaxInt32) + if replicasCount > 1 { // check for shard mapping using configmap if application-controller is a deployment // else use existing logic to infer shard from pod name if application-controller is a statefulset - if enableDynamicClusterDistribution && appControllerDeployment != nil { - + if enableDynamicClusterDistribution { var err error // retry 3 times if we find a conflict while updating shard mapping configMap. // If we still see conflicts after the retries, wait for next iteration of heartbeat process. for i := 0; i <= common.AppControllerHeartbeatUpdateRetryCount; i++ { - shard, err = sharding.GetOrUpdateShardFromConfigMap(kubeClient, settingsMgr, replicas, shard) - if !kubeerrors.IsConflict(err) { + shardNumber, err = sharding.GetOrUpdateShardFromConfigMap(kubeClient, settingsMgr, replicasCount, shardNumber) + if err != nil && !kubeerrors.IsConflict(err) { err = fmt.Errorf("unable to get shard due to error updating the sharding config map: %s", err) break } @@ -250,19 +284,19 @@ func getClusterFilter(kubeClient *kubernetes.Clientset, settingsMgr *settings.Se } errors.CheckError(err) } else { - if shard < 0 { + if shardNumber < 0 { var err error - shard, err = sharding.InferShard() + shardNumber, err = sharding.InferShard() errors.CheckError(err) } + if shardNumber > replicasCount { + log.Warnf("Calculated shard number %d is greated than the number of replicas count. Defaulting to 0", shardNumber) + shardNumber = 0 + } } - log.Infof("Processing clusters from shard %d", shard) - db := db.NewDB(settingsMgr.GetNamespace(), settingsMgr, kubeClient) - log.Infof("Using filter function: %s", shardingAlgorithm) - distributionFunction := sharding.GetDistributionFunction(db, shardingAlgorithm) - clusterFilter = sharding.GetClusterFilter(db, distributionFunction, shard) } else { log.Info("Processing all cluster shards") } - return clusterFilter + db := db.NewDB(settingsMgr.GetNamespace(), settingsMgr, kubeClient) + return sharding.NewClusterSharding(db, shardNumber, replicasCount, shardingAlgorithm), nil } diff --git a/cmd/argocd-cmp-server/commands/argocd_cmp_server.go b/cmd/argocd-cmp-server/commands/argocd_cmp_server.go index 62f45b24aedb5..526a199cb5490 100644 --- a/cmd/argocd-cmp-server/commands/argocd_cmp_server.go +++ b/cmd/argocd-cmp-server/commands/argocd_cmp_server.go @@ -26,6 +26,8 @@ func NewCommand() *cobra.Command { var ( configFilePath string otlpAddress string + otlpInsecure bool + otlpHeaders map[string]string otlpAttrs []string ) var command = cobra.Command{ @@ -56,7 +58,7 @@ func NewCommand() *cobra.Command { if otlpAddress != "" { var closer func() var err error - closer, err = traceutil.InitTracer(ctx, "argocd-cmp-server", otlpAddress, otlpAttrs) + closer, err = traceutil.InitTracer(ctx, "argocd-cmp-server", otlpAddress, otlpInsecure, otlpHeaders, otlpAttrs) if err != nil { log.Fatalf("failed to initialize tracing: %v", err) } @@ -83,6 +85,8 @@ func NewCommand() *cobra.Command { command.Flags().StringVar(&cmdutil.LogLevel, "loglevel", "info", "Set the logging level. One of: debug|info|warn|error") command.Flags().StringVar(&configFilePath, "config-dir-path", common.DefaultPluginConfigFilePath, "Config management plugin configuration file location, Default is '/home/argocd/cmp-server/config/'") command.Flags().StringVar(&otlpAddress, "otlp-address", env.StringFromEnv("ARGOCD_CMP_SERVER_OTLP_ADDRESS", ""), "OpenTelemetry collector address to send traces to") + command.Flags().BoolVar(&otlpInsecure, "otlp-insecure", env.ParseBoolFromEnv("ARGOCD_CMP_SERVER_OTLP_INSECURE", true), "OpenTelemetry collector insecure mode") + command.Flags().StringToStringVar(&otlpHeaders, "otlp-headers", env.ParseStringToStringFromEnv("ARGOCD_CMP_SERVER_OTLP_HEADERS", map[string]string{}, ","), "List of OpenTelemetry collector extra headers sent with traces, headers are comma-separated key-value pairs(e.g. key1=value1,key2=value2)") command.Flags().StringSliceVar(&otlpAttrs, "otlp-attrs", env.StringsFromEnv("ARGOCD_CMP_SERVER_OTLP_ATTRS", []string{}, ","), "List of OpenTelemetry collector extra attrs when send traces, each attribute is separated by a colon(e.g. key:value)") return &command } diff --git a/cmd/argocd-k8s-auth/commands/aws.go b/cmd/argocd-k8s-auth/commands/aws.go index 79a118d2653a3..9b750ac5f92f8 100644 --- a/cmd/argocd-k8s-auth/commands/aws.go +++ b/cmd/argocd-k8s-auth/commands/aws.go @@ -37,13 +37,14 @@ func newAWSCommand() *cobra.Command { var ( clusterName string roleARN string + profile string ) var command = &cobra.Command{ Use: "aws", Run: func(c *cobra.Command, args []string) { ctx := c.Context() - presignedURLString, err := getSignedRequestWithRetry(ctx, time.Minute, 5*time.Second, clusterName, roleARN, getSignedRequest) + presignedURLString, err := getSignedRequestWithRetry(ctx, time.Minute, 5*time.Second, clusterName, roleARN, profile, getSignedRequest) errors.CheckError(err) token := v1Prefix + base64.RawURLEncoding.EncodeToString([]byte(presignedURLString)) // Set token expiration to 1 minute before the presigned URL expires for some cushion @@ -53,16 +54,17 @@ func newAWSCommand() *cobra.Command { } command.Flags().StringVar(&clusterName, "cluster-name", "", "AWS Cluster name") command.Flags().StringVar(&roleARN, "role-arn", "", "AWS Role ARN") + command.Flags().StringVar(&profile, "profile", "", "AWS Profile") return command } -type getSignedRequestFunc func(clusterName, roleARN string) (string, error) +type getSignedRequestFunc func(clusterName, roleARN string, profile string) (string, error) -func getSignedRequestWithRetry(ctx context.Context, timeout, interval time.Duration, clusterName, roleARN string, fn getSignedRequestFunc) (string, error) { +func getSignedRequestWithRetry(ctx context.Context, timeout, interval time.Duration, clusterName, roleARN string, profile string, fn getSignedRequestFunc) (string, error) { ctx, cancel := context.WithTimeout(ctx, timeout) defer cancel() for { - signed, err := fn(clusterName, roleARN) + signed, err := fn(clusterName, roleARN, profile) if err == nil { return signed, nil } @@ -74,8 +76,10 @@ func getSignedRequestWithRetry(ctx context.Context, timeout, interval time.Durat } } -func getSignedRequest(clusterName, roleARN string) (string, error) { - sess, err := session.NewSession() +func getSignedRequest(clusterName, roleARN string, profile string) (string, error) { + sess, err := session.NewSessionWithOptions(session.Options{ + Profile: profile, + }) if err != nil { return "", fmt.Errorf("error creating new AWS session: %s", err) } diff --git a/cmd/argocd-k8s-auth/commands/aws_test.go b/cmd/argocd-k8s-auth/commands/aws_test.go index c22449eba42be..578aae71a2c29 100644 --- a/cmd/argocd-k8s-auth/commands/aws_test.go +++ b/cmd/argocd-k8s-auth/commands/aws_test.go @@ -22,7 +22,7 @@ func TestGetSignedRequestWithRetry(t *testing.T) { } // when - signed, err := getSignedRequestWithRetry(ctx, time.Second, time.Millisecond, "cluster-name", "", mock.getSignedRequestMock) + signed, err := getSignedRequestWithRetry(ctx, time.Second, time.Millisecond, "cluster-name", "", "", mock.getSignedRequestMock) // then assert.NoError(t, err) @@ -41,7 +41,7 @@ func TestGetSignedRequestWithRetry(t *testing.T) { } // when - signed, err := getSignedRequestWithRetry(ctx, time.Second, time.Millisecond, "cluster-name", "", mock.getSignedRequestMock) + signed, err := getSignedRequestWithRetry(ctx, time.Second, time.Millisecond, "cluster-name", "", "", mock.getSignedRequestMock) // then assert.NoError(t, err) @@ -57,7 +57,7 @@ func TestGetSignedRequestWithRetry(t *testing.T) { } // when - signed, err := getSignedRequestWithRetry(ctx, time.Second, time.Millisecond, "cluster-name", "", mock.getSignedRequestMock) + signed, err := getSignedRequestWithRetry(ctx, time.Second, time.Millisecond, "cluster-name", "", "", mock.getSignedRequestMock) // then assert.Error(t, err) @@ -70,7 +70,7 @@ type signedRequestMock struct { returnFunc func(m *signedRequestMock) (string, error) } -func (m *signedRequestMock) getSignedRequestMock(clusterName, roleARN string) (string, error) { +func (m *signedRequestMock) getSignedRequestMock(clusterName, roleARN string, profile string) (string, error) { m.getSignedRequestCalls++ return m.returnFunc(m) } diff --git a/cmd/argocd-notification/commands/controller.go b/cmd/argocd-notification/commands/controller.go index abd9a2e8475f0..cb30fd5277d4b 100644 --- a/cmd/argocd-notification/commands/controller.go +++ b/cmd/argocd-notification/commands/controller.go @@ -43,19 +43,20 @@ func addK8SFlagsToCmd(cmd *cobra.Command) clientcmd.ClientConfig { func NewCommand() *cobra.Command { var ( - clientConfig clientcmd.ClientConfig - processorsCount int - namespace string - appLabelSelector string - logLevel string - logFormat string - metricsPort int - argocdRepoServer string - argocdRepoServerPlaintext bool - argocdRepoServerStrictTLS bool - configMapName string - secretName string - applicationNamespaces []string + clientConfig clientcmd.ClientConfig + processorsCount int + namespace string + appLabelSelector string + logLevel string + logFormat string + metricsPort int + argocdRepoServer string + argocdRepoServerPlaintext bool + argocdRepoServerStrictTLS bool + configMapName string + secretName string + applicationNamespaces []string + selfServiceNotificationEnabled bool ) var command = cobra.Command{ Use: "controller", @@ -139,7 +140,7 @@ func NewCommand() *cobra.Command { log.Infof("serving metrics on port %d", metricsPort) log.Infof("loading configuration %d", metricsPort) - ctrl := notificationscontroller.NewController(k8sClient, dynamicClient, argocdService, namespace, applicationNamespaces, appLabelSelector, registry, secretName, configMapName) + ctrl := notificationscontroller.NewController(k8sClient, dynamicClient, argocdService, namespace, applicationNamespaces, appLabelSelector, registry, secretName, configMapName, selfServiceNotificationEnabled) err = ctrl.Init(ctx) if err != nil { return fmt.Errorf("failed to initialize controller: %w", err) @@ -163,5 +164,6 @@ func NewCommand() *cobra.Command { command.Flags().StringVar(&configMapName, "config-map-name", "argocd-notifications-cm", "Set notifications ConfigMap name") command.Flags().StringVar(&secretName, "secret-name", "argocd-notifications-secret", "Set notifications Secret name") command.Flags().StringSliceVar(&applicationNamespaces, "application-namespaces", env.StringsFromEnv("ARGOCD_APPLICATION_NAMESPACES", []string{}, ","), "List of additional namespaces that this controller should send notifications for") + command.Flags().BoolVar(&selfServiceNotificationEnabled, "self-service-notification-enabled", env.ParseBoolFromEnv("ARGOCD_NOTIFICATION_CONTROLLER_SELF_SERVICE_NOTIFICATION_ENABLED", false), "Allows the Argo CD notification controller to pull notification config from the namespace that the resource is in. This is useful for self-service notification.") return &command } diff --git a/cmd/argocd-repo-server/commands/argocd_repo_server.go b/cmd/argocd-repo-server/commands/argocd_repo_server.go index 69358d2a91efd..84b50e7cd5ab9 100644 --- a/cmd/argocd-repo-server/commands/argocd_repo_server.go +++ b/cmd/argocd-repo-server/commands/argocd_repo_server.go @@ -54,6 +54,8 @@ func NewCommand() *cobra.Command { metricsPort int metricsHost string otlpAddress string + otlpInsecure bool + otlpHeaders map[string]string otlpAttrs []string cacheSrc func() (*reposervercache.Cache, error) tlsConfigCustomizer tls.ConfigCustomizer @@ -129,7 +131,7 @@ func NewCommand() *cobra.Command { if otlpAddress != "" { var closer func() var err error - closer, err = traceutil.InitTracer(ctx, "argocd-repo-server", otlpAddress, otlpAttrs) + closer, err = traceutil.InitTracer(ctx, "argocd-repo-server", otlpAddress, otlpInsecure, otlpHeaders, otlpAttrs) if err != nil { log.Fatalf("failed to initialize tracing: %v", err) } @@ -196,6 +198,8 @@ func NewCommand() *cobra.Command { command.Flags().StringVar(&metricsHost, "metrics-address", env.StringFromEnv("ARGOCD_REPO_SERVER_METRICS_LISTEN_ADDRESS", common.DefaultAddressRepoServerMetrics), "Listen on given address for metrics") command.Flags().IntVar(&metricsPort, "metrics-port", common.DefaultPortRepoServerMetrics, "Start metrics server on given port") command.Flags().StringVar(&otlpAddress, "otlp-address", env.StringFromEnv("ARGOCD_REPO_SERVER_OTLP_ADDRESS", ""), "OpenTelemetry collector address to send traces to") + command.Flags().BoolVar(&otlpInsecure, "otlp-insecure", env.ParseBoolFromEnv("ARGOCD_REPO_SERVER_OTLP_INSECURE", true), "OpenTelemetry collector insecure mode") + command.Flags().StringToStringVar(&otlpHeaders, "otlp-headers", env.ParseStringToStringFromEnv("ARGOCD_REPO_OTLP_HEADERS", map[string]string{}, ","), "List of OpenTelemetry collector extra headers sent with traces, headers are comma-separated key-value pairs(e.g. key1=value1,key2=value2)") command.Flags().StringSliceVar(&otlpAttrs, "otlp-attrs", env.StringsFromEnv("ARGOCD_REPO_SERVER_OTLP_ATTRS", []string{}, ","), "List of OpenTelemetry collector extra attrs when send traces, each attribute is separated by a colon(e.g. key:value)") command.Flags().BoolVar(&disableTLS, "disable-tls", env.ParseBoolFromEnv("ARGOCD_REPO_SERVER_DISABLE_TLS", false), "Disable TLS on the gRPC endpoint") command.Flags().StringVar(&maxCombinedDirectoryManifestsSize, "max-combined-directory-manifests-size", env.StringFromEnv("ARGOCD_REPO_SERVER_MAX_COMBINED_DIRECTORY_MANIFESTS_SIZE", "10M"), "Max combined size of manifest files in a directory-type Application") @@ -206,8 +210,10 @@ func NewCommand() *cobra.Command { command.Flags().StringVar(&helmManifestMaxExtractedSize, "helm-manifest-max-extracted-size", env.StringFromEnv("ARGOCD_REPO_SERVER_HELM_MANIFEST_MAX_EXTRACTED_SIZE", "1G"), "Maximum size of helm manifest archives when extracted") command.Flags().BoolVar(&disableManifestMaxExtractedSize, "disable-helm-manifest-max-extracted-size", env.ParseBoolFromEnv("ARGOCD_REPO_SERVER_DISABLE_HELM_MANIFEST_MAX_EXTRACTED_SIZE", false), "Disable maximum size of helm manifest archives when extracted") tlsConfigCustomizerSrc = tls.AddTLSFlagsToCmd(&command) - cacheSrc = reposervercache.AddCacheFlagsToCmd(&command, func(client *redis.Client) { - redisClient = client + cacheSrc = reposervercache.AddCacheFlagsToCmd(&command, cacheutil.Options{ + OnClientCreated: func(client *redis.Client) { + redisClient = client + }, }) return &command } diff --git a/cmd/argocd-server/commands/argocd_server.go b/cmd/argocd-server/commands/argocd_server.go index eea346eaed03d..646ecd6a2aabe 100644 --- a/cmd/argocd-server/commands/argocd_server.go +++ b/cmd/argocd-server/commands/argocd_server.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "math" + "strings" "time" "github.com/argoproj/pkg/stats" @@ -18,13 +19,16 @@ import ( "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" appclientset "github.com/argoproj/argo-cd/v2/pkg/client/clientset/versioned" "github.com/argoproj/argo-cd/v2/reposerver/apiclient" + reposervercache "github.com/argoproj/argo-cd/v2/reposerver/cache" "github.com/argoproj/argo-cd/v2/server" servercache "github.com/argoproj/argo-cd/v2/server/cache" + cacheutil "github.com/argoproj/argo-cd/v2/util/cache" "github.com/argoproj/argo-cd/v2/util/cli" "github.com/argoproj/argo-cd/v2/util/dex" "github.com/argoproj/argo-cd/v2/util/env" "github.com/argoproj/argo-cd/v2/util/errors" "github.com/argoproj/argo-cd/v2/util/kube" + "github.com/argoproj/argo-cd/v2/util/templates" "github.com/argoproj/argo-cd/v2/util/tls" traceutil "github.com/argoproj/argo-cd/v2/util/trace" ) @@ -49,6 +53,8 @@ func NewCommand() *cobra.Command { metricsHost string metricsPort int otlpAddress string + otlpInsecure bool + otlpHeaders map[string]string otlpAttrs []string glogLevel int clientConfig clientcmd.ClientConfig @@ -58,9 +64,11 @@ func NewCommand() *cobra.Command { repoServerAddress string dexServerAddress string disableAuth bool + contentTypes string enableGZip bool tlsConfigCustomizerSrc func() (tls.ConfigCustomizer, error) cacheSrc func() (*servercache.Cache, error) + repoServerCacheSrc func() (*reposervercache.Cache, error) frameOptions string contentSecurityPolicy string repoServerPlaintext bool @@ -102,6 +110,8 @@ func NewCommand() *cobra.Command { errors.CheckError(err) cache, err := cacheSrc() errors.CheckError(err) + repoServerCache, err := repoServerCacheSrc() + errors.CheckError(err) kubeclientset := kubernetes.NewForConfigOrDie(config) @@ -162,6 +172,11 @@ func NewCommand() *cobra.Command { baseHRef = rootPath } + var contentTypesList []string + if contentTypes != "" { + contentTypesList = strings.Split(contentTypes, ";") + } + argoCDOpts := server.ArgoCDServerOpts{ Insecure: insecure, ListenPort: listenPort, @@ -177,9 +192,11 @@ func NewCommand() *cobra.Command { DexServerAddr: dexServerAddress, DexTLSConfig: dexTlsConfig, DisableAuth: disableAuth, + ContentTypes: contentTypesList, EnableGZip: enableGZip, TLSConfigCustomizer: tlsConfigCustomizer, Cache: cache, + RepoServerCache: repoServerCache, XFrameOptions: frameOptions, ContentSecurityPolicy: contentSecurityPolicy, RedisClient: redisClient, @@ -199,7 +216,7 @@ func NewCommand() *cobra.Command { var closer func() ctx, cancel := context.WithCancel(ctx) if otlpAddress != "" { - closer, err = traceutil.InitTracer(ctx, "argocd-server", otlpAddress, otlpAttrs) + closer, err = traceutil.InitTracer(ctx, "argocd-server", otlpAddress, otlpInsecure, otlpHeaders, otlpAttrs) if err != nil { log.Fatalf("failed to initialize tracing: %v", err) } @@ -211,6 +228,13 @@ func NewCommand() *cobra.Command { } } }, + Example: templates.Examples(` + # Start the Argo CD API server with default settings + $ argocd-server + + # Start the Argo CD API server on a custom port and enable tracing + $ argocd-server --port 8888 --otlp-address localhost:4317 + `), } clientConfig = cli.AddKubectlFlagsToCmd(command) @@ -224,6 +248,7 @@ func NewCommand() *cobra.Command { command.Flags().StringVar(&repoServerAddress, "repo-server", env.StringFromEnv("ARGOCD_SERVER_REPO_SERVER", common.DefaultRepoServerAddr), "Repo server address") command.Flags().StringVar(&dexServerAddress, "dex-server", env.StringFromEnv("ARGOCD_SERVER_DEX_SERVER", common.DefaultDexServerAddr), "Dex server address") command.Flags().BoolVar(&disableAuth, "disable-auth", env.ParseBoolFromEnv("ARGOCD_SERVER_DISABLE_AUTH", false), "Disable client authentication") + command.Flags().StringVar(&contentTypes, "api-content-types", env.StringFromEnv("ARGOCD_API_CONTENT_TYPES", "application/json"), "Semicolon separated list of allowed content types for non GET api requests. Any content type is allowed if empty.") command.Flags().BoolVar(&enableGZip, "enable-gzip", env.ParseBoolFromEnv("ARGOCD_SERVER_ENABLE_GZIP", true), "Enable GZIP compression") command.AddCommand(cli.NewVersionCmd(cliName)) command.Flags().StringVar(&listenHost, "address", env.StringFromEnv("ARGOCD_SERVER_LISTEN_ADDRESS", common.DefaultAddressAPIServer), "Listen on given address") @@ -231,6 +256,8 @@ func NewCommand() *cobra.Command { command.Flags().StringVar(&metricsHost, env.StringFromEnv("ARGOCD_SERVER_METRICS_LISTEN_ADDRESS", "metrics-address"), common.DefaultAddressAPIServerMetrics, "Listen for metrics on given address") command.Flags().IntVar(&metricsPort, "metrics-port", common.DefaultPortArgoCDAPIServerMetrics, "Start metrics on given port") command.Flags().StringVar(&otlpAddress, "otlp-address", env.StringFromEnv("ARGOCD_SERVER_OTLP_ADDRESS", ""), "OpenTelemetry collector address to send traces to") + command.Flags().BoolVar(&otlpInsecure, "otlp-insecure", env.ParseBoolFromEnv("ARGOCD_SERVER_OTLP_INSECURE", true), "OpenTelemetry collector insecure mode") + command.Flags().StringToStringVar(&otlpHeaders, "otlp-headers", env.ParseStringToStringFromEnv("ARGOCD_SERVER_OTLP_HEADERS", map[string]string{}, ","), "List of OpenTelemetry collector extra headers sent with traces, headers are comma-separated key-value pairs(e.g. key1=value1,key2=value2)") command.Flags().StringSliceVar(&otlpAttrs, "otlp-attrs", env.StringsFromEnv("ARGOCD_SERVER_OTLP_ATTRS", []string{}, ","), "List of OpenTelemetry collector extra attrs when send traces, each attribute is separated by a colon(e.g. key:value)") command.Flags().IntVar(&repoServerTimeoutSeconds, "repo-server-timeout-seconds", env.ParseNumFromEnv("ARGOCD_SERVER_REPO_SERVER_TIMEOUT_SECONDS", 60, 0, math.MaxInt64), "Repo server RPC call timeout seconds.") command.Flags().StringVar(&frameOptions, "x-frame-options", env.StringFromEnv("ARGOCD_SERVER_X_FRAME_OPTIONS", "sameorigin"), "Set X-Frame-Options header in HTTP responses to `value`. To disable, set to \"\".") @@ -242,8 +269,11 @@ func NewCommand() *cobra.Command { command.Flags().StringSliceVar(&applicationNamespaces, "application-namespaces", env.StringsFromEnv("ARGOCD_APPLICATION_NAMESPACES", []string{}, ","), "List of additional namespaces where application resources can be managed in") command.Flags().BoolVar(&enableProxyExtension, "enable-proxy-extension", env.ParseBoolFromEnv("ARGOCD_SERVER_ENABLE_PROXY_EXTENSION", false), "Enable Proxy Extension feature") tlsConfigCustomizerSrc = tls.AddTLSFlagsToCmd(command) - cacheSrc = servercache.AddCacheFlagsToCmd(command, func(client *redis.Client) { - redisClient = client + cacheSrc = servercache.AddCacheFlagsToCmd(command, cacheutil.Options{ + OnClientCreated: func(client *redis.Client) { + redisClient = client + }, }) + repoServerCacheSrc = reposervercache.AddCacheFlagsToCmd(command, cacheutil.Options{FlagPrefix: "repo-server-"}) return command } diff --git a/cmd/argocd/commands/admin/admin.go b/cmd/argocd/commands/admin/admin.go index 92cad10479d68..49c81e4da4bfe 100644 --- a/cmd/argocd/commands/admin/admin.go +++ b/cmd/argocd/commands/admin/admin.go @@ -48,6 +48,87 @@ func NewAdminCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { Run: func(c *cobra.Command, args []string) { c.HelpFunc()(c, args) }, + Example: `# List all clusters +$ argocd admin cluster list + +# Add a new cluster +$ argocd admin cluster add my-cluster --name my-cluster --in-cluster-context + +# Remove a cluster +argocd admin cluster remove my-cluster + +# List all projects +$ argocd admin project list + +# Create a new project +$argocd admin project create my-project --src-namespace my-source-namespace --dest-namespace my-dest-namespace + +# Update a project +$ argocd admin project update my-project --src-namespace my-updated-source-namespace --dest-namespace my-updated-dest-namespace + +# Delete a project +$ argocd admin project delete my-project + +# List all settings +$ argocd admin settings list + +# Get the current settings +$ argocd admin settings get + +# Update settings +$ argocd admin settings update --repository.resync --value 15 + +# List all applications +$ argocd admin app list + +# Get application details +$ argocd admin app get my-app + +# Sync an application +$ argocd admin app sync my-app + +# Pause an application +$ argocd admin app pause my-app + +# Resume an application +$ argocd admin app resume my-app + +# List all repositories +$ argocd admin repo list + +# Add a repository +$ argocd admin repo add https://github.com/argoproj/my-repo.git + +# Remove a repository +$ argocd admin repo remove https://github.com/argoproj/my-repo.git + +# Import an application from a YAML file +$ argocd admin app import -f my-app.yaml + +# Export an application to a YAML file +$ argocd admin app export my-app -o my-exported-app.yaml + +# Access the Argo CD web UI +$ argocd admin dashboard + +# List notifications +$ argocd admin notification list + +# Get notification details +$ argocd admin notification get my-notification + +# Create a new notification +$ argocd admin notification create my-notification -f notification-config.yaml + +# Update a notification +$ argocd admin notification update my-notification -f updated-notification-config.yaml + +# Delete a notification +$ argocd admin notification delete my-notification + +# Reset the initial admin password +$ argocd admin initial-password reset +`, } command.AddCommand(NewClusterCommand(clientOpts, pathOpts)) @@ -57,7 +138,7 @@ func NewAdminCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { command.AddCommand(NewRepoCommand()) command.AddCommand(NewImportCommand()) command.AddCommand(NewExportCommand()) - command.AddCommand(NewDashboardCommand()) + command.AddCommand(NewDashboardCommand(clientOpts)) command.AddCommand(NewNotificationsCommand()) command.AddCommand(NewInitialPasswordCommand()) diff --git a/cmd/argocd/commands/admin/app.go b/cmd/argocd/commands/admin/app.go index fbceb436f8609..096c92f9feb01 100644 --- a/cmd/argocd/commands/admin/app.go +++ b/cmd/argocd/commands/admin/app.go @@ -45,6 +45,16 @@ func NewAppCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { var command = &cobra.Command{ Use: "app", Short: "Manage applications configuration", + Example: ` +# Compare results of two reconciliations and print diff +argocd admin app diff-reconcile-results APPNAME [flags] + +# Generate declarative config for an application +argocd admin app generate-spec APPNAME + +# Reconcile all applications and store reconciliation summary in the specified file +argocd admin app get-reconcile-results APPNAME +`, Run: func(c *cobra.Command, args []string) { c.HelpFunc()(c, args) }, @@ -233,6 +243,7 @@ func NewReconcileCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command repoServerAddress string outputFormat string refresh bool + serverSideDiff bool ) var command = &cobra.Command{ @@ -270,7 +281,7 @@ func NewReconcileCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command appClientset := appclientset.NewForConfigOrDie(cfg) kubeClientset := kubernetes.NewForConfigOrDie(cfg) - result, err = reconcileApplications(ctx, kubeClientset, appClientset, namespace, repoServerClient, selector, newLiveStateCache) + result, err = reconcileApplications(ctx, kubeClientset, appClientset, namespace, repoServerClient, selector, newLiveStateCache, serverSideDiff) errors.CheckError(err) } else { appClientset := appclientset.NewForConfigOrDie(cfg) @@ -285,6 +296,7 @@ func NewReconcileCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command command.Flags().StringVar(&selector, "l", "", "Label selector") command.Flags().StringVar(&outputFormat, "o", "yaml", "Output format (yaml|json)") command.Flags().BoolVar(&refresh, "refresh", false, "If set to true then recalculates apps reconciliation") + command.Flags().BoolVar(&serverSideDiff, "server-side-diff", false, "If set to \"true\" will use server-side diff while comparing resources. Default (\"false\")") return command } @@ -334,6 +346,7 @@ func reconcileApplications( repoServerClient reposerverclient.Clientset, selector string, createLiveStateCache func(argoDB db.ArgoDB, appInformer kubecache.SharedIndexInformer, settingsMgr *settings.SettingsManager, server *metrics.MetricsServer) cache.LiveStateCache, + serverSideDiff bool, ) ([]appReconcileResult, error) { settingsMgr := settings.NewSettingsManager(ctx, kubeClientset, namespace) argoDB := db.NewDB(namespace, settingsMgr, kubeClientset) @@ -374,7 +387,7 @@ func reconcileApplications( ) appStateManager := controller.NewAppStateManager( - argoDB, appClientset, repoServerClient, namespace, kubeutil.NewKubectl(), settingsMgr, stateCache, projInformer, server, cache, time.Second, argo.NewResourceTracking(), false) + argoDB, appClientset, repoServerClient, namespace, kubeutil.NewKubectl(), settingsMgr, stateCache, projInformer, server, cache, time.Second, argo.NewResourceTracking(), false, 0, serverSideDiff) appsList, err := appClientset.ArgoprojV1alpha1().Applications(namespace).List(ctx, v1.ListOptions{LabelSelector: selector}) if err != nil { @@ -409,7 +422,10 @@ func reconcileApplications( sources = append(sources, app.Spec.GetSource()) revisions = append(revisions, app.Spec.GetSource().TargetRevision) - res := appStateManager.CompareAppState(&app, proj, revisions, sources, false, false, nil, false) + res, err := appStateManager.CompareAppState(&app, proj, revisions, sources, false, false, nil, false) + if err != nil { + return nil, err + } items = append(items, appReconcileResult{ Name: app.Name, Conditions: app.Status.Conditions, diff --git a/cmd/argocd/commands/admin/app_test.go b/cmd/argocd/commands/admin/app_test.go index 0cad2485e6696..a0284fe8ffa09 100644 --- a/cmd/argocd/commands/admin/app_test.go +++ b/cmd/argocd/commands/admin/app_test.go @@ -113,6 +113,7 @@ func TestGetReconcileResults_Refresh(t *testing.T) { func(argoDB db.ArgoDB, appInformer cache.SharedIndexInformer, settingsMgr *settings.SettingsManager, server *metrics.MetricsServer) statecache.LiveStateCache { return &liveStateCache }, + false, ) if !assert.NoError(t, err) { diff --git a/cmd/argocd/commands/admin/cluster.go b/cmd/argocd/commands/admin/cluster.go index 1bc1417fead4d..abb055cdfa354 100644 --- a/cmd/argocd/commands/admin/cluster.go +++ b/cmd/argocd/commands/admin/cluster.go @@ -25,7 +25,7 @@ import ( "github.com/argoproj/argo-cd/v2/common" "github.com/argoproj/argo-cd/v2/controller/sharding" argocdclient "github.com/argoproj/argo-cd/v2/pkg/apiclient" - argoappv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" "github.com/argoproj/argo-cd/v2/pkg/client/clientset/versioned" "github.com/argoproj/argo-cd/v2/util/argo" cacheutil "github.com/argoproj/argo-cd/v2/util/cache" @@ -44,6 +44,15 @@ func NewClusterCommand(clientOpts *argocdclient.ClientOptions, pathOpts *clientc var command = &cobra.Command{ Use: "cluster", Short: "Manage clusters configuration", + Example: ` +#Generate declarative config for a cluster +argocd admin cluster generate-spec my-cluster -o yaml + +#Generate a kubeconfig for a cluster named "my-cluster" and display it in the console +argocd admin cluster kubeconfig my-cluster + +#Print information namespaces which Argo CD manages in each cluster +argocd admin cluster namespaces my-cluster `, Run: func(c *cobra.Command, args []string) { c.HelpFunc()(c, args) }, @@ -62,14 +71,14 @@ func NewClusterCommand(clientOpts *argocdclient.ClientOptions, pathOpts *clientc } type ClusterWithInfo struct { - argoappv1.Cluster + v1alpha1.Cluster // Shard holds controller shard number that handles the cluster Shard int // Namespaces holds list of namespaces managed by Argo CD in the cluster Namespaces []string } -func loadClusters(ctx context.Context, kubeClient *kubernetes.Clientset, appClient *versioned.Clientset, replicas int, namespace string, portForwardRedis bool, cacheSrc func() (*appstatecache.Cache, error), shard int, redisName string, redisHaProxyName string) ([]ClusterWithInfo, error) { +func loadClusters(ctx context.Context, kubeClient *kubernetes.Clientset, appClient *versioned.Clientset, replicas int, shardingAlgorithm string, namespace string, portForwardRedis bool, cacheSrc func() (*appstatecache.Cache, error), shard int, redisName string, redisHaProxyName string, redisCompressionStr string) ([]ClusterWithInfo, error) { settingsMgr := settings.NewSettingsManager(ctx, kubeClient, namespace) argoDB := db.NewDB(namespace, settingsMgr, kubeClient) @@ -77,6 +86,10 @@ func loadClusters(ctx context.Context, kubeClient *kubernetes.Clientset, appClie if err != nil { return nil, err } + clusterShardingCache := sharding.NewClusterSharding(argoDB, shard, replicas, shardingAlgorithm) + clusterShardingCache.Init(clustersList) + clusterShards := clusterShardingCache.GetDistribution() + var cache *appstatecache.Cache if portForwardRedis { overrides := clientcmd.ConfigOverrides{} @@ -88,7 +101,11 @@ func loadClusters(ctx context.Context, kubeClient *kubernetes.Clientset, appClie return nil, err } client := redis.NewClient(&redis.Options{Addr: fmt.Sprintf("localhost:%d", port)}) - cache = appstatecache.NewCache(cacheutil.NewCache(cacheutil.NewRedisCache(client, time.Hour, cacheutil.RedisCompressionNone)), time.Hour) + compressionType, err := cacheutil.CompressionTypeFromString(redisCompressionStr) + if err != nil { + return nil, err + } + cache = appstatecache.NewCache(cacheutil.NewCache(cacheutil.NewRedisCache(client, time.Hour, compressionType)), time.Hour) } else { cache, err = cacheSrc() if err != nil { @@ -109,8 +126,15 @@ func loadClusters(ctx context.Context, kubeClient *kubernetes.Clientset, appClie apps[i] = app } clusters := make([]ClusterWithInfo, len(clustersList.Items)) + batchSize := 10 batchesCount := int(math.Ceil(float64(len(clusters)) / float64(batchSize))) + clusterSharding := &sharding.ClusterSharding{ + Shard: shard, + Replicas: replicas, + Shards: make(map[string]int), + Clusters: make(map[string]*v1alpha1.Cluster), + } for batchNum := 0; batchNum < batchesCount; batchNum++ { batchStart := batchSize * batchNum batchEnd := batchSize * (batchNum + 1) @@ -122,12 +146,12 @@ func loadClusters(ctx context.Context, kubeClient *kubernetes.Clientset, appClie clusterShard := 0 cluster := batch[i] if replicas > 0 { - distributionFunction := sharding.GetDistributionFunction(argoDB, common.DefaultShardingAlgorithm) + distributionFunction := sharding.GetDistributionFunction(clusterSharding.GetClusterAccessor(), common.DefaultShardingAlgorithm, replicas) distributionFunction(&cluster) - cluster.Shard = pointer.Int64Ptr(int64(clusterShard)) + clusterShard := clusterShards[cluster.Server] + cluster.Shard = pointer.Int64(int64(clusterShard)) log.Infof("Cluster with uid: %s will be processed by shard %d", cluster.ID, clusterShard) } - if shard != -1 && clusterShard != shard { return nil } @@ -161,15 +185,17 @@ func getControllerReplicas(ctx context.Context, kubeClient *kubernetes.Clientset func NewClusterShardsCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { var ( - shard int - replicas int - clientConfig clientcmd.ClientConfig - cacheSrc func() (*appstatecache.Cache, error) - portForwardRedis bool + shard int + replicas int + shardingAlgorithm string + clientConfig clientcmd.ClientConfig + cacheSrc func() (*appstatecache.Cache, error) + portForwardRedis bool + redisCompressionStr string ) var command = cobra.Command{ Use: "shards", - Short: "Print information about each controller shard and portion of Kubernetes resources it is responsible for.", + Short: "Print information about each controller shard and the estimated portion of Kubernetes resources it is responsible for.", Run: func(cmd *cobra.Command, args []string) { ctx := cmd.Context() @@ -189,8 +215,7 @@ func NewClusterShardsCommand(clientOpts *argocdclient.ClientOptions) *cobra.Comm if replicas == 0 { return } - - clusters, err := loadClusters(ctx, kubeClient, appClient, replicas, namespace, portForwardRedis, cacheSrc, shard, clientOpts.RedisName, clientOpts.RedisHaProxyName) + clusters, err := loadClusters(ctx, kubeClient, appClient, replicas, shardingAlgorithm, namespace, portForwardRedis, cacheSrc, shard, clientOpts.RedisName, clientOpts.RedisHaProxyName, redisCompressionStr) errors.CheckError(err) if len(clusters) == 0 { return @@ -202,8 +227,16 @@ func NewClusterShardsCommand(clientOpts *argocdclient.ClientOptions) *cobra.Comm clientConfig = cli.AddKubectlFlagsToCmd(&command) command.Flags().IntVar(&shard, "shard", -1, "Cluster shard filter") command.Flags().IntVar(&replicas, "replicas", 0, "Application controller replicas count. Inferred from number of running controller pods if not specified") + command.Flags().StringVar(&shardingAlgorithm, "sharding-method", common.DefaultShardingAlgorithm, "Sharding method. Defaults: legacy. Supported sharding methods are : [legacy, round-robin] ") command.Flags().BoolVar(&portForwardRedis, "port-forward-redis", true, "Automatically port-forward ha proxy redis from current namespace?") + cacheSrc = appstatecache.AddCacheFlagsToCmd(&command) + + // parse all added flags so far to get the redis-compression flag that was added by AddCacheFlagsToCmd() above + // we can ignore unchecked error here as the command will be parsed again and checked when command.Execute() is run later + // nolint:errcheck + command.ParseFlags(os.Args[1:]) + redisCompressionStr, _ = command.Flags().GetString(cacheutil.CLIFlagRedisCompress) return &command } @@ -439,15 +472,26 @@ func NewClusterDisableNamespacedMode() *cobra.Command { func NewClusterStatsCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { var ( - shard int - replicas int - clientConfig clientcmd.ClientConfig - cacheSrc func() (*appstatecache.Cache, error) - portForwardRedis bool + shard int + replicas int + shardingAlgorithm string + clientConfig clientcmd.ClientConfig + cacheSrc func() (*appstatecache.Cache, error) + portForwardRedis bool + redisCompressionStr string ) var command = cobra.Command{ Use: "stats", Short: "Prints information cluster statistics and inferred shard number", + Example: ` +#Display stats and shards for clusters +argocd admin cluster stats + +#Display Cluster Statistics for a Specific Shard +argocd admin cluster stats --shard=1 + +#In a multi-cluster environment to print stats for a specific cluster say(target-cluster) +argocd admin cluster stats target-cluster`, Run: func(cmd *cobra.Command, args []string) { ctx := cmd.Context() @@ -464,7 +508,7 @@ func NewClusterStatsCommand(clientOpts *argocdclient.ClientOptions) *cobra.Comma replicas, err = getControllerReplicas(ctx, kubeClient, namespace, clientOpts.AppControllerName) errors.CheckError(err) } - clusters, err := loadClusters(ctx, kubeClient, appClient, replicas, namespace, portForwardRedis, cacheSrc, shard, clientOpts.RedisName, clientOpts.RedisHaProxyName) + clusters, err := loadClusters(ctx, kubeClient, appClient, replicas, shardingAlgorithm, namespace, portForwardRedis, cacheSrc, shard, clientOpts.RedisName, clientOpts.RedisHaProxyName, redisCompressionStr) errors.CheckError(err) w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0) @@ -478,8 +522,15 @@ func NewClusterStatsCommand(clientOpts *argocdclient.ClientOptions) *cobra.Comma clientConfig = cli.AddKubectlFlagsToCmd(&command) command.Flags().IntVar(&shard, "shard", -1, "Cluster shard filter") command.Flags().IntVar(&replicas, "replicas", 0, "Application controller replicas count. Inferred from number of running controller pods if not specified") + command.Flags().StringVar(&shardingAlgorithm, "sharding-method", common.DefaultShardingAlgorithm, "Sharding method. Defaults: legacy. Supported sharding methods are : [legacy, round-robin] ") command.Flags().BoolVar(&portForwardRedis, "port-forward-redis", true, "Automatically port-forward ha proxy redis from current namespace?") cacheSrc = appstatecache.AddCacheFlagsToCmd(&command) + + // parse all added flags so far to get the redis-compression flag that was added by AddCacheFlagsToCmd() above + // we can ignore unchecked error here as the command will be parsed again and checked when command.Execute() is run later + // nolint:errcheck + command.ParseFlags(os.Args[1:]) + redisCompressionStr, _ = command.Flags().GetString(cacheutil.CLIFlagRedisCompress) return &command } @@ -492,6 +543,18 @@ func NewClusterConfig() *cobra.Command { Use: "kubeconfig CLUSTER_URL OUTPUT_PATH", Short: "Generates kubeconfig for the specified cluster", DisableAutoGenTag: true, + Example: ` +#Generate a kubeconfig for a cluster named "my-cluster" on console +argocd admin cluster kubeconfig my-cluster + +#Listing available kubeconfigs for clusters managed by argocd +argocd admin cluster kubeconfig + +#Removing a specific kubeconfig file +argocd admin cluster kubeconfig my-cluster --delete + +#Generate a Kubeconfig for a Cluster with TLS Verification Disabled +argocd admin cluster kubeconfig https://cluster-api-url:6443 /path/to/output/kubeconfig.yaml --insecure-skip-tls-verify`, Run: func(c *cobra.Command, args []string) { ctx := c.Context() @@ -562,15 +625,16 @@ func NewGenClusterConfigCommand(pathOpts *clientcmd.PathOptions) *cobra.Command errors.CheckError(err) kubeClientset := fake.NewSimpleClientset() - var awsAuthConf *argoappv1.AWSAuthConfig - var execProviderConf *argoappv1.ExecProviderConfig + var awsAuthConf *v1alpha1.AWSAuthConfig + var execProviderConf *v1alpha1.ExecProviderConfig if clusterOpts.AwsClusterName != "" { - awsAuthConf = &argoappv1.AWSAuthConfig{ + awsAuthConf = &v1alpha1.AWSAuthConfig{ ClusterName: clusterOpts.AwsClusterName, RoleARN: clusterOpts.AwsRoleArn, + Profile: clusterOpts.AwsProfile, } } else if clusterOpts.ExecProviderCommand != "" { - execProviderConf = &argoappv1.ExecProviderConfig{ + execProviderConf = &v1alpha1.ExecProviderConfig{ Command: clusterOpts.ExecProviderCommand, Args: clusterOpts.ExecProviderArgs, Env: clusterOpts.ExecProviderEnv, @@ -594,7 +658,7 @@ func NewGenClusterConfigCommand(pathOpts *clientcmd.PathOptions) *cobra.Command clst := cmdutil.NewCluster(contextName, clusterOpts.Namespaces, clusterOpts.ClusterResources, conf, bearerToken, awsAuthConf, execProviderConf, labelsMap, annotationsMap) if clusterOpts.InClusterEndpoint() { - clst.Server = argoappv1.KubernetesInternalAPIServerAddr + clst.Server = v1alpha1.KubernetesInternalAPIServerAddr } if clusterOpts.ClusterEndpoint == string(cmdutil.KubePublicEndpoint) { // Ignore `kube-public` cluster endpoints, since this command is intended to run without invoking any network connections. diff --git a/cmd/argocd/commands/admin/dashboard.go b/cmd/argocd/commands/admin/dashboard.go index c75476ea8eb2d..21b621d264022 100644 --- a/cmd/argocd/commands/admin/dashboard.go +++ b/cmd/argocd/commands/admin/dashboard.go @@ -3,7 +3,9 @@ package admin import ( "fmt" + "github.com/argoproj/argo-cd/v2/util/cli" "github.com/spf13/cobra" + "k8s.io/client-go/tools/clientcmd" "github.com/argoproj/argo-cd/v2/cmd/argocd/commands/headless" "github.com/argoproj/argo-cd/v2/cmd/argocd/commands/initialize" @@ -14,11 +16,12 @@ import ( "github.com/argoproj/argo-cd/v2/util/errors" ) -func NewDashboardCommand() *cobra.Command { +func NewDashboardCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { var ( port int address string compressionStr string + clientConfig clientcmd.ClientConfig ) cmd := &cobra.Command{ Use: "dashboard", @@ -28,12 +31,22 @@ func NewDashboardCommand() *cobra.Command { compression, err := cache.CompressionTypeFromString(compressionStr) errors.CheckError(err) - errors.CheckError(headless.MaybeStartLocalServer(ctx, &argocdclient.ClientOptions{Core: true}, initialize.RetrieveContextIfChanged(cmd.Flag("context")), &port, &address, compression)) + clientOpts.Core = true + errors.CheckError(headless.MaybeStartLocalServer(ctx, clientOpts, initialize.RetrieveContextIfChanged(cmd.Flag("context")), &port, &address, compression, clientConfig)) println(fmt.Sprintf("Argo CD UI is available at http://%s:%d", address, port)) <-ctx.Done() }, + Example: `# Start the Argo CD Web UI locally on the default port and address +$ argocd admin dashboard + +# Start the Argo CD Web UI locally on a custom port and address +$ argocd admin dashboard --port 8080 --address 127.0.0.1 + +# Start the Argo CD Web UI with GZip compression +$ argocd admin dashboard --redis-compress gzip + `, } - initialize.InitCommand(cmd) + clientConfig = cli.AddKubectlFlagsToSet(cmd.Flags()) cmd.Flags().IntVar(&port, "port", common.DefaultPortAPIServer, "Listen on given port") cmd.Flags().StringVar(&address, "address", common.DefaultAddressAdminDashboard, "Listen on given address") cmd.Flags().StringVar(&compressionStr, "redis-compress", env.StringFromEnv("REDIS_COMPRESSION", string(cache.RedisCompressionGZip)), "Enable this if the application controller is configured with redis compression enabled. (possible values: gzip, none)") diff --git a/cmd/argocd/commands/admin/notifications.go b/cmd/argocd/commands/admin/notifications.go index a1234cc53b7fe..3cbac0a53b5c2 100644 --- a/cmd/argocd/commands/admin/notifications.go +++ b/cmd/argocd/commands/admin/notifications.go @@ -36,7 +36,7 @@ func NewNotificationsCommand() *cobra.Command { "notifications", "argocd admin notifications", applications, - settings.GetFactorySettings(argocdService, "argocd-notifications-secret", "argocd-notifications-cm"), func(clientConfig clientcmd.ClientConfig) { + settings.GetFactorySettings(argocdService, "argocd-notifications-secret", "argocd-notifications-cm", false), func(clientConfig clientcmd.ClientConfig) { k8sCfg, err := clientConfig.ClientConfig() if err != nil { log.Fatalf("Failed to parse k8s config: %v", err) diff --git a/cmd/argocd/commands/admin/project_allowlist.go b/cmd/argocd/commands/admin/project_allowlist.go index 57b855251daa9..460ea21d93329 100644 --- a/cmd/argocd/commands/admin/project_allowlist.go +++ b/cmd/argocd/commands/admin/project_allowlist.go @@ -41,6 +41,8 @@ func NewProjectAllowListGenCommand() *cobra.Command { var command = &cobra.Command{ Use: "generate-allow-list CLUSTERROLE_PATH PROJ_NAME", Short: "Generates project allow list from the specified clusterRole file", + Example: `# Generates project allow list from the specified clusterRole file +argocd admin proj generate-allow-list /path/to/clusterrole.yaml my-project`, Run: func(c *cobra.Command, args []string) { if len(args) != 2 { c.HelpFunc()(c, args) diff --git a/cmd/argocd/commands/admin/settings.go b/cmd/argocd/commands/admin/settings.go index 281d9875691c4..0274b4a422f09 100644 --- a/cmd/argocd/commands/admin/settings.go +++ b/cmd/argocd/commands/admin/settings.go @@ -373,11 +373,7 @@ func executeResourceOverrideCommand(ctx context.Context, cmdCtx commandContext, if gvk.Group != "" { key = fmt.Sprintf("%s/%s", gvk.Group, gvk.Kind) } - override, hasOverride := overrides[key] - if !hasOverride { - _, _ = fmt.Printf("No overrides configured for '%s/%s'\n", gvk.Group, gvk.Kind) - return - } + override := overrides[key] callback(res, override, overrides) } @@ -519,16 +515,16 @@ argocd admin settings resource-overrides health ./deploy.yaml --argocd-cm-path . executeResourceOverrideCommand(ctx, cmdCtx, args, func(res unstructured.Unstructured, override v1alpha1.ResourceOverride, overrides map[string]v1alpha1.ResourceOverride) { gvk := res.GroupVersionKind() - if override.HealthLua == "" { - _, _ = fmt.Printf("Health script is not configured for '%s/%s'\n", gvk.Group, gvk.Kind) - return - } - resHealth, err := healthutil.GetResourceHealth(&res, lua.ResourceHealthOverrides(overrides)) - errors.CheckError(err) - _, _ = fmt.Printf("STATUS: %s\n", resHealth.Status) - _, _ = fmt.Printf("MESSAGE: %s\n", resHealth.Message) + if err != nil { + errors.CheckError(err) + } else if resHealth == nil { + fmt.Printf("Health script is not configured for '%s/%s'\n", gvk.Group, gvk.Kind) + } else { + _, _ = fmt.Printf("STATUS: %s\n", resHealth.Status) + _, _ = fmt.Printf("MESSAGE: %s\n", resHealth.Message) + } }) }, } diff --git a/cmd/argocd/commands/admin/settings_rbac.go b/cmd/argocd/commands/admin/settings_rbac.go index 8d94feeaad466..1c09fa0d1cfe7 100644 --- a/cmd/argocd/commands/admin/settings_rbac.go +++ b/cmd/argocd/commands/admin/settings_rbac.go @@ -189,7 +189,6 @@ argocd admin settings rbac can someuser create application 'default/app' --defau } }, } - clientConfig = cli.AddKubectlFlagsToCmd(command) command.Flags().StringVar(&policyFile, "policy-file", "", "path to the policy file to use") command.Flags().StringVar(&defaultRole, "default-role", "", "name of the default role to use") @@ -202,24 +201,55 @@ argocd admin settings rbac can someuser create application 'default/app' --defau // NewRBACValidateCommand returns a new rbac validate command func NewRBACValidateCommand() *cobra.Command { var ( - policyFile string + policyFile string + namespace string + clientConfig clientcmd.ClientConfig ) var command = &cobra.Command{ - Use: "validate --policy-file=POLICYFILE", + Use: "validate [--policy-file POLICYFILE] [--namespace NAMESPACE]", Short: "Validate RBAC policy", Long: ` Validates an RBAC policy for being syntactically correct. The policy must be -a local file, and in either CSV or K8s ConfigMap format. +a local file or a K8s ConfigMap in the provided namespace, and in either CSV or K8s ConfigMap format. +`, + Example: ` +# Check whether a given policy file is valid using a local policy.csv file. +argocd admin settings rbac validate --policy-file policy.csv + +# Policy file can also be K8s config map with data keys like argocd-rbac-cm, +# i.e. 'policy.csv' and (optionally) 'policy.default' +argocd admin settings rbac validate --policy-file argocd-rbac-cm.yaml + +# If --policy-file is not given, and instead --namespace is giventhe ConfigMap 'argocd-rbac-cm' +# from K8s is used. +argocd admin settings rbac validate --namespace argocd + +# Either --policy-file or --namespace must be given. `, Run: func(c *cobra.Command, args []string) { ctx := c.Context() - if policyFile == "" { + if len(args) > 0 { c.HelpFunc()(c, args) - log.Fatalf("Please specify policy to validate using --policy-file") + log.Fatalf("too many arguments") + } + + if (namespace == "" && policyFile == "") || (namespace != "" && policyFile != "") { + c.HelpFunc()(c, args) + log.Fatalf("please provide exactly one of --policy-file or --namespace") } - userPolicy, _, _ := getPolicy(ctx, policyFile, nil, "") + + restConfig, err := clientConfig.ClientConfig() + if err != nil { + log.Fatalf("could not get config to create k8s client: %v", err) + } + realClientset, err := kubernetes.NewForConfig(restConfig) + if err != nil { + log.Fatalf("could not create k8s client: %v", err) + } + + userPolicy, _, _ := getPolicy(ctx, policyFile, realClientset, namespace) if userPolicy != "" { if err := rbac.ValidatePolicy(userPolicy); err == nil { fmt.Printf("Policy is valid.\n") @@ -228,11 +258,15 @@ a local file, and in either CSV or K8s ConfigMap format. fmt.Printf("Policy is invalid: %v\n", err) os.Exit(1) } + } else { + log.Fatalf("Policy is empty or could not be loaded.") } }, } - + clientConfig = cli.AddKubectlFlagsToCmd(command) command.Flags().StringVar(&policyFile, "policy-file", "", "path to the policy file to use") + command.Flags().StringVar(&namespace, "namespace", "", "namespace to get argo rbac configmap from") + return command } diff --git a/cmd/argocd/commands/admin/settings_rbac_test.go b/cmd/argocd/commands/admin/settings_rbac_test.go index a4b4b437e114c..79835ffd0c14d 100644 --- a/cmd/argocd/commands/admin/settings_rbac_test.go +++ b/cmd/argocd/commands/admin/settings_rbac_test.go @@ -5,15 +5,42 @@ import ( "os" "testing" + "github.com/argoproj/argo-cd/v2/util/assets" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes/fake" - - "github.com/argoproj/argo-cd/v2/util/assets" + restclient "k8s.io/client-go/rest" + "k8s.io/client-go/tools/clientcmd" + clientcmdapi "k8s.io/client-go/tools/clientcmd/api" ) +type FakeClientConfig struct { + clientConfig clientcmd.ClientConfig +} + +func NewFakeClientConfig(clientConfig clientcmd.ClientConfig) *FakeClientConfig { + return &FakeClientConfig{clientConfig: clientConfig} +} + +func (f *FakeClientConfig) RawConfig() (clientcmdapi.Config, error) { + config, err := f.clientConfig.RawConfig() + return config, err +} + +func (f *FakeClientConfig) ClientConfig() (*restclient.Config, error) { + return f.clientConfig.ClientConfig() +} + +func (f *FakeClientConfig) Namespace() (string, bool, error) { + return f.clientConfig.Namespace() +} + +func (f *FakeClientConfig) ConfigAccess() clientcmd.ConfigAccess { + return nil +} + func Test_isValidRBACAction(t *testing.T) { for k := range validRBACActions { t.Run(k, func(t *testing.T) { @@ -200,3 +227,19 @@ p, role:, certificates, get, .*, allow` require.True(t, ok) }) } + +func TestNewRBACCanCommand(t *testing.T) { + command := NewRBACCanCommand() + + require.NotNil(t, command) + assert.Equal(t, "can", command.Name()) + assert.Equal(t, "Check RBAC permissions for a role or subject", command.Short) +} + +func TestNewRBACValidateCommand(t *testing.T) { + command := NewRBACValidateCommand() + + require.NotNil(t, command) + assert.Equal(t, "validate", command.Name()) + assert.Equal(t, "Validate RBAC policy", command.Short) +} diff --git a/cmd/argocd/commands/admin/settings_test.go b/cmd/argocd/commands/admin/settings_test.go index adb18c80ee84e..ff817017f4be5 100644 --- a/cmd/argocd/commands/admin/settings_test.go +++ b/cmd/argocd/commands/admin/settings_test.go @@ -226,6 +226,18 @@ spec: replicas: 0` ) +const ( + testCustomResourceYAML = `apiVersion: v1 +apiVersion: example.com/v1alpha1 +kind: ExampleResource +metadata: + name: example-resource + labels: + app: example +spec: + replicas: 0` +) + const ( testCronJobYAML = `apiVersion: batch/v1 kind: CronJob @@ -285,7 +297,7 @@ func TestResourceOverrideIgnoreDifferences(t *testing.T) { assert.NoError(t, err) }) assert.NoError(t, err) - assert.Contains(t, out, "No overrides configured") + assert.Contains(t, out, "Ignore differences are not configured for 'apps/Deployment'\n") }) t.Run("DataIgnored", func(t *testing.T) { @@ -305,7 +317,7 @@ func TestResourceOverrideIgnoreDifferences(t *testing.T) { } func TestResourceOverrideHealth(t *testing.T) { - f, closer, err := tempFile(testDeploymentYAML) + f, closer, err := tempFile(testCustomResourceYAML) if !assert.NoError(t, err) { return } @@ -313,19 +325,34 @@ func TestResourceOverrideHealth(t *testing.T) { t.Run("NoHealthAssessment", func(t *testing.T) { cmd := NewResourceOverridesCommand(newCmdContext(map[string]string{ - "resource.customizations": `apps/Deployment: {}`})) + "resource.customizations": `example.com/ExampleResource: {}`})) out, err := captureStdout(func() { cmd.SetArgs([]string{"health", f}) err := cmd.Execute() assert.NoError(t, err) }) assert.NoError(t, err) - assert.Contains(t, out, "Health script is not configured") + assert.Contains(t, out, "Health script is not configured for 'example.com/ExampleResource'\n") }) t.Run("HealthAssessmentConfigured", func(t *testing.T) { cmd := NewResourceOverridesCommand(newCmdContext(map[string]string{ - "resource.customizations": `apps/Deployment: + "resource.customizations": `example.com/ExampleResource: + health.lua: | + return { status = "Progressing" } +`})) + out, err := captureStdout(func() { + cmd.SetArgs([]string{"health", f}) + err := cmd.Execute() + assert.NoError(t, err) + }) + assert.NoError(t, err) + assert.Contains(t, out, "Progressing") + }) + + t.Run("HealthAssessmentConfiguredWildcard", func(t *testing.T) { + cmd := NewResourceOverridesCommand(newCmdContext(map[string]string{ + "resource.customizations": `example.com/*: health.lua: | return { status = "Progressing" } `})) @@ -412,7 +439,7 @@ resume false action.lua: | job1 = {} job1.apiVersion = "batch/v1" - job1.kind = "Job" + job1.kind = "Job" job1.metadata = {} job1.metadata.name = "hello-1" job1.metadata.namespace = "obj.metadata.namespace" diff --git a/cmd/argocd/commands/app.go b/cmd/argocd/commands/app.go index 55ed2ee8790f3..99be7d26b76d3 100644 --- a/cmd/argocd/commands/app.go +++ b/cmd/argocd/commands/app.go @@ -318,6 +318,35 @@ func NewApplicationGetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Com var command = &cobra.Command{ Use: "get APPNAME", Short: "Get application details", + Example: templates.Examples(` + # Get basic details about the application "my-app" in wide format + argocd app get my-app -o wide + + # Get detailed information about the application "my-app" in YAML format + argocd app get my-app -o yaml + + # Get details of the application "my-app" in JSON format + argocd get my-app -o json + + # Get application details and include information about the current operation + argocd app get my-app --show-operation + + # Show application parameters and overrides + argocd app get my-app --show-params + + # Refresh application data when retrieving + argocd app get my-app --refresh + + # Perform a hard refresh, including refreshing application data and target manifests cache + argocd app get my-app --hard-refresh + + # Get application details and display them in a tree format + argocd app get my-app --output tree + + # Get application details and display them in a detailed tree format + argocd app get my-app --output tree=detailed + `), + Run: func(c *cobra.Command, args []string) { ctx := c.Context() if len(args) == 0 { @@ -495,8 +524,8 @@ func NewApplicationLogsCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co } else { return } - } //Done with receive message - } //Done with retry + } // Done with receive message + } // Done with retry }, } @@ -860,7 +889,7 @@ func unset(source *argoappv1.ApplicationSource, opts unsetOpts) (updated bool, n for i, item := range source.Kustomize.Images { if argoappv1.KustomizeImage(kustomizeImage).Match(item) { updated = true - //remove i + // remove i a := source.Kustomize.Images copy(a[i:], a[i+1:]) // Shift a[i+1:] left one index. a[len(a)-1] = "" // Erase last element (write zero value). @@ -1033,7 +1062,7 @@ func NewApplicationDiffCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co var command = &cobra.Command{ Use: "diff APPNAME", Short: shortDesc, - Long: shortDesc + "\nUses 'diff' to render the difference. KUBECTL_EXTERNAL_DIFF environment variable can be used to select your own diff tool.\nReturns the following exit codes: 2 on general errors, 1 when a diff is found, and 0 when no diff is found", + Long: shortDesc + "\nUses 'diff' to render the difference. KUBECTL_EXTERNAL_DIFF environment variable can be used to select your own diff tool.\nReturns the following exit codes: 2 on general errors, 1 when a diff is found, and 0 when no diff is found\nKubernetes Secrets are ignored from this diff.", Run: func(c *cobra.Command, args []string) { ctx := c.Context() @@ -1087,6 +1116,7 @@ func NewApplicationDiffCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co defer argoio.Close(conn) cluster, err := clusterIf.Get(ctx, &clusterpkg.ClusterQuery{Name: app.Spec.Destination.Name, Server: app.Spec.Destination.Server}) errors.CheckError(err) + diffOption.local = local diffOption.localRepoRoot = localRepoRoot diffOption.cluster = cluster @@ -1595,7 +1625,7 @@ func NewApplicationWaitCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co list, err := appIf.List(ctx, &application.ApplicationQuery{Selector: pointer.String(selector)}) errors.CheckError(err) for _, i := range list.Items { - appNames = append(appNames, i.Name) + appNames = append(appNames, i.QualifiedName()) } } for _, appName := range appNames { @@ -1875,7 +1905,7 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co Backoff: &argoappv1.Backoff{ Duration: retryBackoffDuration.String(), MaxDuration: retryBackoffMaxDuration.String(), - Factor: pointer.Int64Ptr(retryBackoffFactor), + Factor: pointer.Int64(retryBackoffFactor), }, } } @@ -1966,7 +1996,7 @@ func getAppNamesBySelector(ctx context.Context, appIf application.ApplicationSer return []string{}, fmt.Errorf("no apps match selector %v", selector) } for _, i := range list.Items { - appNames = append(appNames, i.Name) + appNames = append(appNames, i.QualifiedName()) } } return appNames, nil @@ -2114,7 +2144,7 @@ func checkResourceStatus(watch watchOpts, healthStatus string, syncStatus string } else if watch.degraded && watch.health { healthCheckPassed = healthStatus == string(health.HealthStatusHealthy) || healthStatus == string(health.HealthStatusDegraded) - //below are good + // below are good } else if watch.suspended && watch.health { healthCheckPassed = healthStatus == string(health.HealthStatusHealthy) || healthStatus == string(health.HealthStatusSuspended) diff --git a/cmd/argocd/commands/app_resources.go b/cmd/argocd/commands/app_resources.go index e48465c7e4693..4cffb706ff1bc 100644 --- a/cmd/argocd/commands/app_resources.go +++ b/cmd/argocd/commands/app_resources.go @@ -3,6 +3,7 @@ package commands import ( "fmt" "os" + "text/tabwriter" "github.com/argoproj/argo-cd/v2/cmd/util" "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" @@ -18,8 +19,6 @@ import ( "github.com/argoproj/argo-cd/v2/util/argo" "github.com/argoproj/argo-cd/v2/util/errors" argoio "github.com/argoproj/argo-cd/v2/util/io" - - "text/tabwriter" ) func NewApplicationPatchResourceCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { @@ -30,6 +29,7 @@ func NewApplicationPatchResourceCommand(clientOpts *argocdclient.ClientOptions) var kind string var group string var all bool + var project string command := &cobra.Command{ Use: "patch-resource APPNAME", Short: "Patch resource in an application", @@ -46,6 +46,7 @@ func NewApplicationPatchResourceCommand(clientOpts *argocdclient.ClientOptions) command.Flags().StringVar(&group, "group", "", "Group") command.Flags().StringVar(&namespace, "namespace", "", "Namespace") command.Flags().BoolVar(&all, "all", false, "Indicates whether to patch multiple matching of resources") + command.Flags().StringVar(&project, "project", "", `The name of the application's project - specifying this allows the command to report "not found" instead of "permission denied" if the app does not exist`) command.Run = func(c *cobra.Command, args []string) { ctx := c.Context() @@ -77,6 +78,7 @@ func NewApplicationPatchResourceCommand(clientOpts *argocdclient.ClientOptions) Kind: pointer.String(gvk.Kind), Patch: pointer.String(patch), PatchType: pointer.String(patchType), + Project: pointer.String(project), }) errors.CheckError(err) log.Infof("Resource '%s' patched", obj.GetName()) @@ -94,6 +96,7 @@ func NewApplicationDeleteResourceCommand(clientOpts *argocdclient.ClientOptions) var force bool var orphan bool var all bool + var project string command := &cobra.Command{ Use: "delete-resource APPNAME", Short: "Delete resource in an application", @@ -108,6 +111,7 @@ func NewApplicationDeleteResourceCommand(clientOpts *argocdclient.ClientOptions) command.Flags().BoolVar(&force, "force", false, "Indicates whether to orphan the dependents of the deleted resource") command.Flags().BoolVar(&orphan, "orphan", false, "Indicates whether to force delete the resource") command.Flags().BoolVar(&all, "all", false, "Indicates whether to patch multiple matching of resources") + command.Flags().StringVar(&project, "project", "", `The name of the application's project - specifying this allows the command to report "not found" instead of "permission denied" if the app does not exist`) command.Run = func(c *cobra.Command, args []string) { ctx := c.Context() @@ -139,6 +143,7 @@ func NewApplicationDeleteResourceCommand(clientOpts *argocdclient.ClientOptions) Kind: pointer.String(gvk.Kind), Force: &force, Orphan: &orphan, + Project: pointer.String(project), }) errors.CheckError(err) log.Infof("Resource '%s' deleted", obj.GetName()) @@ -250,6 +255,7 @@ func printResources(listAll bool, orphaned bool, appResourceTree *v1alpha1.Appli func NewApplicationListResourcesCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { var orphaned bool var output string + var project string var command = &cobra.Command{ Use: "resources APPNAME", Short: "List resource of application", @@ -266,6 +272,7 @@ func NewApplicationListResourcesCommand(clientOpts *argocdclient.ClientOptions) appResourceTree, err := appIf.ResourceTree(ctx, &applicationpkg.ResourcesQuery{ ApplicationName: &appName, AppNamespace: &appNs, + Project: &project, }) errors.CheckError(err) printResources(listAll, orphaned, appResourceTree, output) @@ -273,5 +280,6 @@ func NewApplicationListResourcesCommand(clientOpts *argocdclient.ClientOptions) } command.Flags().BoolVar(&orphaned, "orphaned", false, "Lists only orphaned resources") command.Flags().StringVar(&output, "output", "", "Provides the tree view of the resources") + command.Flags().StringVar(&project, "project", "", `The name of the application's project - specifying this allows the command to report "not found" instead of "permission denied" if the app does not exist`) return command } diff --git a/cmd/argocd/commands/cluster.go b/cmd/argocd/commands/cluster.go index a1d1589540af0..f203b82ae9ac0 100644 --- a/cmd/argocd/commands/cluster.go +++ b/cmd/argocd/commands/cluster.go @@ -111,6 +111,7 @@ func NewClusterAddCommand(clientOpts *argocdclient.ClientOptions, pathOpts *clie awsAuthConf = &argoappv1.AWSAuthConfig{ ClusterName: clusterOpts.AwsClusterName, RoleARN: clusterOpts.AwsRoleArn, + Profile: clusterOpts.AwsProfile, } } else if clusterOpts.ExecProviderCommand != "" { execProviderConf = &argoappv1.ExecProviderConfig{ @@ -485,6 +486,23 @@ func NewClusterListCommand(clientOpts *argocdclient.ClientOptions) *cobra.Comman errors.CheckError(fmt.Errorf("unknown output format: %s", output)) } }, + Example: ` +# List Clusters in Default "Wide" Format +argocd cluster list + +# List Cluster via specifing the server +argocd cluster list --server + +# List Clusters in JSON Format +argocd cluster list -o json --server + +# List Clusters in YAML Format +argocd cluster list -o yaml --server + +# List Clusters that have been added to your Argo CD +argocd cluster list -o server + +`, } command.Flags().StringVarP(&output, "output", "o", "wide", "Output format. One of: json|yaml|wide|server") return command diff --git a/cmd/argocd/commands/gpg.go b/cmd/argocd/commands/gpg.go index 7a48a915bebec..73768fc18a324 100644 --- a/cmd/argocd/commands/gpg.go +++ b/cmd/argocd/commands/gpg.go @@ -14,6 +14,7 @@ import ( appsv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" "github.com/argoproj/argo-cd/v2/util/errors" argoio "github.com/argoproj/argo-cd/v2/util/io" + "github.com/argoproj/argo-cd/v2/util/templates" ) // NewGPGCommand returns a new instance of an `argocd repo` command @@ -42,6 +43,17 @@ func NewGPGListCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { var command = &cobra.Command{ Use: "list", Short: "List configured GPG public keys", + Example: templates.Examples(` + # List all configured GPG public keys in wide format (default). + argocd gpg list + + # List all configured GPG public keys in JSON format. + argocd gpg list -o json + + # List all configured GPG public keys in YAML format. + argocd gpg list -o yaml + `), + Run: func(c *cobra.Command, args []string) { ctx := c.Context() @@ -72,6 +84,17 @@ func NewGPGGetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { var command = &cobra.Command{ Use: "get KEYID", Short: "Get the GPG public key with ID from the server", + Example: templates.Examples(` + # Get a GPG public key with the specified KEYID in wide format (default). + argocd gpg get KEYID + + # Get a GPG public key with the specified KEYID in JSON format. + argocd gpg get KEYID -o json + + # Get a GPG public key with the specified KEYID in YAML format. + argocd gpg get KEYID -o yaml + `), + Run: func(c *cobra.Command, args []string) { ctx := c.Context() @@ -109,6 +132,11 @@ func NewGPGAddCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { var command = &cobra.Command{ Use: "add", Short: "Adds a GPG public key to the server's keyring", + Example: templates.Examples(` + # Add a GPG public key to the server's keyring from a file. + argocd gpg add --from /path/to/keyfile + `), + Run: func(c *cobra.Command, args []string) { ctx := c.Context() diff --git a/cmd/argocd/commands/headless/headless.go b/cmd/argocd/commands/headless/headless.go index 070d9c9c83bcb..d48019a2216b9 100644 --- a/cmd/argocd/commands/headless/headless.go +++ b/cmd/argocd/commands/headless/headless.go @@ -78,6 +78,12 @@ func (c *forwardCacheClient) Set(item *cache.Item) error { }) } +func (c *forwardCacheClient) Rename(oldKey string, newKey string, expiration time.Duration) error { + return c.doLazy(func(client cache.CacheClient) error { + return client.Rename(oldKey, newKey, expiration) + }) +} + func (c *forwardCacheClient) Get(key string, obj interface{}) error { return c.doLazy(func(client cache.CacheClient) error { return client.Get(key, obj) @@ -153,9 +159,11 @@ func testAPI(ctx context.Context, clientOpts *apiclient.ClientOptions) error { // // If the clientOpts enables core mode, but the local config does not have core mode enabled, this function will // not start the local server. -func MaybeStartLocalServer(ctx context.Context, clientOpts *apiclient.ClientOptions, ctxStr string, port *int, address *string, compression cache.RedisCompressionType) error { - flags := pflag.NewFlagSet("tmp", pflag.ContinueOnError) - clientConfig := cli.AddKubectlFlagsToSet(flags) +func MaybeStartLocalServer(ctx context.Context, clientOpts *apiclient.ClientOptions, ctxStr string, port *int, address *string, compression cache.RedisCompressionType, clientConfig clientcmd.ClientConfig) error { + if clientConfig == nil { + flags := pflag.NewFlagSet("tmp", pflag.ContinueOnError) + clientConfig = cli.AddKubectlFlagsToSet(flags) + } startInProcessAPI := clientOpts.Core if !startInProcessAPI { // Core mode is enabled on client options. Check the local config to see if we should start the API server. @@ -244,6 +252,7 @@ func MaybeStartLocalServer(ctx context.Context, clientOpts *apiclient.ClientOpti if !cache2.WaitForCacheSync(ctx.Done(), srv.Initialized) { log.Fatal("Timed out waiting for project cache to sync") } + tries := 5 for i := 0; i < tries; i++ { err = testAPI(ctx, clientOpts) @@ -265,7 +274,7 @@ func NewClientOrDie(opts *apiclient.ClientOptions, c *cobra.Command) apiclient.C ctxStr := initialize.RetrieveContextIfChanged(c.Flag("context")) // If we're in core mode, start the API server on the fly and configure the client `opts` to use it. // If we're not in core mode, this function call will do nothing. - err := MaybeStartLocalServer(ctx, opts, ctxStr, nil, nil, cache.RedisCompressionNone) + err := MaybeStartLocalServer(ctx, opts, ctxStr, nil, nil, cache.RedisCompressionNone, nil) if err != nil { log.Fatal(err) } diff --git a/cmd/argocd/commands/login.go b/cmd/argocd/commands/login.go index 3e2ad4e7d1b73..abb2b004291c2 100644 --- a/cmd/argocd/commands/login.go +++ b/cmd/argocd/commands/login.go @@ -106,6 +106,7 @@ argocd login cd.argoproj.io --core`, PortForwardNamespace: globalClientOpts.PortForwardNamespace, Headers: globalClientOpts.Headers, KubeOverrides: globalClientOpts.KubeOverrides, + ServerName: globalClientOpts.ServerName, } if ctxName == "" { diff --git a/cmd/argocd/commands/project.go b/cmd/argocd/commands/project.go index dc894b4a79f27..32fb9e779e8ed 100644 --- a/cmd/argocd/commands/project.go +++ b/cmd/argocd/commands/project.go @@ -106,7 +106,7 @@ func NewProjectCreateCommand(clientOpts *argocdclient.ClientOptions) *cobra.Comm # Create a new project with name PROJECT argocd proj create PROJECT - # Create a new project with name PROJECT from a file or URL to a kubernetes manifest + # Create a new project with name PROJECT from a file or URL to a Kubernetes manifest argocd proj create PROJECT -f FILE|URL `), Run: func(c *cobra.Command, args []string) { diff --git a/cmd/argocd/commands/project_role.go b/cmd/argocd/commands/project_role.go index 987e61914d858..5920bac0dc8e4 100644 --- a/cmd/argocd/commands/project_role.go +++ b/cmd/argocd/commands/project_role.go @@ -18,6 +18,7 @@ import ( "github.com/argoproj/argo-cd/v2/util/errors" "github.com/argoproj/argo-cd/v2/util/io" "github.com/argoproj/argo-cd/v2/util/jwt" + "github.com/argoproj/argo-cd/v2/util/templates" ) const ( @@ -56,6 +57,30 @@ func NewProjectRoleAddPolicyCommand(clientOpts *argocdclient.ClientOptions) *cob var command = &cobra.Command{ Use: "add-policy PROJECT ROLE-NAME", Short: "Add a policy to a project role", + Example: `# Before adding new policy +$ argocd proj role get test-project test-role +Role Name: test-role +Description: +Policies: +p, proj:test-project:test-role, projects, get, test-project, allow +JWT Tokens: +ID ISSUED-AT EXPIRES-AT +1696759698 2023-10-08T11:08:18+01:00 (3 hours ago) + +# Add a new policy to allow update to the project +$ argocd proj role add-policy test-project test-role -a update -p allow -o project + +# Policy should be updated +$ argocd proj role get test-project test-role +Role Name: test-role +Description: +Policies: +p, proj:test-project:test-role, projects, get, test-project, allow +p, proj:test-project:test-role, applications, update, test-project/project, allow +JWT Tokens: +ID ISSUED-AT EXPIRES-AT +1696759698 2023-10-08T11:08:18+01:00 (3 hours ago) +`, Run: func(c *cobra.Command, args []string) { ctx := c.Context() @@ -93,6 +118,30 @@ func NewProjectRoleRemovePolicyCommand(clientOpts *argocdclient.ClientOptions) * var command = &cobra.Command{ Use: "remove-policy PROJECT ROLE-NAME", Short: "Remove a policy from a role within a project", + Example: `List the policy of the test-role before removing a policy +$ argocd proj role get test-project test-role +Role Name: test-role +Description: +Policies: +p, proj:test-project:test-role, projects, get, test-project, allow +p, proj:test-project:test-role, applications, update, test-project/project, allow +JWT Tokens: +ID ISSUED-AT EXPIRES-AT +1696759698 2023-10-08T11:08:18+01:00 (3 hours ago) + +# Remove the policy to allow update to objects +$ argocd proj role remove-policy test-project test-role -a update -p allow -o project + +# The role should be removed now. +$ argocd proj role get test-project test-role +Role Name: test-role +Description: +Policies: +p, proj:test-project:test-role, projects, get, test-project, allow +JWT Tokens: +ID ISSUED-AT EXPIRES-AT +1696759698 2023-10-08T11:08:18+01:00 (4 hours ago) +`, Run: func(c *cobra.Command, args []string) { ctx := c.Context() @@ -140,6 +189,11 @@ func NewProjectRoleCreateCommand(clientOpts *argocdclient.ClientOptions) *cobra. var command = &cobra.Command{ Use: "create PROJECT ROLE-NAME", Short: "Create a project role", + Example: templates.Examples(` + # Create a project role in the "my-project" project with the name "my-role". + argocd proj role create my-project my-role --description "My project role description" + `), + Run: func(c *cobra.Command, args []string) { ctx := c.Context() @@ -174,8 +228,9 @@ func NewProjectRoleCreateCommand(clientOpts *argocdclient.ClientOptions) *cobra. // NewProjectRoleDeleteCommand returns a new instance of an `argocd proj role delete` command func NewProjectRoleDeleteCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { var command = &cobra.Command{ - Use: "delete PROJECT ROLE-NAME", - Short: "Delete a project role", + Use: "delete PROJECT ROLE-NAME", + Short: "Delete a project role", + Example: `$ argocd proj role delete test-project test-role`, Run: func(c *cobra.Command, args []string) { ctx := c.Context() @@ -223,8 +278,15 @@ func NewProjectRoleCreateTokenCommand(clientOpts *argocdclient.ClientOptions) *c tokenID string ) var command = &cobra.Command{ - Use: "create-token PROJECT ROLE-NAME", - Short: "Create a project token", + Use: "create-token PROJECT ROLE-NAME", + Short: "Create a project token", + Example: `$ argocd proj role create-token test-project test-role +Create token succeeded for proj:test-project:test-role. + ID: f316c466-40bd-4cfd-8a8c-1392e92255d4 + Issued At: 2023-10-08T15:21:40+01:00 + Expires At: Never + Token: xxx +`, Aliases: []string{"token-create"}, Run: func(c *cobra.Command, args []string) { ctx := c.Context() @@ -288,8 +350,13 @@ func NewProjectRoleListTokensCommand(clientOpts *argocdclient.ClientOptions) *co useUnixTime bool ) var command = &cobra.Command{ - Use: "list-tokens PROJECT ROLE-NAME", - Short: "List tokens for a given role.", + Use: "list-tokens PROJECT ROLE-NAME", + Short: "List tokens for a given role.", + Example: `$ argocd proj role list-tokens test-project test-role +ID ISSUED AT EXPIRES AT +f316c466-40bd-4cfd-8a8c-1392e92255d4 2023-10-08T15:21:40+01:00 Never +fa9d3517-c52d-434c-9bff-215b38508842 2023-10-08T11:08:18+01:00 Never +`, Aliases: []string{"list-token", "token-list"}, Run: func(c *cobra.Command, args []string) { ctx := c.Context() @@ -339,8 +406,35 @@ func NewProjectRoleListTokensCommand(clientOpts *argocdclient.ClientOptions) *co // NewProjectRoleDeleteTokenCommand returns a new instance of an `argocd proj role delete-token` command func NewProjectRoleDeleteTokenCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { var command = &cobra.Command{ - Use: "delete-token PROJECT ROLE-NAME ISSUED-AT", - Short: "Delete a project token", + Use: "delete-token PROJECT ROLE-NAME ISSUED-AT", + Short: "Delete a project token", + Example: `#Create project test-project +$ argocd proj create test-project + +# Create a role associated with test-project +$ argocd proj role create test-project test-role +Role 'test-role' created + +# Create test-role associated with test-project +$ argocd proj role create-token test-project test-role +Create token succeeded for proj:test-project:test-role. + ID: c312450e-12e1-4e0d-9f65-fac9cb027b32 + Issued At: 2023-10-08T13:58:57+01:00 + Expires At: Never + Token: xxx + +# Get test-role id to input into the delete-token command below +$ argocd proj role get test-project test-role +Role Name: test-role +Description: +Policies: +p, proj:test-project:test-role, projects, get, test-project, allow +JWT Tokens: +ID ISSUED-AT EXPIRES-AT +1696769937 2023-10-08T13:58:57+01:00 (6 minutes ago) + +$ argocd proj role delete-token test-project test-role 1696769937 +`, Aliases: []string{"token-delete", "remove-token"}, Run: func(c *cobra.Command, args []string) { ctx := c.Context() @@ -389,6 +483,15 @@ func NewProjectRoleListCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co var command = &cobra.Command{ Use: "list PROJECT", Short: "List all the roles in a project", + Example: templates.Examples(` + # This command will list all the roles in argocd-project in a default table format. + argocd proj role list PROJECT + + # List the roles in the project in formats like json, yaml, wide, or name. + argocd proj role list PROJECT --output json + + `), + Run: func(c *cobra.Command, args []string) { ctx := c.Context() @@ -424,6 +527,16 @@ func NewProjectRoleGetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Com var command = &cobra.Command{ Use: "get PROJECT ROLE-NAME", Short: "Get the details of a specific role", + Example: `$ argocd proj role get test-project test-role +Role Name: test-role +Description: +Policies: +p, proj:test-project:test-role, projects, get, test-project, allow +JWT Tokens: +ID ISSUED-AT EXPIRES-AT +1696774900 2023-10-08T15:21:40+01:00 (4 minutes ago) +1696759698 2023-10-08T11:08:18+01:00 (4 hours ago) +`, Run: func(c *cobra.Command, args []string) { ctx := c.Context() diff --git a/cmd/argocd/commands/projectwindows.go b/cmd/argocd/commands/projectwindows.go index 0bc867cc6cf68..93843130ebb13 100644 --- a/cmd/argocd/commands/projectwindows.go +++ b/cmd/argocd/commands/projectwindows.go @@ -22,6 +22,18 @@ func NewProjectWindowsCommand(clientOpts *argocdclient.ClientOptions) *cobra.Com roleCommand := &cobra.Command{ Use: "windows", Short: "Manage a project's sync windows", + Example: ` +#Add a sync window to a project +argocd proj windows add my-project \ +--schedule "0 0 * * 1-5" \ +--duration 3600 \ +--prune + +#Delete a sync window from a project +argocd proj windows delete + +#List project sync windows +argocd proj windows list `, Run: func(c *cobra.Command, args []string) { c.HelpFunc()(c, args) os.Exit(1) @@ -42,6 +54,12 @@ func NewProjectWindowsDisableManualSyncCommand(clientOpts *argocdclient.ClientOp Use: "disable-manual-sync PROJECT ID", Short: "Disable manual sync for a sync window", Long: "Disable manual sync for a sync window. Requires ID which can be found by running \"argocd proj windows list PROJECT\"", + Example: ` +#Disable manual sync for a sync window for the Project +argocd proj windows disable-manual-sync PROJECT ID + +#Disbaling manual sync for a windows set on the default project with Id 0 +argocd proj windows disable-manual-sync default 0`, Run: func(c *cobra.Command, args []string) { ctx := c.Context() @@ -79,6 +97,15 @@ func NewProjectWindowsEnableManualSyncCommand(clientOpts *argocdclient.ClientOpt Use: "enable-manual-sync PROJECT ID", Short: "Enable manual sync for a sync window", Long: "Enable manual sync for a sync window. Requires ID which can be found by running \"argocd proj windows list PROJECT\"", + Example: ` +#Enabling manual sync for a general case +argocd proj windows enable-manual-sync PROJECT ID + +#Enabling manual sync for a windows set on the default project with Id 2 +argocd proj windows enable-manual-sync default 2 + +#Enabling manual sync with a custom message +argocd proj windows enable-manual-sync my-app-project --message "Manual sync initiated by admin`, Run: func(c *cobra.Command, args []string) { ctx := c.Context() @@ -125,6 +152,24 @@ func NewProjectWindowsAddWindowCommand(clientOpts *argocdclient.ClientOptions) * var command = &cobra.Command{ Use: "add PROJECT", Short: "Add a sync window to a project", + Example: ` +#Add a 1 hour allow sync window +argocd proj windows add PROJECT \ + --kind allow \ + --schedule "0 22 * * *" \ + --duration 1h \ + --applications "*" + +#Add a deny sync window with the ability to manually sync. +argocd proj windows add PROJECT \ + --kind deny \ + --schedule "30 10 * * *" \ + --duration 30m \ + --applications "prod-\\*,website" \ + --namespaces "default,\\*-prod" \ + --clusters "prod,staging" \ + --manual-sync + `, Run: func(c *cobra.Command, args []string) { ctx := c.Context() @@ -158,11 +203,17 @@ func NewProjectWindowsAddWindowCommand(clientOpts *argocdclient.ClientOptions) * return command } -// NewProjectWindowsAddWindowCommand returns a new instance of an `argocd proj windows delete` command +// NewProjectWindowsDeleteCommand returns a new instance of an `argocd proj windows delete` command func NewProjectWindowsDeleteCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { var command = &cobra.Command{ Use: "delete PROJECT ID", Short: "Delete a sync window from a project. Requires ID which can be found by running \"argocd proj windows list PROJECT\"", + Example: ` +#Delete a sync window from a project (default) with ID 0 +argocd proj windows delete default 0 + +#Delete a sync window from a project (new-project) with ID 1 +argocd proj windows delete new-project 1`, Run: func(c *cobra.Command, args []string) { ctx := c.Context() @@ -205,6 +256,10 @@ func NewProjectWindowsUpdateCommand(clientOpts *argocdclient.ClientOptions) *cob Use: "update PROJECT ID", Short: "Update a project sync window", Long: "Update a project sync window. Requires ID which can be found by running \"argocd proj windows list PROJECT\"", + Example: `# Change a sync window's schedule +argocd proj windows update PROJECT ID \ + --schedule "0 20 * * *" +`, Run: func(c *cobra.Command, args []string) { ctx := c.Context() @@ -253,6 +308,15 @@ func NewProjectWindowsListCommand(clientOpts *argocdclient.ClientOptions) *cobra var command = &cobra.Command{ Use: "list PROJECT", Short: "List project sync windows", + Example: ` +#List project windows +argocd proj windows list PROJECT + +#List project windows in yaml format +argocd proj windows list PROJECT -o yaml + +#List project windows info for a project name (test-project) +argocd proj windows list test-project`, Run: func(c *cobra.Command, args []string) { ctx := c.Context() @@ -285,8 +349,8 @@ func NewProjectWindowsListCommand(clientOpts *argocdclient.ClientOptions) *cobra func printSyncWindows(proj *v1alpha1.AppProject) { w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0) var fmtStr string - headers := []interface{}{"ID", "STATUS", "KIND", "SCHEDULE", "DURATION", "APPLICATIONS", "NAMESPACES", "CLUSTERS", "MANUALSYNC"} - fmtStr = "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n" + headers := []interface{}{"ID", "STATUS", "KIND", "SCHEDULE", "DURATION", "APPLICATIONS", "NAMESPACES", "CLUSTERS", "MANUALSYNC", "TIMEZONE"} + fmtStr = strings.Repeat("%s\t", len(headers)) + "\n" fmt.Fprintf(w, fmtStr, headers...) if proj.Spec.SyncWindows.HasWindows() { for i, window := range proj.Spec.SyncWindows { @@ -300,6 +364,7 @@ func printSyncWindows(proj *v1alpha1.AppProject) { formatListOutput(window.Namespaces), formatListOutput(window.Clusters), formatManualOutput(window.ManualSync), + window.TimeZone, } fmt.Fprintf(w, fmtStr, vals...) } diff --git a/cmd/argocd/commands/repo.go b/cmd/argocd/commands/repo.go index 2bf9714a06f11..1a5b4388fbeba 100644 --- a/cmd/argocd/commands/repo.go +++ b/cmd/argocd/commands/repo.go @@ -64,6 +64,12 @@ func NewRepoAddCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { # Add a Git repository via SSH on a non-default port - need to use ssh:// style URLs here argocd repo add ssh://git@git.example.com:2222/repos/repo --ssh-private-key-path ~/id_rsa + # Add a Git repository via SSH using socks5 proxy with no proxy credentials + argocd repo add ssh://git@github.com/argoproj/argocd-example-apps --ssh-private-key-path ~/id_rsa --proxy socks5://your.proxy.server.ip:1080 + + # Add a Git repository via SSH using socks5 proxy with proxy credentials + argocd repo add ssh://git@github.com/argoproj/argocd-example-apps --ssh-private-key-path ~/id_rsa --proxy socks5://username:password@your.proxy.server.ip:1080 + # Add a private Git repository via HTTPS using username/password and TLS client certificates: argocd repo add https://git.example.com/repos/repo --username git --password secret --tls-client-cert-path ~/mycert.crt --tls-client-cert-key-path ~/mycert.key diff --git a/cmd/argocd/commands/repocreds.go b/cmd/argocd/commands/repocreds.go index cf764e7d84de9..e43b9713a2927 100644 --- a/cmd/argocd/commands/repocreds.go +++ b/cmd/argocd/commands/repocreds.go @@ -247,11 +247,17 @@ func NewRepoCredsListCommand(clientOpts *argocdclient.ClientOptions) *cobra.Comm Use: "list", Short: "List configured repository credentials", Example: templates.Examples(` - # List all the configured repository credentials + # List all repo urls argocd repocreds list - # List all the configured repository credentials in json format + # List all repo urls in json format argocd repocreds list -o json + + # List all repo urls in yaml format + argocd repocreds list -o yaml + + # List all repo urls in url format + argocd repocreds list -o url `), Run: func(c *cobra.Command, args []string) { ctx := c.Context() diff --git a/cmd/util/app.go b/cmd/util/app.go index d64c5ed02e6cb..e08ee80305c48 100644 --- a/cmd/util/app.go +++ b/cmd/util/app.go @@ -295,7 +295,7 @@ func SetAppSpecOptions(flags *pflag.FlagSet, spec *argoappv1.ApplicationSpec, ap Backoff: &argoappv1.Backoff{ Duration: appOpts.retryBackoffDuration.String(), MaxDuration: appOpts.retryBackoffMaxDuration.String(), - Factor: pointer.Int64Ptr(appOpts.retryBackoffFactor), + Factor: pointer.Int64(appOpts.retryBackoffFactor), }, } } else if appOpts.retryLimit == 0 { diff --git a/cmd/util/cluster.go b/cmd/util/cluster.go index 95c071c882b12..dffb52e775a97 100644 --- a/cmd/util/cluster.go +++ b/cmd/util/cluster.go @@ -144,6 +144,7 @@ type ClusterOptions struct { Upsert bool ServiceAccount string AwsRoleArn string + AwsProfile string AwsClusterName string SystemNamespace string Namespaces []string @@ -169,6 +170,7 @@ func AddClusterFlags(command *cobra.Command, opts *ClusterOptions) { command.Flags().BoolVar(&opts.InCluster, "in-cluster", false, "Indicates Argo CD resides inside this cluster and should connect using the internal k8s hostname (kubernetes.default.svc)") command.Flags().StringVar(&opts.AwsClusterName, "aws-cluster-name", "", "AWS Cluster name if set then aws cli eks token command will be used to access cluster") command.Flags().StringVar(&opts.AwsRoleArn, "aws-role-arn", "", "Optional AWS role arn. If set then AWS IAM Authenticator assumes a role to perform cluster operations instead of the default AWS credential provider chain.") + command.Flags().StringVar(&opts.AwsProfile, "aws-profile", "", "Optional AWS profile. If set then AWS IAM Authenticator uses this profile to perform cluster operations instead of the default AWS credential provider chain.") command.Flags().StringArrayVar(&opts.Namespaces, "namespace", nil, "List of namespaces which are allowed to manage") command.Flags().BoolVar(&opts.ClusterResources, "cluster-resources", false, "Indicates if cluster level resources should be managed. The setting is used only if list of managed namespaces is not empty.") command.Flags().StringVar(&opts.Name, "name", "", "Overwrite the cluster name") diff --git a/cmd/util/project.go b/cmd/util/project.go index ef157f6873081..fa446ceb3b41c 100644 --- a/cmd/util/project.go +++ b/cmd/util/project.go @@ -115,7 +115,7 @@ func GetOrphanedResourcesSettings(flagSet *pflag.FlagSet, opts ProjectOpts) *v1a if opts.orphanedResourcesEnabled || warnChanged { settings := v1alpha1.OrphanedResourcesMonitorSettings{} if warnChanged { - settings.Warn = pointer.BoolPtr(opts.orphanedResourcesWarn) + settings.Warn = pointer.Bool(opts.orphanedResourcesWarn) } return &settings } diff --git a/cmpserver/plugin/plugin.go b/cmpserver/plugin/plugin.go index f03b73f24dcf6..ca1e7592218ea 100644 --- a/cmpserver/plugin/plugin.go +++ b/cmpserver/plugin/plugin.go @@ -120,11 +120,16 @@ func runCommand(ctx context.Context, command Command, path string, env []string) logCtx.Error(err.Error()) return strings.TrimSuffix(output, "\n"), err } + + logCtx = logCtx.WithFields(log.Fields{ + "stderr": stderr.String(), + "command": command, + }) if len(output) == 0 { - log.WithFields(log.Fields{ - "stderr": stderr.String(), - "command": command, - }).Warn("Plugin command returned zero output") + logCtx.Warn("Plugin command returned zero output") + } else { + // Log stderr even on successfull commands to help develop plugins + logCtx.Info("Plugin command successfull") } return strings.TrimSuffix(output, "\n"), nil diff --git a/cmpserver/server.go b/cmpserver/server.go index bbb493f6b1d66..1d07e531394d3 100644 --- a/cmpserver/server.go +++ b/cmpserver/server.go @@ -65,7 +65,7 @@ func NewServer(initConstants plugin.CMPServerInitConstants) (*ArgoCDCMPServer, e grpc.MaxSendMsgSize(apiclient.MaxGRPCMessageSize), grpc.KeepaliveEnforcementPolicy( keepalive.EnforcementPolicy{ - MinTime: common.GRPCKeepAliveEnforcementMinimum, + MinTime: common.GetGRPCKeepAliveEnforcementMinimum(), }, ), } diff --git a/common/common.go b/common/common.go index d7c2d24738b58..2f053d7a28198 100644 --- a/common/common.go +++ b/common/common.go @@ -115,9 +115,9 @@ const ( LegacyShardingAlgorithm = "legacy" // RoundRobinShardingAlgorithm is a flag value that can be opted for Sharding Algorithm it uses an equal distribution accross all shards RoundRobinShardingAlgorithm = "round-robin" - DefaultShardingAlgorithm = LegacyShardingAlgorithm // AppControllerHeartbeatUpdateRetryCount is the retry count for updating the Shard Mapping to the Shard Mapping ConfigMap used by Application Controller AppControllerHeartbeatUpdateRetryCount = 3 + DefaultShardingAlgorithm = LegacyShardingAlgorithm ) // Dex related constants @@ -258,6 +258,11 @@ const ( EnvRedisName = "ARGOCD_REDIS_NAME" // EnvRedisHaProxyName is the name of the Argo CD Redis HA proxy component, as specified by the value under the LabelKeyAppName label key. EnvRedisHaProxyName = "ARGOCD_REDIS_HAPROXY_NAME" + // EnvGRPCKeepAliveMin defines the GRPCKeepAliveEnforcementMinimum, used in the grpc.KeepaliveEnforcementPolicy. Expects a "Duration" format (e.g. 10s). + EnvGRPCKeepAliveMin = "ARGOCD_GRPC_KEEP_ALIVE_MIN" + // EnvServerSideDiff defines the env var used to enable ServerSide Diff feature. + // If defined, value must be "true" or "false". + EnvServerSideDiff = "ARGOCD_APPLICATION_CONTROLLER_SERVER_SIDE_DIFF" ) // Config Management Plugin related constants @@ -351,11 +356,26 @@ const ( // gRPC settings const ( - GRPCKeepAliveEnforcementMinimum = 10 * time.Second - // GRPCKeepAliveTime is 2x enforcement minimum to ensure network jitter does not introduce ENHANCE_YOUR_CALM errors - GRPCKeepAliveTime = 2 * GRPCKeepAliveEnforcementMinimum + defaultGRPCKeepAliveEnforcementMinimum = 10 * time.Second ) +func GetGRPCKeepAliveEnforcementMinimum() time.Duration { + if GRPCKeepAliveMinStr := os.Getenv(EnvGRPCKeepAliveMin); GRPCKeepAliveMinStr != "" { + GRPCKeepAliveMin, err := time.ParseDuration(GRPCKeepAliveMinStr) + if err != nil { + logrus.Warnf("invalid env var value for %s: cannot parse: %s. Default value %s will be used.", EnvGRPCKeepAliveMin, err, defaultGRPCKeepAliveEnforcementMinimum) + return defaultGRPCKeepAliveEnforcementMinimum + } + return GRPCKeepAliveMin + } + return defaultGRPCKeepAliveEnforcementMinimum +} + +func GetGRPCKeepAliveTime() time.Duration { + // GRPCKeepAliveTime is 2x enforcement minimum to ensure network jitter does not introduce ENHANCE_YOUR_CALM errors + return 2 * GetGRPCKeepAliveEnforcementMinimum() +} + // Security severity logging const ( SecurityField = "security" diff --git a/common/common_test.go b/common/common_test.go new file mode 100644 index 0000000000000..5632c1e7a78cc --- /dev/null +++ b/common/common_test.go @@ -0,0 +1,46 @@ +package common + +import ( + "fmt" + "os" + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +// Test env var not set for EnvGRPCKeepAliveMin +func Test_GRPCKeepAliveMinNotSet(t *testing.T) { + grpcKeepAliveMin := GetGRPCKeepAliveEnforcementMinimum() + grpcKeepAliveExpectedMin := defaultGRPCKeepAliveEnforcementMinimum + assert.Equal(t, grpcKeepAliveExpectedMin, grpcKeepAliveMin) + + grpcKeepAliveTime := GetGRPCKeepAliveTime() + assert.Equal(t, 2*grpcKeepAliveExpectedMin, grpcKeepAliveTime) +} + +// Test valid env var set for EnvGRPCKeepAliveMin +func Test_GRPCKeepAliveMinIsSet(t *testing.T) { + numSeconds := 15 + os.Setenv(EnvGRPCKeepAliveMin, fmt.Sprintf("%ds", numSeconds)) + + grpcKeepAliveMin := GetGRPCKeepAliveEnforcementMinimum() + grpcKeepAliveExpectedMin := time.Duration(numSeconds) * time.Second + assert.Equal(t, grpcKeepAliveExpectedMin, grpcKeepAliveMin) + + grpcKeepAliveTime := GetGRPCKeepAliveTime() + assert.Equal(t, 2*grpcKeepAliveExpectedMin, grpcKeepAliveTime) +} + +// Test invalid env var set for EnvGRPCKeepAliveMin +func Test_GRPCKeepAliveMinIncorrectlySet(t *testing.T) { + numSeconds := 15 + os.Setenv(EnvGRPCKeepAliveMin, fmt.Sprintf("%d", numSeconds)) + + grpcKeepAliveMin := GetGRPCKeepAliveEnforcementMinimum() + grpcKeepAliveExpectedMin := defaultGRPCKeepAliveEnforcementMinimum + assert.Equal(t, grpcKeepAliveExpectedMin, grpcKeepAliveMin) + + grpcKeepAliveTime := GetGRPCKeepAliveTime() + assert.Equal(t, 2*grpcKeepAliveExpectedMin, grpcKeepAliveTime) +} diff --git a/controller/appcontroller.go b/controller/appcontroller.go index afa2a2d7b8186..f038b770c29c4 100644 --- a/controller/appcontroller.go +++ b/controller/appcontroller.go @@ -3,8 +3,10 @@ package controller import ( "context" "encoding/json" + goerrors "errors" "fmt" "math" + "math/rand" "net/http" "reflect" "runtime/debug" @@ -46,7 +48,6 @@ import ( "github.com/argoproj/argo-cd/v2/controller/sharding" "github.com/argoproj/argo-cd/v2/pkg/apis/application" appv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" - argov1alpha "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" appclientset "github.com/argoproj/argo-cd/v2/pkg/client/clientset/versioned" "github.com/argoproj/argo-cd/v2/pkg/client/informers/externalversions/application/v1alpha1" applisters "github.com/argoproj/argo-cd/v2/pkg/client/listers/application/v1alpha1" @@ -57,6 +58,7 @@ import ( kubeerrors "k8s.io/apimachinery/pkg/api/errors" + "github.com/argoproj/argo-cd/v2/pkg/ratelimiter" appstatecache "github.com/argoproj/argo-cd/v2/util/cache/appstate" "github.com/argoproj/argo-cd/v2/util/db" "github.com/argoproj/argo-cd/v2/util/errors" @@ -68,7 +70,7 @@ import ( const ( updateOperationStateTimeout = 1 * time.Second - defaultDeploymentInformerResyncDuration = 10 + defaultDeploymentInformerResyncDuration = 10 * time.Second // orphanedIndex contains application which monitor orphaned resources by namespace orphanedIndex = "orphaned" ) @@ -111,11 +113,11 @@ type ApplicationController struct { appInformer cache.SharedIndexInformer appLister applisters.ApplicationLister projInformer cache.SharedIndexInformer - deploymentInformer informerv1.DeploymentInformer appStateManager AppStateManager stateCache statecache.LiveStateCache statusRefreshTimeout time.Duration statusHardRefreshTimeout time.Duration + statusRefreshJitter time.Duration selfHealTimeout time.Duration repoClientset apiclient.Clientset db db.ArgoDB @@ -124,9 +126,13 @@ type ApplicationController struct { refreshRequestedAppsMutex *sync.Mutex metricsServer *metrics.MetricsServer kubectlSemaphore *semaphore.Weighted - clusterFilter func(cluster *appv1.Cluster) bool + clusterSharding sharding.ClusterShardingCache projByNameCache sync.Map applicationNamespaces []string + + // dynamicClusterDistributionEnabled if disabled deploymentInformer is never initialized + dynamicClusterDistributionEnabled bool + deploymentInformer informerv1.DeploymentInformer } // NewApplicationController creates new instance of ApplicationController. @@ -140,39 +146,50 @@ func NewApplicationController( kubectl kube.Kubectl, appResyncPeriod time.Duration, appHardResyncPeriod time.Duration, + appResyncJitter time.Duration, selfHealTimeout time.Duration, + repoErrorGracePeriod time.Duration, metricsPort int, metricsCacheExpiration time.Duration, metricsApplicationLabels []string, kubectlParallelismLimit int64, persistResourceHealth bool, - clusterFilter func(cluster *appv1.Cluster) bool, + clusterSharding sharding.ClusterShardingCache, applicationNamespaces []string, + rateLimiterConfig *ratelimiter.AppControllerRateLimiterConfig, + serverSideDiff bool, + dynamicClusterDistributionEnabled bool, ) (*ApplicationController, error) { - log.Infof("appResyncPeriod=%v, appHardResyncPeriod=%v", appResyncPeriod, appHardResyncPeriod) + log.Infof("appResyncPeriod=%v, appHardResyncPeriod=%v, appResyncJitter=%v", appResyncPeriod, appHardResyncPeriod, appResyncJitter) db := db.NewDB(namespace, settingsMgr, kubeClientset) + if rateLimiterConfig == nil { + rateLimiterConfig = ratelimiter.GetDefaultAppRateLimiterConfig() + log.Info("Using default workqueue rate limiter config") + } ctrl := ApplicationController{ - cache: argoCache, - namespace: namespace, - kubeClientset: kubeClientset, - kubectl: kubectl, - applicationClientset: applicationClientset, - repoClientset: repoClientset, - appRefreshQueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "app_reconciliation_queue"), - appOperationQueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "app_operation_processing_queue"), - projectRefreshQueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "project_reconciliation_queue"), - appComparisonTypeRefreshQueue: workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter()), - db: db, - statusRefreshTimeout: appResyncPeriod, - statusHardRefreshTimeout: appHardResyncPeriod, - refreshRequestedApps: make(map[string]CompareWith), - refreshRequestedAppsMutex: &sync.Mutex{}, - auditLogger: argo.NewAuditLogger(namespace, kubeClientset, common.ApplicationController), - settingsMgr: settingsMgr, - selfHealTimeout: selfHealTimeout, - clusterFilter: clusterFilter, - projByNameCache: sync.Map{}, - applicationNamespaces: applicationNamespaces, + cache: argoCache, + namespace: namespace, + kubeClientset: kubeClientset, + kubectl: kubectl, + applicationClientset: applicationClientset, + repoClientset: repoClientset, + appRefreshQueue: workqueue.NewNamedRateLimitingQueue(ratelimiter.NewCustomAppControllerRateLimiter(rateLimiterConfig), "app_reconciliation_queue"), + appOperationQueue: workqueue.NewNamedRateLimitingQueue(ratelimiter.NewCustomAppControllerRateLimiter(rateLimiterConfig), "app_operation_processing_queue"), + projectRefreshQueue: workqueue.NewNamedRateLimitingQueue(ratelimiter.NewCustomAppControllerRateLimiter(rateLimiterConfig), "project_reconciliation_queue"), + appComparisonTypeRefreshQueue: workqueue.NewRateLimitingQueue(ratelimiter.NewCustomAppControllerRateLimiter(rateLimiterConfig)), + db: db, + statusRefreshTimeout: appResyncPeriod, + statusHardRefreshTimeout: appHardResyncPeriod, + statusRefreshJitter: appResyncJitter, + refreshRequestedApps: make(map[string]CompareWith), + refreshRequestedAppsMutex: &sync.Mutex{}, + auditLogger: argo.NewAuditLogger(namespace, kubeClientset, common.ApplicationController), + settingsMgr: settingsMgr, + selfHealTimeout: selfHealTimeout, + clusterSharding: clusterSharding, + projByNameCache: sync.Map{}, + applicationNamespaces: applicationNamespaces, + dynamicClusterDistributionEnabled: dynamicClusterDistributionEnabled, } if kubectlParallelismLimit > 0 { ctrl.kubectlSemaphore = semaphore.NewWeighted(kubectlParallelismLimit) @@ -181,10 +198,11 @@ func NewApplicationController( appInformer, appLister := ctrl.newApplicationInformerAndLister() indexers := cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc} projInformer := v1alpha1.NewAppProjectInformer(applicationClientset, namespace, appResyncPeriod, indexers) - projInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{ + var err error + _, err = projInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{ AddFunc: func(obj interface{}) { if key, err := cache.MetaNamespaceKeyFunc(obj); err == nil { - ctrl.projectRefreshQueue.Add(key) + ctrl.projectRefreshQueue.AddRateLimited(key) if projMeta, ok := obj.(metav1.Object); ok { ctrl.InvalidateProjectsCache(projMeta.GetName()) } @@ -193,7 +211,7 @@ func NewApplicationController( }, UpdateFunc: func(old, new interface{}) { if key, err := cache.MetaNamespaceKeyFunc(new); err == nil { - ctrl.projectRefreshQueue.Add(key) + ctrl.projectRefreshQueue.AddRateLimited(key) if projMeta, ok := new.(metav1.Object); ok { ctrl.InvalidateProjectsCache(projMeta.GetName()) } @@ -201,6 +219,7 @@ func NewApplicationController( }, DeleteFunc: func(obj interface{}) { if key, err := cache.DeletionHandlingMetaNamespaceKeyFunc(obj); err == nil { + // immediately push to queue for deletes ctrl.projectRefreshQueue.Add(key) if projMeta, ok := obj.(metav1.Object); ok { ctrl.InvalidateProjectsCache(projMeta.GetName()) @@ -208,34 +227,45 @@ func NewApplicationController( } }, }) + if err != nil { + return nil, err + } factory := informers.NewSharedInformerFactoryWithOptions(ctrl.kubeClientset, defaultDeploymentInformerResyncDuration, informers.WithNamespace(settingsMgr.GetNamespace())) - deploymentInformer := factory.Apps().V1().Deployments() + + var deploymentInformer informerv1.DeploymentInformer + + // only initialize deployment informer if dynamic distribution is enabled + if dynamicClusterDistributionEnabled { + deploymentInformer = factory.Apps().V1().Deployments() + } readinessHealthCheck := func(r *http.Request) error { - applicationControllerName := env.StringFromEnv(common.EnvAppControllerName, common.DefaultApplicationControllerName) - appControllerDeployment, err := deploymentInformer.Lister().Deployments(settingsMgr.GetNamespace()).Get(applicationControllerName) - if err != nil { - if kubeerrors.IsNotFound(err) { - appControllerDeployment = nil - } else { - return fmt.Errorf("error retrieving Application Controller Deployment: %s", err) - } - } - if appControllerDeployment != nil { - if appControllerDeployment.Spec.Replicas != nil && int(*appControllerDeployment.Spec.Replicas) <= 0 { - return fmt.Errorf("application controller deployment replicas is not set or is less than 0, replicas: %d", appControllerDeployment.Spec.Replicas) + if dynamicClusterDistributionEnabled { + applicationControllerName := env.StringFromEnv(common.EnvAppControllerName, common.DefaultApplicationControllerName) + appControllerDeployment, err := deploymentInformer.Lister().Deployments(settingsMgr.GetNamespace()).Get(applicationControllerName) + if err != nil { + if kubeerrors.IsNotFound(err) { + appControllerDeployment = nil + } else { + return fmt.Errorf("error retrieving Application Controller Deployment: %s", err) + } } - shard := env.ParseNumFromEnv(common.EnvControllerShard, -1, -math.MaxInt32, math.MaxInt32) - if _, err := sharding.GetOrUpdateShardFromConfigMap(kubeClientset.(*kubernetes.Clientset), settingsMgr, int(*appControllerDeployment.Spec.Replicas), shard); err != nil { - return fmt.Errorf("error while updating the heartbeat for to the Shard Mapping ConfigMap: %s", err) + if appControllerDeployment != nil { + if appControllerDeployment.Spec.Replicas != nil && int(*appControllerDeployment.Spec.Replicas) <= 0 { + return fmt.Errorf("application controller deployment replicas is not set or is less than 0, replicas: %d", appControllerDeployment.Spec.Replicas) + } + shard := env.ParseNumFromEnv(common.EnvControllerShard, -1, -math.MaxInt32, math.MaxInt32) + if _, err := sharding.GetOrUpdateShardFromConfigMap(kubeClientset.(*kubernetes.Clientset), settingsMgr, int(*appControllerDeployment.Spec.Replicas), shard); err != nil { + return fmt.Errorf("error while updating the heartbeat for to the Shard Mapping ConfigMap: %s", err) + } } } return nil } metricsAddr := fmt.Sprintf("0.0.0.0:%d", metricsPort) - var err error + ctrl.metricsServer, err = metrics.NewMetricsServer(metricsAddr, appLister, ctrl.canProcessApp, readinessHealthCheck, metricsApplicationLabels) if err != nil { return nil, err @@ -246,8 +276,8 @@ func NewApplicationController( return nil, err } } - stateCache := statecache.NewLiveStateCache(db, appInformer, ctrl.settingsMgr, kubectl, ctrl.metricsServer, ctrl.handleObjectUpdated, clusterFilter, argo.NewResourceTracking()) - appStateManager := NewAppStateManager(db, applicationClientset, repoClientset, namespace, kubectl, ctrl.settingsMgr, stateCache, projInformer, ctrl.metricsServer, argoCache, ctrl.statusRefreshTimeout, argo.NewResourceTracking(), persistResourceHealth) + stateCache := statecache.NewLiveStateCache(db, appInformer, ctrl.settingsMgr, kubectl, ctrl.metricsServer, ctrl.handleObjectUpdated, clusterSharding, argo.NewResourceTracking()) + appStateManager := NewAppStateManager(db, applicationClientset, repoClientset, namespace, kubectl, ctrl.settingsMgr, stateCache, projInformer, ctrl.metricsServer, argoCache, ctrl.statusRefreshTimeout, argo.NewResourceTracking(), persistResourceHealth, repoErrorGracePeriod, serverSideDiff) ctrl.appInformer = appInformer ctrl.appLister = appLister ctrl.projInformer = projInformer @@ -756,7 +786,18 @@ func (ctrl *ApplicationController) Run(ctx context.Context, statusProcessors int go ctrl.appInformer.Run(ctx.Done()) go ctrl.projInformer.Run(ctx.Done()) - go ctrl.deploymentInformer.Informer().Run(ctx.Done()) + + if ctrl.dynamicClusterDistributionEnabled { + // only start deployment informer if dynamic distribution is enabled + go ctrl.deploymentInformer.Informer().Run(ctx.Done()) + } + + clusters, err := ctrl.db.ListClusters(ctx) + if err != nil { + log.Warnf("Cannot init sharding. Error while querying clusters list from database: %v", err) + } else { + ctrl.clusterSharding.Init(clusters) + } errors.CheckError(ctrl.stateCache.Init()) @@ -811,8 +852,8 @@ func (ctrl *ApplicationController) requestAppRefresh(appName string, compareWith ctrl.appRefreshQueue.AddAfter(key, *after) ctrl.appOperationQueue.AddAfter(key, *after) } else { - ctrl.appRefreshQueue.Add(key) - ctrl.appOperationQueue.Add(key) + ctrl.appRefreshQueue.AddRateLimited(key) + ctrl.appOperationQueue.AddRateLimited(key) } } } @@ -871,11 +912,10 @@ func (ctrl *ApplicationController) processAppOperationQueueItem() (processNext b if app.Operation != nil { ctrl.processRequestedAppOperation(app) - } else if app.DeletionTimestamp != nil && app.CascadedDeletion() { - _, err = ctrl.finalizeApplicationDeletion(app, func(project string) ([]*appv1.Cluster, error) { + } else if app.DeletionTimestamp != nil { + if err = ctrl.finalizeApplicationDeletion(app, func(project string) ([]*appv1.Cluster, error) { return ctrl.db.GetProjectClusters(context.Background(), project) - }) - if err != nil { + }); err != nil { ctrl.setAppCondition(app, appv1.ApplicationCondition{ Type: appv1.ApplicationConditionDeletionError, Message: err.Error(), @@ -1010,57 +1050,63 @@ func (ctrl *ApplicationController) getPermittedAppLiveObjects(app *appv1.Applica return objsMap, nil } -func (ctrl *ApplicationController) finalizeApplicationDeletion(app *appv1.Application, projectClusters func(project string) ([]*appv1.Cluster, error)) ([]*unstructured.Unstructured, error) { +func (ctrl *ApplicationController) isValidDestination(app *appv1.Application) (bool, *appv1.Cluster) { + // Validate the cluster using the Application destination's `name` field, if applicable, + // and set the Server field, if needed. + if err := argo.ValidateDestination(context.Background(), &app.Spec.Destination, ctrl.db); err != nil { + log.Warnf("Unable to validate destination of the Application being deleted: %v", err) + return false, nil + } + + cluster, err := ctrl.db.GetCluster(context.Background(), app.Spec.Destination.Server) + if err != nil { + log.Warnf("Unable to locate cluster URL for Application being deleted: %v", err) + return false, nil + } + return true, cluster +} + +func (ctrl *ApplicationController) finalizeApplicationDeletion(app *appv1.Application, projectClusters func(project string) ([]*appv1.Cluster, error)) error { logCtx := log.WithField("application", app.QualifiedName()) - logCtx.Infof("Deleting resources") // Get refreshed application info, since informer app copy might be stale app, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(app.Namespace).Get(context.Background(), app.Name, metav1.GetOptions{}) if err != nil { if !apierr.IsNotFound(err) { logCtx.Errorf("Unable to get refreshed application info prior deleting resources: %v", err) } - return nil, nil + return nil } proj, err := ctrl.getAppProj(app) if err != nil { - return nil, err - } - - // validDestination is true if the Application destination points to a cluster that is managed by Argo CD - // (and thus either a cluster secret exists for it, or it's local); validDestination is false otherwise. - validDestination := true - - // Validate the cluster using the Application destination's `name` field, if applicable, - // and set the Server field, if needed. - if err := argo.ValidateDestination(context.Background(), &app.Spec.Destination, ctrl.db); err != nil { - log.Warnf("Unable to validate destination of the Application being deleted: %v", err) - validDestination = false + return err } - objs := make([]*unstructured.Unstructured, 0) - var cluster *appv1.Cluster - - // Attempt to validate the destination via its URL - if validDestination { - if cluster, err = ctrl.db.GetCluster(context.Background(), app.Spec.Destination.Server); err != nil { - log.Warnf("Unable to locate cluster URL for Application being deleted: %v", err) - validDestination = false + isValid, cluster := ctrl.isValidDestination(app) + if !isValid { + app.UnSetCascadedDeletion() + app.UnSetPostDeleteFinalizer() + if err := ctrl.updateFinalizers(app); err != nil { + return err } + logCtx.Infof("Resource entries removed from undefined cluster") + return nil } + config := metrics.AddMetricsTransportWrapper(ctrl.metricsServer, app, cluster.RESTConfig()) - if validDestination { + if app.CascadedDeletion() { + logCtx.Infof("Deleting resources") // ApplicationDestination points to a valid cluster, so we may clean up the live objects - + objs := make([]*unstructured.Unstructured, 0) objsMap, err := ctrl.getPermittedAppLiveObjects(app, proj, projectClusters) if err != nil { - return nil, err + return err } for k := range objsMap { // Wait for objects pending deletion to complete before proceeding with next sync wave if objsMap[k].GetDeletionTimestamp() != nil { logCtx.Infof("%d objects remaining for deletion", len(objsMap)) - return objs, nil + return nil } if ctrl.shouldBeDeleted(app, objsMap[k]) { @@ -1068,8 +1114,6 @@ func (ctrl *ApplicationController) finalizeApplicationDeletion(app *appv1.Applic } } - config := metrics.AddMetricsTransportWrapper(ctrl.metricsServer, app, cluster.RESTConfig()) - filteredObjs := FilterObjectsForDeletion(objs) propagationPolicy := metav1.DeletePropagationForeground @@ -1083,12 +1127,12 @@ func (ctrl *ApplicationController) finalizeApplicationDeletion(app *appv1.Applic return ctrl.kubectl.DeleteResource(context.Background(), config, obj.GroupVersionKind(), obj.GetName(), obj.GetNamespace(), metav1.DeleteOptions{PropagationPolicy: &propagationPolicy}) }) if err != nil { - return objs, err + return err } objsMap, err = ctrl.getPermittedAppLiveObjects(app, proj, projectClusters) if err != nil { - return nil, err + return err } for k, obj := range objsMap { @@ -1098,38 +1142,67 @@ func (ctrl *ApplicationController) finalizeApplicationDeletion(app *appv1.Applic } if len(objsMap) > 0 { logCtx.Infof("%d objects remaining for deletion", len(objsMap)) - return objs, nil + return nil } + logCtx.Infof("Successfully deleted %d resources", len(objs)) + app.UnSetCascadedDeletion() + return ctrl.updateFinalizers(app) } - if err := ctrl.cache.SetAppManagedResources(app.Name, nil); err != nil { - return objs, err - } + if app.HasPostDeleteFinalizer() { + objsMap, err := ctrl.getPermittedAppLiveObjects(app, proj, projectClusters) + if err != nil { + return err + } - if err := ctrl.cache.SetAppResourcesTree(app.Name, nil); err != nil { - return objs, err + done, err := ctrl.executePostDeleteHooks(app, proj, objsMap, config, logCtx) + if err != nil { + return err + } + if !done { + return nil + } + app.UnSetPostDeleteFinalizer() + return ctrl.updateFinalizers(app) } - if err := ctrl.removeCascadeFinalizer(app); err != nil { - return objs, err + if app.HasPostDeleteFinalizer("cleanup") { + objsMap, err := ctrl.getPermittedAppLiveObjects(app, proj, projectClusters) + if err != nil { + return err + } + + done, err := ctrl.cleanupPostDeleteHooks(objsMap, config, logCtx) + if err != nil { + return err + } + if !done { + return nil + } + app.UnSetPostDeleteFinalizer("cleanup") + return ctrl.updateFinalizers(app) } - if validDestination { - logCtx.Infof("Successfully deleted %d resources", len(objs)) - } else { - logCtx.Infof("Resource entries removed from undefined cluster") + if !app.CascadedDeletion() && !app.HasPostDeleteFinalizer() { + if err := ctrl.cache.SetAppManagedResources(app.Name, nil); err != nil { + return err + } + + if err := ctrl.cache.SetAppResourcesTree(app.Name, nil); err != nil { + return err + } + ctrl.projectRefreshQueue.Add(fmt.Sprintf("%s/%s", ctrl.namespace, app.Spec.GetProject())) } - ctrl.projectRefreshQueue.Add(fmt.Sprintf("%s/%s", ctrl.namespace, app.Spec.GetProject())) - return objs, nil + return nil } -func (ctrl *ApplicationController) removeCascadeFinalizer(app *appv1.Application) error { +func (ctrl *ApplicationController) updateFinalizers(app *appv1.Application) error { _, err := ctrl.getAppProj(app) if err != nil { return fmt.Errorf("error getting project: %w", err) } - app.UnSetCascadedDeletion() + var patch []byte patch, _ = json.Marshal(map[string]interface{}{ "metadata": map[string]interface{}{ @@ -1319,8 +1392,7 @@ func (ctrl *ApplicationController) setOperationState(app *appv1.Application, sta } kube.RetryUntilSucceed(context.Background(), updateOperationStateTimeout, "Update application operation state", logutils.NewLogrusLogger(logutils.NewWithCurrentConfig()), func() error { - appClient := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(app.Namespace) - _, err = appClient.Patch(context.Background(), app.Name, types.MergePatchType, patchJSON, metav1.PatchOptions{}) + _, err := ctrl.PatchAppWithWriteBack(context.Background(), app.Name, app.Namespace, types.MergePatchType, patchJSON, metav1.PatchOptions{}) if err != nil { // Stop retrying updating deleted application if apierr.IsNotFound(err) { @@ -1358,6 +1430,27 @@ func (ctrl *ApplicationController) setOperationState(app *appv1.Application, sta } } +// writeBackToInformer writes a just recently updated App back into the informer cache. +// This prevents the situation where the controller operates on a stale app and repeats work +func (ctrl *ApplicationController) writeBackToInformer(app *appv1.Application) { + logCtx := log.WithFields(log.Fields{"application": app.Name, "appNamespace": app.Namespace, "project": app.Spec.Project, "informer-writeBack": true}) + err := ctrl.appInformer.GetStore().Update(app) + if err != nil { + logCtx.Errorf("failed to update informer store: %v", err) + return + } +} + +// PatchAppWithWriteBack patches an application and writes it back to the informer cache +func (ctrl *ApplicationController) PatchAppWithWriteBack(ctx context.Context, name, ns string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *appv1.Application, err error) { + patchedApp, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(ns).Patch(ctx, name, pt, data, opts, subresources...) + if err != nil { + return patchedApp, err + } + ctrl.writeBackToInformer(patchedApp) + return patchedApp, err +} + func (ctrl *ApplicationController) processAppRefreshQueueItem() (processNext bool) { patchMs := time.Duration(0) // time spent in doing patch/update calls setOpMs := time.Duration(0) // time spent in doing Operation patch calls in autosync @@ -1480,10 +1573,15 @@ func (ctrl *ApplicationController) processAppRefreshQueueItem() (processNext boo } now := metav1.Now() - compareResult := ctrl.appStateManager.CompareAppState(app, project, revisions, sources, + compareResult, err := ctrl.appStateManager.CompareAppState(app, project, revisions, sources, refreshType == appv1.RefreshTypeHard, comparisonLevel == CompareWithLatestForceResolve, localManifests, hasMultipleSources) + if goerrors.Is(err, CompareStateRepoError) { + logCtx.Warnf("Ignoring temporary failed attempt to compare app state against repo: %v", err) + return // short circuit if git error is encountered + } + for k, v := range compareResult.timings { logCtx = logCtx.WithField(k, v.Milliseconds()) } @@ -1528,6 +1626,20 @@ func (ctrl *ApplicationController) processAppRefreshQueueItem() (processNext boo app.Status.SourceTypes = compareResult.appSourceTypes app.Status.ControllerNamespace = ctrl.namespace patchMs = ctrl.persistAppStatus(origApp, &app.Status) + if (compareResult.hasPostDeleteHooks != app.HasPostDeleteFinalizer() || compareResult.hasPostDeleteHooks != app.HasPostDeleteFinalizer("cleanup")) && + app.GetDeletionTimestamp() == nil { + if compareResult.hasPostDeleteHooks { + app.SetPostDeleteFinalizer() + app.SetPostDeleteFinalizer("cleanup") + } else { + app.UnSetPostDeleteFinalizer() + app.UnSetPostDeleteFinalizer("cleanup") + } + + if err := ctrl.updateFinalizers(app); err != nil { + logCtx.Errorf("Failed to update finalizers: %v", err) + } + } return } @@ -1551,6 +1663,7 @@ func (ctrl *ApplicationController) needRefreshAppStatus(app *appv1.Application, var reason string compareWith := CompareWithLatest refreshType := appv1.RefreshTypeNormal + softExpired := app.Status.ReconciledAt == nil || app.Status.ReconciledAt.Add(statusRefreshTimeout).Before(time.Now().UTC()) hardExpired := (app.Status.ReconciledAt == nil || app.Status.ReconciledAt.Add(statusHardRefreshTimeout).Before(time.Now().UTC())) && statusHardRefreshTimeout.Seconds() != 0 @@ -1569,7 +1682,7 @@ func (ctrl *ApplicationController) needRefreshAppStatus(app *appv1.Application, } else if hardExpired || softExpired { // The commented line below mysteriously crashes if app.Status.ReconciledAt is nil // reason = fmt.Sprintf("comparison expired. reconciledAt: %v, expiry: %v", app.Status.ReconciledAt, statusRefreshTimeout) - //TODO: find existing Golang bug or create a new one + // TODO: find existing Golang bug or create a new one reconciledAtStr := "never" if app.Status.ReconciledAt != nil { reconciledAtStr = app.Status.ReconciledAt.String() @@ -1631,8 +1744,7 @@ func (ctrl *ApplicationController) normalizeApplication(orig, app *appv1.Applica if err != nil { logCtx.Errorf("error constructing app spec patch: %v", err) } else if modified { - appClient := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(app.Namespace) - _, err = appClient.Patch(context.Background(), app.Name, types.MergePatchType, patch, metav1.PatchOptions{}) + _, err := ctrl.PatchAppWithWriteBack(context.Background(), app.Name, app.Namespace, types.MergePatchType, patch, metav1.PatchOptions{}) if err != nil { logCtx.Errorf("Error persisting normalized application spec: %v", err) } else { @@ -1676,8 +1788,7 @@ func (ctrl *ApplicationController) persistAppStatus(orig *appv1.Application, new defer func() { patchMs = time.Since(start) }() - appClient := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(orig.Namespace) - _, err = appClient.Patch(context.Background(), orig.Name, types.MergePatchType, patch, metav1.PatchOptions{}) + _, err = ctrl.PatchAppWithWriteBack(context.Background(), orig.Name, orig.Namespace, types.MergePatchType, patch, metav1.PatchOptions{}) if err != nil { logCtx.Warnf("Error updating application: %v", err) } else { @@ -1787,11 +1898,20 @@ func (ctrl *ApplicationController) autoSync(app *appv1.Application, syncStatus * appIf := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(app.Namespace) start := time.Now() - _, err := argo.SetAppOperation(appIf, app.Name, &op) + updatedApp, err := argo.SetAppOperation(appIf, app.Name, &op) setOpTime := time.Since(start) if err != nil { + if goerrors.Is(err, argo.ErrAnotherOperationInProgress) { + // skipping auto-sync because another operation is in progress and was not noticed due to stale data in informer + // it is safe to skip auto-sync because it is already running + logCtx.Warnf("Failed to initiate auto-sync to %s: %v", desiredCommitSHA, err) + return nil, 0 + } + logCtx.Errorf("Failed to initiate auto-sync to %s: %v", desiredCommitSHA, err) return &appv1.ApplicationCondition{Type: appv1.ApplicationConditionSyncError, Message: err.Error()}, setOpTime + } else { + ctrl.writeBackToInformer(updatedApp) } message := fmt.Sprintf("Initiated automated sync to '%s'", desiredCommitSHA) ctrl.auditLogger.LogAppEvent(app, argo.EventInfo{Reason: argo.EventReasonOperationStarted, Type: v1.EventTypeNormal}, message, "") @@ -1884,15 +2004,11 @@ func (ctrl *ApplicationController) canProcessApp(obj interface{}) bool { } } - if ctrl.clusterFilter != nil { - cluster, err := ctrl.db.GetCluster(context.Background(), app.Spec.Destination.Server) - if err != nil { - return ctrl.clusterFilter(nil) - } - return ctrl.clusterFilter(cluster) + cluster, err := ctrl.db.GetCluster(context.Background(), app.Spec.Destination.Server) + if err != nil { + return ctrl.clusterSharding.IsManagedCluster(nil) } - - return true + return ctrl.clusterSharding.IsManagedCluster(cluster) } func (ctrl *ApplicationController) newApplicationInformerAndLister() (cache.SharedIndexInformer, applisters.ApplicationLister) { @@ -1979,7 +2095,7 @@ func (ctrl *ApplicationController) newApplicationInformerAndLister() (cache.Shar }, ) lister := applisters.NewApplicationLister(informer.GetIndexer()) - informer.AddEventHandler( + _, err := informer.AddEventHandler( cache.ResourceEventHandlerFuncs{ AddFunc: func(obj interface{}) { if !ctrl.canProcessApp(obj) { @@ -1987,8 +2103,8 @@ func (ctrl *ApplicationController) newApplicationInformerAndLister() (cache.Shar } key, err := cache.MetaNamespaceKeyFunc(obj) if err == nil { - ctrl.appRefreshQueue.Add(key) - ctrl.appOperationQueue.Add(key) + ctrl.appRefreshQueue.AddRateLimited(key) + ctrl.appOperationQueue.AddRateLimited(key) } }, UpdateFunc: func(old, new interface{}) { @@ -2000,15 +2116,26 @@ func (ctrl *ApplicationController) newApplicationInformerAndLister() (cache.Shar if err != nil { return } + var compareWith *CompareWith + var delay *time.Duration + oldApp, oldOK := old.(*appv1.Application) newApp, newOK := new.(*appv1.Application) - if oldOK && newOK && automatedSyncEnabled(oldApp, newApp) { - log.WithField("application", newApp.QualifiedName()).Info("Enabled automated sync") - compareWith = CompareWithLatest.Pointer() + if oldOK && newOK { + if automatedSyncEnabled(oldApp, newApp) { + log.WithField("application", newApp.QualifiedName()).Info("Enabled automated sync") + compareWith = CompareWithLatest.Pointer() + } + if ctrl.statusRefreshJitter != 0 && oldApp.ResourceVersion == newApp.ResourceVersion { + // Handler is refreshing the apps, add a random jitter to spread the load and avoid spikes + jitter := time.Duration(float64(ctrl.statusRefreshJitter) * rand.Float64()) + delay = &jitter + } } - ctrl.requestAppRefresh(newApp.QualifiedName(), compareWith, nil) - ctrl.appOperationQueue.Add(key) + + ctrl.requestAppRefresh(newApp.QualifiedName(), compareWith, delay) + ctrl.appOperationQueue.AddRateLimited(key) }, DeleteFunc: func(obj interface{}) { if !ctrl.canProcessApp(obj) { @@ -2018,11 +2145,15 @@ func (ctrl *ApplicationController) newApplicationInformerAndLister() (cache.Shar // key function. key, err := cache.DeletionHandlingMetaNamespaceKeyFunc(obj) if err == nil { + // for deletes, we immediately add to the refresh queue ctrl.appRefreshQueue.Add(key) } }, }, ) + if err != nil { + return nil, nil + } return informer, lister } @@ -2040,7 +2171,7 @@ func (ctrl *ApplicationController) projectErrorToCondition(err error, app *appv1 } func (ctrl *ApplicationController) RegisterClusterSecretUpdater(ctx context.Context) { - updater := NewClusterInfoUpdater(ctrl.stateCache, ctrl.db, ctrl.appLister.Applications(""), ctrl.cache, ctrl.clusterFilter, ctrl.getAppProj, ctrl.namespace) + updater := NewClusterInfoUpdater(ctrl.stateCache, ctrl.db, ctrl.appLister.Applications(""), ctrl.cache, ctrl.clusterSharding.IsManagedCluster, ctrl.getAppProj, ctrl.namespace) go updater.Run(ctx) } @@ -2092,4 +2223,4 @@ func (ctrl *ApplicationController) toAppQualifiedName(appName, appNamespace stri return fmt.Sprintf("%s/%s", appNamespace, appName) } -type ClusterFilterFunction func(c *argov1alpha.Cluster, distributionFunction sharding.DistributionFunction) bool +type ClusterFilterFunction func(c *appv1.Cluster, distributionFunction sharding.DistributionFunction) bool diff --git a/controller/appcontroller_test.go b/controller/appcontroller_test.go index cfb2141664348..33a29bc5ca3f8 100644 --- a/controller/appcontroller_test.go +++ b/controller/appcontroller_test.go @@ -7,18 +7,22 @@ import ( "testing" "time" + "github.com/argoproj/gitops-engine/pkg/utils/kube/kubetest" "github.com/sirupsen/logrus" + "github.com/stretchr/testify/require" "k8s.io/apimachinery/pkg/api/resource" + "k8s.io/client-go/rest" clustercache "github.com/argoproj/gitops-engine/pkg/cache" "github.com/argoproj/argo-cd/v2/common" statecache "github.com/argoproj/argo-cd/v2/controller/cache" + "github.com/argoproj/argo-cd/v2/controller/sharding" + dbmocks "github.com/argoproj/argo-cd/v2/util/db/mocks" "github.com/argoproj/gitops-engine/pkg/cache/mocks" synccommon "github.com/argoproj/gitops-engine/pkg/sync/common" "github.com/argoproj/gitops-engine/pkg/utils/kube" - "github.com/argoproj/gitops-engine/pkg/utils/kube/kubetest" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" corev1 "k8s.io/api/core/v1" @@ -59,7 +63,24 @@ type fakeData struct { applicationNamespaces []string } -func newFakeController(data *fakeData) *ApplicationController { +type MockKubectl struct { + kube.Kubectl + + DeletedResources []kube.ResourceKey + CreatedResources []*unstructured.Unstructured +} + +func (m *MockKubectl) CreateResource(ctx context.Context, config *rest.Config, gvk schema.GroupVersionKind, name string, namespace string, obj *unstructured.Unstructured, createOptions metav1.CreateOptions, subresources ...string) (*unstructured.Unstructured, error) { + m.CreatedResources = append(m.CreatedResources, obj) + return m.Kubectl.CreateResource(ctx, config, gvk, name, namespace, obj, createOptions, subresources...) +} + +func (m *MockKubectl) DeleteResource(ctx context.Context, config *rest.Config, gvk schema.GroupVersionKind, name string, namespace string, deleteOptions metav1.DeleteOptions) error { + m.DeletedResources = append(m.DeletedResources, kube.NewResourceKey(gvk.Group, gvk.Kind, namespace, name)) + return m.Kubectl.DeleteResource(ctx, config, gvk, name, namespace, deleteOptions) +} + +func newFakeController(data *fakeData, repoErr error) *ApplicationController { var clust corev1.Secret err := yaml.Unmarshal([]byte(fakeCluster), &clust) if err != nil { @@ -71,10 +92,18 @@ func newFakeController(data *fakeData) *ApplicationController { if len(data.manifestResponses) > 0 { for _, response := range data.manifestResponses { - mockRepoClient.On("GenerateManifest", mock.Anything, mock.Anything).Return(response, nil).Once() + if repoErr != nil { + mockRepoClient.On("GenerateManifest", mock.Anything, mock.Anything).Return(response, repoErr).Once() + } else { + mockRepoClient.On("GenerateManifest", mock.Anything, mock.Anything).Return(response, nil).Once() + } } } else { - mockRepoClient.On("GenerateManifest", mock.Anything, mock.Anything).Return(data.manifestResponse, nil) + if repoErr != nil { + mockRepoClient.On("GenerateManifest", mock.Anything, mock.Anything).Return(data.manifestResponse, repoErr).Once() + } else { + mockRepoClient.On("GenerateManifest", mock.Anything, mock.Anything).Return(data.manifestResponse, nil).Once() + } } mockRepoClientset := mockrepoclient.Clientset{RepoServerServiceClient: &mockRepoClient} @@ -101,7 +130,7 @@ func newFakeController(data *fakeData) *ApplicationController { } kubeClient := fake.NewSimpleClientset(&clust, &cm, &secret) settingsMgr := settings.NewSettingsManager(context.Background(), kubeClient, test.FakeArgoCDNamespace) - kubectl := &kubetest.MockKubectlCmd{} + kubectl := &MockKubectl{Kubectl: &kubetest.MockKubectlCmd{}} ctrl, err := NewApplicationController( test.FakeArgoCDNamespace, settingsMgr, @@ -115,7 +144,9 @@ func newFakeController(data *fakeData) *ApplicationController { kubectl, time.Minute, time.Hour, + time.Second, time.Minute, + time.Second*10, common.DefaultPortArgoCDMetrics, data.metricsCacheExpiration, []string{}, @@ -123,7 +154,15 @@ func newFakeController(data *fakeData) *ApplicationController { true, nil, data.applicationNamespaces, + nil, + + false, + false, ) + db := &dbmocks.ArgoDB{} + db.On("GetApplicationControllerReplicas").Return(1) + // Setting a default sharding algorithm for the tests where we cannot set it. + ctrl.clusterSharding = sharding.NewClusterSharding(db, 0, 1, common.DefaultShardingAlgorithm) if err != nil { panic(err) } @@ -327,6 +366,38 @@ metadata: data: ` +var fakePostDeleteHook = ` +{ + "apiVersion": "v1", + "kind": "Pod", + "metadata": { + "name": "post-delete-hook", + "namespace": "default", + "labels": { + "app.kubernetes.io/instance": "my-app" + }, + "annotations": { + "argocd.argoproj.io/hook": "PostDelete", + "argocd.argoproj.io/hook-delete-policy": "HookSucceeded" + } + }, + "spec": { + "containers": [ + { + "name": "post-delete-hook", + "image": "busybox", + "restartPolicy": "Never", + "command": [ + "/bin/sh", + "-c", + "sleep 5 && echo hello from the post-delete-hook pod" + ] + } + ] + } +} +` + func newFakeApp() *v1alpha1.Application { return createFakeApp(fakeApp) } @@ -361,9 +432,18 @@ func newFakeCM() map[string]interface{} { return cm } +func newFakePostDeleteHook() map[string]interface{} { + var cm map[string]interface{} + err := yaml.Unmarshal([]byte(fakePostDeleteHook), &cm) + if err != nil { + panic(err) + } + return cm +} + func TestAutoSync(t *testing.T) { app := newFakeApp() - ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}) + ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil) syncStatus := v1alpha1.SyncStatus{ Status: v1alpha1.SyncStatusCodeOutOfSync, Revision: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", @@ -380,7 +460,7 @@ func TestAutoSync(t *testing.T) { func TestAutoSyncNotAllowEmpty(t *testing.T) { app := newFakeApp() app.Spec.SyncPolicy.Automated.Prune = true - ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}) + ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil) syncStatus := v1alpha1.SyncStatus{ Status: v1alpha1.SyncStatusCodeOutOfSync, Revision: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", @@ -393,7 +473,7 @@ func TestAutoSyncAllowEmpty(t *testing.T) { app := newFakeApp() app.Spec.SyncPolicy.Automated.Prune = true app.Spec.SyncPolicy.Automated.AllowEmpty = true - ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}) + ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil) syncStatus := v1alpha1.SyncStatus{ Status: v1alpha1.SyncStatusCodeOutOfSync, Revision: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", @@ -407,7 +487,7 @@ func TestSkipAutoSync(t *testing.T) { // Set current to 'aaaaa', desired to 'aaaa' and mark system OutOfSync t.Run("PreviouslySyncedToRevision", func(t *testing.T) { app := newFakeApp() - ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}) + ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil) syncStatus := v1alpha1.SyncStatus{ Status: v1alpha1.SyncStatusCodeOutOfSync, Revision: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", @@ -422,7 +502,7 @@ func TestSkipAutoSync(t *testing.T) { // Verify we skip when we are already Synced (even if revision is different) t.Run("AlreadyInSyncedState", func(t *testing.T) { app := newFakeApp() - ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}) + ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil) syncStatus := v1alpha1.SyncStatus{ Status: v1alpha1.SyncStatusCodeSynced, Revision: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", @@ -438,7 +518,7 @@ func TestSkipAutoSync(t *testing.T) { t.Run("AutoSyncIsDisabled", func(t *testing.T) { app := newFakeApp() app.Spec.SyncPolicy = nil - ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}) + ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil) syncStatus := v1alpha1.SyncStatus{ Status: v1alpha1.SyncStatusCodeOutOfSync, Revision: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", @@ -455,7 +535,7 @@ func TestSkipAutoSync(t *testing.T) { app := newFakeApp() now := metav1.Now() app.DeletionTimestamp = &now - ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}) + ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil) syncStatus := v1alpha1.SyncStatus{ Status: v1alpha1.SyncStatusCodeOutOfSync, Revision: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", @@ -481,7 +561,7 @@ func TestSkipAutoSync(t *testing.T) { Source: *app.Spec.Source.DeepCopy(), }, } - ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}) + ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil) syncStatus := v1alpha1.SyncStatus{ Status: v1alpha1.SyncStatusCodeOutOfSync, Revision: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", @@ -495,7 +575,7 @@ func TestSkipAutoSync(t *testing.T) { t.Run("NeedsToPruneResourcesOnlyButAutomatedPruneDisabled", func(t *testing.T) { app := newFakeApp() - ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}) + ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil) syncStatus := v1alpha1.SyncStatus{ Status: v1alpha1.SyncStatusCodeOutOfSync, Revision: "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", @@ -521,7 +601,7 @@ func TestAutoSyncIndicateError(t *testing.T) { }, }, } - ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}) + ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil) syncStatus := v1alpha1.SyncStatus{ Status: v1alpha1.SyncStatusCodeOutOfSync, Revision: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", @@ -556,7 +636,7 @@ func TestAutoSyncParameterOverrides(t *testing.T) { }, }, } - ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}) + ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil) syncStatus := v1alpha1.SyncStatus{ Status: v1alpha1.SyncStatusCodeOutOfSync, Revision: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", @@ -609,12 +689,12 @@ func TestFinalizeAppDeletion(t *testing.T) { // Ensure app can be deleted cascading t.Run("CascadingDelete", func(t *testing.T) { app := newFakeApp() + app.SetCascadedDeletion(v1alpha1.ResourcesFinalizerName) app.Spec.Destination.Namespace = test.FakeArgoCDNamespace appObj := kube.MustToUnstructured(&app) ctrl := newFakeController(&fakeData{apps: []runtime.Object{app, &defaultProj}, managedLiveObjs: map[kube.ResourceKey]*unstructured.Unstructured{ kube.GetResourceKey(appObj): appObj, - }}) - + }}, nil) patched := false fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset) defaultReactor := fakeAppCs.ReactionChain[0] @@ -624,9 +704,9 @@ func TestFinalizeAppDeletion(t *testing.T) { }) fakeAppCs.AddReactor("patch", "*", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) { patched = true - return true, nil, nil + return true, &v1alpha1.Application{}, nil }) - _, err := ctrl.finalizeApplicationDeletion(app, func(project string) ([]*v1alpha1.Cluster, error) { + err := ctrl.finalizeApplicationDeletion(app, func(project string) ([]*v1alpha1.Cluster, error) { return []*v1alpha1.Cluster{}, nil }) assert.NoError(t, err) @@ -652,6 +732,7 @@ func TestFinalizeAppDeletion(t *testing.T) { }, } app := newFakeApp() + app.SetCascadedDeletion(v1alpha1.ResourcesFinalizerName) app.Spec.Destination.Namespace = test.FakeArgoCDNamespace app.Spec.Project = "restricted" appObj := kube.MustToUnstructured(&app) @@ -663,7 +744,7 @@ func TestFinalizeAppDeletion(t *testing.T) { kube.GetResourceKey(appObj): appObj, kube.GetResourceKey(strayObj): strayObj, }, - }) + }, nil) patched := false fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset) @@ -674,9 +755,9 @@ func TestFinalizeAppDeletion(t *testing.T) { }) fakeAppCs.AddReactor("patch", "*", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) { patched = true - return true, nil, nil + return true, &v1alpha1.Application{}, nil }) - objs, err := ctrl.finalizeApplicationDeletion(app, func(project string) ([]*v1alpha1.Cluster, error) { + err := ctrl.finalizeApplicationDeletion(app, func(project string) ([]*v1alpha1.Cluster, error) { return []*v1alpha1.Cluster{}, nil }) assert.NoError(t, err) @@ -687,18 +768,20 @@ func TestFinalizeAppDeletion(t *testing.T) { } // Managed objects must be empty assert.Empty(t, objsMap) + // Loop through all deleted objects, ensure that test-cm is none of them - for _, o := range objs { - assert.NotEqual(t, "test-cm", o.GetName()) + for _, o := range ctrl.kubectl.(*MockKubectl).DeletedResources { + assert.NotEqual(t, "test-cm", o.Name) } }) t.Run("DeleteWithDestinationClusterName", func(t *testing.T) { app := newFakeAppWithDestName() + app.SetCascadedDeletion(v1alpha1.ResourcesFinalizerName) appObj := kube.MustToUnstructured(&app) ctrl := newFakeController(&fakeData{apps: []runtime.Object{app, &defaultProj}, managedLiveObjs: map[kube.ResourceKey]*unstructured.Unstructured{ kube.GetResourceKey(appObj): appObj, - }}) + }}, nil) patched := false fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset) defaultReactor := fakeAppCs.ReactionChain[0] @@ -708,9 +791,9 @@ func TestFinalizeAppDeletion(t *testing.T) { }) fakeAppCs.AddReactor("patch", "*", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) { patched = true - return true, nil, nil + return true, &v1alpha1.Application{}, nil }) - _, err := ctrl.finalizeApplicationDeletion(app, func(project string) ([]*v1alpha1.Cluster, error) { + err := ctrl.finalizeApplicationDeletion(app, func(project string) ([]*v1alpha1.Cluster, error) { return []*v1alpha1.Cluster{}, nil }) assert.NoError(t, err) @@ -727,7 +810,7 @@ func TestFinalizeAppDeletion(t *testing.T) { appObj := kube.MustToUnstructured(&app) ctrl := newFakeController(&fakeData{apps: []runtime.Object{app, &defaultProj}, managedLiveObjs: map[kube.ResourceKey]*unstructured.Unstructured{ kube.GetResourceKey(appObj): appObj, - }}) + }}, nil) fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset) defaultReactor := fakeAppCs.ReactionChain[0] @@ -735,7 +818,7 @@ func TestFinalizeAppDeletion(t *testing.T) { fakeAppCs.AddReactor("get", "*", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) { return defaultReactor.React(action) }) - _, err := ctrl.finalizeApplicationDeletion(app, func(project string) ([]*v1alpha1.Cluster, error) { + err := ctrl.finalizeApplicationDeletion(app, func(project string) ([]*v1alpha1.Cluster, error) { return []*v1alpha1.Cluster{}, nil }) assert.NoError(t, err) @@ -756,6 +839,109 @@ func TestFinalizeAppDeletion(t *testing.T) { }) + t.Run("PostDelete_HookIsCreated", func(t *testing.T) { + app := newFakeApp() + app.SetPostDeleteFinalizer() + app.Spec.Destination.Namespace = test.FakeArgoCDNamespace + ctrl := newFakeController(&fakeData{ + manifestResponses: []*apiclient.ManifestResponse{{ + Manifests: []string{fakePostDeleteHook}, + }}, + apps: []runtime.Object{app, &defaultProj}, + managedLiveObjs: map[kube.ResourceKey]*unstructured.Unstructured{}}, nil) + + patched := false + fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset) + defaultReactor := fakeAppCs.ReactionChain[0] + fakeAppCs.ReactionChain = nil + fakeAppCs.AddReactor("get", "*", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) { + return defaultReactor.React(action) + }) + fakeAppCs.AddReactor("patch", "*", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) { + patched = true + return true, &v1alpha1.Application{}, nil + }) + err := ctrl.finalizeApplicationDeletion(app, func(project string) ([]*v1alpha1.Cluster, error) { + return []*v1alpha1.Cluster{}, nil + }) + assert.NoError(t, err) + // finalizer is not deleted + assert.False(t, patched) + // post-delete hook is created + require.Len(t, ctrl.kubectl.(*MockKubectl).CreatedResources, 1) + require.Equal(t, "post-delete-hook", ctrl.kubectl.(*MockKubectl).CreatedResources[0].GetName()) + }) + + t.Run("PostDelete_HookIsExecuted", func(t *testing.T) { + app := newFakeApp() + app.SetPostDeleteFinalizer() + app.Spec.Destination.Namespace = test.FakeArgoCDNamespace + liveHook := &unstructured.Unstructured{Object: newFakePostDeleteHook()} + require.NoError(t, unstructured.SetNestedField(liveHook.Object, "Succeeded", "status", "phase")) + ctrl := newFakeController(&fakeData{ + manifestResponses: []*apiclient.ManifestResponse{{ + Manifests: []string{fakePostDeleteHook}, + }}, + apps: []runtime.Object{app, &defaultProj}, + managedLiveObjs: map[kube.ResourceKey]*unstructured.Unstructured{ + kube.GetResourceKey(liveHook): liveHook, + }}, nil) + + patched := false + fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset) + defaultReactor := fakeAppCs.ReactionChain[0] + fakeAppCs.ReactionChain = nil + fakeAppCs.AddReactor("get", "*", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) { + return defaultReactor.React(action) + }) + fakeAppCs.AddReactor("patch", "*", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) { + patched = true + return true, &v1alpha1.Application{}, nil + }) + err := ctrl.finalizeApplicationDeletion(app, func(project string) ([]*v1alpha1.Cluster, error) { + return []*v1alpha1.Cluster{}, nil + }) + assert.NoError(t, err) + // finalizer is removed + assert.True(t, patched) + }) + + t.Run("PostDelete_HookIsDeleted", func(t *testing.T) { + app := newFakeApp() + app.SetPostDeleteFinalizer("cleanup") + app.Spec.Destination.Namespace = test.FakeArgoCDNamespace + liveHook := &unstructured.Unstructured{Object: newFakePostDeleteHook()} + require.NoError(t, unstructured.SetNestedField(liveHook.Object, "Succeeded", "status", "phase")) + ctrl := newFakeController(&fakeData{ + manifestResponses: []*apiclient.ManifestResponse{{ + Manifests: []string{fakePostDeleteHook}, + }}, + apps: []runtime.Object{app, &defaultProj}, + managedLiveObjs: map[kube.ResourceKey]*unstructured.Unstructured{ + kube.GetResourceKey(liveHook): liveHook, + }}, nil) + + patched := false + fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset) + defaultReactor := fakeAppCs.ReactionChain[0] + fakeAppCs.ReactionChain = nil + fakeAppCs.AddReactor("get", "*", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) { + return defaultReactor.React(action) + }) + fakeAppCs.AddReactor("patch", "*", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) { + patched = true + return true, &v1alpha1.Application{}, nil + }) + err := ctrl.finalizeApplicationDeletion(app, func(project string) ([]*v1alpha1.Cluster, error) { + return []*v1alpha1.Cluster{}, nil + }) + assert.NoError(t, err) + // post-delete hook is deleted + require.Len(t, ctrl.kubectl.(*MockKubectl).DeletedResources, 1) + require.Equal(t, "post-delete-hook", ctrl.kubectl.(*MockKubectl).DeletedResources[0].Name) + // finalizer is not removed + assert.False(t, patched) + }) } // TestNormalizeApplication verifies we normalize an application during reconciliation @@ -791,9 +977,9 @@ func TestNormalizeApplication(t *testing.T) { { // Verify we normalize the app because project is missing - ctrl := newFakeController(&data) + ctrl := newFakeController(&data, nil) key, _ := cache.MetaNamespaceKeyFunc(app) - ctrl.appRefreshQueue.Add(key) + ctrl.appRefreshQueue.AddRateLimited(key) fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset) fakeAppCs.ReactionChain = nil normalized := false @@ -803,7 +989,7 @@ func TestNormalizeApplication(t *testing.T) { normalized = true } } - return true, nil, nil + return true, &v1alpha1.Application{}, nil }) ctrl.processAppRefreshQueueItem() assert.True(t, normalized) @@ -813,9 +999,9 @@ func TestNormalizeApplication(t *testing.T) { // Verify we don't unnecessarily normalize app when project is set app.Spec.Project = "default" data.apps[0] = app - ctrl := newFakeController(&data) + ctrl := newFakeController(&data, nil) key, _ := cache.MetaNamespaceKeyFunc(app) - ctrl.appRefreshQueue.Add(key) + ctrl.appRefreshQueue.AddRateLimited(key) fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset) fakeAppCs.ReactionChain = nil normalized := false @@ -825,7 +1011,7 @@ func TestNormalizeApplication(t *testing.T) { normalized = true } } - return true, nil, nil + return true, &v1alpha1.Application{}, nil }) ctrl.processAppRefreshQueueItem() assert.False(t, normalized) @@ -838,7 +1024,7 @@ func TestHandleAppUpdated(t *testing.T) { app.Spec.Destination.Server = v1alpha1.KubernetesInternalAPIServerAddr proj := defaultProj.DeepCopy() proj.Spec.SourceNamespaces = []string{test.FakeArgoCDNamespace} - ctrl := newFakeController(&fakeData{apps: []runtime.Object{app, proj}}) + ctrl := newFakeController(&fakeData{apps: []runtime.Object{app, proj}}, nil) ctrl.handleObjectUpdated(map[string]bool{app.InstanceName(ctrl.namespace): true}, kube.GetObjectRef(kube.MustToUnstructured(app))) isRequested, level := ctrl.isRefreshRequested(app.QualifiedName()) @@ -865,7 +1051,7 @@ func TestHandleOrphanedResourceUpdated(t *testing.T) { proj := defaultProj.DeepCopy() proj.Spec.OrphanedResources = &v1alpha1.OrphanedResourcesMonitorSettings{} - ctrl := newFakeController(&fakeData{apps: []runtime.Object{app1, app2, proj}}) + ctrl := newFakeController(&fakeData{apps: []runtime.Object{app1, app2, proj}}, nil) ctrl.handleObjectUpdated(map[string]bool{}, corev1.ObjectReference{UID: "test", Kind: kube.DeploymentKind, Name: "test", Namespace: test.FakeArgoCDNamespace}) @@ -900,7 +1086,7 @@ func TestGetResourceTree_HasOrphanedResources(t *testing.T) { kube.NewResourceKey("apps", "Deployment", "default", "deploy1"): {ResourceNode: orphanedDeploy1}, kube.NewResourceKey("apps", "Deployment", "default", "deploy2"): {ResourceNode: orphanedDeploy2}, }, - }) + }, nil) tree, err := ctrl.getResourceTree(app, []*v1alpha1.ResourceDiff{{ Namespace: "default", Name: "nginx-deployment", @@ -916,13 +1102,13 @@ func TestGetResourceTree_HasOrphanedResources(t *testing.T) { } func TestSetOperationStateOnDeletedApp(t *testing.T) { - ctrl := newFakeController(&fakeData{apps: []runtime.Object{}}) + ctrl := newFakeController(&fakeData{apps: []runtime.Object{}}, nil) fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset) fakeAppCs.ReactionChain = nil patched := false fakeAppCs.AddReactor("patch", "*", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) { patched = true - return true, nil, apierr.NewNotFound(schema.GroupResource{}, "my-app") + return true, &v1alpha1.Application{}, apierr.NewNotFound(schema.GroupResource{}, "my-app") }) ctrl.setOperationState(newFakeApp(), &v1alpha1.OperationState{Phase: synccommon.OperationSucceeded}) assert.True(t, patched) @@ -947,16 +1133,16 @@ func TestSetOperationStateLogRetries(t *testing.T) { t.Cleanup(func() { logrus.StandardLogger().ReplaceHooks(logrus.LevelHooks{}) }) - ctrl := newFakeController(&fakeData{apps: []runtime.Object{}}) + ctrl := newFakeController(&fakeData{apps: []runtime.Object{}}, nil) fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset) fakeAppCs.ReactionChain = nil patched := false fakeAppCs.AddReactor("patch", "*", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) { if !patched { patched = true - return true, nil, errors.New("fake error") + return true, &v1alpha1.Application{}, errors.New("fake error") } - return true, nil, nil + return true, &v1alpha1.Application{}, nil }) ctrl.setOperationState(newFakeApp(), &v1alpha1.OperationState{Phase: synccommon.OperationSucceeded}) assert.True(t, patched) @@ -998,7 +1184,7 @@ func TestNeedRefreshAppStatus(t *testing.T) { app.Status.Sync.ComparedTo.Source = app.Spec.GetSource() } - ctrl := newFakeController(&fakeData{apps: []runtime.Object{}}) + ctrl := newFakeController(&fakeData{apps: []runtime.Object{}}, nil) t.Run("no need to refresh just reconciled application", func(t *testing.T) { needRefresh, _, _ := ctrl.needRefreshAppStatus(app, 1*time.Hour, 2*time.Hour) @@ -1010,7 +1196,7 @@ func TestNeedRefreshAppStatus(t *testing.T) { assert.False(t, needRefresh) // use a one-off controller so other tests don't have a manual refresh request - ctrl := newFakeController(&fakeData{apps: []runtime.Object{}}) + ctrl := newFakeController(&fakeData{apps: []runtime.Object{}}, nil) // refresh app using the 'deepest' requested comparison level ctrl.requestAppRefresh(app.Name, CompareWithRecent.Pointer(), nil) @@ -1038,7 +1224,7 @@ func TestNeedRefreshAppStatus(t *testing.T) { app := app.DeepCopy() // use a one-off controller so other tests don't have a manual refresh request - ctrl := newFakeController(&fakeData{apps: []runtime.Object{}}) + ctrl := newFakeController(&fakeData{apps: []runtime.Object{}}, nil) needRefresh, _, _ := ctrl.needRefreshAppStatus(app, 1*time.Hour, 2*time.Hour) assert.False(t, needRefresh) @@ -1068,7 +1254,7 @@ func TestNeedRefreshAppStatus(t *testing.T) { } // use a one-off controller so other tests don't have a manual refresh request - ctrl := newFakeController(&fakeData{apps: []runtime.Object{}}) + ctrl := newFakeController(&fakeData{apps: []runtime.Object{}}, nil) needRefresh, _, _ := ctrl.needRefreshAppStatus(app, 1*time.Hour, 2*time.Hour) assert.False(t, needRefresh) @@ -1148,7 +1334,7 @@ func TestNeedRefreshAppStatus(t *testing.T) { } func TestUpdatedManagedNamespaceMetadata(t *testing.T) { - ctrl := newFakeController(&fakeData{apps: []runtime.Object{}}) + ctrl := newFakeController(&fakeData{apps: []runtime.Object{}}, nil) app := newFakeApp() app.Spec.SyncPolicy.ManagedNamespaceMetadata = &v1alpha1.ManagedNamespaceMetadata{ Labels: map[string]string{ @@ -1172,7 +1358,7 @@ func TestUpdatedManagedNamespaceMetadata(t *testing.T) { } func TestUnchangedManagedNamespaceMetadata(t *testing.T) { - ctrl := newFakeController(&fakeData{apps: []runtime.Object{}}) + ctrl := newFakeController(&fakeData{apps: []runtime.Object{}}, nil) app := newFakeApp() app.Spec.SyncPolicy.ManagedNamespaceMetadata = &v1alpha1.ManagedNamespaceMetadata{ Labels: map[string]string{ @@ -1215,7 +1401,7 @@ func TestRefreshAppConditions(t *testing.T) { t.Run("NoErrorConditions", func(t *testing.T) { app := newFakeApp() - ctrl := newFakeController(&fakeData{apps: []runtime.Object{app, &defaultProj}}) + ctrl := newFakeController(&fakeData{apps: []runtime.Object{app, &defaultProj}}, nil) _, hasErrors := ctrl.refreshAppConditions(app) assert.False(t, hasErrors) @@ -1226,7 +1412,7 @@ func TestRefreshAppConditions(t *testing.T) { app := newFakeApp() app.Status.SetConditions([]v1alpha1.ApplicationCondition{{Type: v1alpha1.ApplicationConditionExcludedResourceWarning}}, nil) - ctrl := newFakeController(&fakeData{apps: []runtime.Object{app, &defaultProj}}) + ctrl := newFakeController(&fakeData{apps: []runtime.Object{app, &defaultProj}}, nil) _, hasErrors := ctrl.refreshAppConditions(app) assert.False(t, hasErrors) @@ -1239,7 +1425,7 @@ func TestRefreshAppConditions(t *testing.T) { app.Spec.Project = "wrong project" app.Status.SetConditions([]v1alpha1.ApplicationCondition{{Type: v1alpha1.ApplicationConditionInvalidSpecError, Message: "old message"}}, nil) - ctrl := newFakeController(&fakeData{apps: []runtime.Object{app, &defaultProj}}) + ctrl := newFakeController(&fakeData{apps: []runtime.Object{app, &defaultProj}}, nil) _, hasErrors := ctrl.refreshAppConditions(app) assert.True(t, hasErrors) @@ -1263,7 +1449,7 @@ func TestUpdateReconciledAt(t *testing.T) { Revision: "abc123", }, managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured), - }) + }, nil) key, _ := cache.MetaNamespaceKeyFunc(app) fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset) fakeAppCs.ReactionChain = nil @@ -1272,13 +1458,13 @@ func TestUpdateReconciledAt(t *testing.T) { if patchAction, ok := action.(kubetesting.PatchAction); ok { assert.NoError(t, json.Unmarshal(patchAction.GetPatch(), &receivedPatch)) } - return true, nil, nil + return true, &v1alpha1.Application{}, nil }) t.Run("UpdatedOnFullReconciliation", func(t *testing.T) { receivedPatch = map[string]interface{}{} ctrl.requestAppRefresh(app.Name, CompareWithLatest.Pointer(), nil) - ctrl.appRefreshQueue.Add(key) + ctrl.appRefreshQueue.AddRateLimited(key) ctrl.processAppRefreshQueueItem() @@ -1293,7 +1479,7 @@ func TestUpdateReconciledAt(t *testing.T) { t.Run("NotUpdatedOnPartialReconciliation", func(t *testing.T) { receivedPatch = map[string]interface{}{} - ctrl.appRefreshQueue.Add(key) + ctrl.appRefreshQueue.AddRateLimited(key) ctrl.requestAppRefresh(app.Name, CompareWithRecent.Pointer(), nil) ctrl.processAppRefreshQueueItem() @@ -1321,9 +1507,9 @@ func TestProjectErrorToCondition(t *testing.T) { Revision: "abc123", }, managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured), - }) + }, nil) key, _ := cache.MetaNamespaceKeyFunc(app) - ctrl.appRefreshQueue.Add(key) + ctrl.appRefreshQueue.AddRateLimited(key) ctrl.requestAppRefresh(app.Name, CompareWithRecent.Pointer(), nil) ctrl.processAppRefreshQueueItem() @@ -1340,13 +1526,13 @@ func TestProjectErrorToCondition(t *testing.T) { func TestFinalizeProjectDeletion_HasApplications(t *testing.T) { app := newFakeApp() proj := &v1alpha1.AppProject{ObjectMeta: metav1.ObjectMeta{Name: "default", Namespace: test.FakeArgoCDNamespace}} - ctrl := newFakeController(&fakeData{apps: []runtime.Object{app, proj}}) + ctrl := newFakeController(&fakeData{apps: []runtime.Object{app, proj}}, nil) fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset) patched := false fakeAppCs.PrependReactor("patch", "*", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) { patched = true - return true, nil, nil + return true, &v1alpha1.Application{}, nil }) err := ctrl.finalizeProjectDeletion(proj) @@ -1356,7 +1542,7 @@ func TestFinalizeProjectDeletion_HasApplications(t *testing.T) { func TestFinalizeProjectDeletion_DoesNotHaveApplications(t *testing.T) { proj := &v1alpha1.AppProject{ObjectMeta: metav1.ObjectMeta{Name: "default", Namespace: test.FakeArgoCDNamespace}} - ctrl := newFakeController(&fakeData{apps: []runtime.Object{&defaultProj}}) + ctrl := newFakeController(&fakeData{apps: []runtime.Object{&defaultProj}}, nil) fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset) receivedPatch := map[string]interface{}{} @@ -1364,7 +1550,7 @@ func TestFinalizeProjectDeletion_DoesNotHaveApplications(t *testing.T) { if patchAction, ok := action.(kubetesting.PatchAction); ok { assert.NoError(t, json.Unmarshal(patchAction.GetPatch(), &receivedPatch)) } - return true, nil, nil + return true, &v1alpha1.AppProject{}, nil }) err := ctrl.finalizeProjectDeletion(proj) @@ -1382,14 +1568,14 @@ func TestProcessRequestedAppOperation_FailedNoRetries(t *testing.T) { app.Operation = &v1alpha1.Operation{ Sync: &v1alpha1.SyncOperation{}, } - ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}) + ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil) fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset) receivedPatch := map[string]interface{}{} fakeAppCs.PrependReactor("patch", "*", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) { if patchAction, ok := action.(kubetesting.PatchAction); ok { assert.NoError(t, json.Unmarshal(patchAction.GetPatch(), &receivedPatch)) } - return true, nil, nil + return true, &v1alpha1.Application{}, nil }) ctrl.processRequestedAppOperation(app) @@ -1407,7 +1593,7 @@ func TestProcessRequestedAppOperation_InvalidDestination(t *testing.T) { proj := defaultProj proj.Name = "test-project" proj.Spec.SourceNamespaces = []string{test.FakeArgoCDNamespace} - ctrl := newFakeController(&fakeData{apps: []runtime.Object{app, &proj}}) + ctrl := newFakeController(&fakeData{apps: []runtime.Object{app, &proj}}, nil) fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset) receivedPatch := map[string]interface{}{} func() { @@ -1417,7 +1603,7 @@ func TestProcessRequestedAppOperation_InvalidDestination(t *testing.T) { if patchAction, ok := action.(kubetesting.PatchAction); ok { assert.NoError(t, json.Unmarshal(patchAction.GetPatch(), &receivedPatch)) } - return true, nil, nil + return true, &v1alpha1.Application{}, nil }) }() @@ -1436,14 +1622,14 @@ func TestProcessRequestedAppOperation_FailedHasRetries(t *testing.T) { Sync: &v1alpha1.SyncOperation{}, Retry: v1alpha1.RetryStrategy{Limit: 1}, } - ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}) + ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil) fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset) receivedPatch := map[string]interface{}{} fakeAppCs.PrependReactor("patch", "*", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) { if patchAction, ok := action.(kubetesting.PatchAction); ok { assert.NoError(t, json.Unmarshal(patchAction.GetPatch(), &receivedPatch)) } - return true, nil, nil + return true, &v1alpha1.Application{}, nil }) ctrl.processRequestedAppOperation(app) @@ -1479,14 +1665,14 @@ func TestProcessRequestedAppOperation_RunningPreviouslyFailed(t *testing.T) { Revision: "abc123", }, } - ctrl := newFakeController(data) + ctrl := newFakeController(data, nil) fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset) receivedPatch := map[string]interface{}{} fakeAppCs.PrependReactor("patch", "*", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) { if patchAction, ok := action.(kubetesting.PatchAction); ok { assert.NoError(t, json.Unmarshal(patchAction.GetPatch(), &receivedPatch)) } - return true, nil, nil + return true, &v1alpha1.Application{}, nil }) ctrl.processRequestedAppOperation(app) @@ -1512,14 +1698,14 @@ func TestProcessRequestedAppOperation_HasRetriesTerminated(t *testing.T) { Revision: "abc123", }, } - ctrl := newFakeController(data) + ctrl := newFakeController(data, nil) fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset) receivedPatch := map[string]interface{}{} fakeAppCs.PrependReactor("patch", "*", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) { if patchAction, ok := action.(kubetesting.PatchAction); ok { assert.NoError(t, json.Unmarshal(patchAction.GetPatch(), &receivedPatch)) } - return true, nil, nil + return true, &v1alpha1.Application{}, nil }) ctrl.processRequestedAppOperation(app) @@ -1539,7 +1725,7 @@ func TestGetAppHosts(t *testing.T) { Revision: "abc123", }, } - ctrl := newFakeController(data) + ctrl := newFakeController(data, nil) mockStateCache := &mockstatecache.LiveStateCache{} mockStateCache.On("IterateResources", mock.Anything, mock.MatchedBy(func(callback func(res *clustercache.Resource, info *statecache.ResourceInfo)) bool { // node resource @@ -1589,15 +1775,15 @@ func TestGetAppHosts(t *testing.T) { func TestMetricsExpiration(t *testing.T) { app := newFakeApp() // Check expiration is disabled by default - ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}) + ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil) assert.False(t, ctrl.metricsServer.HasExpiration()) // Check expiration is enabled if set - ctrl = newFakeController(&fakeData{apps: []runtime.Object{app}, metricsCacheExpiration: 10 * time.Second}) + ctrl = newFakeController(&fakeData{apps: []runtime.Object{app}, metricsCacheExpiration: 10 * time.Second}, nil) assert.True(t, ctrl.metricsServer.HasExpiration()) } func TestToAppKey(t *testing.T) { - ctrl := newFakeController(&fakeData{}) + ctrl := newFakeController(&fakeData{}, nil) tests := []struct { name string input string @@ -1617,7 +1803,7 @@ func TestToAppKey(t *testing.T) { func Test_canProcessApp(t *testing.T) { app := newFakeApp() - ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}) + ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil) ctrl.applicationNamespaces = []string{"good"} t.Run("without cluster filter, good namespace", func(t *testing.T) { app.Namespace = "good" @@ -1631,13 +1817,11 @@ func Test_canProcessApp(t *testing.T) { }) t.Run("with cluster filter, good namespace", func(t *testing.T) { app.Namespace = "good" - ctrl.clusterFilter = func(_ *v1alpha1.Cluster) bool { return true } canProcess := ctrl.canProcessApp(app) assert.True(t, canProcess) }) t.Run("with cluster filter, bad namespace", func(t *testing.T) { app.Namespace = "bad" - ctrl.clusterFilter = func(_ *v1alpha1.Cluster) bool { return true } canProcess := ctrl.canProcessApp(app) assert.False(t, canProcess) }) @@ -1650,7 +1834,7 @@ func Test_canProcessAppSkipReconcileAnnotation(t *testing.T) { appSkipReconcileFalse.Annotations = map[string]string{common.AnnotationKeyAppSkipReconcile: "false"} appSkipReconcileTrue := newFakeApp() appSkipReconcileTrue.Annotations = map[string]string{common.AnnotationKeyAppSkipReconcile: "true"} - ctrl := newFakeController(&fakeData{}) + ctrl := newFakeController(&fakeData{}, nil) tests := []struct { name string input interface{} @@ -1671,7 +1855,7 @@ func Test_canProcessAppSkipReconcileAnnotation(t *testing.T) { func Test_syncDeleteOption(t *testing.T) { app := newFakeApp() - ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}) + ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}, nil) cm := newFakeCM() t.Run("without delete option object is deleted", func(t *testing.T) { cmObj := kube.MustToUnstructured(&cm) @@ -1698,7 +1882,7 @@ func TestAddControllerNamespace(t *testing.T) { ctrl := newFakeController(&fakeData{ apps: []runtime.Object{app, &defaultProj}, manifestResponse: &apiclient.ManifestResponse{}, - }) + }, nil) ctrl.processAppRefreshQueueItem() @@ -1717,7 +1901,7 @@ func TestAddControllerNamespace(t *testing.T) { apps: []runtime.Object{app, &proj}, manifestResponse: &apiclient.ManifestResponse{}, applicationNamespaces: []string{appNamespace}, - }) + }, nil) ctrl.processAppRefreshQueueItem() diff --git a/controller/cache/cache.go b/controller/cache/cache.go index 9eac161714089..e3b1d7b77f19d 100644 --- a/controller/cache/cache.go +++ b/controller/cache/cache.go @@ -29,6 +29,7 @@ import ( "k8s.io/client-go/tools/cache" "github.com/argoproj/argo-cd/v2/controller/metrics" + "github.com/argoproj/argo-cd/v2/controller/sharding" "github.com/argoproj/argo-cd/v2/pkg/apis/application" appv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" "github.com/argoproj/argo-cd/v2/util/argo" @@ -168,7 +169,7 @@ func NewLiveStateCache( kubectl kube.Kubectl, metricsServer *metrics.MetricsServer, onObjectUpdated ObjectUpdatedHandler, - clusterFilter func(cluster *appv1.Cluster) bool, + clusterSharding sharding.ClusterShardingCache, resourceTracking argo.ResourceTracking) LiveStateCache { return &liveStateCache{ @@ -179,7 +180,7 @@ func NewLiveStateCache( kubectl: kubectl, settingsMgr: settingsMgr, metricsServer: metricsServer, - clusterFilter: clusterFilter, + clusterSharding: clusterSharding, resourceTracking: resourceTracking, } } @@ -202,7 +203,7 @@ type liveStateCache struct { kubectl kube.Kubectl settingsMgr *settings.SettingsManager metricsServer *metrics.MetricsServer - clusterFilter func(cluster *appv1.Cluster) bool + clusterSharding sharding.ClusterShardingCache resourceTracking argo.ResourceTracking clusters map[string]clustercache.ClusterCache @@ -722,22 +723,24 @@ func (c *liveStateCache) Run(ctx context.Context) error { } func (c *liveStateCache) canHandleCluster(cluster *appv1.Cluster) bool { - if c.clusterFilter == nil { - return true - } - return c.clusterFilter(cluster) + return c.clusterSharding.IsManagedCluster(cluster) } func (c *liveStateCache) handleAddEvent(cluster *appv1.Cluster) { + c.clusterSharding.Add(cluster) if !c.canHandleCluster(cluster) { log.Infof("Ignoring cluster %s", cluster.Server) return } - c.lock.Lock() _, ok := c.clusters[cluster.Server] c.lock.Unlock() if !ok { + log.Debugf("Checking if cache %v / cluster %v has appInformer %v", c, cluster, c.appInformer) + if c.appInformer == nil { + log.Warn("Cannot get a cluster appInformer. Cache may not be started this time") + return + } if c.isClusterHasApps(c.appInformer.GetStore().List(), cluster) { go func() { // warm up cache for cluster with apps @@ -748,6 +751,7 @@ func (c *liveStateCache) handleAddEvent(cluster *appv1.Cluster) { } func (c *liveStateCache) handleModEvent(oldCluster *appv1.Cluster, newCluster *appv1.Cluster) { + c.clusterSharding.Update(newCluster) c.lock.Lock() cluster, ok := c.clusters[newCluster.Server] c.lock.Unlock() @@ -790,6 +794,7 @@ func (c *liveStateCache) handleModEvent(oldCluster *appv1.Cluster, newCluster *a func (c *liveStateCache) handleDeleteEvent(clusterServer string) { c.lock.RLock() + c.clusterSharding.Delete(clusterServer) cluster, ok := c.clusters[clusterServer] c.lock.RUnlock() if ok { diff --git a/controller/cache/cache_test.go b/controller/cache/cache_test.go index de2d96eb7aa28..53a03ca81995e 100644 --- a/controller/cache/cache_test.go +++ b/controller/cache/cache_test.go @@ -21,7 +21,11 @@ import ( "github.com/stretchr/testify/mock" "k8s.io/client-go/kubernetes/fake" + "github.com/argoproj/argo-cd/v2/common" + "github.com/argoproj/argo-cd/v2/controller/metrics" + "github.com/argoproj/argo-cd/v2/controller/sharding" appv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + dbmocks "github.com/argoproj/argo-cd/v2/util/db/mocks" argosettings "github.com/argoproj/argo-cd/v2/util/settings" ) @@ -35,11 +39,13 @@ func TestHandleModEvent_HasChanges(t *testing.T) { clusterCache := &mocks.ClusterCache{} clusterCache.On("Invalidate", mock.Anything, mock.Anything).Return(nil).Once() clusterCache.On("EnsureSynced").Return(nil).Once() - + db := &dbmocks.ArgoDB{} + db.On("GetApplicationControllerReplicas").Return(1) clustersCache := liveStateCache{ clusters: map[string]cache.ClusterCache{ "https://mycluster": clusterCache, }, + clusterSharding: sharding.NewClusterSharding(db, 0, 1, common.DefaultShardingAlgorithm), } clustersCache.handleModEvent(&appv1.Cluster{ @@ -56,14 +62,22 @@ func TestHandleModEvent_ClusterExcluded(t *testing.T) { clusterCache := &mocks.ClusterCache{} clusterCache.On("Invalidate", mock.Anything, mock.Anything).Return(nil).Once() clusterCache.On("EnsureSynced").Return(nil).Once() - + db := &dbmocks.ArgoDB{} + db.On("GetApplicationControllerReplicas").Return(1) clustersCache := liveStateCache{ - clusters: map[string]cache.ClusterCache{ - "https://mycluster": clusterCache, - }, - clusterFilter: func(cluster *appv1.Cluster) bool { - return false + db: nil, + appInformer: nil, + onObjectUpdated: func(managedByApp map[string]bool, ref v1.ObjectReference) { }, + kubectl: nil, + settingsMgr: &argosettings.SettingsManager{}, + metricsServer: &metrics.MetricsServer{}, + // returns a shard that never process any cluster + clusterSharding: sharding.NewClusterSharding(db, 0, 1, common.DefaultShardingAlgorithm), + resourceTracking: nil, + clusters: map[string]cache.ClusterCache{"https://mycluster": clusterCache}, + cacheSettings: cacheSettings{}, + lock: sync.RWMutex{}, } clustersCache.handleModEvent(&appv1.Cluster{ @@ -75,18 +89,20 @@ func TestHandleModEvent_ClusterExcluded(t *testing.T) { Namespaces: []string{"default"}, }) - assert.Len(t, clustersCache.clusters, 0) + assert.Len(t, clustersCache.clusters, 1) } func TestHandleModEvent_NoChanges(t *testing.T) { clusterCache := &mocks.ClusterCache{} clusterCache.On("Invalidate", mock.Anything).Panic("should not invalidate") clusterCache.On("EnsureSynced").Return(nil).Panic("should not re-sync") - + db := &dbmocks.ArgoDB{} + db.On("GetApplicationControllerReplicas").Return(1) clustersCache := liveStateCache{ clusters: map[string]cache.ClusterCache{ "https://mycluster": clusterCache, }, + clusterSharding: sharding.NewClusterSharding(db, 0, 1, common.DefaultShardingAlgorithm), } clustersCache.handleModEvent(&appv1.Cluster{ @@ -99,11 +115,11 @@ func TestHandleModEvent_NoChanges(t *testing.T) { } func TestHandleAddEvent_ClusterExcluded(t *testing.T) { + db := &dbmocks.ArgoDB{} + db.On("GetApplicationControllerReplicas").Return(1) clustersCache := liveStateCache{ - clusters: map[string]cache.ClusterCache{}, - clusterFilter: func(cluster *appv1.Cluster) bool { - return false - }, + clusters: map[string]cache.ClusterCache{}, + clusterSharding: sharding.NewClusterSharding(db, 0, 2, common.DefaultShardingAlgorithm), } clustersCache.handleAddEvent(&appv1.Cluster{ Server: "https://mycluster", @@ -118,25 +134,28 @@ func TestHandleDeleteEvent_CacheDeadlock(t *testing.T) { Server: "https://mycluster", Config: appv1.ClusterConfig{Username: "bar"}, } + db := &dbmocks.ArgoDB{} + db.On("GetApplicationControllerReplicas").Return(1) fakeClient := fake.NewSimpleClientset() settingsMgr := argosettings.NewSettingsManager(context.TODO(), fakeClient, "argocd") - externalLockRef := sync.RWMutex{} + liveStateCacheLock := sync.RWMutex{} gitopsEngineClusterCache := &mocks.ClusterCache{} clustersCache := liveStateCache{ clusters: map[string]cache.ClusterCache{ testCluster.Server: gitopsEngineClusterCache, }, - clusterFilter: func(cluster *appv1.Cluster) bool { - return true - }, - settingsMgr: settingsMgr, + clusterSharding: sharding.NewClusterSharding(db, 0, 1, common.DefaultShardingAlgorithm), + settingsMgr: settingsMgr, // Set the lock here so we can reference it later // nolint We need to overwrite here to have access to the lock - lock: externalLockRef, + lock: liveStateCacheLock, } channel := make(chan string) // Mocked lock held by the gitops-engine cluster cache - mockMutex := sync.RWMutex{} + gitopsEngineClusterCacheLock := sync.Mutex{} + // Ensure completion of both EnsureSynced and Invalidate + ensureSyncedCompleted := sync.Mutex{} + invalidateCompleted := sync.Mutex{} // Locks to force trigger condition during test // Condition order: // EnsuredSynced -> Locks gitops-engine @@ -144,40 +163,39 @@ func TestHandleDeleteEvent_CacheDeadlock(t *testing.T) { // EnsureSynced via sync, newResource, populateResourceInfoHandler -> attempts to Lock liveStateCache // handleDeleteEvent via cluster.Invalidate -> attempts to Lock gitops-engine handleDeleteWasCalled := sync.Mutex{} - engineHoldsLock := sync.Mutex{} + engineHoldsEngineLock := sync.Mutex{} + ensureSyncedCompleted.Lock() + invalidateCompleted.Lock() handleDeleteWasCalled.Lock() - engineHoldsLock.Lock() + engineHoldsEngineLock.Lock() + gitopsEngineClusterCache.On("EnsureSynced").Run(func(args mock.Arguments) { - // Held by EnsureSync calling into sync and watchEvents - mockMutex.Lock() - defer mockMutex.Unlock() - // Continue Execution of timer func - engineHoldsLock.Unlock() - // Wait for handleDeleteEvent to be called triggering the lock - // on the liveStateCache + gitopsEngineClusterCacheLock.Lock() + t.Log("EnsureSynced: Engine has engine lock") + engineHoldsEngineLock.Unlock() + defer gitopsEngineClusterCacheLock.Unlock() + // Wait until handleDeleteEvent holds the liveStateCache lock handleDeleteWasCalled.Lock() - t.Logf("handleDelete was called, EnsureSynced continuing...") - handleDeleteWasCalled.Unlock() - // Try and obtain the lock on the liveStateCache - alreadyFailed := !externalLockRef.TryLock() - if alreadyFailed { - channel <- "DEADLOCKED -- EnsureSynced could not obtain lock on liveStateCache" - return - } - externalLockRef.Lock() - t.Logf("EnsureSynce was able to lock liveStateCache") - externalLockRef.Unlock() + // Try and obtain the liveStateCache lock + clustersCache.lock.Lock() + t.Log("EnsureSynced: Engine has LiveStateCache lock") + clustersCache.lock.Unlock() + ensureSyncedCompleted.Unlock() }).Return(nil).Once() + gitopsEngineClusterCache.On("Invalidate").Run(func(args mock.Arguments) { - // If deadlock is fixed should be able to acquire lock here - alreadyFailed := !mockMutex.TryLock() - if alreadyFailed { - channel <- "DEADLOCKED -- Invalidate could not obtain lock on gitops-engine" - return - } - mockMutex.Lock() - t.Logf("Invalidate was able to lock gitops-engine cache") - mockMutex.Unlock() + // Allow EnsureSynced to continue now that we're in the deadlock condition + handleDeleteWasCalled.Unlock() + // Wait until gitops engine holds the gitops lock + // This prevents timing issues if we reach this point before EnsureSynced has obtained the lock + engineHoldsEngineLock.Lock() + t.Log("Invalidate: Engine has engine lock") + engineHoldsEngineLock.Unlock() + // Lock engine lock + gitopsEngineClusterCacheLock.Lock() + t.Log("Invalidate: Invalidate has engine lock") + gitopsEngineClusterCacheLock.Unlock() + invalidateCompleted.Unlock() }).Return() go func() { // Start the gitops-engine lock holds @@ -187,14 +205,14 @@ func TestHandleDeleteEvent_CacheDeadlock(t *testing.T) { assert.Fail(t, err.Error()) } }() - // Wait for EnsureSynced to grab the lock for gitops-engine - engineHoldsLock.Lock() - t.Log("EnsureSynced has obtained lock on gitops-engine") - engineHoldsLock.Unlock() // Run in background go clustersCache.handleDeleteEvent(testCluster.Server) // Allow execution to continue on clusters cache call to trigger lock - handleDeleteWasCalled.Unlock() + ensureSyncedCompleted.Lock() + invalidateCompleted.Lock() + t.Log("Competing functions were able to obtain locks") + invalidateCompleted.Unlock() + ensureSyncedCompleted.Unlock() channel <- "PASSED" }() select { diff --git a/controller/cache/info.go b/controller/cache/info.go index cf0d12318a447..53512de6b713a 100644 --- a/controller/cache/info.go +++ b/controller/cache/info.go @@ -37,6 +37,16 @@ func populateNodeInfo(un *unstructured.Unstructured, res *ResourceInfo, customLa } } } + + for k, v := range un.GetAnnotations() { + if strings.HasPrefix(k, common.AnnotationKeyLinkPrefix) { + if res.NetworkingInfo == nil { + res.NetworkingInfo = &v1alpha1.ResourceNetworkingInfo{} + } + res.NetworkingInfo.ExternalURLs = append(res.NetworkingInfo.ExternalURLs, v) + } + } + switch gvk.Group { case "": switch gvk.Kind { @@ -58,15 +68,6 @@ func populateNodeInfo(un *unstructured.Unstructured, res *ResourceInfo, customLa populateIstioVirtualServiceInfo(un, res) } } - - for k, v := range un.GetAnnotations() { - if strings.HasPrefix(k, common.AnnotationKeyLinkPrefix) { - if res.NetworkingInfo == nil { - res.NetworkingInfo = &v1alpha1.ResourceNetworkingInfo{} - } - res.NetworkingInfo.ExternalURLs = append(res.NetworkingInfo.ExternalURLs, v) - } - } } func getIngress(un *unstructured.Unstructured) []v1.LoadBalancerIngress { @@ -93,7 +94,13 @@ func populateServiceInfo(un *unstructured.Unstructured, res *ResourceInfo) { if serviceType, ok, err := unstructured.NestedString(un.Object, "spec", "type"); ok && err == nil && serviceType == string(v1.ServiceTypeLoadBalancer) { ingress = getIngress(un) } - res.NetworkingInfo = &v1alpha1.ResourceNetworkingInfo{TargetLabels: targetLabels, Ingress: ingress} + + var urls []string + if res.NetworkingInfo != nil { + urls = res.NetworkingInfo.ExternalURLs + } + + res.NetworkingInfo = &v1alpha1.ResourceNetworkingInfo{TargetLabels: targetLabels, Ingress: ingress, ExternalURLs: urls} } func getServiceName(backend map[string]interface{}, gvk schema.GroupVersionKind) (string, error) { @@ -263,7 +270,12 @@ func populateIstioVirtualServiceInfo(un *unstructured.Unstructured, res *Resourc targets = append(targets, target) } - res.NetworkingInfo = &v1alpha1.ResourceNetworkingInfo{TargetRefs: targets} + var urls []string + if res.NetworkingInfo != nil { + urls = res.NetworkingInfo.ExternalURLs + } + + res.NetworkingInfo = &v1alpha1.ResourceNetworkingInfo{TargetRefs: targets, ExternalURLs: urls} } func populatePodInfo(un *unstructured.Unstructured, res *ResourceInfo) { @@ -374,7 +386,13 @@ func populatePodInfo(un *unstructured.Unstructured, res *ResourceInfo) { if restarts > 0 { res.Info = append(res.Info, v1alpha1.InfoItem{Name: "Restart Count", Value: fmt.Sprintf("%d", restarts)}) } - res.NetworkingInfo = &v1alpha1.ResourceNetworkingInfo{Labels: un.GetLabels()} + + var urls []string + if res.NetworkingInfo != nil { + urls = res.NetworkingInfo.ExternalURLs + } + + res.NetworkingInfo = &v1alpha1.ResourceNetworkingInfo{Labels: un.GetLabels(), ExternalURLs: urls} } func populateHostNodeInfo(un *unstructured.Unstructured, res *ResourceInfo) { diff --git a/controller/cache/info_test.go b/controller/cache/info_test.go index 8a06d3745e13b..7b48040009284 100644 --- a/controller/cache/info_test.go +++ b/controller/cache/info_test.go @@ -52,7 +52,7 @@ var ( resourceVersion: "123" uid: "4" annotations: - link.argocd.argoproj.io/external-link: http://my-grafana.com/pre-generated-link + link.argocd.argoproj.io/external-link: http://my-grafana.example.com/pre-generated-link spec: selector: app: guestbook @@ -74,7 +74,7 @@ var ( serviceName: not-found-service servicePort: 443 rules: - - host: helm-guestbook.com + - host: helm-guestbook.example.com http: paths: - backend: @@ -86,7 +86,7 @@ var ( servicePort: https path: / tls: - - host: helm-guestbook.com + - host: helm-guestbook.example.com secretName: my-tls-secret status: loadBalancer: @@ -101,13 +101,13 @@ var ( namespace: default uid: "4" annotations: - link.argocd.argoproj.io/external-link: http://my-grafana.com/ingress-link + link.argocd.argoproj.io/external-link: http://my-grafana.example.com/ingress-link spec: backend: serviceName: not-found-service servicePort: 443 rules: - - host: helm-guestbook.com + - host: helm-guestbook.example.com http: paths: - backend: @@ -119,7 +119,7 @@ var ( servicePort: https path: / tls: - - host: helm-guestbook.com + - host: helm-guestbook.example.com secretName: my-tls-secret status: loadBalancer: @@ -138,7 +138,7 @@ var ( serviceName: not-found-service servicePort: 443 rules: - - host: helm-guestbook.com + - host: helm-guestbook.example.com http: paths: - backend: @@ -150,7 +150,7 @@ var ( servicePort: https path: /* tls: - - host: helm-guestbook.com + - host: helm-guestbook.example.com secretName: my-tls-secret status: loadBalancer: @@ -169,7 +169,7 @@ var ( serviceName: not-found-service servicePort: 443 rules: - - host: helm-guestbook.com + - host: helm-guestbook.example.com http: paths: - backend: @@ -199,7 +199,7 @@ var ( port: number: 443 rules: - - host: helm-guestbook.com + - host: helm-guestbook.example.com http: paths: - backend: @@ -215,7 +215,7 @@ var ( name: https path: / tls: - - host: helm-guestbook.com + - host: helm-guestbook.example.com secretName: my-tls-secret status: loadBalancer: @@ -327,7 +327,7 @@ func TestGetLinkAnnotatedServiceInfo(t *testing.T) { assert.Equal(t, &v1alpha1.ResourceNetworkingInfo{ TargetLabels: map[string]string{"app": "guestbook"}, Ingress: []v1.LoadBalancerIngress{{Hostname: "localhost"}}, - ExternalURLs: []string{"http://my-grafana.com/pre-generated-link"}, + ExternalURLs: []string{"http://my-grafana.example.com/pre-generated-link"}, }, info.NetworkingInfo) } @@ -381,7 +381,7 @@ func TestGetIngressInfo(t *testing.T) { Kind: kube.ServiceKind, Name: "helm-guestbook", }}, - ExternalURLs: []string{"https://helm-guestbook.com/"}, + ExternalURLs: []string{"https://helm-guestbook.example.com/"}, }, info.NetworkingInfo) } } @@ -406,7 +406,7 @@ func TestGetLinkAnnotatedIngressInfo(t *testing.T) { Kind: kube.ServiceKind, Name: "helm-guestbook", }}, - ExternalURLs: []string{"https://helm-guestbook.com/", "http://my-grafana.com/ingress-link"}, + ExternalURLs: []string{"http://my-grafana.example.com/ingress-link", "https://helm-guestbook.example.com/"}, }, info.NetworkingInfo) } @@ -430,7 +430,7 @@ func TestGetIngressInfoWildCardPath(t *testing.T) { Kind: kube.ServiceKind, Name: "helm-guestbook", }}, - ExternalURLs: []string{"https://helm-guestbook.com/"}, + ExternalURLs: []string{"https://helm-guestbook.example.com/"}, }, info.NetworkingInfo) } @@ -454,7 +454,7 @@ func TestGetIngressInfoWithoutTls(t *testing.T) { Kind: kube.ServiceKind, Name: "helm-guestbook", }}, - ExternalURLs: []string{"http://helm-guestbook.com/"}, + ExternalURLs: []string{"http://helm-guestbook.example.com/"}, }, info.NetworkingInfo) } @@ -563,7 +563,7 @@ func TestExternalUrlWithMultipleSubPaths(t *testing.T) { namespace: default spec: rules: - - host: helm-guestbook.com + - host: helm-guestbook.example.com http: paths: - backend: @@ -587,7 +587,7 @@ func TestExternalUrlWithMultipleSubPaths(t *testing.T) { info := &ResourceInfo{} populateNodeInfo(ingress, info, []string{}) - expectedExternalUrls := []string{"https://helm-guestbook.com/my/sub/path/", "https://helm-guestbook.com/my/sub/path/2", "https://helm-guestbook.com"} + expectedExternalUrls := []string{"https://helm-guestbook.example.com/my/sub/path/", "https://helm-guestbook.example.com/my/sub/path/2", "https://helm-guestbook.example.com"} actualURLs := info.NetworkingInfo.ExternalURLs sort.Strings(expectedExternalUrls) sort.Strings(actualURLs) diff --git a/controller/hook.go b/controller/hook.go new file mode 100644 index 0000000000000..0c019ac6a1e08 --- /dev/null +++ b/controller/hook.go @@ -0,0 +1,158 @@ +package controller + +import ( + "context" + + "github.com/argoproj/gitops-engine/pkg/health" + "github.com/argoproj/gitops-engine/pkg/sync/common" + "github.com/argoproj/gitops-engine/pkg/sync/hook" + "github.com/argoproj/gitops-engine/pkg/utils/kube" + log "github.com/sirupsen/logrus" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/client-go/rest" + + "github.com/argoproj/argo-cd/v2/util/lua" + + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" +) + +var ( + postDeleteHook = "PostDelete" + postDeleteHooks = map[string]string{ + "argocd.argoproj.io/hook": postDeleteHook, + "helm.sh/hook": "post-delete", + } +) + +func isHook(obj *unstructured.Unstructured) bool { + return hook.IsHook(obj) || isPostDeleteHook(obj) +} + +func isPostDeleteHook(obj *unstructured.Unstructured) bool { + if obj == nil || obj.GetAnnotations() == nil { + return false + } + for k, v := range postDeleteHooks { + if val, ok := obj.GetAnnotations()[k]; ok && val == v { + return true + } + } + return false +} + +func (ctrl *ApplicationController) executePostDeleteHooks(app *v1alpha1.Application, proj *v1alpha1.AppProject, liveObjs map[kube.ResourceKey]*unstructured.Unstructured, config *rest.Config, logCtx *log.Entry) (bool, error) { + appLabelKey, err := ctrl.settingsMgr.GetAppInstanceLabelKey() + if err != nil { + return false, err + } + var revisions []string + for _, src := range app.Spec.GetSources() { + revisions = append(revisions, src.TargetRevision) + } + + targets, _, err := ctrl.appStateManager.GetRepoObjs(app, app.Spec.GetSources(), appLabelKey, revisions, false, false, false, proj) + if err != nil { + return false, err + } + runningHooks := map[kube.ResourceKey]*unstructured.Unstructured{} + for key, obj := range liveObjs { + if isPostDeleteHook(obj) { + runningHooks[key] = obj + } + } + + expectedHook := map[kube.ResourceKey]*unstructured.Unstructured{} + for _, obj := range targets { + if obj.GetNamespace() == "" { + obj.SetNamespace(app.Spec.Destination.Namespace) + } + if !isPostDeleteHook(obj) { + continue + } + if runningHook := runningHooks[kube.GetResourceKey(obj)]; runningHook == nil { + expectedHook[kube.GetResourceKey(obj)] = obj + } + } + createdCnt := 0 + for _, obj := range expectedHook { + _, err = ctrl.kubectl.CreateResource(context.Background(), config, obj.GroupVersionKind(), obj.GetName(), obj.GetNamespace(), obj, v1.CreateOptions{}) + if err != nil { + return false, err + } + createdCnt++ + } + if createdCnt > 0 { + logCtx.Infof("Created %d post-delete hooks", createdCnt) + return false, nil + } + resourceOverrides, err := ctrl.settingsMgr.GetResourceOverrides() + if err != nil { + return false, err + } + healthOverrides := lua.ResourceHealthOverrides(resourceOverrides) + + progressingHooksCnt := 0 + for _, obj := range runningHooks { + hookHealth, err := health.GetResourceHealth(obj, healthOverrides) + if err != nil { + return false, err + } + if hookHealth.Status == health.HealthStatusProgressing { + progressingHooksCnt++ + } + } + if progressingHooksCnt > 0 { + logCtx.Infof("Waiting for %d post-delete hooks to complete", progressingHooksCnt) + return false, nil + } + + return true, nil +} + +func (ctrl *ApplicationController) cleanupPostDeleteHooks(liveObjs map[kube.ResourceKey]*unstructured.Unstructured, config *rest.Config, logCtx *log.Entry) (bool, error) { + resourceOverrides, err := ctrl.settingsMgr.GetResourceOverrides() + if err != nil { + return false, err + } + healthOverrides := lua.ResourceHealthOverrides(resourceOverrides) + + pendingDeletionCount := 0 + aggregatedHealth := health.HealthStatusHealthy + var hooks []*unstructured.Unstructured + for _, obj := range liveObjs { + if !isPostDeleteHook(obj) { + continue + } + hookHealth, err := health.GetResourceHealth(obj, healthOverrides) + if err != nil { + return false, err + } + if health.IsWorse(aggregatedHealth, hookHealth.Status) { + aggregatedHealth = hookHealth.Status + } + hooks = append(hooks, obj) + } + + for _, obj := range hooks { + for _, policy := range hook.DeletePolicies(obj) { + if policy == common.HookDeletePolicyHookFailed && aggregatedHealth == health.HealthStatusDegraded || policy == common.HookDeletePolicyHookSucceeded && aggregatedHealth == health.HealthStatusHealthy { + pendingDeletionCount++ + if obj.GetDeletionTimestamp() != nil { + continue + } + logCtx.Infof("Deleting post-delete hook %s/%s", obj.GetNamespace(), obj.GetName()) + err = ctrl.kubectl.DeleteResource(context.Background(), config, obj.GroupVersionKind(), obj.GetName(), obj.GetNamespace(), v1.DeleteOptions{}) + if err != nil { + return false, err + } + } + } + + } + if pendingDeletionCount > 0 { + logCtx.Infof("Waiting for %d post-delete hooks to be deleted", pendingDeletionCount) + return false, nil + } + return true, nil +} diff --git a/controller/sharding/cache.go b/controller/sharding/cache.go new file mode 100644 index 0000000000000..d16574accdf8a --- /dev/null +++ b/controller/sharding/cache.go @@ -0,0 +1,163 @@ +package sharding + +import ( + "sync" + + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + "github.com/argoproj/argo-cd/v2/util/db" + log "github.com/sirupsen/logrus" +) + +type ClusterShardingCache interface { + Init(clusters *v1alpha1.ClusterList) + Add(c *v1alpha1.Cluster) + Delete(clusterServer string) + Update(c *v1alpha1.Cluster) + IsManagedCluster(c *v1alpha1.Cluster) bool + GetDistribution() map[string]int +} + +type ClusterSharding struct { + Shard int + Replicas int + Shards map[string]int + Clusters map[string]*v1alpha1.Cluster + lock sync.RWMutex + getClusterShard DistributionFunction +} + +func NewClusterSharding(db db.ArgoDB, shard, replicas int, shardingAlgorithm string) ClusterShardingCache { + log.Debugf("Processing clusters from shard %d: Using filter function: %s", shard, shardingAlgorithm) + clusterSharding := &ClusterSharding{ + Shard: shard, + Replicas: replicas, + Shards: make(map[string]int), + Clusters: make(map[string]*v1alpha1.Cluster), + } + distributionFunction := NoShardingDistributionFunction() + if replicas > 1 { + log.Debugf("Processing clusters from shard %d: Using filter function: %s", shard, shardingAlgorithm) + distributionFunction = GetDistributionFunction(clusterSharding.GetClusterAccessor(), shardingAlgorithm, replicas) + } else { + log.Info("Processing all cluster shards") + } + clusterSharding.getClusterShard = distributionFunction + return clusterSharding +} + +// IsManagedCluster returns wheter or not the cluster should be processed by a given shard. +func (s *ClusterSharding) IsManagedCluster(c *v1alpha1.Cluster) bool { + s.lock.RLock() + defer s.lock.RUnlock() + if c == nil { // nil cluster (in-cluster) is always managed by current clusterShard + return true + } + clusterShard := 0 + if shard, ok := s.Shards[c.Server]; ok { + clusterShard = shard + } else { + log.Warnf("The cluster %s has no assigned shard.", c.Server) + } + log.Debugf("Checking if cluster %s with clusterShard %d should be processed by shard %d", c.Server, clusterShard, s.Shard) + return clusterShard == s.Shard +} + +func (sharding *ClusterSharding) Init(clusters *v1alpha1.ClusterList) { + sharding.lock.Lock() + defer sharding.lock.Unlock() + newClusters := make(map[string]*v1alpha1.Cluster, len(clusters.Items)) + for _, c := range clusters.Items { + newClusters[c.Server] = &c + } + sharding.Clusters = newClusters + sharding.updateDistribution() +} + +func (sharding *ClusterSharding) Add(c *v1alpha1.Cluster) { + sharding.lock.Lock() + defer sharding.lock.Unlock() + + old, ok := sharding.Clusters[c.Server] + sharding.Clusters[c.Server] = c + if !ok || hasShardingUpdates(old, c) { + sharding.updateDistribution() + } else { + log.Debugf("Skipping sharding distribution update. Cluster already added") + } +} + +func (sharding *ClusterSharding) Delete(clusterServer string) { + sharding.lock.Lock() + defer sharding.lock.Unlock() + if _, ok := sharding.Clusters[clusterServer]; ok { + delete(sharding.Clusters, clusterServer) + delete(sharding.Shards, clusterServer) + sharding.updateDistribution() + } +} + +func (sharding *ClusterSharding) Update(c *v1alpha1.Cluster) { + sharding.lock.Lock() + defer sharding.lock.Unlock() + + old, ok := sharding.Clusters[c.Server] + sharding.Clusters[c.Server] = c + if !ok || hasShardingUpdates(old, c) { + sharding.updateDistribution() + } else { + log.Debugf("Skipping sharding distribution update. No relevant changes") + } +} + +func (sharding *ClusterSharding) GetDistribution() map[string]int { + sharding.lock.RLock() + shards := sharding.Shards + sharding.lock.RUnlock() + + distribution := make(map[string]int, len(shards)) + for k, v := range shards { + distribution[k] = v + } + return distribution +} + +func (sharding *ClusterSharding) updateDistribution() { + log.Info("Updating cluster shards") + + for _, c := range sharding.Clusters { + shard := 0 + if c.Shard != nil { + requestedShard := int(*c.Shard) + if requestedShard < sharding.Replicas { + shard = requestedShard + } else { + log.Warnf("Specified cluster shard (%d) for cluster: %s is greater than the number of available shard (%d). Using shard 0.", requestedShard, c.Server, sharding.Replicas) + } + } else { + shard = sharding.getClusterShard(c) + } + var shard64 int64 = int64(shard) + c.Shard = &shard64 + sharding.Shards[c.Server] = shard + } +} + +// hasShardingUpdates returns true if the sharding distribution has been updated. +// nil checking is done for the corner case of the in-cluster cluster which may +// have a nil shard assigned +func hasShardingUpdates(old, new *v1alpha1.Cluster) bool { + if old == nil || new == nil || (old.Shard == nil && new.Shard == nil) { + return false + } + return old.Shard != new.Shard +} + +func (d *ClusterSharding) GetClusterAccessor() clusterAccessor { + return func() []*v1alpha1.Cluster { + clusters := make([]*v1alpha1.Cluster, 0, len(d.Clusters)) + for _, c := range d.Clusters { + clusters = append(clusters, c) + } + return clusters + } +} diff --git a/controller/sharding/sharding.go b/controller/sharding/sharding.go index 526896531dbca..2b86ed3f82bc6 100644 --- a/controller/sharding/sharding.go +++ b/controller/sharding/sharding.go @@ -40,6 +40,7 @@ const ShardControllerMappingKey = "shardControllerMapping" type DistributionFunction func(c *v1alpha1.Cluster) int type ClusterFilterFunction func(c *v1alpha1.Cluster) bool +type clusterAccessor func() []*v1alpha1.Cluster // shardApplicationControllerMapping stores the mapping of Shard Number to Application Controller in ConfigMap. // It also stores the heartbeat of last synced time of the application controller. @@ -53,8 +54,7 @@ type shardApplicationControllerMapping struct { // and returns wheter or not the cluster should be processed by a given shard. It calls the distributionFunction // to determine which shard will process the cluster, and if the given shard is equal to the calculated shard // the function will return true. -func GetClusterFilter(db db.ArgoDB, distributionFunction DistributionFunction, shard int) ClusterFilterFunction { - replicas := db.GetApplicationControllerReplicas() +func GetClusterFilter(db db.ArgoDB, distributionFunction DistributionFunction, replicas, shard int) ClusterFilterFunction { return func(c *v1alpha1.Cluster) bool { clusterShard := 0 if c != nil && c.Shard != nil { @@ -73,14 +73,14 @@ func GetClusterFilter(db db.ArgoDB, distributionFunction DistributionFunction, s // GetDistributionFunction returns which DistributionFunction should be used based on the passed algorithm and // the current datas. -func GetDistributionFunction(db db.ArgoDB, shardingAlgorithm string) DistributionFunction { - log.Infof("Using filter function: %s", shardingAlgorithm) - distributionFunction := LegacyDistributionFunction(db) +func GetDistributionFunction(clusters clusterAccessor, shardingAlgorithm string, replicasCount int) DistributionFunction { + log.Debugf("Using filter function: %s", shardingAlgorithm) + distributionFunction := LegacyDistributionFunction(replicasCount) switch shardingAlgorithm { case common.RoundRobinShardingAlgorithm: - distributionFunction = RoundRobinDistributionFunction(db) + distributionFunction = RoundRobinDistributionFunction(clusters, replicasCount) case common.LegacyShardingAlgorithm: - distributionFunction = LegacyDistributionFunction(db) + distributionFunction = LegacyDistributionFunction(replicasCount) default: log.Warnf("distribution type %s is not supported, defaulting to %s", shardingAlgorithm, common.DefaultShardingAlgorithm) } @@ -92,15 +92,21 @@ func GetDistributionFunction(db db.ArgoDB, shardingAlgorithm string) Distributio // is lightweight and can be distributed easily, however, it does not ensure an homogenous distribution as // some shards may get assigned more clusters than others. It is the legacy function distribution that is // kept for compatibility reasons -func LegacyDistributionFunction(db db.ArgoDB) DistributionFunction { - replicas := db.GetApplicationControllerReplicas() +func LegacyDistributionFunction(replicas int) DistributionFunction { return func(c *v1alpha1.Cluster) int { if replicas == 0 { + log.Debugf("Replicas count is : %d, returning -1", replicas) return -1 } if c == nil { + log.Debug("In-cluster: returning 0") return 0 } + // if Shard is manually set and the assigned value is lower than the number of replicas, + // then its value is returned otherwise it is the default calculated value + if c.Shard != nil && int(*c.Shard) < replicas { + return int(*c.Shard) + } id := c.ID log.Debugf("Calculating cluster shard for cluster id: %s", id) if id == "" { @@ -121,14 +127,19 @@ func LegacyDistributionFunction(db db.ArgoDB) DistributionFunction { // This function ensures an homogenous distribution: each shards got assigned the same number of // clusters +/-1 , but with the drawback of a reshuffling of clusters accross shards in case of some changes // in the cluster list -func RoundRobinDistributionFunction(db db.ArgoDB) DistributionFunction { - replicas := db.GetApplicationControllerReplicas() + +func RoundRobinDistributionFunction(clusters clusterAccessor, replicas int) DistributionFunction { return func(c *v1alpha1.Cluster) int { if replicas > 0 { if c == nil { // in-cluster does not necessarly have a secret assigned. So we are receiving a nil cluster here. return 0 + } + // if Shard is manually set and the assigned value is lower than the number of replicas, + // then its value is returned otherwise it is the default calculated value + if c.Shard != nil && int(*c.Shard) < replicas { + return int(*c.Shard) } else { - clusterIndexdByClusterIdMap := createClusterIndexByClusterIdMap(db) + clusterIndexdByClusterIdMap := createClusterIndexByClusterIdMap(clusters) clusterIndex, ok := clusterIndexdByClusterIdMap[c.ID] if !ok { log.Warnf("Cluster with id=%s not found in cluster map.", c.ID) @@ -144,6 +155,12 @@ func RoundRobinDistributionFunction(db db.ArgoDB) DistributionFunction { } } +// NoShardingDistributionFunction returns a DistributionFunction that will process all cluster by shard 0 +// the function is created for API compatibility purposes and is not supposed to be activated. +func NoShardingDistributionFunction() DistributionFunction { + return func(c *v1alpha1.Cluster) int { return 0 } +} + // InferShard extracts the shard index based on its hostname. func InferShard() (int, error) { hostname, err := osHostnameFunction() @@ -152,33 +169,29 @@ func InferShard() (int, error) { } parts := strings.Split(hostname, "-") if len(parts) == 0 { - return 0, fmt.Errorf("hostname should ends with shard number separated by '-' but got: %s", hostname) + log.Warnf("hostname should end with shard number separated by '-' but got: %s", hostname) + return 0, nil } shard, err := strconv.Atoi(parts[len(parts)-1]) if err != nil { - return 0, fmt.Errorf("hostname should ends with shard number separated by '-' but got: %s", hostname) + log.Warnf("hostname should end with shard number separated by '-' but got: %s", hostname) + return 0, nil } return int(shard), nil } -func getSortedClustersList(db db.ArgoDB) []v1alpha1.Cluster { - ctx := context.Background() - clustersList, dbErr := db.ListClusters(ctx) - if dbErr != nil { - log.Warnf("Error while querying clusters list from database: %v", dbErr) - return []v1alpha1.Cluster{} - } - clusters := clustersList.Items +func getSortedClustersList(getCluster clusterAccessor) []*v1alpha1.Cluster { + clusters := getCluster() sort.Slice(clusters, func(i, j int) bool { return clusters[i].ID < clusters[j].ID }) return clusters } -func createClusterIndexByClusterIdMap(db db.ArgoDB) map[string]int { - clusters := getSortedClustersList(db) +func createClusterIndexByClusterIdMap(getCluster clusterAccessor) map[string]int { + clusters := getSortedClustersList(getCluster) log.Debugf("ClustersList has %d items", len(clusters)) - clusterById := make(map[string]v1alpha1.Cluster) + clusterById := make(map[string]*v1alpha1.Cluster) clusterIndexedByClusterId := make(map[string]int) for i, cluster := range clusters { log.Debugf("Adding cluster with id=%s and name=%s to cluster's map", cluster.ID, cluster.Name) @@ -194,7 +207,6 @@ func createClusterIndexByClusterIdMap(db db.ArgoDB) map[string]int { // If the shard value passed to this function is -1, that is, the shard was not set as an environment variable, // we default the shard number to 0 for computing the default config map. func GetOrUpdateShardFromConfigMap(kubeClient *kubernetes.Clientset, settingsMgr *settings.SettingsManager, replicas, shard int) (int, error) { - hostname, err := osHostnameFunction() if err != nil { return -1, err diff --git a/controller/sharding/sharding_test.go b/controller/sharding/sharding_test.go index a8a25e11c4978..0992f7a9dfd7f 100644 --- a/controller/sharding/sharding_test.go +++ b/controller/sharding/sharding_test.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "os" + "strconv" "testing" "time" @@ -19,18 +20,20 @@ import ( func TestGetShardByID_NotEmptyID(t *testing.T) { db := &dbmocks.ArgoDB{} - db.On("GetApplicationControllerReplicas").Return(1) - assert.Equal(t, 0, LegacyDistributionFunction(db)(&v1alpha1.Cluster{ID: "1"})) - assert.Equal(t, 0, LegacyDistributionFunction(db)(&v1alpha1.Cluster{ID: "2"})) - assert.Equal(t, 0, LegacyDistributionFunction(db)(&v1alpha1.Cluster{ID: "3"})) - assert.Equal(t, 0, LegacyDistributionFunction(db)(&v1alpha1.Cluster{ID: "4"})) + replicasCount := 1 + db.On("GetApplicationControllerReplicas").Return(replicasCount) + assert.Equal(t, 0, LegacyDistributionFunction(replicasCount)(&v1alpha1.Cluster{ID: "1"})) + assert.Equal(t, 0, LegacyDistributionFunction(replicasCount)(&v1alpha1.Cluster{ID: "2"})) + assert.Equal(t, 0, LegacyDistributionFunction(replicasCount)(&v1alpha1.Cluster{ID: "3"})) + assert.Equal(t, 0, LegacyDistributionFunction(replicasCount)(&v1alpha1.Cluster{ID: "4"})) } func TestGetShardByID_EmptyID(t *testing.T) { db := &dbmocks.ArgoDB{} - db.On("GetApplicationControllerReplicas").Return(1) + replicasCount := 1 + db.On("GetApplicationControllerReplicas").Return(replicasCount) distributionFunction := LegacyDistributionFunction - shard := distributionFunction(db)(&v1alpha1.Cluster{}) + shard := distributionFunction(replicasCount)(&v1alpha1.Cluster{}) assert.Equal(t, 0, shard) } @@ -38,7 +41,7 @@ func TestGetShardByID_NoReplicas(t *testing.T) { db := &dbmocks.ArgoDB{} db.On("GetApplicationControllerReplicas").Return(0) distributionFunction := LegacyDistributionFunction - shard := distributionFunction(db)(&v1alpha1.Cluster{}) + shard := distributionFunction(0)(&v1alpha1.Cluster{}) assert.Equal(t, -1, shard) } @@ -46,16 +49,16 @@ func TestGetShardByID_NoReplicasUsingHashDistributionFunction(t *testing.T) { db := &dbmocks.ArgoDB{} db.On("GetApplicationControllerReplicas").Return(0) distributionFunction := LegacyDistributionFunction - shard := distributionFunction(db)(&v1alpha1.Cluster{}) + shard := distributionFunction(0)(&v1alpha1.Cluster{}) assert.Equal(t, -1, shard) } func TestGetShardByID_NoReplicasUsingHashDistributionFunctionWithClusters(t *testing.T) { - db, cluster1, cluster2, cluster3, cluster4, cluster5 := createTestClusters() + clusters, db, cluster1, cluster2, cluster3, cluster4, cluster5 := createTestClusters() // Test with replicas set to 0 db.On("GetApplicationControllerReplicas").Return(0) t.Setenv(common.EnvControllerShardingAlgorithm, common.RoundRobinShardingAlgorithm) - distributionFunction := RoundRobinDistributionFunction(db) + distributionFunction := RoundRobinDistributionFunction(clusters, 0) assert.Equal(t, -1, distributionFunction(nil)) assert.Equal(t, -1, distributionFunction(&cluster1)) assert.Equal(t, -1, distributionFunction(&cluster2)) @@ -65,137 +68,112 @@ func TestGetShardByID_NoReplicasUsingHashDistributionFunctionWithClusters(t *tes } func TestGetClusterFilterDefault(t *testing.T) { - shardIndex := 1 // ensuring that a shard with index 1 will process all the clusters with an "even" id (2,4,6,...) + //shardIndex := 1 // ensuring that a shard with index 1 will process all the clusters with an "even" id (2,4,6,...) + clusterAccessor, _, cluster1, cluster2, cluster3, cluster4, _ := createTestClusters() os.Unsetenv(common.EnvControllerShardingAlgorithm) - db := &dbmocks.ArgoDB{} - db.On("GetApplicationControllerReplicas").Return(2) - filter := GetClusterFilter(db, GetDistributionFunction(db, common.DefaultShardingAlgorithm), shardIndex) - assert.False(t, filter(&v1alpha1.Cluster{ID: "1"})) - assert.True(t, filter(&v1alpha1.Cluster{ID: "2"})) - assert.False(t, filter(&v1alpha1.Cluster{ID: "3"})) - assert.True(t, filter(&v1alpha1.Cluster{ID: "4"})) + replicasCount := 2 + distributionFunction := RoundRobinDistributionFunction(clusterAccessor, replicasCount) + assert.Equal(t, 0, distributionFunction(nil)) + assert.Equal(t, 0, distributionFunction(&cluster1)) + assert.Equal(t, 1, distributionFunction(&cluster2)) + assert.Equal(t, 0, distributionFunction(&cluster3)) + assert.Equal(t, 1, distributionFunction(&cluster4)) } func TestGetClusterFilterLegacy(t *testing.T) { - shardIndex := 1 // ensuring that a shard with index 1 will process all the clusters with an "even" id (2,4,6,...) - db := &dbmocks.ArgoDB{} - db.On("GetApplicationControllerReplicas").Return(2) + //shardIndex := 1 // ensuring that a shard with index 1 will process all the clusters with an "even" id (2,4,6,...) + clusterAccessor, db, cluster1, cluster2, cluster3, cluster4, _ := createTestClusters() + replicasCount := 2 + db.On("GetApplicationControllerReplicas").Return(replicasCount) t.Setenv(common.EnvControllerShardingAlgorithm, common.LegacyShardingAlgorithm) - filter := GetClusterFilter(db, GetDistributionFunction(db, common.LegacyShardingAlgorithm), shardIndex) - assert.False(t, filter(&v1alpha1.Cluster{ID: "1"})) - assert.True(t, filter(&v1alpha1.Cluster{ID: "2"})) - assert.False(t, filter(&v1alpha1.Cluster{ID: "3"})) - assert.True(t, filter(&v1alpha1.Cluster{ID: "4"})) + distributionFunction := RoundRobinDistributionFunction(clusterAccessor, replicasCount) + assert.Equal(t, 0, distributionFunction(nil)) + assert.Equal(t, 0, distributionFunction(&cluster1)) + assert.Equal(t, 1, distributionFunction(&cluster2)) + assert.Equal(t, 0, distributionFunction(&cluster3)) + assert.Equal(t, 1, distributionFunction(&cluster4)) } func TestGetClusterFilterUnknown(t *testing.T) { - shardIndex := 1 // ensuring that a shard with index 1 will process all the clusters with an "even" id (2,4,6,...) - db := &dbmocks.ArgoDB{} - db.On("GetApplicationControllerReplicas").Return(2) + clusterAccessor, db, cluster1, cluster2, cluster3, cluster4, _ := createTestClusters() + // Test with replicas set to 0 + t.Setenv(common.EnvControllerReplicas, "2") + os.Unsetenv(common.EnvControllerShardingAlgorithm) t.Setenv(common.EnvControllerShardingAlgorithm, "unknown") - filter := GetClusterFilter(db, GetDistributionFunction(db, "unknown"), shardIndex) - assert.False(t, filter(&v1alpha1.Cluster{ID: "1"})) - assert.True(t, filter(&v1alpha1.Cluster{ID: "2"})) - assert.False(t, filter(&v1alpha1.Cluster{ID: "3"})) - assert.True(t, filter(&v1alpha1.Cluster{ID: "4"})) + replicasCount := 2 + db.On("GetApplicationControllerReplicas").Return(replicasCount) + distributionFunction := GetDistributionFunction(clusterAccessor, "unknown", replicasCount) + assert.Equal(t, 0, distributionFunction(nil)) + assert.Equal(t, 0, distributionFunction(&cluster1)) + assert.Equal(t, 1, distributionFunction(&cluster2)) + assert.Equal(t, 0, distributionFunction(&cluster3)) + assert.Equal(t, 1, distributionFunction(&cluster4)) } func TestLegacyGetClusterFilterWithFixedShard(t *testing.T) { - shardIndex := 1 // ensuring that a shard with index 1 will process all the clusters with an "even" id (2,4,6,...) - db := &dbmocks.ArgoDB{} - db.On("GetApplicationControllerReplicas").Return(2) - filter := GetClusterFilter(db, GetDistributionFunction(db, common.DefaultShardingAlgorithm), shardIndex) - assert.False(t, filter(nil)) - assert.False(t, filter(&v1alpha1.Cluster{ID: "1"})) - assert.True(t, filter(&v1alpha1.Cluster{ID: "2"})) - assert.False(t, filter(&v1alpha1.Cluster{ID: "3"})) - assert.True(t, filter(&v1alpha1.Cluster{ID: "4"})) + //shardIndex := 1 // ensuring that a shard with index 1 will process all the clusters with an "even" id (2,4,6,...) + t.Setenv(common.EnvControllerReplicas, "5") + clusterAccessor, db, cluster1, cluster2, cluster3, cluster4, _ := createTestClusters() + replicasCount := 5 + db.On("GetApplicationControllerReplicas").Return(replicasCount) + filter := GetDistributionFunction(clusterAccessor, common.DefaultShardingAlgorithm, replicasCount) + assert.Equal(t, 0, filter(nil)) + assert.Equal(t, 4, filter(&cluster1)) + assert.Equal(t, 1, filter(&cluster2)) + assert.Equal(t, 2, filter(&cluster3)) + assert.Equal(t, 2, filter(&cluster4)) var fixedShard int64 = 4 - filter = GetClusterFilter(db, GetDistributionFunction(db, common.DefaultShardingAlgorithm), int(fixedShard)) - assert.False(t, filter(&v1alpha1.Cluster{ID: "4", Shard: &fixedShard})) + cluster5 := &v1alpha1.Cluster{ID: "5", Shard: &fixedShard} + clusterAccessor = getClusterAccessor([]v1alpha1.Cluster{cluster1, cluster2, cluster2, cluster4, *cluster5}) + filter = GetDistributionFunction(clusterAccessor, common.DefaultShardingAlgorithm, replicasCount) + assert.Equal(t, int(fixedShard), filter(cluster5)) fixedShard = 1 - filter = GetClusterFilter(db, GetDistributionFunction(db, common.DefaultShardingAlgorithm), int(fixedShard)) - assert.True(t, filter(&v1alpha1.Cluster{Name: "cluster4", ID: "4", Shard: &fixedShard})) + cluster5.Shard = &fixedShard + clusterAccessor = getClusterAccessor([]v1alpha1.Cluster{cluster1, cluster2, cluster2, cluster4, *cluster5}) + filter = GetDistributionFunction(clusterAccessor, common.DefaultShardingAlgorithm, replicasCount) + assert.Equal(t, int(fixedShard), filter(&v1alpha1.Cluster{ID: "4", Shard: &fixedShard})) } func TestRoundRobinGetClusterFilterWithFixedShard(t *testing.T) { - shardIndex := 1 // ensuring that a shard with index 1 will process all the clusters with an "even" id (2,4,6,...) - db, cluster1, cluster2, cluster3, cluster4, _ := createTestClusters() - db.On("GetApplicationControllerReplicas").Return(2) - filter := GetClusterFilter(db, GetDistributionFunction(db, common.RoundRobinShardingAlgorithm), shardIndex) - assert.False(t, filter(nil)) - assert.False(t, filter(&cluster1)) - assert.True(t, filter(&cluster2)) - assert.False(t, filter(&cluster3)) - assert.True(t, filter(&cluster4)) + //shardIndex := 1 // ensuring that a shard with index 1 will process all the clusters with an "even" id (2,4,6,...) + t.Setenv(common.EnvControllerReplicas, "4") + clusterAccessor, db, cluster1, cluster2, cluster3, cluster4, _ := createTestClusters() + replicasCount := 4 + db.On("GetApplicationControllerReplicas").Return(replicasCount) + + filter := GetDistributionFunction(clusterAccessor, common.RoundRobinShardingAlgorithm, replicasCount) + assert.Equal(t, filter(nil), 0) + assert.Equal(t, filter(&cluster1), 0) + assert.Equal(t, filter(&cluster2), 1) + assert.Equal(t, filter(&cluster3), 2) + assert.Equal(t, filter(&cluster4), 3) // a cluster with a fixed shard should be processed by the specified exact // same shard unless the specified shard index is greater than the number of replicas. - var fixedShard int64 = 4 - filter = GetClusterFilter(db, GetDistributionFunction(db, common.RoundRobinShardingAlgorithm), int(fixedShard)) - assert.False(t, filter(&v1alpha1.Cluster{Name: "cluster4", ID: "4", Shard: &fixedShard})) + var fixedShard int64 = 1 + cluster5 := v1alpha1.Cluster{Name: "cluster5", ID: "5", Shard: &fixedShard} + clusters := []v1alpha1.Cluster{cluster1, cluster2, cluster3, cluster4, cluster5} + clusterAccessor = getClusterAccessor(clusters) + filter = GetDistributionFunction(clusterAccessor, common.RoundRobinShardingAlgorithm, replicasCount) + assert.Equal(t, int(fixedShard), filter(&cluster5)) fixedShard = 1 - filter = GetClusterFilter(db, GetDistributionFunction(db, common.RoundRobinShardingAlgorithm), int(fixedShard)) - assert.True(t, filter(&v1alpha1.Cluster{Name: "cluster4", ID: "4", Shard: &fixedShard})) -} - -func TestGetClusterFilterLegacyHash(t *testing.T) { - shardIndex := 1 // ensuring that a shard with index 1 will process all the clusters with an "even" id (2,4,6,...) - t.Setenv(common.EnvControllerShardingAlgorithm, "hash") - db, cluster1, cluster2, cluster3, cluster4, _ := createTestClusters() - db.On("GetApplicationControllerReplicas").Return(2) - filter := GetClusterFilter(db, GetDistributionFunction(db, common.LegacyShardingAlgorithm), shardIndex) - assert.False(t, filter(&cluster1)) - assert.True(t, filter(&cluster2)) - assert.False(t, filter(&cluster3)) - assert.True(t, filter(&cluster4)) - - // a cluster with a fixed shard should be processed by the specified exact - // same shard unless the specified shard index is greater than the number of replicas. - var fixedShard int64 = 4 - filter = GetClusterFilter(db, GetDistributionFunction(db, common.LegacyShardingAlgorithm), int(fixedShard)) - assert.False(t, filter(&v1alpha1.Cluster{Name: "cluster4", ID: "4", Shard: &fixedShard})) - - fixedShard = 1 - filter = GetClusterFilter(db, GetDistributionFunction(db, common.LegacyShardingAlgorithm), int(fixedShard)) - assert.True(t, filter(&v1alpha1.Cluster{Name: "cluster4", ID: "4", Shard: &fixedShard})) -} - -func TestGetClusterFilterWithEnvControllerShardingAlgorithms(t *testing.T) { - db, cluster1, cluster2, cluster3, cluster4, _ := createTestClusters() - shardIndex := 1 - db.On("GetApplicationControllerReplicas").Return(2) - - t.Run("legacy", func(t *testing.T) { - t.Setenv(common.EnvControllerShardingAlgorithm, common.LegacyShardingAlgorithm) - shardShouldProcessCluster := GetClusterFilter(db, GetDistributionFunction(db, common.LegacyShardingAlgorithm), shardIndex) - assert.False(t, shardShouldProcessCluster(&cluster1)) - assert.True(t, shardShouldProcessCluster(&cluster2)) - assert.False(t, shardShouldProcessCluster(&cluster3)) - assert.True(t, shardShouldProcessCluster(&cluster4)) - assert.False(t, shardShouldProcessCluster(nil)) - }) - - t.Run("roundrobin", func(t *testing.T) { - t.Setenv(common.EnvControllerShardingAlgorithm, common.RoundRobinShardingAlgorithm) - shardShouldProcessCluster := GetClusterFilter(db, GetDistributionFunction(db, common.LegacyShardingAlgorithm), shardIndex) - assert.False(t, shardShouldProcessCluster(&cluster1)) - assert.True(t, shardShouldProcessCluster(&cluster2)) - assert.False(t, shardShouldProcessCluster(&cluster3)) - assert.True(t, shardShouldProcessCluster(&cluster4)) - assert.False(t, shardShouldProcessCluster(nil)) - }) + cluster5 = v1alpha1.Cluster{Name: "cluster5", ID: "5", Shard: &fixedShard} + clusters = []v1alpha1.Cluster{cluster1, cluster2, cluster3, cluster4, cluster5} + clusterAccessor = getClusterAccessor(clusters) + filter = GetDistributionFunction(clusterAccessor, common.RoundRobinShardingAlgorithm, replicasCount) + assert.Equal(t, int(fixedShard), filter(&v1alpha1.Cluster{Name: "cluster4", ID: "4", Shard: &fixedShard})) } func TestGetShardByIndexModuloReplicasCountDistributionFunction2(t *testing.T) { - db, cluster1, cluster2, cluster3, cluster4, cluster5 := createTestClusters() + clusters, db, cluster1, cluster2, cluster3, cluster4, cluster5 := createTestClusters() t.Run("replicas set to 1", func(t *testing.T) { - db.On("GetApplicationControllerReplicas").Return(1).Once() - distributionFunction := RoundRobinDistributionFunction(db) + replicasCount := 1 + db.On("GetApplicationControllerReplicas").Return(replicasCount).Once() + distributionFunction := RoundRobinDistributionFunction(clusters, replicasCount) assert.Equal(t, 0, distributionFunction(nil)) assert.Equal(t, 0, distributionFunction(&cluster1)) assert.Equal(t, 0, distributionFunction(&cluster2)) @@ -205,8 +183,9 @@ func TestGetShardByIndexModuloReplicasCountDistributionFunction2(t *testing.T) { }) t.Run("replicas set to 2", func(t *testing.T) { - db.On("GetApplicationControllerReplicas").Return(2).Once() - distributionFunction := RoundRobinDistributionFunction(db) + replicasCount := 2 + db.On("GetApplicationControllerReplicas").Return(replicasCount).Once() + distributionFunction := RoundRobinDistributionFunction(clusters, replicasCount) assert.Equal(t, 0, distributionFunction(nil)) assert.Equal(t, 0, distributionFunction(&cluster1)) assert.Equal(t, 1, distributionFunction(&cluster2)) @@ -216,8 +195,9 @@ func TestGetShardByIndexModuloReplicasCountDistributionFunction2(t *testing.T) { }) t.Run("replicas set to 3", func(t *testing.T) { - db.On("GetApplicationControllerReplicas").Return(3).Once() - distributionFunction := RoundRobinDistributionFunction(db) + replicasCount := 3 + db.On("GetApplicationControllerReplicas").Return(replicasCount).Once() + distributionFunction := RoundRobinDistributionFunction(clusters, replicasCount) assert.Equal(t, 0, distributionFunction(nil)) assert.Equal(t, 0, distributionFunction(&cluster1)) assert.Equal(t, 1, distributionFunction(&cluster2)) @@ -233,17 +213,19 @@ func TestGetShardByIndexModuloReplicasCountDistributionFunctionWhenClusterNumber // Initial tests where showing that under 1024 clusters, execution time was around 400ms // and for 4096 clusters, execution time was under 9s // The other implementation was giving almost linear time of 400ms up to 10'000 clusters - db := dbmocks.ArgoDB{} - clusterList := &v1alpha1.ClusterList{Items: []v1alpha1.Cluster{}} + clusterPointers := []*v1alpha1.Cluster{} for i := 0; i < 2048; i++ { cluster := createCluster(fmt.Sprintf("cluster-%d", i), fmt.Sprintf("%d", i)) - clusterList.Items = append(clusterList.Items, cluster) + clusterPointers = append(clusterPointers, &cluster) } - db.On("ListClusters", mock.Anything).Return(clusterList, nil) - db.On("GetApplicationControllerReplicas").Return(2) - distributionFunction := RoundRobinDistributionFunction(&db) - for i, c := range clusterList.Items { - assert.Equal(t, i%2, distributionFunction(&c)) + replicasCount := 2 + t.Setenv(common.EnvControllerReplicas, strconv.Itoa(replicasCount)) + _, db, _, _, _, _, _ := createTestClusters() + clusterAccessor := func() []*v1alpha1.Cluster { return clusterPointers } + db.On("GetApplicationControllerReplicas").Return(replicasCount) + distributionFunction := RoundRobinDistributionFunction(clusterAccessor, replicasCount) + for i, c := range clusterPointers { + assert.Equal(t, i%2, distributionFunction(c)) } } @@ -256,12 +238,15 @@ func TestGetShardByIndexModuloReplicasCountDistributionFunctionWhenClusterIsAdde cluster5 := createCluster("cluster5", "5") cluster6 := createCluster("cluster6", "6") + clusters := []v1alpha1.Cluster{cluster1, cluster2, cluster3, cluster4, cluster5} + clusterAccessor := getClusterAccessor(clusters) + clusterList := &v1alpha1.ClusterList{Items: []v1alpha1.Cluster{cluster1, cluster2, cluster3, cluster4, cluster5}} db.On("ListClusters", mock.Anything).Return(clusterList, nil) - // Test with replicas set to 2 - db.On("GetApplicationControllerReplicas").Return(2) - distributionFunction := RoundRobinDistributionFunction(&db) + replicasCount := 2 + db.On("GetApplicationControllerReplicas").Return(replicasCount) + distributionFunction := RoundRobinDistributionFunction(clusterAccessor, replicasCount) assert.Equal(t, 0, distributionFunction(nil)) assert.Equal(t, 0, distributionFunction(&cluster1)) assert.Equal(t, 1, distributionFunction(&cluster2)) @@ -272,17 +257,20 @@ func TestGetShardByIndexModuloReplicasCountDistributionFunctionWhenClusterIsAdde // Now, the database knows cluster6. Shard should be assigned a proper shard clusterList.Items = append(clusterList.Items, cluster6) + distributionFunction = RoundRobinDistributionFunction(getClusterAccessor(clusterList.Items), replicasCount) assert.Equal(t, 1, distributionFunction(&cluster6)) // Now, we remove the last added cluster, it should be unassigned as well clusterList.Items = clusterList.Items[:len(clusterList.Items)-1] + distributionFunction = RoundRobinDistributionFunction(getClusterAccessor(clusterList.Items), replicasCount) assert.Equal(t, -1, distributionFunction(&cluster6)) } func TestGetShardByIndexModuloReplicasCountDistributionFunction(t *testing.T) { - db, cluster1, cluster2, _, _, _ := createTestClusters() - db.On("GetApplicationControllerReplicas").Return(2) - distributionFunction := RoundRobinDistributionFunction(db) + clusters, db, cluster1, cluster2, _, _, _ := createTestClusters() + replicasCount := 2 + db.On("GetApplicationControllerReplicas").Return(replicasCount) + distributionFunction := RoundRobinDistributionFunction(clusters, replicasCount) // Test that the function returns the correct shard for cluster1 and cluster2 expectedShardForCluster1 := 0 @@ -315,14 +303,14 @@ func TestInferShard(t *testing.T) { osHostnameFunction = func() (string, error) { return "exampleshard", nil } _, err = InferShard() - assert.NotNil(t, err) + assert.Nil(t, err) osHostnameFunction = func() (string, error) { return "example-shard", nil } _, err = InferShard() - assert.NotNil(t, err) + assert.Nil(t, err) } -func createTestClusters() (*dbmocks.ArgoDB, v1alpha1.Cluster, v1alpha1.Cluster, v1alpha1.Cluster, v1alpha1.Cluster, v1alpha1.Cluster) { +func createTestClusters() (clusterAccessor, *dbmocks.ArgoDB, v1alpha1.Cluster, v1alpha1.Cluster, v1alpha1.Cluster, v1alpha1.Cluster, v1alpha1.Cluster) { db := dbmocks.ArgoDB{} cluster1 := createCluster("cluster1", "1") cluster2 := createCluster("cluster2", "2") @@ -330,10 +318,27 @@ func createTestClusters() (*dbmocks.ArgoDB, v1alpha1.Cluster, v1alpha1.Cluster, cluster4 := createCluster("cluster4", "4") cluster5 := createCluster("cluster5", "5") + clusters := []v1alpha1.Cluster{cluster1, cluster2, cluster3, cluster4, cluster5} + db.On("ListClusters", mock.Anything).Return(&v1alpha1.ClusterList{Items: []v1alpha1.Cluster{ cluster1, cluster2, cluster3, cluster4, cluster5, }}, nil) - return &db, cluster1, cluster2, cluster3, cluster4, cluster5 + return getClusterAccessor(clusters), &db, cluster1, cluster2, cluster3, cluster4, cluster5 +} + +func getClusterAccessor(clusters []v1alpha1.Cluster) clusterAccessor { + // Convert the array to a slice of pointers + clusterPointers := getClusterPointers(clusters) + clusterAccessor := func() []*v1alpha1.Cluster { return clusterPointers } + return clusterAccessor +} + +func getClusterPointers(clusters []v1alpha1.Cluster) []*v1alpha1.Cluster { + var clusterPointers []*v1alpha1.Cluster + for i := range clusters { + clusterPointers = append(clusterPointers, &clusters[i]) + } + return clusterPointers } func createCluster(name string, id string) v1alpha1.Cluster { diff --git a/controller/sharding/shuffle_test.go b/controller/sharding/shuffle_test.go index 9e089e31bad0f..1cca783a2afe9 100644 --- a/controller/sharding/shuffle_test.go +++ b/controller/sharding/shuffle_test.go @@ -3,6 +3,7 @@ package sharding import ( "fmt" "math" + "strconv" "testing" "github.com/argoproj/argo-cd/v2/common" @@ -22,9 +23,11 @@ func TestLargeShuffle(t *testing.T) { clusterList.Items = append(clusterList.Items, cluster) } db.On("ListClusters", mock.Anything).Return(clusterList, nil) + clusterAccessor := getClusterAccessor(clusterList.Items) // Test with replicas set to 256 - t.Setenv(common.EnvControllerReplicas, "256") - distributionFunction := RoundRobinDistributionFunction(&db) + replicasCount := 256 + t.Setenv(common.EnvControllerReplicas, strconv.Itoa(replicasCount)) + distributionFunction := RoundRobinDistributionFunction(clusterAccessor, replicasCount) for i, c := range clusterList.Items { assert.Equal(t, i%2567, distributionFunction(&c)) } @@ -44,10 +47,11 @@ func TestShuffle(t *testing.T) { clusterList := &v1alpha1.ClusterList{Items: []v1alpha1.Cluster{cluster1, cluster2, cluster3, cluster4, cluster5, cluster6}} db.On("ListClusters", mock.Anything).Return(clusterList, nil) - + clusterAccessor := getClusterAccessor(clusterList.Items) // Test with replicas set to 3 t.Setenv(common.EnvControllerReplicas, "3") - distributionFunction := RoundRobinDistributionFunction(&db) + replicasCount := 3 + distributionFunction := RoundRobinDistributionFunction(clusterAccessor, replicasCount) assert.Equal(t, 0, distributionFunction(nil)) assert.Equal(t, 0, distributionFunction(&cluster1)) assert.Equal(t, 1, distributionFunction(&cluster2)) diff --git a/controller/state.go b/controller/state.go index 19757510aa71d..704411558669b 100644 --- a/controller/state.go +++ b/controller/state.go @@ -3,12 +3,15 @@ package controller import ( "context" "encoding/json" + "errors" "fmt" - v1 "k8s.io/api/core/v1" "reflect" "strings" + goSync "sync" "time" + v1 "k8s.io/api/core/v1" + "github.com/argoproj/gitops-engine/pkg/diff" "github.com/argoproj/gitops-engine/pkg/health" "github.com/argoproj/gitops-engine/pkg/sync" @@ -40,6 +43,10 @@ import ( "github.com/argoproj/argo-cd/v2/util/stats" ) +var ( + CompareStateRepoError = errors.New("failed to get repo objects") +) + type resourceInfoProviderStub struct { } @@ -62,8 +69,9 @@ type managedResource struct { // AppStateManager defines methods which allow to compare application spec and actual application state. type AppStateManager interface { - CompareAppState(app *v1alpha1.Application, project *v1alpha1.AppProject, revisions []string, sources []v1alpha1.ApplicationSource, noCache bool, noRevisionCache bool, localObjects []string, hasMultipleSources bool) *comparisonResult + CompareAppState(app *v1alpha1.Application, project *v1alpha1.AppProject, revisions []string, sources []v1alpha1.ApplicationSource, noCache bool, noRevisionCache bool, localObjects []string, hasMultipleSources bool) (*comparisonResult, error) SyncAppState(app *v1alpha1.Application, state *v1alpha1.OperationState) + GetRepoObjs(app *v1alpha1.Application, sources []v1alpha1.ApplicationSource, appLabelKey string, revisions []string, noCache, noRevisionCache, verifySignature bool, proj *v1alpha1.AppProject) ([]*unstructured.Unstructured, []*apiclient.ManifestResponse, error) } // comparisonResult holds the state of an application after the reconciliation @@ -78,8 +86,9 @@ type comparisonResult struct { // appSourceTypes stores the SourceType for each application source under sources field appSourceTypes []v1alpha1.ApplicationSourceType // timings maps phases of comparison to the duration it took to complete (for statistical purposes) - timings map[string]time.Duration - diffResultList *diff.DiffResultList + timings map[string]time.Duration + diffResultList *diff.DiffResultList + hasPostDeleteHooks bool } func (res *comparisonResult) GetSyncStatus() *v1alpha1.SyncStatus { @@ -105,10 +114,16 @@ type appStateManager struct { statusRefreshTimeout time.Duration resourceTracking argo.ResourceTracking persistResourceHealth bool + repoErrorCache goSync.Map + repoErrorGracePeriod time.Duration + serverSideDiff bool } -func (m *appStateManager) getRepoObjs(app *v1alpha1.Application, sources []v1alpha1.ApplicationSource, appLabelKey string, revisions []string, noCache, noRevisionCache, verifySignature bool, proj *v1alpha1.AppProject) ([]*unstructured.Unstructured, []*apiclient.ManifestResponse, error) { - +// GetRepoObjs will generate the manifests for the given application delegating the +// task to the repo-server. It returns the list of generated manifests as unstructured +// objects. It also returns the full response from all calls to the repo server as the +// second argument. +func (m *appStateManager) GetRepoObjs(app *v1alpha1.Application, sources []v1alpha1.ApplicationSource, appLabelKey string, revisions []string, noCache, noRevisionCache, verifySignature bool, proj *v1alpha1.AppProject) ([]*unstructured.Unstructured, []*apiclient.ManifestResponse, error) { ts := stats.NewTimingStats() helmRepos, err := m.db.ListHelmRepositories(context.Background()) if err != nil { @@ -224,7 +239,7 @@ func (m *appStateManager) getRepoObjs(app *v1alpha1.Application, sources []v1alp logCtx = logCtx.WithField(k, v.Milliseconds()) } logCtx = logCtx.WithField("time_ms", time.Since(ts.StartTime).Milliseconds()) - logCtx.Info("getRepoObjs stats") + logCtx.Info("GetRepoObjs stats") return targetObjs, manifestInfos, nil } @@ -345,7 +360,7 @@ func isManagedNamespace(ns *unstructured.Unstructured, app *v1alpha1.Application // CompareAppState compares application git state to the live app state, using the specified // revision and supplied source. If revision or overrides are empty, then compares against // revision and overrides in the app spec. -func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *v1alpha1.AppProject, revisions []string, sources []v1alpha1.ApplicationSource, noCache bool, noRevisionCache bool, localManifests []string, hasMultipleSources bool) *comparisonResult { +func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *v1alpha1.AppProject, revisions []string, sources []v1alpha1.ApplicationSource, noCache bool, noRevisionCache bool, localManifests []string, hasMultipleSources bool) (*comparisonResult, error) { ts := stats.NewTimingStats() appLabelKey, resourceOverrides, resFilter, err := m.getComparisonSettings() @@ -361,7 +376,7 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *v1 Revisions: revisions, }, healthStatus: &v1alpha1.HealthStatus{Status: health.HealthStatusUnknown}, - } + }, nil } else { return &comparisonResult{ syncStatus: &v1alpha1.SyncStatus{ @@ -370,7 +385,7 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *v1 Revision: revisions[0], }, healthStatus: &v1alpha1.HealthStatus{Status: health.HealthStatusUnknown}, - } + }, nil } } @@ -391,6 +406,7 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *v1 now := metav1.Now() var manifestInfos []*apiclient.ManifestResponse + targetNsExists := false if len(localManifests) == 0 { // If the length of revisions is not same as the length of sources, @@ -402,12 +418,26 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *v1 } } - targetObjs, manifestInfos, err = m.getRepoObjs(app, sources, appLabelKey, revisions, noCache, noRevisionCache, verifySignature, project) + targetObjs, manifestInfos, err = m.GetRepoObjs(app, sources, appLabelKey, revisions, noCache, noRevisionCache, verifySignature, project) if err != nil { targetObjs = make([]*unstructured.Unstructured, 0) msg := fmt.Sprintf("Failed to load target state: %s", err.Error()) conditions = append(conditions, v1alpha1.ApplicationCondition{Type: v1alpha1.ApplicationConditionComparisonError, Message: msg, LastTransitionTime: &now}) + if firstSeen, ok := m.repoErrorCache.Load(app.Name); ok { + if time.Since(firstSeen.(time.Time)) <= m.repoErrorGracePeriod && !noRevisionCache { + // if first seen is less than grace period and it's not a Level 3 comparison, + // ignore error and short circuit + logCtx.Debugf("Ignoring repo error %v, already encountered error in grace period", err.Error()) + return nil, CompareStateRepoError + } + } else if !noRevisionCache { + logCtx.Debugf("Ignoring repo error %v, new occurrence", err.Error()) + m.repoErrorCache.Store(app.Name, time.Now()) + return nil, CompareStateRepoError + } failedToLoadObjs = true + } else { + m.repoErrorCache.Delete(app.Name) } } else { // Prevent applying local manifests for now when signature verification is enabled @@ -453,6 +483,13 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *v1 LastTransitionTime: &now, }) } + + // If we reach this path, this means that a namespace has been both defined in Git, as well in the + // application's managedNamespaceMetadata. We want to ensure that this manifest is the one being used instead + // of what is present in managedNamespaceMetadata. + if isManagedNamespace(targetObj, app) { + targetNsExists = true + } } ts.AddCheckpoint("dedup_ms") @@ -511,7 +548,10 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *v1 // entry in source control. In order for the namespace not to risk being pruned, we'll need to generate a // namespace which we can compare the live namespace with. For that, we'll do the same as is done in // gitops-engine, the difference here being that we create a managed namespace which is only used for comparison. - if isManagedNamespace(liveObj, app) { + // + // targetNsExists == true implies that it already exists as a target, so no need to add the namespace to the + // targetObjs array. + if isManagedNamespace(liveObj, app) && !targetNsExists { nsSpec := &v1.Namespace{TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: kubeutil.NamespaceKind}, ObjectMeta: metav1.ObjectMeta{Name: liveObj.GetName()}} managedNs, err := kubeutil.ToUnstructured(nsSpec) @@ -532,6 +572,12 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *v1 } } } + hasPostDeleteHooks := false + for _, obj := range targetObjs { + if isPostDeleteHook(obj) { + hasPostDeleteHooks = true + } + } reconciliation := sync.Reconcile(targetObjs, liveObjByKey, app.Spec.Destination.Namespace, infoProvider) ts.AddCheckpoint("live_ms") @@ -547,21 +593,29 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *v1 manifestRevisions = append(manifestRevisions, manifestInfo.Revision) } - // restore comparison using cached diff result if previous comparison was performed for the same revision - revisionChanged := len(manifestInfos) != len(sources) || !reflect.DeepEqual(app.Status.Sync.Revisions, manifestRevisions) - specChanged := !reflect.DeepEqual(app.Status.Sync.ComparedTo, v1alpha1.ComparedTo{Source: app.Spec.GetSource(), Destination: app.Spec.Destination, Sources: sources, IgnoreDifferences: app.Spec.IgnoreDifferences}) + serverSideDiff := m.serverSideDiff || + resourceutil.HasAnnotationOption(app, common.AnnotationCompareOptions, "ServerSideDiff=true") - _, refreshRequested := app.IsRefreshRequested() - noCache = noCache || refreshRequested || app.Status.Expired(m.statusRefreshTimeout) || specChanged || revisionChanged + // This allows turning SSD off for a given app if it is enabled at the + // controller level + if resourceutil.HasAnnotationOption(app, common.AnnotationCompareOptions, "ServerSideDiff=false") { + serverSideDiff = false + } + + useDiffCache := useDiffCache(noCache, manifestInfos, sources, app, manifestRevisions, m.statusRefreshTimeout, serverSideDiff, logCtx) diffConfigBuilder := argodiff.NewDiffConfigBuilder(). WithDiffSettings(app.Spec.IgnoreDifferences, resourceOverrides, compareOptions.IgnoreAggregatedRoles). WithTracking(appLabelKey, string(trackingMethod)) - if noCache { - diffConfigBuilder.WithNoCache() + if useDiffCache { + diffConfigBuilder.WithCache(m.cache, app.InstanceName(m.namespace)) } else { - diffConfigBuilder.WithCache(m.cache, app.GetName()) + diffConfigBuilder.WithNoCache() + } + + if resourceutil.HasAnnotationOption(app, common.AnnotationCompareOptions, "IncludeMutationWebhook=true") { + diffConfigBuilder.WithIgnoreMutationWebhook(false) } gvkParser, err := m.getGVKParser(app.Spec.Destination.Server) @@ -571,6 +625,18 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *v1 diffConfigBuilder.WithGVKParser(gvkParser) diffConfigBuilder.WithManager(common.ArgoCDSSAManager) + diffConfigBuilder.WithServerSideDiff(serverSideDiff) + + if serverSideDiff { + resourceOps, cleanup, err := m.getResourceOperations(app.Spec.Destination.Server) + if err != nil { + log.Errorf("CompareAppState error getting resource operations: %s", err) + conditions = append(conditions, v1alpha1.ApplicationCondition{Type: v1alpha1.ApplicationConditionUnknownError, Message: err.Error(), LastTransitionTime: &now}) + } + defer cleanup() + diffConfigBuilder.WithServerSideDryRunner(diff.NewK8sServerSideDryRunner(resourceOps)) + } + // enable structured merge diff if application syncs with server-side apply if app.Spec.SyncPolicy != nil && app.Spec.SyncPolicy.SyncOptions.HasOption("ServerSideApply=true") { diffConfigBuilder.WithStructuredMergeDiff(true) @@ -611,7 +677,7 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *v1 Kind: gvk.Kind, Version: gvk.Version, Group: gvk.Group, - Hook: hookutil.IsHook(obj), + Hook: isHook(obj), RequiresPruning: targetObj == nil && liveObj != nil && isSelfReferencedObj, } if targetObj != nil { @@ -744,6 +810,7 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *v1 reconciliationResult: reconciliation, diffConfig: diffConfig, diffResultList: diffResults, + hasPostDeleteHooks: hasPostDeleteHooks, } if hasMultipleSources { @@ -765,10 +832,64 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *v1 }) ts.AddCheckpoint("health_ms") compRes.timings = ts.Timings() - return &compRes + return &compRes, nil +} + +// useDiffCache will determine if the diff should be calculated based +// on the existing live state cache or not. +func useDiffCache(noCache bool, manifestInfos []*apiclient.ManifestResponse, sources []v1alpha1.ApplicationSource, app *v1alpha1.Application, manifestRevisions []string, statusRefreshTimeout time.Duration, serverSideDiff bool, log *log.Entry) bool { + + if noCache { + log.WithField("useDiffCache", "false").Debug("noCache is true") + return false + } + refreshType, refreshRequested := app.IsRefreshRequested() + if refreshRequested { + log.WithField("useDiffCache", "false").Debugf("refresh type %s requested", string(refreshType)) + return false + } + // serverSideDiff should still use cache even if status is expired. + // This is an attempt to avoid hitting k8s API server too frequently during + // app refresh with serverSideDiff is enabled. If there are negative side + // effects identified with this approach, the serverSideDiff should be removed + // from this condition. + if app.Status.Expired(statusRefreshTimeout) && !serverSideDiff { + log.WithField("useDiffCache", "false").Debug("app.status.expired") + return false + } + + if len(manifestInfos) != len(sources) { + log.WithField("useDiffCache", "false").Debug("manifestInfos len != sources len") + return false + } + + revisionChanged := !reflect.DeepEqual(app.Status.GetRevisions(), manifestRevisions) + if revisionChanged { + log.WithField("useDiffCache", "false").Debug("revisionChanged") + return false + } + + currentSpec := app.BuildComparedToStatus() + specChanged := !reflect.DeepEqual(app.Status.Sync.ComparedTo, currentSpec) + if specChanged { + log.WithField("useDiffCache", "false").Debug("specChanged") + return false + } + + log.WithField("useDiffCache", "true").Debug("using diff cache") + return true } -func (m *appStateManager) persistRevisionHistory(app *v1alpha1.Application, revision string, source v1alpha1.ApplicationSource, revisions []string, sources []v1alpha1.ApplicationSource, hasMultipleSources bool, startedAt metav1.Time) error { +func (m *appStateManager) persistRevisionHistory( + app *v1alpha1.Application, + revision string, + source v1alpha1.ApplicationSource, + revisions []string, + sources []v1alpha1.ApplicationSource, + hasMultipleSources bool, + startedAt metav1.Time, + initiatedBy v1alpha1.OperationInitiator, +) error { var nextID int64 if len(app.Status.History) > 0 { nextID = app.Status.History.LastRevisionHistory().ID + 1 @@ -781,6 +902,7 @@ func (m *appStateManager) persistRevisionHistory(app *v1alpha1.Application, revi ID: nextID, Sources: sources, Revisions: revisions, + InitiatedBy: initiatedBy, }) } else { app.Status.History = append(app.Status.History, v1alpha1.RevisionHistory{ @@ -789,6 +911,7 @@ func (m *appStateManager) persistRevisionHistory(app *v1alpha1.Application, revi DeployStartedAt: &startedAt, ID: nextID, Source: source, + InitiatedBy: initiatedBy, }) } @@ -821,6 +944,8 @@ func NewAppStateManager( statusRefreshTimeout time.Duration, resourceTracking argo.ResourceTracking, persistResourceHealth bool, + repoErrorGracePeriod time.Duration, + serverSideDiff bool, ) AppStateManager { return &appStateManager{ liveStateCache: liveStateCache, @@ -836,6 +961,8 @@ func NewAppStateManager( statusRefreshTimeout: statusRefreshTimeout, resourceTracking: resourceTracking, persistResourceHealth: persistResourceHealth, + repoErrorGracePeriod: repoErrorGracePeriod, + serverSideDiff: serverSideDiff, } } diff --git a/controller/state_test.go b/controller/state_test.go index dcb48e87fce9b..1a55e25b262d1 100644 --- a/controller/state_test.go +++ b/controller/state_test.go @@ -2,6 +2,7 @@ package controller import ( "encoding/json" + "fmt" "os" "testing" "time" @@ -10,6 +11,9 @@ import ( synccommon "github.com/argoproj/gitops-engine/pkg/sync/common" "github.com/argoproj/gitops-engine/pkg/utils/kube" . "github.com/argoproj/gitops-engine/pkg/utils/testing" + "github.com/imdario/mergo" + "github.com/sirupsen/logrus" + logrustest "github.com/sirupsen/logrus/hooks/test" "github.com/stretchr/testify/assert" v1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" @@ -19,6 +23,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "github.com/argoproj/argo-cd/v2/common" + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" argoappv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" "github.com/argoproj/argo-cd/v2/reposerver/apiclient" "github.com/argoproj/argo-cd/v2/test" @@ -37,12 +42,13 @@ func TestCompareAppStateEmpty(t *testing.T) { }, managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured), } - ctrl := newFakeController(&data) + ctrl := newFakeController(&data, nil) sources := make([]argoappv1.ApplicationSource, 0) sources = append(sources, app.Spec.GetSource()) revisions := make([]string, 0) revisions = append(revisions, "") - compRes := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false) + compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false) + assert.Nil(t, err) assert.NotNil(t, compRes) assert.NotNil(t, compRes.syncStatus) assert.Equal(t, argoappv1.SyncStatusCodeSynced, compRes.syncStatus.Status) @@ -51,6 +57,31 @@ func TestCompareAppStateEmpty(t *testing.T) { assert.Len(t, app.Status.Conditions, 0) } +// TestCompareAppStateRepoError tests the case when CompareAppState notices a repo error +func TestCompareAppStateRepoError(t *testing.T) { + app := newFakeApp() + ctrl := newFakeController(&fakeData{manifestResponses: make([]*apiclient.ManifestResponse, 3)}, fmt.Errorf("test repo error")) + sources := make([]argoappv1.ApplicationSource, 0) + sources = append(sources, app.Spec.GetSource()) + revisions := make([]string, 0) + revisions = append(revisions, "") + compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false) + assert.Nil(t, compRes) + assert.EqualError(t, err, CompareStateRepoError.Error()) + + // expect to still get compare state error to as inside grace period + compRes, err = ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false) + assert.Nil(t, compRes) + assert.EqualError(t, err, CompareStateRepoError.Error()) + + time.Sleep(10 * time.Second) + // expect to not get error as outside of grace period, but status should be unknown + compRes, err = ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false) + assert.NotNil(t, compRes) + assert.Nil(t, err) + assert.Equal(t, compRes.syncStatus.Status, argoappv1.SyncStatusCodeUnknown) +} + // TestCompareAppStateNamespaceMetadataDiffers tests comparison when managed namespace metadata differs func TestCompareAppStateNamespaceMetadataDiffers(t *testing.T) { app := newFakeApp() @@ -75,12 +106,13 @@ func TestCompareAppStateNamespaceMetadataDiffers(t *testing.T) { }, managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured), } - ctrl := newFakeController(&data) + ctrl := newFakeController(&data, nil) sources := make([]argoappv1.ApplicationSource, 0) sources = append(sources, app.Spec.GetSource()) revisions := make([]string, 0) revisions = append(revisions, "") - compRes := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false) + compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false) + assert.Nil(t, err) assert.NotNil(t, compRes) assert.NotNil(t, compRes.syncStatus) assert.Equal(t, argoappv1.SyncStatusCodeOutOfSync, compRes.syncStatus.Status) @@ -89,6 +121,124 @@ func TestCompareAppStateNamespaceMetadataDiffers(t *testing.T) { assert.Len(t, app.Status.Conditions, 0) } +// TestCompareAppStateNamespaceMetadataDiffers tests comparison when managed namespace metadata differs to live and manifest ns +func TestCompareAppStateNamespaceMetadataDiffersToManifest(t *testing.T) { + ns := NewNamespace() + ns.SetName(test.FakeDestNamespace) + ns.SetNamespace(test.FakeDestNamespace) + ns.SetAnnotations(map[string]string{"bar": "bat"}) + + app := newFakeApp() + app.Spec.SyncPolicy.ManagedNamespaceMetadata = &argoappv1.ManagedNamespaceMetadata{ + Labels: map[string]string{ + "foo": "bar", + }, + Annotations: map[string]string{ + "foo": "bar", + }, + } + app.Status.OperationState = &argoappv1.OperationState{ + SyncResult: &argoappv1.SyncOperationResult{}, + } + + liveNs := ns.DeepCopy() + liveNs.SetAnnotations(nil) + + data := fakeData{ + manifestResponse: &apiclient.ManifestResponse{ + Manifests: []string{toJSON(t, liveNs)}, + Namespace: test.FakeDestNamespace, + Server: test.FakeClusterURL, + Revision: "abc123", + }, + managedLiveObjs: map[kube.ResourceKey]*unstructured.Unstructured{ + kube.GetResourceKey(ns): ns, + }, + } + ctrl := newFakeController(&data, nil) + sources := make([]argoappv1.ApplicationSource, 0) + sources = append(sources, app.Spec.GetSource()) + revisions := make([]string, 0) + revisions = append(revisions, "") + compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false) + assert.Nil(t, err) + assert.NotNil(t, compRes) + assert.NotNil(t, compRes.syncStatus) + assert.Equal(t, argoappv1.SyncStatusCodeOutOfSync, compRes.syncStatus.Status) + assert.Len(t, compRes.resources, 1) + assert.Len(t, compRes.managedResources, 1) + assert.NotNil(t, compRes.diffResultList) + assert.Len(t, compRes.diffResultList.Diffs, 1) + + result := NewNamespace() + assert.NoError(t, json.Unmarshal(compRes.diffResultList.Diffs[0].PredictedLive, result)) + + labels := result.GetLabels() + delete(labels, "kubernetes.io/metadata.name") + + assert.Equal(t, map[string]string{}, labels) + // Manifests override definitions in managedNamespaceMetadata + assert.Equal(t, map[string]string{"bar": "bat"}, result.GetAnnotations()) + assert.Len(t, app.Status.Conditions, 0) +} + +// TestCompareAppStateNamespaceMetadata tests comparison when managed namespace metadata differs to live +func TestCompareAppStateNamespaceMetadata(t *testing.T) { + ns := NewNamespace() + ns.SetName(test.FakeDestNamespace) + ns.SetNamespace(test.FakeDestNamespace) + ns.SetAnnotations(map[string]string{"bar": "bat"}) + + app := newFakeApp() + app.Spec.SyncPolicy.ManagedNamespaceMetadata = &argoappv1.ManagedNamespaceMetadata{ + Labels: map[string]string{ + "foo": "bar", + }, + Annotations: map[string]string{ + "foo": "bar", + }, + } + app.Status.OperationState = &argoappv1.OperationState{ + SyncResult: &argoappv1.SyncOperationResult{}, + } + + data := fakeData{ + manifestResponse: &apiclient.ManifestResponse{ + Manifests: []string{}, + Namespace: test.FakeDestNamespace, + Server: test.FakeClusterURL, + Revision: "abc123", + }, + managedLiveObjs: map[kube.ResourceKey]*unstructured.Unstructured{ + kube.GetResourceKey(ns): ns, + }, + } + ctrl := newFakeController(&data, nil) + sources := make([]argoappv1.ApplicationSource, 0) + sources = append(sources, app.Spec.GetSource()) + revisions := make([]string, 0) + revisions = append(revisions, "") + compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false) + assert.Nil(t, err) + assert.NotNil(t, compRes) + assert.NotNil(t, compRes.syncStatus) + assert.Equal(t, argoappv1.SyncStatusCodeOutOfSync, compRes.syncStatus.Status) + assert.Len(t, compRes.resources, 1) + assert.Len(t, compRes.managedResources, 1) + assert.NotNil(t, compRes.diffResultList) + assert.Len(t, compRes.diffResultList.Diffs, 1) + + result := NewNamespace() + assert.NoError(t, json.Unmarshal(compRes.diffResultList.Diffs[0].PredictedLive, result)) + + labels := result.GetLabels() + delete(labels, "kubernetes.io/metadata.name") + + assert.Equal(t, map[string]string{"foo": "bar"}, labels) + assert.Equal(t, map[string]string{"argocd.argoproj.io/sync-options": "ServerSideApply=true", "bar": "bat", "foo": "bar"}, result.GetAnnotations()) + assert.Len(t, app.Status.Conditions, 0) +} + // TestCompareAppStateNamespaceMetadataIsTheSame tests comparison when managed namespace metadata is the same func TestCompareAppStateNamespaceMetadataIsTheSame(t *testing.T) { app := newFakeApp() @@ -122,12 +272,13 @@ func TestCompareAppStateNamespaceMetadataIsTheSame(t *testing.T) { }, managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured), } - ctrl := newFakeController(&data) + ctrl := newFakeController(&data, nil) sources := make([]argoappv1.ApplicationSource, 0) sources = append(sources, app.Spec.GetSource()) revisions := make([]string, 0) revisions = append(revisions, "") - compRes := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false) + compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false) + assert.Nil(t, err) assert.NotNil(t, compRes) assert.NotNil(t, compRes.syncStatus) assert.Equal(t, argoappv1.SyncStatusCodeSynced, compRes.syncStatus.Status) @@ -149,12 +300,13 @@ func TestCompareAppStateMissing(t *testing.T) { }, managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured), } - ctrl := newFakeController(&data) + ctrl := newFakeController(&data, nil) sources := make([]argoappv1.ApplicationSource, 0) sources = append(sources, app.Spec.GetSource()) revisions := make([]string, 0) revisions = append(revisions, "") - compRes := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false) + compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false) + assert.Nil(t, err) assert.NotNil(t, compRes) assert.NotNil(t, compRes.syncStatus) assert.Equal(t, argoappv1.SyncStatusCodeOutOfSync, compRes.syncStatus.Status) @@ -180,12 +332,13 @@ func TestCompareAppStateExtra(t *testing.T) { key: pod, }, } - ctrl := newFakeController(&data) + ctrl := newFakeController(&data, nil) sources := make([]argoappv1.ApplicationSource, 0) sources = append(sources, app.Spec.GetSource()) revisions := make([]string, 0) revisions = append(revisions, "") - compRes := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false) + compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false) + assert.Nil(t, err) assert.NotNil(t, compRes) assert.Equal(t, argoappv1.SyncStatusCodeOutOfSync, compRes.syncStatus.Status) assert.Equal(t, 1, len(compRes.resources)) @@ -210,12 +363,13 @@ func TestCompareAppStateHook(t *testing.T) { }, managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured), } - ctrl := newFakeController(&data) + ctrl := newFakeController(&data, nil) sources := make([]argoappv1.ApplicationSource, 0) sources = append(sources, app.Spec.GetSource()) revisions := make([]string, 0) revisions = append(revisions, "") - compRes := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false) + compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false) + assert.Nil(t, err) assert.NotNil(t, compRes) assert.Equal(t, argoappv1.SyncStatusCodeSynced, compRes.syncStatus.Status) assert.Equal(t, 0, len(compRes.resources)) @@ -241,12 +395,13 @@ func TestCompareAppStateSkipHook(t *testing.T) { }, managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured), } - ctrl := newFakeController(&data) + ctrl := newFakeController(&data, nil) sources := make([]argoappv1.ApplicationSource, 0) sources = append(sources, app.Spec.GetSource()) revisions := make([]string, 0) revisions = append(revisions, "") - compRes := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false) + compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false) + assert.Nil(t, err) assert.NotNil(t, compRes) assert.Equal(t, argoappv1.SyncStatusCodeSynced, compRes.syncStatus.Status) assert.Equal(t, 1, len(compRes.resources)) @@ -270,13 +425,14 @@ func TestCompareAppStateCompareOptionIgnoreExtraneous(t *testing.T) { }, managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured), } - ctrl := newFakeController(&data) + ctrl := newFakeController(&data, nil) sources := make([]argoappv1.ApplicationSource, 0) sources = append(sources, app.Spec.GetSource()) revisions := make([]string, 0) revisions = append(revisions, "") - compRes := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false) + compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false) + assert.Nil(t, err) assert.NotNil(t, compRes) assert.Equal(t, argoappv1.SyncStatusCodeSynced, compRes.syncStatus.Status) @@ -303,12 +459,13 @@ func TestCompareAppStateExtraHook(t *testing.T) { key: pod, }, } - ctrl := newFakeController(&data) + ctrl := newFakeController(&data, nil) sources := make([]argoappv1.ApplicationSource, 0) sources = append(sources, app.Spec.GetSource()) revisions := make([]string, 0) revisions = append(revisions, "") - compRes := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false) + compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false) + assert.Nil(t, err) assert.NotNil(t, compRes) assert.Equal(t, argoappv1.SyncStatusCodeSynced, compRes.syncStatus.Status) @@ -331,12 +488,13 @@ func TestAppRevisionsSingleSource(t *testing.T) { }, managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured), } - ctrl := newFakeController(&data) + ctrl := newFakeController(&data, nil) app := newFakeApp() revisions := make([]string, 0) revisions = append(revisions, "") - compRes := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, app.Spec.GetSources(), false, false, nil, app.Spec.HasMultipleSources()) + compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, app.Spec.GetSources(), false, false, nil, app.Spec.HasMultipleSources()) + assert.Nil(t, err) assert.NotNil(t, compRes) assert.NotNil(t, compRes.syncStatus) assert.NotEmpty(t, compRes.syncStatus.Revision) @@ -370,12 +528,13 @@ func TestAppRevisionsMultiSource(t *testing.T) { }, managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured), } - ctrl := newFakeController(&data) + ctrl := newFakeController(&data, nil) app := newFakeMultiSourceApp() revisions := make([]string, 0) revisions = append(revisions, "") - compRes := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, app.Spec.GetSources(), false, false, nil, app.Spec.HasMultipleSources()) + compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, app.Spec.GetSources(), false, false, nil, app.Spec.HasMultipleSources()) + assert.Nil(t, err) assert.NotNil(t, compRes) assert.NotNil(t, compRes.syncStatus) assert.Empty(t, compRes.syncStatus.Revision) @@ -417,12 +576,13 @@ func TestCompareAppStateDuplicatedNamespacedResources(t *testing.T) { kube.GetResourceKey(obj3): obj3, }, } - ctrl := newFakeController(&data) + ctrl := newFakeController(&data, nil) sources := make([]argoappv1.ApplicationSource, 0) sources = append(sources, app.Spec.GetSource()) revisions := make([]string, 0) revisions = append(revisions, "") - compRes := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false) + compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false) + assert.Nil(t, err) assert.NotNil(t, compRes) assert.Equal(t, 1, len(app.Status.Conditions)) @@ -457,8 +617,9 @@ func TestCompareAppStateManagedNamespaceMetadataWithLiveNsDoesNotGetPruned(t *te kube.GetResourceKey(ns): ns, }, } - ctrl := newFakeController(&data) - compRes := ctrl.appStateManager.CompareAppState(app, &defaultProj, []string{}, app.Spec.Sources, false, false, nil, false) + ctrl := newFakeController(&data, nil) + compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, []string{}, app.Spec.Sources, false, false, nil, false) + assert.Nil(t, err) assert.NotNil(t, compRes) assert.Equal(t, 0, len(app.Status.Conditions)) @@ -512,13 +673,14 @@ func TestSetHealth(t *testing.T) { managedLiveObjs: map[kube.ResourceKey]*unstructured.Unstructured{ kube.GetResourceKey(deployment): deployment, }, - }) + }, nil) sources := make([]argoappv1.ApplicationSource, 0) sources = append(sources, app.Spec.GetSource()) revisions := make([]string, 0) revisions = append(revisions, "") - compRes := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false) + compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false) + assert.Nil(t, err) assert.Equal(t, health.HealthStatusHealthy, compRes.healthStatus.Status) } @@ -548,13 +710,14 @@ func TestSetHealthSelfReferencedApp(t *testing.T) { kube.GetResourceKey(deployment): deployment, kube.GetResourceKey(unstructuredApp): unstructuredApp, }, - }) + }, nil) sources := make([]argoappv1.ApplicationSource, 0) sources = append(sources, app.Spec.GetSource()) revisions := make([]string, 0) revisions = append(revisions, "") - compRes := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false) + compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false) + assert.Nil(t, err) assert.Equal(t, health.HealthStatusHealthy, compRes.healthStatus.Status) } @@ -574,7 +737,7 @@ func TestSetManagedResourcesWithOrphanedResources(t *testing.T) { AppName: "", }, }, - }) + }, nil) tree, err := ctrl.setAppManagedResources(app, &comparisonResult{managedResources: make([]managedResource, 0)}) @@ -603,7 +766,7 @@ func TestSetManagedResourcesWithResourcesOfAnotherApp(t *testing.T) { AppName: "app2", }, }, - }) + }, nil) tree, err := ctrl.setAppManagedResources(app1, &comparisonResult{managedResources: make([]managedResource, 0)}) @@ -622,13 +785,14 @@ func TestReturnUnknownComparisonStateOnSettingLoadError(t *testing.T) { configMapData: map[string]string{ "resource.customizations": "invalid setting", }, - }) + }, nil) sources := make([]argoappv1.ApplicationSource, 0) sources = append(sources, app.Spec.GetSource()) revisions := make([]string, 0) revisions = append(revisions, "") - compRes := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false) + compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false) + assert.Nil(t, err) assert.Equal(t, health.HealthStatusUnknown, compRes.healthStatus.Status) assert.Equal(t, argoappv1.SyncStatusCodeUnknown, compRes.syncStatus.Status) @@ -655,7 +819,7 @@ func TestSetManagedResourcesKnownOrphanedResourceExceptions(t *testing.T) { ResourceNode: argoappv1.ResourceNode{ResourceRef: argoappv1.ResourceRef{Kind: kube.ServiceAccountKind, Name: "kubernetes", Namespace: app.Namespace}}, }, }, - }) + }, nil) tree, err := ctrl.setAppManagedResources(app, &comparisonResult{managedResources: make([]managedResource, 0)}) @@ -668,14 +832,14 @@ func Test_appStateManager_persistRevisionHistory(t *testing.T) { app := newFakeApp() ctrl := newFakeController(&fakeData{ apps: []runtime.Object{app}, - }) + }, nil) manager := ctrl.appStateManager.(*appStateManager) setRevisionHistoryLimit := func(value int) { i := int64(value) app.Spec.RevisionHistoryLimit = &i } addHistory := func() { - err := manager.persistRevisionHistory(app, "my-revision", argoappv1.ApplicationSource{}, []string{}, []argoappv1.ApplicationSource{}, false, metav1.Time{}) + err := manager.persistRevisionHistory(app, "my-revision", argoappv1.ApplicationSource{}, []string{}, []argoappv1.ApplicationSource{}, false, metav1.Time{}, v1alpha1.OperationInitiator{}) assert.NoError(t, err) } addHistory() @@ -711,7 +875,7 @@ func Test_appStateManager_persistRevisionHistory(t *testing.T) { assert.Len(t, app.Status.History, 9) metav1NowTime := metav1.NewTime(time.Now()) - err := manager.persistRevisionHistory(app, "my-revision", argoappv1.ApplicationSource{}, []string{}, []argoappv1.ApplicationSource{}, false, metav1NowTime) + err := manager.persistRevisionHistory(app, "my-revision", argoappv1.ApplicationSource{}, []string{}, []argoappv1.ApplicationSource{}, false, metav1NowTime, v1alpha1.OperationInitiator{}) assert.NoError(t, err) assert.Equal(t, app.Status.History.LastRevisionHistory().DeployStartedAt, &metav1NowTime) } @@ -763,12 +927,13 @@ func TestSignedResponseNoSignatureRequired(t *testing.T) { }, managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured), } - ctrl := newFakeController(&data) + ctrl := newFakeController(&data, nil) sources := make([]argoappv1.ApplicationSource, 0) sources = append(sources, app.Spec.GetSource()) revisions := make([]string, 0) revisions = append(revisions, "") - compRes := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false) + compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false) + assert.Nil(t, err) assert.NotNil(t, compRes) assert.NotNil(t, compRes.syncStatus) assert.Equal(t, argoappv1.SyncStatusCodeSynced, compRes.syncStatus.Status) @@ -789,12 +954,13 @@ func TestSignedResponseNoSignatureRequired(t *testing.T) { }, managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured), } - ctrl := newFakeController(&data) + ctrl := newFakeController(&data, nil) sources := make([]argoappv1.ApplicationSource, 0) sources = append(sources, app.Spec.GetSource()) revisions := make([]string, 0) revisions = append(revisions, "") - compRes := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false) + compRes, err := ctrl.appStateManager.CompareAppState(app, &defaultProj, revisions, sources, false, false, nil, false) + assert.Nil(t, err) assert.NotNil(t, compRes) assert.NotNil(t, compRes.syncStatus) assert.Equal(t, argoappv1.SyncStatusCodeSynced, compRes.syncStatus.Status) @@ -820,12 +986,13 @@ func TestSignedResponseSignatureRequired(t *testing.T) { }, managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured), } - ctrl := newFakeController(&data) + ctrl := newFakeController(&data, nil) sources := make([]argoappv1.ApplicationSource, 0) sources = append(sources, app.Spec.GetSource()) revisions := make([]string, 0) revisions = append(revisions, "") - compRes := ctrl.appStateManager.CompareAppState(app, &signedProj, revisions, sources, false, false, nil, false) + compRes, err := ctrl.appStateManager.CompareAppState(app, &signedProj, revisions, sources, false, false, nil, false) + assert.Nil(t, err) assert.NotNil(t, compRes) assert.NotNil(t, compRes.syncStatus) assert.Equal(t, argoappv1.SyncStatusCodeSynced, compRes.syncStatus.Status) @@ -846,12 +1013,13 @@ func TestSignedResponseSignatureRequired(t *testing.T) { }, managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured), } - ctrl := newFakeController(&data) + ctrl := newFakeController(&data, nil) sources := make([]argoappv1.ApplicationSource, 0) sources = append(sources, app.Spec.GetSource()) revisions := make([]string, 0) revisions = append(revisions, "abc123") - compRes := ctrl.appStateManager.CompareAppState(app, &signedProj, revisions, sources, false, false, nil, false) + compRes, err := ctrl.appStateManager.CompareAppState(app, &signedProj, revisions, sources, false, false, nil, false) + assert.Nil(t, err) assert.NotNil(t, compRes) assert.NotNil(t, compRes.syncStatus) assert.Equal(t, argoappv1.SyncStatusCodeSynced, compRes.syncStatus.Status) @@ -872,12 +1040,13 @@ func TestSignedResponseSignatureRequired(t *testing.T) { }, managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured), } - ctrl := newFakeController(&data) + ctrl := newFakeController(&data, nil) sources := make([]argoappv1.ApplicationSource, 0) sources = append(sources, app.Spec.GetSource()) revisions := make([]string, 0) revisions = append(revisions, "abc123") - compRes := ctrl.appStateManager.CompareAppState(app, &signedProj, revisions, sources, false, false, nil, false) + compRes, err := ctrl.appStateManager.CompareAppState(app, &signedProj, revisions, sources, false, false, nil, false) + assert.Nil(t, err) assert.NotNil(t, compRes) assert.NotNil(t, compRes.syncStatus) assert.Equal(t, argoappv1.SyncStatusCodeSynced, compRes.syncStatus.Status) @@ -898,12 +1067,13 @@ func TestSignedResponseSignatureRequired(t *testing.T) { }, managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured), } - ctrl := newFakeController(&data) + ctrl := newFakeController(&data, nil) sources := make([]argoappv1.ApplicationSource, 0) sources = append(sources, app.Spec.GetSource()) revisions := make([]string, 0) revisions = append(revisions, "abc123") - compRes := ctrl.appStateManager.CompareAppState(app, &signedProj, revisions, sources, false, false, nil, false) + compRes, err := ctrl.appStateManager.CompareAppState(app, &signedProj, revisions, sources, false, false, nil, false) + assert.Nil(t, err) assert.NotNil(t, compRes) assert.NotNil(t, compRes.syncStatus) assert.Equal(t, argoappv1.SyncStatusCodeSynced, compRes.syncStatus.Status) @@ -925,14 +1095,15 @@ func TestSignedResponseSignatureRequired(t *testing.T) { }, managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured), } - ctrl := newFakeController(&data) + ctrl := newFakeController(&data, nil) testProj := signedProj testProj.Spec.SignatureKeys[0].KeyID = "4AEE18F83AFDEB24" sources := make([]argoappv1.ApplicationSource, 0) sources = append(sources, app.Spec.GetSource()) revisions := make([]string, 0) revisions = append(revisions, "abc123") - compRes := ctrl.appStateManager.CompareAppState(app, &testProj, revisions, sources, false, false, nil, false) + compRes, err := ctrl.appStateManager.CompareAppState(app, &testProj, revisions, sources, false, false, nil, false) + assert.Nil(t, err) assert.NotNil(t, compRes) assert.NotNil(t, compRes.syncStatus) assert.Equal(t, argoappv1.SyncStatusCodeSynced, compRes.syncStatus.Status) @@ -956,12 +1127,13 @@ func TestSignedResponseSignatureRequired(t *testing.T) { } // it doesn't matter for our test whether local manifests are valid localManifests := []string{"foobar"} - ctrl := newFakeController(&data) + ctrl := newFakeController(&data, nil) sources := make([]argoappv1.ApplicationSource, 0) sources = append(sources, app.Spec.GetSource()) revisions := make([]string, 0) revisions = append(revisions, "abc123") - compRes := ctrl.appStateManager.CompareAppState(app, &signedProj, revisions, sources, false, false, localManifests, false) + compRes, err := ctrl.appStateManager.CompareAppState(app, &signedProj, revisions, sources, false, false, localManifests, false) + assert.Nil(t, err) assert.NotNil(t, compRes) assert.NotNil(t, compRes.syncStatus) assert.Equal(t, argoappv1.SyncStatusCodeUnknown, compRes.syncStatus.Status) @@ -985,12 +1157,13 @@ func TestSignedResponseSignatureRequired(t *testing.T) { }, managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured), } - ctrl := newFakeController(&data) + ctrl := newFakeController(&data, nil) sources := make([]argoappv1.ApplicationSource, 0) sources = append(sources, app.Spec.GetSource()) revisions := make([]string, 0) revisions = append(revisions, "abc123") - compRes := ctrl.appStateManager.CompareAppState(app, &signedProj, revisions, sources, false, false, nil, false) + compRes, err := ctrl.appStateManager.CompareAppState(app, &signedProj, revisions, sources, false, false, nil, false) + assert.Nil(t, err) assert.NotNil(t, compRes) assert.NotNil(t, compRes.syncStatus) assert.Equal(t, argoappv1.SyncStatusCodeSynced, compRes.syncStatus.Status) @@ -1014,12 +1187,13 @@ func TestSignedResponseSignatureRequired(t *testing.T) { } // it doesn't matter for our test whether local manifests are valid localManifests := []string{""} - ctrl := newFakeController(&data) + ctrl := newFakeController(&data, nil) sources := make([]argoappv1.ApplicationSource, 0) sources = append(sources, app.Spec.GetSource()) revisions := make([]string, 0) revisions = append(revisions, "abc123") - compRes := ctrl.appStateManager.CompareAppState(app, &signedProj, revisions, sources, false, false, localManifests, false) + compRes, err := ctrl.appStateManager.CompareAppState(app, &signedProj, revisions, sources, false, false, localManifests, false) + assert.Nil(t, err) assert.NotNil(t, compRes) assert.NotNil(t, compRes.syncStatus) assert.Equal(t, argoappv1.SyncStatusCodeSynced, compRes.syncStatus.Status) @@ -1154,7 +1328,7 @@ func TestIsLiveResourceManaged(t *testing.T) { kube.GetResourceKey(unmanagedObjWrongGroup): unmanagedObjWrongGroup, kube.GetResourceKey(unmanagedObjWrongNamespace): unmanagedObjWrongNamespace, }, - }) + }, nil) manager := ctrl.appStateManager.(*appStateManager) appName := "guestbook" @@ -1223,3 +1397,272 @@ func TestIsLiveResourceManaged(t *testing.T) { assert.True(t, manager.isSelfReferencedObj(managedWrongAPIGroup, config, appName, common.AnnotationKeyAppInstance, argo.TrackingMethodAnnotation)) }) } + +func TestUseDiffCache(t *testing.T) { + type fixture struct { + testName string + noCache bool + manifestInfos []*apiclient.ManifestResponse + sources []argoappv1.ApplicationSource + app *argoappv1.Application + manifestRevisions []string + statusRefreshTimeout time.Duration + expectedUseCache bool + serverSideDiff bool + } + + manifestInfos := func(revision string) []*apiclient.ManifestResponse { + return []*apiclient.ManifestResponse{ + { + Manifests: []string{ + "{\"apiVersion\":\"v1\",\"kind\":\"Service\",\"metadata\":{\"labels\":{\"app.kubernetes.io/instance\":\"httpbin\"},\"name\":\"httpbin-svc\",\"namespace\":\"httpbin\"},\"spec\":{\"ports\":[{\"name\":\"http-port\",\"port\":7777,\"targetPort\":80},{\"name\":\"test\",\"port\":333}],\"selector\":{\"app\":\"httpbin\"}}}", + "{\"apiVersion\":\"apps/v1\",\"kind\":\"Deployment\",\"metadata\":{\"labels\":{\"app.kubernetes.io/instance\":\"httpbin\"},\"name\":\"httpbin-deployment\",\"namespace\":\"httpbin\"},\"spec\":{\"replicas\":2,\"selector\":{\"matchLabels\":{\"app\":\"httpbin\"}},\"template\":{\"metadata\":{\"labels\":{\"app\":\"httpbin\"}},\"spec\":{\"containers\":[{\"image\":\"kennethreitz/httpbin\",\"imagePullPolicy\":\"Always\",\"name\":\"httpbin\",\"ports\":[{\"containerPort\":80}]}]}}}}", + }, + Namespace: "", + Server: "", + Revision: revision, + SourceType: "Kustomize", + VerifyResult: "", + }, + } + } + sources := func() []argoappv1.ApplicationSource { + return []argoappv1.ApplicationSource{ + { + RepoURL: "https://some-repo.com", + Path: "argocd/httpbin", + TargetRevision: "HEAD", + }, + } + } + + app := func(namespace string, revision string, refresh bool, a *argoappv1.Application) *argoappv1.Application { + app := &argoappv1.Application{ + ObjectMeta: metav1.ObjectMeta{ + Name: "httpbin", + Namespace: namespace, + }, + Spec: argoappv1.ApplicationSpec{ + Source: &argoappv1.ApplicationSource{ + RepoURL: "https://some-repo.com", + Path: "argocd/httpbin", + TargetRevision: "HEAD", + }, + Destination: argoappv1.ApplicationDestination{ + Server: "https://kubernetes.default.svc", + Namespace: "httpbin", + }, + Project: "default", + SyncPolicy: &argoappv1.SyncPolicy{ + SyncOptions: []string{ + "CreateNamespace=true", + "ServerSideApply=true", + }, + }, + }, + Status: argoappv1.ApplicationStatus{ + Resources: []argoappv1.ResourceStatus{}, + Sync: argoappv1.SyncStatus{ + Status: argoappv1.SyncStatusCodeSynced, + ComparedTo: argoappv1.ComparedTo{ + Source: argoappv1.ApplicationSource{ + RepoURL: "https://some-repo.com", + Path: "argocd/httpbin", + TargetRevision: "HEAD", + }, + Destination: argoappv1.ApplicationDestination{ + Server: "https://kubernetes.default.svc", + Namespace: "httpbin", + }, + }, + Revision: revision, + Revisions: []string{}, + }, + ReconciledAt: &metav1.Time{ + Time: time.Now().Add(-time.Hour), + }, + }, + } + if refresh { + annotations := make(map[string]string) + annotations[argoappv1.AnnotationKeyRefresh] = string(argoappv1.RefreshTypeNormal) + app.SetAnnotations(annotations) + } + if a != nil { + err := mergo.Merge(app, a, mergo.WithOverride, mergo.WithOverwriteWithEmptyValue) + if err != nil { + t.Fatalf("error merging app: %s", err) + } + } + return app + } + + cases := []fixture{ + { + testName: "will use diff cache", + noCache: false, + manifestInfos: manifestInfos("rev1"), + sources: sources(), + app: app("httpbin", "rev1", false, nil), + manifestRevisions: []string{"rev1"}, + statusRefreshTimeout: time.Hour * 24, + expectedUseCache: true, + serverSideDiff: false, + }, + { + testName: "will use diff cache for multisource", + noCache: false, + manifestInfos: manifestInfos("rev1"), + sources: sources(), + app: app("httpbin", "", false, &argoappv1.Application{ + Spec: argoappv1.ApplicationSpec{ + Source: nil, + Sources: argoappv1.ApplicationSources{ + { + RepoURL: "multisource repo1", + }, + { + RepoURL: "multisource repo2", + }, + }, + }, + Status: argoappv1.ApplicationStatus{ + Resources: []argoappv1.ResourceStatus{}, + Sync: argoappv1.SyncStatus{ + Status: argoappv1.SyncStatusCodeSynced, + ComparedTo: argoappv1.ComparedTo{ + Source: argoappv1.ApplicationSource{}, + Sources: argoappv1.ApplicationSources{ + { + RepoURL: "multisource repo1", + }, + { + RepoURL: "multisource repo2", + }, + }, + }, + Revisions: []string{"rev1", "rev2"}, + }, + ReconciledAt: &metav1.Time{ + Time: time.Now().Add(-time.Hour), + }, + }, + }), + manifestRevisions: []string{"rev1", "rev2"}, + statusRefreshTimeout: time.Hour * 24, + expectedUseCache: true, + serverSideDiff: false, + }, + { + testName: "will return false if nocache is true", + noCache: true, + manifestInfos: manifestInfos("rev1"), + sources: sources(), + app: app("httpbin", "rev1", false, nil), + manifestRevisions: []string{"rev1"}, + statusRefreshTimeout: time.Hour * 24, + expectedUseCache: false, + serverSideDiff: false, + }, + { + testName: "will return false if requested refresh", + noCache: false, + manifestInfos: manifestInfos("rev1"), + sources: sources(), + app: app("httpbin", "rev1", true, nil), + manifestRevisions: []string{"rev1"}, + statusRefreshTimeout: time.Hour * 24, + expectedUseCache: false, + serverSideDiff: false, + }, + { + testName: "will return false if status expired", + noCache: false, + manifestInfos: manifestInfos("rev1"), + sources: sources(), + app: app("httpbin", "rev1", false, nil), + manifestRevisions: []string{"rev1"}, + statusRefreshTimeout: time.Minute, + expectedUseCache: false, + serverSideDiff: false, + }, + { + testName: "will return true if status expired and server-side diff", + noCache: false, + manifestInfos: manifestInfos("rev1"), + sources: sources(), + app: app("httpbin", "rev1", false, nil), + manifestRevisions: []string{"rev1"}, + statusRefreshTimeout: time.Minute, + expectedUseCache: true, + serverSideDiff: true, + }, + { + testName: "will return false if there is a new revision", + noCache: false, + manifestInfos: manifestInfos("rev1"), + sources: sources(), + app: app("httpbin", "rev1", false, nil), + manifestRevisions: []string{"rev2"}, + statusRefreshTimeout: time.Hour * 24, + expectedUseCache: false, + serverSideDiff: false, + }, + { + testName: "will return false if app spec repo changed", + noCache: false, + manifestInfos: manifestInfos("rev1"), + sources: sources(), + app: app("httpbin", "rev1", false, &argoappv1.Application{ + Spec: argoappv1.ApplicationSpec{ + Source: &argoappv1.ApplicationSource{ + RepoURL: "new-repo", + }, + }, + }), + manifestRevisions: []string{"rev1"}, + statusRefreshTimeout: time.Hour * 24, + expectedUseCache: false, + serverSideDiff: false, + }, + { + testName: "will return false if app spec IgnoreDifferences changed", + noCache: false, + manifestInfos: manifestInfos("rev1"), + sources: sources(), + app: app("httpbin", "rev1", false, &argoappv1.Application{ + Spec: argoappv1.ApplicationSpec{ + IgnoreDifferences: []argoappv1.ResourceIgnoreDifferences{ + { + Group: "app/v1", + Kind: "application", + Name: "httpbin", + Namespace: "httpbin", + JQPathExpressions: []string{"."}, + }, + }, + }, + }), + manifestRevisions: []string{"rev1"}, + statusRefreshTimeout: time.Hour * 24, + expectedUseCache: false, + serverSideDiff: false, + }, + } + + for _, tc := range cases { + tc := tc + t.Run(tc.testName, func(t *testing.T) { + // Given + t.Parallel() + logger, _ := logrustest.NewNullLogger() + log := logrus.NewEntry(logger) + + // When + useDiffCache := useDiffCache(tc.noCache, tc.manifestInfos, tc.sources, tc.app, tc.manifestRevisions, tc.statusRefreshTimeout, tc.serverSideDiff, log) + + // Then + assert.Equal(t, useDiffCache, tc.expectedUseCache) + }) + } +} diff --git a/controller/sync.go b/controller/sync.go index 783183c17fc7c..34c12bdb5da3c 100644 --- a/controller/sync.go +++ b/controller/sync.go @@ -3,6 +3,7 @@ package controller import ( "context" "encoding/json" + goerrors "errors" "fmt" "os" "strconv" @@ -56,6 +57,27 @@ func (m *appStateManager) getGVKParser(server string) (*managedfields.GvkParser, return cluster.GetGVKParser(), nil } +// getResourceOperations will return the kubectl implementation of the ResourceOperations +// interface that provides functionality to manage kubernetes resources. Returns a +// cleanup function that must be called to remove the generated kube config for this +// server. +func (m *appStateManager) getResourceOperations(server string) (kube.ResourceOperations, func(), error) { + clusterCache, err := m.liveStateCache.GetClusterCache(server) + if err != nil { + return nil, nil, fmt.Errorf("error getting cluster cache: %w", err) + } + + cluster, err := m.db.GetCluster(context.Background(), server) + if err != nil { + return nil, nil, fmt.Errorf("error getting cluster: %w", err) + } + ops, cleanup, err := m.kubectl.ManageResources(cluster.RawRestConfig(), clusterCache.GetOpenAPISchema()) + if err != nil { + return nil, nil, fmt.Errorf("error creating kubectl ResourceOperations: %w", err) + } + return ops, cleanup, nil +} + func (m *appStateManager) SyncAppState(app *v1alpha1.Application, state *v1alpha1.OperationState) { // Sync requests might be requested with ambiguous revisions (e.g. master, HEAD, v1.2.3). // This can change meaning when resuming operations (e.g a hook sync). After calculating a @@ -81,7 +103,7 @@ func (m *appStateManager) SyncAppState(app *v1alpha1.Application, state *v1alpha if syncOp.SyncOptions.HasOption("FailOnSharedResource=true") && hasSharedResource { state.Phase = common.OperationFailed - state.Message = fmt.Sprintf("Shared resouce found: %s", sharedResourceMessage) + state.Message = fmt.Sprintf("Shared resource found: %s", sharedResourceMessage) return } @@ -152,7 +174,13 @@ func (m *appStateManager) SyncAppState(app *v1alpha1.Application, state *v1alpha revisions = []string{revision} } - compareResult := m.CompareAppState(app, proj, revisions, sources, false, true, syncOp.Manifests, app.Spec.HasMultipleSources()) + // ignore error if CompareStateRepoError, this shouldn't happen as noRevisionCache is true + compareResult, err := m.CompareAppState(app, proj, revisions, sources, false, true, syncOp.Manifests, app.Spec.HasMultipleSources()) + if err != nil && !goerrors.Is(err, CompareStateRepoError) { + state.Phase = common.OperationError + state.Message = err.Error() + return + } // We now have a concrete commit SHA. Save this in the sync result revision so that we remember // what we should be syncing to when resuming operations. @@ -276,6 +304,7 @@ func (m *appStateManager) SyncAppState(app *v1alpha1.Application, state *v1alpha sync.WithInitialState(state.Phase, state.Message, initialResourcesRes, state.StartedAt), sync.WithResourcesFilter(func(key kube.ResourceKey, target *unstructured.Unstructured, live *unstructured.Unstructured) bool { return (len(syncOp.Resources) == 0 || + isPostDeleteHook(target) || argo.ContainsSyncResource(key.Name, key.Namespace, schema.GroupVersionKind{Kind: key.Kind, Group: key.Group}, syncOp.Resources)) && m.isSelfReferencedObj(live, target, app.GetName(), appLabelKey, trackingMethod) }), @@ -362,7 +391,7 @@ func (m *appStateManager) SyncAppState(app *v1alpha1.Application, state *v1alpha logEntry.WithField("duration", time.Since(start)).Info("sync/terminate complete") if !syncOp.DryRun && len(syncOp.Resources) == 0 && state.Phase.Successful() { - err := m.persistRevisionHistory(app, compareResult.syncStatus.Revision, source, compareResult.syncStatus.Revisions, compareResult.syncStatus.ComparedTo.Sources, app.Spec.HasMultipleSources(), state.StartedAt) + err := m.persistRevisionHistory(app, compareResult.syncStatus.Revision, source, compareResult.syncStatus.Revisions, compareResult.syncStatus.ComparedTo.Sources, app.Spec.HasMultipleSources(), state.StartedAt, state.Operation.InitiatedBy) if err != nil { state.Phase = common.OperationError state.Message = fmt.Sprintf("failed to record sync to history: %v", err) diff --git a/controller/sync_test.go b/controller/sync_test.go index da68e5d9a3dfe..309f846ca6460 100644 --- a/controller/sync_test.go +++ b/controller/sync_test.go @@ -41,7 +41,7 @@ func TestPersistRevisionHistory(t *testing.T) { }, managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured), } - ctrl := newFakeController(&data) + ctrl := newFakeController(&data, nil) // Sync with source unspecified opState := &v1alpha1.OperationState{Operation: v1alpha1.Operation{ @@ -87,7 +87,7 @@ func TestPersistManagedNamespaceMetadataState(t *testing.T) { }, managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured), } - ctrl := newFakeController(&data) + ctrl := newFakeController(&data, nil) // Sync with source unspecified opState := &v1alpha1.OperationState{Operation: v1alpha1.Operation{ @@ -118,7 +118,7 @@ func TestPersistRevisionHistoryRollback(t *testing.T) { }, managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured), } - ctrl := newFakeController(&data) + ctrl := newFakeController(&data, nil) // Sync with source specified source := v1alpha1.ApplicationSource{ @@ -172,7 +172,7 @@ func TestSyncComparisonError(t *testing.T) { }, managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured), } - ctrl := newFakeController(&data) + ctrl := newFakeController(&data, nil) // Sync with source unspecified opState := &v1alpha1.OperationState{Operation: v1alpha1.Operation{ @@ -217,7 +217,7 @@ func TestAppStateManager_SyncAppState(t *testing.T) { }, managedLiveObjs: make(map[kube.ResourceKey]*unstructured.Unstructured), } - ctrl := newFakeController(&data) + ctrl := newFakeController(&data, nil) return &fixture{ project: project, diff --git a/docs/assets/api-management.png b/docs/assets/api-management.png deleted file mode 100644 index ae066f0a6a87d..0000000000000 Binary files a/docs/assets/api-management.png and /dev/null differ diff --git a/docs/assets/groups-claim.png b/docs/assets/groups-claim.png deleted file mode 100644 index d27e03b661f82..0000000000000 Binary files a/docs/assets/groups-claim.png and /dev/null differ diff --git a/docs/assets/groups-scope.png b/docs/assets/groups-scope.png deleted file mode 100644 index 45557b51ead7f..0000000000000 Binary files a/docs/assets/groups-scope.png and /dev/null differ diff --git a/docs/assets/identity-center-1.png b/docs/assets/identity-center-1.png new file mode 100644 index 0000000000000..0cd49528d90f7 Binary files /dev/null and b/docs/assets/identity-center-1.png differ diff --git a/docs/assets/identity-center-2.png b/docs/assets/identity-center-2.png new file mode 100644 index 0000000000000..5a96899193168 Binary files /dev/null and b/docs/assets/identity-center-2.png differ diff --git a/docs/assets/identity-center-3.png b/docs/assets/identity-center-3.png new file mode 100644 index 0000000000000..79414b119d335 Binary files /dev/null and b/docs/assets/identity-center-3.png differ diff --git a/docs/assets/identity-center-4.png b/docs/assets/identity-center-4.png new file mode 100644 index 0000000000000..fbe48e4400974 Binary files /dev/null and b/docs/assets/identity-center-4.png differ diff --git a/docs/assets/identity-center-5.png b/docs/assets/identity-center-5.png new file mode 100644 index 0000000000000..f170c8d5069e0 Binary files /dev/null and b/docs/assets/identity-center-5.png differ diff --git a/docs/assets/identity-center-6.png b/docs/assets/identity-center-6.png new file mode 100644 index 0000000000000..01fe6f73f0642 Binary files /dev/null and b/docs/assets/identity-center-6.png differ diff --git a/docs/assets/okta-app.png b/docs/assets/okta-app.png new file mode 100644 index 0000000000000..bfc4570826b0a Binary files /dev/null and b/docs/assets/okta-app.png differ diff --git a/docs/assets/okta-auth-policy.png b/docs/assets/okta-auth-policy.png new file mode 100644 index 0000000000000..dbf99a88ed6e3 Binary files /dev/null and b/docs/assets/okta-auth-policy.png differ diff --git a/docs/assets/okta-auth-rule.png b/docs/assets/okta-auth-rule.png new file mode 100644 index 0000000000000..4e85b062f357b Binary files /dev/null and b/docs/assets/okta-auth-rule.png differ diff --git a/docs/assets/okta-create-oidc-app.png b/docs/assets/okta-create-oidc-app.png new file mode 100644 index 0000000000000..cf0b75b0e4a21 Binary files /dev/null and b/docs/assets/okta-create-oidc-app.png differ diff --git a/docs/assets/okta-groups-claim.png b/docs/assets/okta-groups-claim.png new file mode 100644 index 0000000000000..4edb93d42ea91 Binary files /dev/null and b/docs/assets/okta-groups-claim.png differ diff --git a/docs/assets/okta-groups-scope.png b/docs/assets/okta-groups-scope.png new file mode 100644 index 0000000000000..6cd1783c72653 Binary files /dev/null and b/docs/assets/okta-groups-scope.png differ diff --git a/docs/cli_installation.md b/docs/cli_installation.md index 42938bcd751ba..5a314d4ce6be2 100644 --- a/docs/cli_installation.md +++ b/docs/cli_installation.md @@ -37,6 +37,17 @@ sudo install -m 555 argocd-linux-amd64 /usr/local/bin/argocd rm argocd-linux-amd64 ``` +#### Download latest stable version + +You can download the latest stable release by executing below steps: + +```bash +VERSION=$(curl -L -s https://raw.githubusercontent.com/argoproj/argo-cd/stable/VERSION) +curl -sSL -o argocd-linux-amd64 https://github.com/argoproj/argo-cd/releases/download/v$VERSION/argocd-linux-amd64 +sudo install -m 555 argocd-linux-amd64 /usr/local/bin/argocd +rm argocd-linux-amd64 +``` + You should now be able to run `argocd` commands. diff --git a/docs/developer-guide/api-docs.md b/docs/developer-guide/api-docs.md index 289e4d466652e..63e3cd901e3d3 100644 --- a/docs/developer-guide/api-docs.md +++ b/docs/developer-guide/api-docs.md @@ -24,10 +24,9 @@ $ curl $ARGOCD_SERVER/api/v1/applications -H "Authorization: Bearer $ARGOCD_TOKE #### How to Avoid 403 Errors for Missing Applications -All endpoints of the Applications API accept an optional `project` query string parameter. If the parameter is -specified, and the specified Application does not exist, or if the Application does exist but is not in the given -project, the API will return a `404` error. +All endpoints of the Applications API accept an optional `project` query string parameter. If the parameter +is specified, and the specified Application does not exist, the API will return a `404` error. -If the `project` query string parameter is specified, and the Application does not exist, the API will return a `403` -error. This is to prevent leaking information about the existence of Applications to users who do not have access to -them. +Additionally, if the `project` query string parameter is specified and the Application exists but is not in +the given `project`, the API will return a `403` error. This is to prevent leaking information about the +existence of Applications to users who do not have access to them. \ No newline at end of file diff --git a/docs/developer-guide/architecture/components.md b/docs/developer-guide/architecture/components.md index eb2904b531ccb..e073751da4867 100644 --- a/docs/developer-guide/architecture/components.md +++ b/docs/developer-guide/architecture/components.md @@ -71,7 +71,7 @@ and the CLI functionalities. ### Application Controller The Application Controller is responsible for reconciling the -Application resource in Kubernetes syncronizing the desired +Application resource in Kubernetes synchronizing the desired application state (provided in Git) with the live state (in Kubernetes). The Application Controller is also responsible for reconciling the Project resource. diff --git a/docs/developer-guide/contributors-quickstart.md b/docs/developer-guide/contributors-quickstart.md index 0e98fab7ec940..a7646a6cf5f25 100644 --- a/docs/developer-guide/contributors-quickstart.md +++ b/docs/developer-guide/contributors-quickstart.md @@ -9,6 +9,8 @@ and the [toolchain guide](toolchain-guide.md). ### Install Go + + Install version 1.18 or newer (Verify version by running `go version`) ### Clone the Argo CD repo @@ -23,16 +25,29 @@ git clone https://github.com/argoproj/argo-cd.git -### Install or Upgrade `kind` (Optional - Should work with any local cluster) +### Install or Upgrade a Tool for Running Local Clusters (e.g. kind or minikube) + +#### Installation guide for kind: +#### Installation guide for minikube: + + + ### Start Your Local Cluster +For example, if you are using kind: ```shell kind create cluster ``` +Or, if you are using minikube: + +```shell +minikube start +``` + ### Install Argo CD ```shell diff --git a/docs/developer-guide/debugging-remote-environment.md b/docs/developer-guide/debugging-remote-environment.md index 7f8102a75c502..5548d3444af8c 100644 --- a/docs/developer-guide/debugging-remote-environment.md +++ b/docs/developer-guide/debugging-remote-environment.md @@ -45,7 +45,7 @@ And uninstall telepresence from your cluster: telepresence helm uninstall ``` -See [this quickstart](https://www.telepresence.io/docs/latest/howtos/intercepts/) for more information on how to intercept services using Telepresence. +See [this quickstart](https://www.telepresence.io/docs/latest/quick-start/) for more information on how to intercept services using Telepresence. ### Connect (telepresence v1) Use the following command instead: diff --git a/docs/developer-guide/extensions/ui-extensions.md b/docs/developer-guide/extensions/ui-extensions.md index 2c25748beb148..8d3d9dc4a3882 100644 --- a/docs/developer-guide/extensions/ui-extensions.md +++ b/docs/developer-guide/extensions/ui-extensions.md @@ -36,7 +36,7 @@ registerResourceExtension(component: ExtensionComponent, group: string, kind: st - `component: ExtensionComponent` is a React component that receives the following properties: - application: Application - Argo CD Application resource; - - resource: State - the kubernetes resource object; + - resource: State - the Kubernetes resource object; - tree: ApplicationTree - includes list of all resources that comprise the application; See properties interfaces in [models.ts](https://github.com/argoproj/argo-cd/blob/master/ui/src/app/shared/models.ts) @@ -95,3 +95,66 @@ Below is an example of a simple system level extension: Since the Argo CD Application is a Kubernetes resource, application tabs can be the same as any other resource tab. Make sure to use 'argoproj.io'/'Application' as group/kind and an extension will be used to render the application-level tab. + +## Application Status Panel Extensions + +The status panel is the bar at the top of the application view where the sync status is displayed. Argo CD allows you to add new items to the status panel of an application. The extension should be registered using the `extensionsAPI.registerStatusPanelExtension` method: + +```typescript +registerStatusPanelExtension(component: StatusPanelExtensionComponent, title: string, id: string, flyout?: ExtensionComponent) +``` + +Below is an example of a simple extension: + +```typescript +((window) => { + const component = () => { + return React.createElement( + "div", + { style: { padding: "10px" } }, + "Hello World" + ); + }; + window.extensionsAPI.registerStatusPanelExtension( + component, + "My Extension", + "my_extension" + ); +})(window); +``` + +### Flyout widget + +It is also possible to add an optional flyout widget to your extension. It can be opened by calling `openFlyout()` from your extension's component. Your flyout component will then be rendered in a sliding panel, similar to the panel that opens when clicking on `History and rollback`. + +Below is an example of an extension using the flyout widget: + +```typescript +((window) => { + const component = (props: { + openFlyout: () => any + }) => { + return React.createElement( + "div", + { + style: { padding: "10px" }, + onClick: () => props.openFlyout() + }, + "Hello World" + ); + }; + const flyout = () => { + return React.createElement( + "div", + { style: { padding: "10px" } }, + "This is a flyout" + ); + }; + window.extensionsAPI.registerStatusPanelExtension( + component, + "My Extension", + "my_extension", + flyout + ); +})(window); +``` diff --git a/docs/developer-guide/release-process-and-cadence.md b/docs/developer-guide/release-process-and-cadence.md index 051de617f0776..737c6eba6a8d9 100644 --- a/docs/developer-guide/release-process-and-cadence.md +++ b/docs/developer-guide/release-process-and-cadence.md @@ -6,14 +6,15 @@ These are the upcoming releases dates: -| Release | Release Planning Meeting | Release Candidate 1 | General Availability | Release Champion | Checklist | -|---------|--------------------------|-----------------------|----------------------|-------------------------------------------------------|---------------------------------------------------------------| -| v2.6 | Monday, Dec. 12, 2022 | Monday, Dec. 19, 2022 | Monday, Feb. 6, 2023 | [William Tam](https://github.com/wtam2018) | [checklist](https://github.com/argoproj/argo-cd/issues/11563) | -| v2.7 | Monday, Mar. 6, 2023 | Monday, Mar. 20, 2023 | Monday, May. 1, 2023 | [Pavel Kostohrys](https://github.com/pasha-codefresh) | [checklist](https://github.com/argoproj/argo-cd/issues/12762) | -| v2.8 | Monday, Jun. 20, 2023 | Monday, Jun. 26, 2023 | Monday, Aug. 7, 2023 | [Keith Chong](https://github.com/keithchong) | [checklist](https://github.com/argoproj/argo-cd/issues/13742) | -| v2.9 | Monday, Sep. 4, 2023 | Monday, Sep. 18, 2023 | Monday, Nov. 6, 2023 | [Leonardo Almeida](https://github.com/leoluz) | [checklist](https://github.com/argoproj/argo-cd/issues/14078) | -| v2.10 | Monday, Dec. 4, 2023 | Monday, Dec. 18, 2023 | Monday, Feb. 5, 2024 | - +| Release | Release Candidate 1 | General Availability | Release Champion | Release Approver |Checklist | +|---------|-----------------------|----------------------|-------------------------------------------------------|-------------------------------------------------------|---------------------------------------------------------------| +| v2.6 | Monday, Dec. 19, 2022 | Monday, Feb. 6, 2023 | [William Tam](https://github.com/wtam2018) | [William Tam](https://github.com/wtam2018) | [checklist](https://github.com/argoproj/argo-cd/issues/11563) | +| v2.7 | Monday, Mar. 20, 2023 | Monday, May 1, 2023 | [Pavel Kostohrys](https://github.com/pasha-codefresh) | [Pavel Kostohrys](https://github.com/pasha-codefresh) | [checklist](https://github.com/argoproj/argo-cd/issues/12762) | +| v2.8 | Monday, Jun. 26, 2023 | Monday, Aug. 7, 2023 | [Keith Chong](https://github.com/keithchong) | [Keith Chong](https://github.com/keithchong) | [checklist](https://github.com/argoproj/argo-cd/issues/13742) | +| v2.9 | Monday, Sep. 18, 2023 | Monday, Nov. 6, 2023 | [Leonardo Almeida](https://github.com/leoluz) | [Leonardo Almeida](https://github.com/leoluz) | [checklist](https://github.com/argoproj/argo-cd/issues/14078) | +| v2.10 | Monday, Dec. 18, 2023 | Monday, Feb. 5, 2024 | [Katie Lamkin](https://github.com/kmlamkin9) | | [checklist](https://github.com/argoproj/argo-cd/issues/16339) | +| v2.11 | Monday, Mar. 18, 2024 | Monday, May 6, 2024 | +| v2.12 | Monday, Jun. 17, 2024 | Monday, Aug. 5, 2024 | Actual release dates might differ from the plan by a few days. @@ -22,8 +23,8 @@ Actual release dates might differ from the plan by a few days. #### Minor Releases (e.g. 2.x.0) A minor Argo CD release occurs four times a year, once every three months. Each General Availability (GA) release is -preceded by several Release Candidates (RCs). The first RC is released three weeks before the scheduled GA date. This -effectively means that there is a three-week feature freeze. +preceded by several Release Candidates (RCs). The first RC is released seven weeks before the scheduled GA date. This +effectively means that there is a seven-week feature freeze. These are the approximate release dates: @@ -40,17 +41,6 @@ Argo CD patch releases occur on an as-needed basis. Only the three most recent m releases. Versions older than the three most recent minor versions are considered EOL and will not receive bug fixes or security updates. -#### Minor Release Planning Meeting - -Roughly two weeks before the RC date, there will be a meeting to discuss which features are planned for the RC. This meeting is -for contributors to advocate for certain features. Features which have at least one approver (besides the contributor) -who can assure they will review/merge by the RC date will be included in the release milestone. All other features will -be dropped from the milestone (and potentially shifted to the next one). - -Since not everyone will be able to attend the meeting, there will be a meeting doc. Contributors can add their feature -to a table, and Approvers can add their name to the table. Features with a corresponding approver will remain in the -release milestone. - #### Release Champion To help manage all the steps involved in a release, we will have a Release Champion. The Release Champion will be @@ -78,3 +68,21 @@ The feature PR must include: If these criteria are not met by the RC date, the feature will be ineligible for inclusion in the RC series or GA for that minor release. It will have to wait for the next minor release. + +### Security Patch Policy + +CVEs in Argo CD code will be patched for all [supported versions](../operator-manual/installation.md#supported-versions). + +### Dependencies Lifecycle Policy + +Dependencies are evaluated before being introduced to ensure they: + +1) are actively maintained +2) are maintained by trustworthy maintainers + +These evaluations vary from dependency to dependencies. + +Dependencies are also scheduled for removal if the project has been deprecated or if the project is no longer maintained. + +CVEs in dependencies will be patched for all supported versions if the CVE is applicable and is assessed by Snyk to be +of high or critical severity. Automation generates a [new Snyk scan weekly](../snyk). diff --git a/docs/developer-guide/site.md b/docs/developer-guide/site.md index 47c1f57e29bb7..efd6aece9aedb 100644 --- a/docs/developer-guide/site.md +++ b/docs/developer-guide/site.md @@ -2,24 +2,19 @@ ## Developing And Testing -The website is build using `mkdocs` and `mkdocs-material`. +The website is built using `mkdocs` and `mkdocs-material`. To test: ```bash +make build-docs make serve-docs ``` Once running, you can view your locally built documentation at [http://0.0.0.0:8000/](http://0.0.0.0:8000/). -## Deploying - -```bash -make publish-docs -``` - ## Analytics !!! tip Don't forget to disable your ad-blocker when testing. -We collect [Google Analytics](https://analytics.google.com/analytics/web/#/report-home/a105170809w198079555p192782995). \ No newline at end of file +We collect [Google Analytics](https://analytics.google.com/analytics/web/#/report-home/a105170809w198079555p192782995). diff --git a/docs/developer-guide/toolchain-guide.md b/docs/developer-guide/toolchain-guide.md index 42ca7fac87404..335180438dac6 100644 --- a/docs/developer-guide/toolchain-guide.md +++ b/docs/developer-guide/toolchain-guide.md @@ -304,7 +304,7 @@ For installing the tools required to build and test Argo CD on your local system You can change the target location by setting the `BIN` environment before running the installer scripts. For example, you can install the binaries into `~/go/bin` (which should then be the first component in your `PATH` environment, i.e. `export PATH=~/go/bin:$PATH`): ```shell -make BIN=~/go/bin install-tools-local +BIN=~/go/bin make install-tools-local ``` Additionally, you have to install at least the following tools via your OS's package manager (this list might not be always up-to-date): diff --git a/docs/faq.md b/docs/faq.md index 19273acc04d23..83bdf8d7d38b5 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -36,6 +36,15 @@ which might cause health check to return `Progressing` state instead of `Healthy As workaround Argo CD allows providing [health check](operator-manual/health.md) customization which overrides default behavior. +If you are using Traefik for your Ingress, you can update the Traefik config to publish the loadBalancer IP using [publishedservice](https://doc.traefik.io/traefik/providers/kubernetes-ingress/#publishedservice), which will resolve this issue. + +```yaml +providers: + kubernetesIngress: + publishedService: + enabled: true +``` + ## I forgot the admin password, how do I reset it? For Argo CD v1.8 and earlier, the initial password is set to the name of the server pod, as @@ -88,7 +97,7 @@ data: ## After deploying my Helm application with Argo CD I cannot see it with `helm ls` and other Helm commands -When deploying a Helm application Argo CD is using Helm +When deploying a Helm application Argo CD is using Helm only as a template mechanism. It runs `helm template` and then deploys the resulting manifests on the cluster instead of doing `helm install`. This means that you cannot use any Helm command to view/verify the application. It is fully managed by Argo CD. @@ -131,15 +140,15 @@ Argo CD automatically sets the `app.kubernetes.io/instance` label and uses it to If the tool does this too, this causes confusion. You can change this label by setting the `application.instanceLabelKey` value in the `argocd-cm`. We recommend that you use `argocd.argoproj.io/instance`. -!!! note +!!! note When you make this change your applications will become out of sync and will need re-syncing. See [#1482](https://github.com/argoproj/argo-cd/issues/1482). ## How often does Argo CD check for changes to my Git or Helm repository ? -The default polling interval is 3 minutes (180 seconds). -You can change the setting by updating the `timeout.reconciliation` value in the [argocd-cm](https://github.com/argoproj/argo-cd/blob/2d6ce088acd4fb29271ffb6f6023dbb27594d59b/docs/operator-manual/argocd-cm.yaml#L279-L282) config map. If there are any Git changes, Argo CD will only update applications with the [auto-sync setting](user-guide/auto_sync.md) enabled. If you set it to `0` then Argo CD will stop polling Git repositories automatically and you can only use alternative methods such as [webhooks](operator-manual/webhook.md) and/or manual syncs for deploying applications. +The default polling interval is 3 minutes (180 seconds) with a configurable jitter. +You can change the setting by updating the `timeout.reconciliation` value and the `timeout.reconciliation.jitter` in the [argocd-cm](https://github.com/argoproj/argo-cd/blob/2d6ce088acd4fb29271ffb6f6023dbb27594d59b/docs/operator-manual/argocd-cm.yaml#L279-L282) config map. If there are any Git changes, Argo CD will only update applications with the [auto-sync setting](user-guide/auto_sync.md) enabled. If you set it to `0` then Argo CD will stop polling Git repositories automatically and you can only use alternative methods such as [webhooks](operator-manual/webhook.md) and/or manual syncs for deploying applications. ## Why Are My Resource Limits `Out Of Sync`? @@ -241,7 +250,7 @@ There are two parts to the message: > map[name:**KEY_BC** value:150] map[name:**KEY_BC** value:500] map[name:**KEY_BD** value:250] map[name:**KEY_BD** value:500] map[name:KEY_BI value:something] - You'll want to identify the keys that are duplicated -- you can focus on the first part, as each duplicated key will appear, once for each of its value with its value in the first list. The second list is really just + You'll want to identify the keys that are duplicated -- you can focus on the first part, as each duplicated key will appear, once for each of its value with its value in the first list. The second list is really just `]` @@ -250,7 +259,7 @@ There are two parts to the message: This includes all of the keys. It's included for debugging purposes -- you don't need to pay much attention to it. It will give you a hint about the precise location in the list for the duplicated keys: > map[name:KEY_AA] map[name:KEY_AB] map[name:KEY_AC] map[name:KEY_AD] map[name:KEY_AE] map[name:KEY_AF] map[name:KEY_AG] map[name:KEY_AH] map[name:KEY_AI] map[name:KEY_AJ] map[name:KEY_AK] map[name:KEY_AL] map[name:KEY_AM] map[name:KEY_AN] map[name:KEY_AO] map[name:KEY_AP] map[name:KEY_AQ] map[name:KEY_AR] map[name:KEY_AS] map[name:KEY_AT] map[name:KEY_AU] map[name:KEY_AV] map[name:KEY_AW] map[name:KEY_AX] map[name:KEY_AY] map[name:KEY_AZ] map[name:KEY_BA] map[name:KEY_BB] map[name:**KEY_BC**] map[name:**KEY_BD**] map[name:KEY_BE] map[name:KEY_BF] map[name:KEY_BG] map[name:KEY_BH] map[name:KEY_BI] map[name:**KEY_BC**] map[name:**KEY_BD**] - + `]` In this case, the duplicated keys have been **emphasized** to help you identify the problematic keys. Many editors have the ability to highlight all instances of a string, using such an editor can help with such problems. diff --git a/docs/getting_started.md b/docs/getting_started.md index d81bd08897ad8..1000206eaf972 100644 --- a/docs/getting_started.md +++ b/docs/getting_started.md @@ -22,12 +22,8 @@ This will create a new namespace, `argocd`, where Argo CD services and applicati The installation manifests include `ClusterRoleBinding` resources that reference `argocd` namespace. If you are installing Argo CD into a different namespace then make sure to update the namespace reference. -If you are not interested in UI, SSO, multi-cluster features then you can install [core](operator-manual/installation.md#core) Argo CD components only: - -```bash -kubectl create namespace argocd -kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/core-install.yaml -``` +!!! tip + If you are not interested in UI, SSO, and multi-cluster features, then you can install only the [core](operator-manual/core/#installing) Argo CD components. This default installation will have a self-signed certificate and cannot be accessed without a bit of extra work. Do one of: diff --git a/docs/index.md b/docs/index.md index 6315ced37efad..ddb17c2bdc36a 100644 --- a/docs/index.md +++ b/docs/index.md @@ -53,7 +53,7 @@ meeting: ![Argo CD Architecture](assets/argocd_architecture.png) -Argo CD is implemented as a kubernetes controller which continuously monitors running applications +Argo CD is implemented as a Kubernetes controller which continuously monitors running applications and compares the current, live state against the desired target state (as specified in the Git repo). A deployed application whose live state deviates from the target state is considered `OutOfSync`. Argo CD reports & visualizes the differences, while providing facilities to automatically or diff --git a/docs/operator-manual/app-any-namespace.md b/docs/operator-manual/app-any-namespace.md index 21743b7bc003d..21bfa5c4f5a0b 100644 --- a/docs/operator-manual/app-any-namespace.md +++ b/docs/operator-manual/app-any-namespace.md @@ -15,7 +15,10 @@ Some manual steps will need to be performed by the Argo CD administrator in orde !!! note This feature is considered beta as of now. Some of the implementation details may change over the course of time until it is promoted to a stable status. We will be happy if early adopters use this feature and provide us with bug reports and feedback. - + + +One additional advantage of adopting applications in any namespace is to allow end-users to configure notifications for their Argo CD application in the namespace where Argo CD application is running in. See notifications [namespace based configuration](notifications/index.md#namespace-based-configuration) page for more information. + ## Prerequisites ### Cluster-scoped Argo CD installation diff --git a/docs/operator-manual/application.yaml b/docs/operator-manual/application.yaml index 75a0d3b0df8ae..864a293ce6890 100644 --- a/docs/operator-manual/application.yaml +++ b/docs/operator-manual/application.yaml @@ -119,7 +119,7 @@ spec: extVars: - name: foo value: bar - # You can use "code to determine if the value is either string (false, the default) or Jsonnet code (if code is true). + # You can use "code" to determine if the value is either string (false, the default) or Jsonnet code (if code is true). - code: true name: baz value: "true" @@ -189,6 +189,7 @@ spec: - PrunePropagationPolicy=foreground # Supported policies are background, foreground and orphan. - PruneLast=true # Allow the ability for resource pruning to happen as a final, implicit wave of a sync operation - RespectIgnoreDifferences=true # When syncing changes, respect fields ignored by the ignoreDifferences configuration + - ApplyOutOfSyncOnly=true # Only sync out-of-sync resources, rather than applying every object in the application managedNamespaceMetadata: # Sets the metadata for the application namespace. Only valid if CreateNamespace=true (see above), otherwise it's a no-op. labels: # The labels to set on the application namespace any: label diff --git a/docs/operator-manual/applicationset.yaml b/docs/operator-manual/applicationset.yaml index 65935802c674a..d05b08f1101a0 100644 --- a/docs/operator-manual/applicationset.yaml +++ b/docs/operator-manual/applicationset.yaml @@ -33,6 +33,6 @@ spec: - jsonPointers: - /spec/source/targetRevision - name: some-app - jqExpressions: + jqPathExpressions: - .spec.source.helm.values diff --git a/docs/operator-manual/applicationset/Appset-Any-Namespace.md b/docs/operator-manual/applicationset/Appset-Any-Namespace.md index 61716414aeb69..bf3f8ffecfaf1 100644 --- a/docs/operator-manual/applicationset/Appset-Any-Namespace.md +++ b/docs/operator-manual/applicationset/Appset-Any-Namespace.md @@ -35,6 +35,8 @@ kind: ApplicationSet metadata: name: myapps spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - scmProvider: gitea: @@ -137,17 +139,19 @@ metadata: name: team-one-product-one namespace: team-one-cd spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: list: - - id: infra + - name: infra project: infra-project - - id: team-two + - name: team-two project: team-two-project - template: - metadata: - name: '{{name}}-escalation' - spec: - project: "{{project}}" + template: + metadata: + name: '{{.name}}-escalation' + spec: + project: "{{.project}}" ``` ### ApplicationSet names diff --git a/docs/operator-manual/applicationset/Controlling-Resource-Modification.md b/docs/operator-manual/applicationset/Controlling-Resource-Modification.md index 73f8a5a3eeb50..d72cee60ad401 100644 --- a/docs/operator-manual/applicationset/Controlling-Resource-Modification.md +++ b/docs/operator-manual/applicationset/Controlling-Resource-Modification.md @@ -6,7 +6,7 @@ These settings allow you to exert control over when, and how, changes are made t Here are some of the controller settings that may be modified to alter the ApplicationSet controller's resource-handling behaviour. -### Dry run: prevent ApplicationSet from creating, modifying, or deleting all Applications +## Dry run: prevent ApplicationSet from creating, modifying, or deleting all Applications To prevent the ApplicationSet controller from creating, modifying, or deleting any `Application` resources, you may enable `dry-run` mode. This essentially switches the controller into a "read only" mode, where the controller Reconcile loop will run, but no resources will be modified. @@ -14,7 +14,7 @@ To enable dry-run, add `--dryrun true` to the ApplicationSet Deployment's contai See 'How to modify ApplicationSet container parameters' below for detailed steps on how to add this parameter to the controller. -### Managed Applications modification Policies +## Managed Applications modification Policies The ApplicationSet controller supports a parameter `--policy`, which is specified on launch (within the controller Deployment container), and which restricts what types of modifications will be made to managed Argo CD `Application` resources. @@ -32,16 +32,14 @@ spec: ``` -- Policy `create-only`: Prevents ApplicationSet controller from modifying or deleting Applications. -- Policy `create-update`: Prevents ApplicationSet controller from deleting Applications. Update is allowed. +- Policy `create-only`: Prevents ApplicationSet controller from modifying or deleting Applications. Prevents Application controller from deleting Applications according to [ownerReferences](https://kubernetes.io/docs/concepts/overview/working-with-objects/owners-dependents/). +- Policy `create-update`: Prevents ApplicationSet controller from deleting Applications. Update is allowed. Prevents Application controller from deleting Applications according to [ownerReferences](https://kubernetes.io/docs/concepts/overview/working-with-objects/owners-dependents/). - Policy `create-delete`: Prevents ApplicationSet controller from modifying Applications. Delete is allowed. - Policy `sync`: Update and Delete are allowed. If the controller parameter `--policy` is set, it takes precedence on the field `applicationsSync`. It is possible to allow per ApplicationSet sync policy by setting variable `ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_POLICY_OVERRIDE` to argocd-cmd-params-cm `applicationsetcontroller.enable.policy.override` or directly with controller parameter `--enable-policy-override` (default to `false`). -This does not prevent deletion of Applications if the ApplicationSet is deleted - -#### Controller parameter +### Controller parameter To allow the ApplicationSet controller to *create* `Application` resources, but prevent any further modification, such as deletion, or modification of Application fields, add this parameter in the ApplicationSet controller: ``` @@ -59,7 +57,7 @@ spec: applicationsSync: create-only ``` -### Policy - `create-update`: Prevent ApplicationSet controller from deleting Applications +## Policy - `create-update`: Prevent ApplicationSet controller from deleting Applications To allow the ApplicationSet controller to create or modify `Application` resources, but prevent Applications from being deleted, add the following parameter to the ApplicationSet controller `Deployment`: ``` @@ -79,7 +77,7 @@ spec: applicationsSync: create-update ``` -### Ignore certain changes to Applications +## Ignore certain changes to Applications The ApplicationSet spec includes an `ignoreApplicationDifferences` field, which allows you to specify which fields of the ApplicationSet should be ignored when comparing Applications. @@ -98,11 +96,94 @@ spec: - jsonPointers: - /spec/source/targetRevision - name: some-app - jqExpressions: + jqPathExpressions: - .spec.source.helm.values ``` -### Prevent an `Application`'s child resources from being deleted, when the parent Application is deleted +### Allow temporarily toggling auto-sync + +One of the most common use cases for ignoring differences is to allow temporarily toggling auto-sync for an Application. + +For example, if you have an ApplicationSet that is configured to automatically sync Applications, you may want to temporarily +disable auto-sync for a specific Application. You can do this by adding an ignore rule for the `spec.syncPolicy.automated` field. + +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: ApplicationSet +spec: + ignoreApplicationDifferences: + - jsonPointers: + - /spec/syncPolicy +``` + +### Limitations of `ignoreApplicationDifferences` + +When an ApplicationSet is reconciled, the controller will compare the ApplicationSet spec with the spec of each Application +that it manages. If there are any differences, the controller will generate a patch to update the Application to match the +ApplicationSet spec. + +The generated patch is a MergePatch. According to the MergePatch documentation, "existing lists will be completely +replaced by new lists" when there is a change to the list. + +This limits the effectiveness of `ignoreApplicationDifferences` when the ignored field is in a list. For example, if you +have an application with multiple sources, and you want to ignore changes to the `targetRevision` of one of the sources, +changes in other fields or in other sources will cause the entire `sources` list to be replaced, and the `targetRevision` +field will be reset to the value defined in the ApplicationSet. + +For example, consider this ApplicationSet: + +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: ApplicationSet +spec: + ignoreApplicationDifferences: + - jqPathExpressions: + - .spec.sources[] | select(.repoURL == "https://git.example.com/org/repo1").targetRevision + template: + spec: + sources: + - repoURL: https://git.example.com/org/repo1 + targetRevision: main + - repoURL: https://git.example.com/org/repo2 + targetRevision: main +``` + +You can freely change the `targetRevision` of the `repo1` source, and the ApplicationSet controller will not overwrite +your change. + +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: Application +spec: + sources: + - repoURL: https://git.example.com/org/repo1 + targetRevision: fix/bug-123 + - repoURL: https://git.example.com/org/repo2 + targetRevision: main +``` + +However, if you change the `targetRevision` of the `repo2` source, the ApplicationSet controller will overwrite the entire +`sources` field. + +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: Application +spec: + sources: + - repoURL: https://git.example.com/org/repo1 + targetRevision: main + - repoURL: https://git.example.com/org/repo2 + targetRevision: main +``` + +!!! note + [Future improvements](https://github.com/argoproj/argo-cd/issues/15975) to the ApplicationSet controller may + eliminate this problem. For example, the `ref` field might be made a merge key, allowing the ApplicationSet + controller to generate and use a StrategicMergePatch instead of a MergePatch. You could then target a specific + source by `ref`, ignore changes to a field in that source, and changes to other sources would not cause the ignored + field to be overwritten. + +## Prevent an `Application`'s child resources from being deleted, when the parent Application is deleted By default, when an `Application` resource is deleted by the ApplicationSet controller, all of the child resources of the Application will be deleted as well (such as, all of the Application's `Deployments`, `Services`, etc). @@ -119,7 +200,7 @@ spec: More information on the specific behaviour of `preserveResourcesOnDeletion`, and deletion in ApplicationSet controller and Argo CD in general, can be found on the [Application Deletion](Application-Deletion.md) page. -### Prevent an Application's child resources from being modified +## Prevent an Application's child resources from being modified Changes made to the ApplicationSet will propagate to the Applications managed by the ApplicationSet, and then Argo CD will propagate the Application changes to the underlying cluster resources (as per [Argo CD Integration](Argo-CD-Integration.md)). @@ -185,6 +266,11 @@ kubectl apply -n argocd -f install.yaml ## Preserving changes made to an Applications annotations and labels +!!! note + The same behavior can be achieved on a per-app basis using the [`ignoreApplicationDifferences`](#ignore-certain-changes-to-applications) + feature described above. However, preserved fields may be configured globally, a feature that is not yet available + for `ignoreApplicationDifferences`. + It is common practice in Kubernetes to store state in annotations, operators will often make use of this. To allow for this, it is possible to configure a list of annotations that the ApplicationSet should preserve when reconciling. For example, imagine that we have an Application created from an ApplicationSet, but a custom annotation and label has since been added (to the Application) that does not exist in the `ApplicationSet` resource: @@ -220,3 +306,18 @@ By default, the Argo CD notifications and the Argo CD refresh type annotations a !!!note One can also set global preserved fields for the controller by passing a comma separated list of annotations and labels to `ARGOCD_APPLICATIONSET_CONTROLLER_GLOBAL_PRESERVED_ANNOTATIONS` and `ARGOCD_APPLICATIONSET_CONTROLLER_GLOBAL_PRESERVED_LABELS` respectively. + +## Debugging unexpected changes to Applications + +When the ApplicationSet controller makes a change to an application, it logs the patch at the debug level. To see these +logs, set the log level to debug in the `argocd-cmd-params-cm` ConfigMap in the `argocd` namespace: + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: argocd-cmd-params-cm + namespace: argocd +data: + applicationsetcontroller.log.level: debug +``` diff --git a/docs/operator-manual/applicationset/Generators-Cluster-Decision-Resource.md b/docs/operator-manual/applicationset/Generators-Cluster-Decision-Resource.md index 8f5bb491b8b44..95c60d95cd68c 100644 --- a/docs/operator-manual/applicationset/Generators-Cluster-Decision-Resource.md +++ b/docs/operator-manual/applicationset/Generators-Cluster-Decision-Resource.md @@ -1,6 +1,6 @@ # Cluster Decision Resource Generator -The cluster decision resource generates a list of Argo CD clusters. This is done using [duck-typing](https://pkg.go.dev/knative.dev/pkg/apis/duck), which does not require knowledge of the full shape of the referenced kubernetes resource. The following is an example of a cluster-decision-resource-based ApplicationSet generator: +The cluster decision resource generates a list of Argo CD clusters. This is done using [duck-typing](https://pkg.go.dev/knative.dev/pkg/apis/duck), which does not require knowledge of the full shape of the referenced Kubernetes resource. The following is an example of a cluster-decision-resource-based ApplicationSet generator: ```yaml apiVersion: argoproj.io/v1alpha1 kind: ApplicationSet @@ -8,6 +8,8 @@ metadata: name: guestbook namespace: argocd spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - clusterDecisionResource: # ConfigMap with GVK information for the duck type resource @@ -26,7 +28,7 @@ spec: requeueAfterSeconds: 60 template: metadata: - name: '{{name}}-guestbook' + name: '{{.name}}-guestbook' spec: project: "default" source: @@ -34,7 +36,7 @@ spec: targetRevision: HEAD path: guestbook destination: - server: '{{clusterName}}' # 'server' field of the secret + server: '{{.clusterName}}' # 'server' field of the secret namespace: guestbook ``` The `quak` resource, referenced by the ApplicationSet `clusterDecisionResource` generator: diff --git a/docs/operator-manual/applicationset/Generators-Cluster.md b/docs/operator-manual/applicationset/Generators-Cluster.md index 92507645a4ffe..ca1a49aad295b 100644 --- a/docs/operator-manual/applicationset/Generators-Cluster.md +++ b/docs/operator-manual/applicationset/Generators-Cluster.md @@ -39,11 +39,13 @@ metadata: name: guestbook namespace: argocd spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - clusters: {} # Automatically use all clusters defined within Argo CD template: metadata: - name: '{{name}}-guestbook' # 'name' field of the Secret + name: '{{.name}}-guestbook' # 'name' field of the Secret spec: project: "my-project" source: @@ -51,7 +53,7 @@ spec: targetRevision: HEAD path: guestbook destination: - server: '{{server}}' # 'server' field of the secret + server: '{{.server}}' # 'server' field of the secret namespace: guestbook ``` (*The full example can be found [here](https://github.com/argoproj/argo-cd/tree/master/applicationset/examples/cluster).*) @@ -67,6 +69,8 @@ metadata: name: guestbook namespace: argocd spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - clusters: selector: @@ -105,6 +109,8 @@ The cluster generator will automatically target both local and non-local cluster If you wish to target only remote clusters with your Applications (e.g. you want to exclude the local cluster), then use a cluster selector with labels, for example: ```yaml spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - clusters: selector: @@ -137,6 +143,8 @@ You may pass additional, arbitrary string key-value pairs via the `values` field In this example, a `revision` parameter value is passed, based on matching labels on the cluster secret: ```yaml spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - clusters: selector: @@ -154,16 +162,16 @@ spec: revision: stable template: metadata: - name: '{{name}}-guestbook' + name: '{{.name}}-guestbook' spec: project: "my-project" source: repoURL: https://github.com/argoproj/argocd-example-apps/ # The cluster values field for each generator will be substituted here: - targetRevision: '{{values.revision}}' + targetRevision: '{{.values.revision}}' path: guestbook destination: - server: '{{server}}' + server: '{{.server}}' namespace: guestbook ``` @@ -184,6 +192,8 @@ Extending the example above, we could do something like this: ```yaml spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - clusters: selector: @@ -192,8 +202,8 @@ spec: # A key-value map for arbitrary parameters values: # If `my-custom-annotation` is in your cluster secret, `revision` will be substituted with it. - revision: '{{metadata.annotations.my-custom-annotation}}' - clusterName: '{{name}}' + revision: '{{index .metadata.annotations "my-custom-annotation"}}' + clusterName: '{{.name}}' - clusters: selector: matchLabels: @@ -201,19 +211,19 @@ spec: values: # production uses a different revision value, for 'stable' branch revision: stable - clusterName: '{{name}}' + clusterName: '{{.name}}' template: metadata: - name: '{{name}}-guestbook' + name: '{{.name}}-guestbook' spec: project: "my-project" source: repoURL: https://github.com/argoproj/argocd-example-apps/ # The cluster values field for each generator will be substituted here: - targetRevision: '{{values.revision}}' + targetRevision: '{{.values.revision}}' path: guestbook destination: # In this case this is equivalent to just using {{name}} - server: '{{values.clusterName}}' + server: '{{.values.clusterName}}' namespace: guestbook ``` diff --git a/docs/operator-manual/applicationset/Generators-Git.md b/docs/operator-manual/applicationset/Generators-Git.md index 1dcd85ea24b2a..7e4aa5fdb1c24 100644 --- a/docs/operator-manual/applicationset/Generators-Git.md +++ b/docs/operator-manual/applicationset/Generators-Git.md @@ -210,6 +210,8 @@ metadata: name: cluster-addons namespace: argocd spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - git: repoURL: https://github.com/example/example-repo.git @@ -217,19 +219,19 @@ spec: directories: - path: '*' values: - cluster: '{{branch}}-{{path}}' + cluster: '{{.branch}}-{{.path.basename}}' template: metadata: - name: '{{path.basename}}' + name: '{{.path.basename}}' spec: project: "my-project" source: repoURL: https://github.com/example/example-repo.git targetRevision: HEAD - path: '{{path}}' + path: '{{.path.path}}' destination: server: https://kubernetes.default.svc - namespace: '{{values.cluster}}' + namespace: '{{.values.cluster}}' ``` !!! note @@ -323,15 +325,15 @@ As with other generators, clusters *must* already be defined within Argo CD, in In addition to the flattened key/value pairs from the configuration file, the following generator parameters are provided: -- `{{path}}`: The path to the directory containing matching configuration file within the Git repository. Example: `/clusters/clusterA`, if the config file was `/clusters/clusterA/config.json` -- `{{path[n]}}`: The path to the matching configuration file within the Git repository, split into array elements (`n` - array index). Example: `path[0]: clusters`, `path[1]: clusterA` -- `{{path.basename}}`: Basename of the path to the directory containing the configuration file (e.g. `clusterA`, with the above example.) -- `{{path.basenameNormalized}}`: This field is the same as `path.basename` with unsupported characters replaced with `-` (e.g. a `path` of `/directory/directory_2`, and `path.basename` of `directory_2` would produce `directory-2` here). -- `{{path.filename}}`: The matched filename. e.g., `config.json` in the above example. -- `{{path.filenameNormalized}}`: The matched filename with unsupported characters replaced with `-`. +- `{{.path.path}}`: The path to the directory containing matching configuration file within the Git repository. Example: `/clusters/clusterA`, if the config file was `/clusters/clusterA/config.json` +- `{{index .path n}}`: The path to the matching configuration file within the Git repository, split into array elements (`n` - array index). Example: `index .path 0: clusters`, `index .path 1: clusterA` +- `{{.path.basename}}`: Basename of the path to the directory containing the configuration file (e.g. `clusterA`, with the above example.) +- `{{.path.basenameNormalized}}`: This field is the same as `.path.basename` with unsupported characters replaced with `-` (e.g. a `path` of `/directory/directory_2`, and `.path.basename` of `directory_2` would produce `directory-2` here). +- `{{.path.filename}}`: The matched filename. e.g., `config.json` in the above example. +- `{{.path.filenameNormalized}}`: The matched filename with unsupported characters replaced with `-`. -**Note**: The right-most *directory* name always becomes `{{path.basename}}`. For example, from `- path: /one/two/three/four/config.json`, `{{path.basename}}` will be `four`. -The filename can always be accessed using `{{path.filename}}`. +**Note**: The right-most *directory* name always becomes `{{.path.basename}}`. For example, from `- path: /one/two/three/four/config.json`, `{{.path.basename}}` will be `four`. +The filename can always be accessed using `{{.path.filename}}`. **Note**: If the `pathParamPrefix` option is specified, all `path`-related parameter names above will be prefixed with the specified value and a dot separator. E.g., if `pathParamPrefix` is `myRepo`, then the generated parameter name would be `myRepo.path` instead of `path`. Using this option is necessary in a Matrix generator where both child generators are Git generators (to avoid conflicts when merging the child generators’ items). @@ -349,6 +351,8 @@ metadata: name: guestbook namespace: argocd spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - git: repoURL: https://github.com/argoproj/argo-cd.git @@ -356,18 +360,18 @@ spec: files: - path: "applicationset/examples/git-generator-files-discovery/cluster-config/**/config.json" values: - base_dir: "{{path[0]}}/{{path[1]}}/{{path[2]}}" + base_dir: "{{index .path 0}}/{{index .path 1}}/{{index .path 2}}" template: metadata: - name: '{{cluster.name}}-guestbook' + name: '{{.cluster.name}}-guestbook' spec: project: default source: repoURL: https://github.com/argoproj/argo-cd.git targetRevision: HEAD - path: "{{values.base_dir}}/apps/guestbook" + path: "{{.values.base_dir}}/apps/guestbook" destination: - server: '{{cluster.address}}' + server: '{{.cluster.address}}' namespace: guestbook ``` @@ -405,15 +409,15 @@ the contents of webhook payloads are considered untrusted, and will only result application (a process which already occurs at three-minute intervals). If ApplicationSet is publicly accessible, then configuring a webhook secret is recommended to prevent a DDoS attack. -In the `argocd-secret` kubernetes secret, include the Git provider's webhook secret configured in step 1. +In the `argocd-secret` Kubernetes secret, include the Git provider's webhook secret configured in step 1. -Edit the Argo CD kubernetes secret: +Edit the Argo CD Kubernetes secret: ```bash kubectl edit secret argocd-secret -n argocd ``` -TIP: for ease of entering secrets, kubernetes supports inputting secrets in the `stringData` field, +TIP: for ease of entering secrets, Kubernetes supports inputting secrets in the `stringData` field, which saves you the trouble of base64 encoding the values and copying it to the `data` field. Simply copy the shared webhook secret created in step 1, to the corresponding GitHub/GitLab/BitBucket key under the `stringData` field: diff --git a/docs/operator-manual/applicationset/Generators-List.md b/docs/operator-manual/applicationset/Generators-List.md index a99229f858da4..e5696f37b9745 100644 --- a/docs/operator-manual/applicationset/Generators-List.md +++ b/docs/operator-manual/applicationset/Generators-List.md @@ -8,25 +8,26 @@ metadata: name: guestbook namespace: argocd spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - list: elements: - cluster: engineering-dev url: https://kubernetes.default.svc -# - cluster: engineering-prod -# url: https://kubernetes.default.svc -# foo: bar + - cluster: engineering-prod + url: https://kubernetes.default.svc template: metadata: - name: '{{cluster}}-guestbook' + name: '{{.cluster}}-guestbook' spec: project: "my-project" source: repoURL: https://github.com/argoproj/argo-cd.git targetRevision: HEAD - path: applicationset/examples/list-generator/guestbook/{{cluster}} + path: applicationset/examples/list-generator/guestbook/{{.cluster}} destination: - server: '{{url}}' + server: '{{.url}}' namespace: guestbook ``` (*The full example can be found [here](https://github.com/argoproj/argo-cd/tree/master/applicationset/examples/list-generator).*) diff --git a/docs/operator-manual/applicationset/Generators-Matrix.md b/docs/operator-manual/applicationset/Generators-Matrix.md index 6684cdc90f73b..0396b8c0e06d3 100644 --- a/docs/operator-manual/applicationset/Generators-Matrix.md +++ b/docs/operator-manual/applicationset/Generators-Matrix.md @@ -35,6 +35,8 @@ kind: ApplicationSet metadata: name: cluster-git spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: # matrix 'parent' generator - matrix: @@ -52,16 +54,16 @@ spec: argocd.argoproj.io/secret-type: cluster template: metadata: - name: '{{path.basename}}-{{name}}' + name: '{{.path.basename}}-{{.name}}' spec: - project: '{{metadata.labels.environment}}' + project: '{{index .metadata.labels "environment"}}' source: repoURL: https://github.com/argoproj/argo-cd.git targetRevision: HEAD - path: '{{path}}' + path: '{{.path.path}}' destination: - server: '{{server}}' - namespace: '{{path.basename}}' + server: '{{.server}}' + namespace: '{{.path.basename}}' ``` First, the Git directory generator will scan the Git repository, discovering directories under the specified path. It discovers the argo-workflows and prometheus-operator applications, and produces two corresponding sets of parameters: @@ -117,6 +119,8 @@ kind: ApplicationSet metadata: name: cluster-git spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: # matrix 'parent' generator - matrix: @@ -132,10 +136,10 @@ spec: selector: matchLabels: argocd.argoproj.io/secret-type: cluster - kubernetes.io/environment: '{{path.basename}}' + kubernetes.io/environment: '{{.path.basename}}' template: metadata: - name: '{{name}}-guestbook' + name: '{{.name}}-guestbook' spec: project: default source: @@ -143,7 +147,7 @@ spec: targetRevision: HEAD path: "examples/git-generator-files-discovery/apps/guestbook" destination: - server: '{{server}}' + server: '{{.server}}' namespace: guestbook ``` Here is the corresponding folder structure for the git repository used by the git-files generator: @@ -162,8 +166,8 @@ Here is the corresponding folder structure for the git repository used by the gi │ └── config.json └── git-generator-files.yaml ``` -In the above example, the `{{path.basename}}` parameters produced by the git-files generator will resolve to `dev` and `prod`. -In the 2nd child generator, the label selector with label `kubernetes.io/environment: {{path.basename}}` will resolve with the values produced by the first child generator's parameters (`kubernetes.io/environment: prod` and `kubernetes.io/environment: dev`). +In the above example, the `{{.path.basename}}` parameters produced by the git-files generator will resolve to `dev` and `prod`. +In the 2nd child generator, the label selector with label `kubernetes.io/environment: {{.path.basename}}` will resolve with the values produced by the first child generator's parameters (`kubernetes.io/environment: prod` and `kubernetes.io/environment: dev`). So in the above example, clusters with the label `kubernetes.io/environment: prod` will have only prod-specific configuration (ie. `prod/config.json`) applied to it, wheres clusters with the label `kubernetes.io/environment: dev` will have only dev-specific configuration (ie. `dev/config.json`) @@ -262,6 +266,8 @@ kind: ApplicationSet metadata: name: two-gits-with-path-param-prefix spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - matrix: generators: @@ -280,7 +286,7 @@ spec: repoURL: https://github.com/some-org/some-repo.git revision: HEAD files: - - path: "targets/{{appName}}/*.json" + - path: "targets/{{.appName}}/*.json" pathParamPrefix: target template: {} # ... ``` @@ -390,7 +396,7 @@ For example, the below example would be invalid (cluster-generator must come aft selector: matchLabels: argocd.argoproj.io/secret-type: cluster - kubernetes.io/environment: '{{path.basename}}' # {{path.basename}} is produced by git-files generator + kubernetes.io/environment: '{{.path.basename}}' # {{.path.basename}} is produced by git-files generator # git generator, 'child' #2 - git: repoURL: https://github.com/argoproj/applicationset.git @@ -398,7 +404,7 @@ For example, the below example would be invalid (cluster-generator must come aft files: - path: "examples/git-generator-files-discovery/cluster-config/**/config.json" -1. You cannot have both child generators consuming parameters from each another. In the example below, the cluster generator is consuming the `{{path.basename}}` parameter produced by the git-files generator, whereas the git-files generator is consuming the `{{name}}` parameter produced by the cluster generator. This will result in a circular dependency, which is invalid. +1. You cannot have both child generators consuming parameters from each another. In the example below, the cluster generator is consuming the `{{.path.basename}}` parameter produced by the git-files generator, whereas the git-files generator is consuming the `{{.name}}` parameter produced by the cluster generator. This will result in a circular dependency, which is invalid. - matrix: generators: @@ -407,13 +413,13 @@ For example, the below example would be invalid (cluster-generator must come aft selector: matchLabels: argocd.argoproj.io/secret-type: cluster - kubernetes.io/environment: '{{path.basename}}' # {{path.basename}} is produced by git-files generator + kubernetes.io/environment: '{{.path.basename}}' # {{.path.basename}} is produced by git-files generator # git generator, 'child' #2 - git: repoURL: https://github.com/argoproj/applicationset.git revision: HEAD files: - - path: "examples/git-generator-files-discovery/cluster-config/engineering/{{name}}**/config.json" # {{name}} is produced by cluster generator + - path: "examples/git-generator-files-discovery/cluster-config/engineering/{{.name}}**/config.json" # {{.name}} is produced by cluster generator 1. When using a Matrix generator nested inside another Matrix or Merge generator, [Post Selectors](Generators-Post-Selector.md) for this nested generator's generators will only be applied when enabled via `spec.applyNestedSelectors`. You may also need to enable this even if your Post Selectors are not within the nested matrix or Merge generator, but are instead a sibling of a nested Matrix or Merge generator. diff --git a/docs/operator-manual/applicationset/Generators-Merge.md b/docs/operator-manual/applicationset/Generators-Merge.md index 50da174cf349a..b2ccfe86fb66d 100644 --- a/docs/operator-manual/applicationset/Generators-Merge.md +++ b/docs/operator-manual/applicationset/Generators-Merge.md @@ -17,6 +17,8 @@ kind: ApplicationSet metadata: name: cluster-git spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: # merge 'parent' generator - merge: @@ -41,9 +43,9 @@ spec: values.redis: 'true' template: metadata: - name: '{{name}}' + name: '{{.name}}' spec: - project: '{{metadata.labels.environment}}' + project: '{{index .metadata.labels "environment"}}' source: repoURL: https://github.com/argoproj/argo-cd.git targetRevision: HEAD @@ -51,11 +53,11 @@ spec: helm: parameters: - name: kafka - value: '{{values.kafka}}' + value: '{{.values.kafka}}' - name: redis - value: '{{values.redis}}' + value: '{{.values.redis}}' destination: - server: '{{server}}' + server: '{{.server}}' namespace: default ``` @@ -122,6 +124,8 @@ kind: ApplicationSet metadata: name: cluster-git spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: # merge 'parent' generator: # Use the selector set by both child generators to combine them. @@ -135,7 +139,7 @@ spec: # Set the selector to this location. - clusters: values: - selector: '{{ metadata.labels.location }}' + selector: '{{index .metadata.labels "location"}}' # The git repo may have different directories which correspond to the # cluster locations, using these as a selector. - git: @@ -144,19 +148,19 @@ spec: directories: - path: '*' values: - selector: '{{ path }}' + selector: '{{.path.path}}' template: metadata: - name: '{{name}}' + name: '{{.name}}' spec: - project: '{{metadata.labels.environment}}' + project: '{{index .metadata.labels "environment"}}' source: repoURL: https://github.com/argoproj/argocd-example-apps/ # The cluster values field for each generator will be substituted here: targetRevision: HEAD - path: '{{path}}' + path: '{{.path.path}}' destination: - server: '{{server}}' + server: '{{.server}}' namespace: default ``` diff --git a/docs/operator-manual/applicationset/Generators-Plugin.md b/docs/operator-manual/applicationset/Generators-Plugin.md index 3747c38865df5..d0888b9949b8e 100644 --- a/docs/operator-manual/applicationset/Generators-Plugin.md +++ b/docs/operator-manual/applicationset/Generators-Plugin.md @@ -22,6 +22,8 @@ kind: ApplicationSet metadata: name: myplugin spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - plugin: # Specify the configMap where the plugin configuration is located. @@ -51,10 +53,10 @@ spec: metadata: name: myplugin annotations: - example.from.input.parameters: "{{ generator.input.parameters.map.key1 }}" - example.from.values: "{{ values.value1 }}" + example.from.input.parameters: "{{ index .generator.input.parameters.map "key1" }}" + example.from.values: "{{ .values.value1 }}" # The plugin determines what else it produces. - example.from.plugin.output: "{{ something.from.the.plugin }}" + example.from.plugin.output: "{{ .something.from.the.plugin }}" ``` - `configMapRef.name`: A `ConfigMap` name containing the plugin configuration to use for RPC call. @@ -230,6 +232,7 @@ metadata: name: fb-matrix spec: goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - matrix: generators: diff --git a/docs/operator-manual/applicationset/Generators-Post-Selector.md b/docs/operator-manual/applicationset/Generators-Post-Selector.md index d8570859084ff..896e89e267d7c 100644 --- a/docs/operator-manual/applicationset/Generators-Post-Selector.md +++ b/docs/operator-manual/applicationset/Generators-Post-Selector.md @@ -1,6 +1,6 @@ # Post Selector all generators -The Selector allows to post-filter based on generated values using the kubernetes common labelSelector format. In the example, the list generator generates a set of two application which then filter by the key value to only select the `env` with value `staging`: +The Selector allows to post-filter based on generated values using the Kubernetes common labelSelector format. In the example, the list generator generates a set of two application which then filter by the key value to only select the `env` with value `staging`: ## Example: List generator + Post Selector ```yaml @@ -9,6 +9,8 @@ kind: ApplicationSet metadata: name: guestbook spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - list: elements: @@ -23,15 +25,15 @@ spec: env: staging template: metadata: - name: '{{cluster}}-guestbook' + name: '{{.cluster}}-guestbook' spec: project: default source: repoURL: https://github.com/argoproj-labs/applicationset.git targetRevision: HEAD - path: examples/list-generator/guestbook/{{cluster}} + path: examples/list-generator/guestbook/{{.cluster}} destination: - server: '{{url}}' + server: '{{.url}}' namespace: guestbook ``` diff --git a/docs/operator-manual/applicationset/Generators-Pull-Request.md b/docs/operator-manual/applicationset/Generators-Pull-Request.md index 298e5135392ce..e54fc385d7d28 100644 --- a/docs/operator-manual/applicationset/Generators-Pull-Request.md +++ b/docs/operator-manual/applicationset/Generators-Pull-Request.md @@ -8,6 +8,8 @@ kind: ApplicationSet metadata: name: myapps spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - pullRequest: # When using a Pull Request generator, the ApplicationSet controller polls every `requeueAfterSeconds` interval (defaulting to every 30 minutes) to detect changes. @@ -33,6 +35,8 @@ kind: ApplicationSet metadata: name: myapps spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - pullRequest: github: @@ -75,6 +79,8 @@ kind: ApplicationSet metadata: name: myapps spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - pullRequest: gitlab: @@ -117,6 +123,8 @@ kind: ApplicationSet metadata: name: myapps spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - pullRequest: gitea: @@ -153,6 +161,8 @@ kind: ApplicationSet metadata: name: myapps spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - pullRequest: bitbucketServer: @@ -195,6 +205,8 @@ kind: ApplicationSet metadata: name: myapps spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - pullRequest: bitbucket: @@ -251,6 +263,8 @@ kind: ApplicationSet metadata: name: myapps spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - pullRequest: azuredevops: @@ -292,6 +306,8 @@ kind: ApplicationSet metadata: name: myapps spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - pullRequest: # ... @@ -319,21 +335,23 @@ kind: ApplicationSet metadata: name: myapps spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - pullRequest: # ... template: metadata: - name: 'myapp-{{branch}}-{{number}}' + name: 'myapp-{{.branch}}-{{.number}}' spec: source: repoURL: 'https://github.com/myorg/myrepo.git' - targetRevision: '{{head_sha}}' + targetRevision: '{{.head_sha}}' path: kubernetes/ helm: parameters: - name: "image.tag" - value: "pull-{{head_sha}}" + value: "pull-{{.head_sha}}" project: "my-project" destination: server: https://kubernetes.default.svc @@ -348,23 +366,25 @@ kind: ApplicationSet metadata: name: myapps spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - pullRequest: # ... template: metadata: - name: 'myapp-{{branch}}-{{number}}' + name: 'myapp-{{.branch}}-{{.number}}' spec: source: repoURL: 'https://github.com/myorg/myrepo.git' - targetRevision: '{{head_sha}}' + targetRevision: '{{.head_sha}}' path: kubernetes/ kustomize: - nameSuffix: {{branch}} + nameSuffix: '{{.branch}}' commonLabels: - app.kubernetes.io/instance: {{branch}}-{{number}} + app.kubernetes.io/instance: '{{.branch}}-{{.number}}' images: - - ghcr.io/myorg/myrepo:{{head_sha}} + - 'ghcr.io/myorg/myrepo:{{.head_sha}}' project: "my-project" destination: server: https://kubernetes.default.svc diff --git a/docs/operator-manual/applicationset/Generators-SCM-Provider.md b/docs/operator-manual/applicationset/Generators-SCM-Provider.md index 5e3c4a6ab8aa4..40c8e552fe573 100644 --- a/docs/operator-manual/applicationset/Generators-SCM-Provider.md +++ b/docs/operator-manual/applicationset/Generators-SCM-Provider.md @@ -111,7 +111,7 @@ spec: * `tokenRef`: A `Secret` name and key containing the GitLab access token to use for requests. If not specified, will make anonymous requests which have a lower rate limit and can only see public repositories. * `insecure`: By default (false) - Skip checking the validity of the SCM's certificate - useful for self-signed TLS certificates. -For label filtering, the repository tags are used. +For label filtering, the repository topics are used. Available clone protocols are `ssh` and `https`. @@ -395,16 +395,18 @@ kind: ApplicationSet metadata: name: myapps spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - scmProvider: # ... template: metadata: - name: '{{ repository }}' + name: '{{ .repository }}' spec: source: - repoURL: '{{ url }}' - targetRevision: '{{ branch }}' + repoURL: '{{ .url }}' + targetRevision: '{{ .branch }}' path: kubernetes/ project: default destination: @@ -433,6 +435,8 @@ kind: ApplicationSet metadata: name: myapps spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - scmProvider: bitbucketServer: @@ -445,15 +449,15 @@ spec: secretName: mypassword key: password values: - name: "{{organization}}-{{repository}}" + name: "{{.organization}}-{{.repository}}" template: metadata: - name: '{{ values.name }}' + name: '{{ .values.name }}' spec: source: - repoURL: '{{ url }}' - targetRevision: '{{ branch }}' + repoURL: '{{ .url }}' + targetRevision: '{{ .branch }}' path: kubernetes/ project: default destination: diff --git a/docs/operator-manual/applicationset/GoTemplate.md b/docs/operator-manual/applicationset/GoTemplate.md index 08c1f3feb035a..1d62eeea9f93a 100644 --- a/docs/operator-manual/applicationset/GoTemplate.md +++ b/docs/operator-manual/applicationset/GoTemplate.md @@ -12,6 +12,29 @@ An additional `normalize` function makes any string parameter usable as a valid with hyphens and truncating at 253 characters. This is useful when making parameters safe for things like Application names. +Another `slugify` function has been added which, by default, sanitizes and smart truncates (it doesn't cut a word into 2). This function accepts a couple of arguments: +- The first argument (if provided) is an integer specifying the maximum length of the slug. +- The second argument (if provided) is a boolean indicating whether smart truncation is enabled. +- The last argument (if provided) is the input name that needs to be slugified. + +#### Usage example + +``` +apiVersion: argoproj.io/v1alpha1 +kind: ApplicationSet +metadata: + name: test-appset +spec: + ... + template: + metadata: + name: 'hellos3-{{.name}}-{{ cat .branch | slugify 23 }}' + annotations: + label-1: '{{ cat .branch | slugify }}' + label-2: '{{ cat .branch | slugify 23 }}' + label-3: '{{ cat .branch | slugify 50 false }}' +``` + If you want to customize [options defined by text/template](https://pkg.go.dev/text/template#Template.Option), you can add the `goTemplateOptions: ["opt1", "opt2", ...]` key to your ApplicationSet next to `goTemplate: true`. Note that at the time of writing, there is only one useful option defined, which is `missingkey=error`. @@ -183,6 +206,8 @@ ApplicationSet controller provides: 1. contains no more than 253 characters 2. contains only lowercase alphanumeric characters, '-' or '.' 3. starts and ends with an alphanumeric character + +- `slugify`: sanitizes like `normalize` and smart truncates (it doesn't cut a word into 2) like described in the [introduction](#introduction) section. - `toYaml` / `fromYaml` / `fromYamlArray` helm like functions diff --git a/docs/operator-manual/applicationset/Progressive-Syncs.md b/docs/operator-manual/applicationset/Progressive-Syncs.md index 8864151e9dcb7..edfe0dad101f2 100644 --- a/docs/operator-manual/applicationset/Progressive-Syncs.md +++ b/docs/operator-manual/applicationset/Progressive-Syncs.md @@ -52,8 +52,7 @@ Once a change is pushed, the following will happen in order. * The rollout will wait for all `env-qa` Applications to be manually synced via the `argocd` CLI or by clicking the Sync button in the UI. * 10% of all `env-prod` Applications will be updated at a time until all `env-prod` Applications have been updated. -``` ---- +```yaml apiVersion: argoproj.io/v1alpha1 kind: ApplicationSet metadata: diff --git a/docs/operator-manual/applicationset/Template.md b/docs/operator-manual/applicationset/Template.md index f66a403586bbd..9a7cd574453b4 100644 --- a/docs/operator-manual/applicationset/Template.md +++ b/docs/operator-manual/applicationset/Template.md @@ -108,3 +108,71 @@ spec: (*The full example can be found [here](https://github.com/argoproj/argo-cd/tree/master/applicationset/examples/template-override).*) In this example, the ApplicationSet controller will generate an `Application` resource using the `path` generated by the List generator, rather than the `path` value defined in `.spec.template`. + +## Template Patch + +Templating is only available on string type. However, some use cases may require applying templating on other types. + +Example: + +- Conditionally set the automated sync policy. +- Conditionally switch prune boolean to `true`. +- Add multiple helm value files from a list. + +The `templatePatch` feature enables advanced templating, with support for `json` and `yaml`. + +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: ApplicationSet +metadata: + name: guestbook +spec: + goTemplate: true + generators: + - list: + elements: + - cluster: engineering-dev + url: https://kubernetes.default.svc + autoSync: true + prune: true + valueFiles: + - values.large.yaml + - values.debug.yaml + template: + metadata: + name: '{{.cluster}}-deployment' + spec: + project: "default" + source: + repoURL: https://github.com/infra-team/cluster-deployments.git + targetRevision: HEAD + path: guestbook/{{ .cluster }} + destination: + server: '{{.url}}' + namespace: guestbook + templatePatch: | + spec: + source: + helm: + valueFiles: + {{- range $valueFile := .valueFiles }} + - {{ $valueFile }} + {{- end }} + {{- if .autoSync }} + syncPolicy: + automated: + prune: {{ .prune }} + {{- end }} +``` + +!!! important + The `templatePatch` can apply arbitrary changes to the template. If parameters include untrustworthy user input, it + may be possible to inject malicious changes into the template. It is recommended to use `templatePatch` only with + trusted input or to carefully escape the input before using it in the template. Piping input to `toJson` should help + prevent, for example, a user from successfully injecting a string with newlines. + + The `spec.project` field is not supported in `templatePatch`. If you need to change the project, you can use the + `spec.project` field in the `template` field. + +!!! important + When writing a `templatePatch`, you're crafting a patch. So, if the patch includes an empty `spec: # nothing in here`, it will effectively clear out existing fields. See [#17040](https://github.com/argoproj/argo-cd/issues/17040) for an example of this behavior. diff --git a/docs/operator-manual/applicationset/Use-Cases.md b/docs/operator-manual/applicationset/Use-Cases.md index 0e9c65d3963ee..a13c6598072ca 100644 --- a/docs/operator-manual/applicationset/Use-Cases.md +++ b/docs/operator-manual/applicationset/Use-Cases.md @@ -68,10 +68,26 @@ Thus in the self-service use case, administrators desire to only allow some fiel Fortunately, the ApplicationSet controller presents an alternative solution to this use case: cluster administrators may safely create an `ApplicationSet` resource containing a Git generator that restricts deployment of application resources to fixed values with the `template` field, while allowing customization of 'safe' fields by developers, at will. +The `config.json` files contain information describing the app. + +```json +{ + (...) + "app": { + "source": "https://github.com/argoproj/argo-cd", + "revision": "HEAD", + "path": "applicationset/examples/git-generator-files-discovery/apps/guestbook" + } + (...) +} +``` + ```yaml kind: ApplicationSet # (...) spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - git: repoURL: https://github.com/argoproj/argo-cd.git @@ -82,9 +98,9 @@ spec: project: dev-team-one # project is restricted source: # developers may customize app details using JSON files from above repo URL - repoURL: {{app.source}} - targetRevision: {{app.revision}} - path: {{app.path}} + repoURL: {{.app.source}} + targetRevision: {{.app.revision}} + path: {{.app.path}} destination: name: production-cluster # cluster is restricted namespace: dev-team-one # namespace is restricted diff --git a/docs/operator-manual/applicationset/index.md b/docs/operator-manual/applicationset/index.md index 1fe83fb2a0952..ea7c0f3deaf5d 100644 --- a/docs/operator-manual/applicationset/index.md +++ b/docs/operator-manual/applicationset/index.md @@ -27,6 +27,8 @@ kind: ApplicationSet metadata: name: guestbook spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] generators: - list: elements: @@ -38,15 +40,15 @@ spec: url: https://9.8.7.6 template: metadata: - name: '{{cluster}}-guestbook' + name: '{{.cluster}}-guestbook' spec: project: my-project source: repoURL: https://github.com/infra-team/cluster-deployments.git targetRevision: HEAD - path: guestbook/{{cluster}} + path: guestbook/{{.cluster}} destination: - server: '{{url}}' + server: '{{.url}}' namespace: guestbook ``` diff --git a/docs/operator-manual/argocd-cm.yaml b/docs/operator-manual/argocd-cm.yaml index 5e4ed095be56d..4355354d2faef 100644 --- a/docs/operator-manual/argocd-cm.yaml +++ b/docs/operator-manual/argocd-cm.yaml @@ -308,14 +308,22 @@ data: # have either a permanent banner or a regular closeable banner, and NOT both. eg. A user can't dismiss a # notification message (closeable) banner, to then immediately see a permanent banner. # ui.bannerpermanent: "true" - # An option to specify the position of the banner, either the top or bottom of the page. The default is at the top. - # Uncomment to make the banner appear at the bottom of the page. Any value other than "bottom" will make the banner appear at the top. + # An option to specify the position of the banner, either the top or bottom of the page, or both. The valid values + # are: "top", "bottom" and "both". The default (if the option is not provided), is "top". If "both" is specified, then + # the content appears both at the top and the bottom of the page. Uncomment the following line to make the banner appear + # at the bottom of the page. Change the value as needed. # ui.bannerposition: "bottom" # Application reconciliation timeout is the max amount of time required to discover if a new manifests version got # published to the repository. Reconciliation by timeout is disabled if timeout is set to 0. Three minutes by default. # > Note: argocd-repo-server deployment must be manually restarted after changing the setting. timeout.reconciliation: 180s + # With a large number of applications, the periodic refresh for each application can cause a spike in the refresh queue + # and can cause a spike in the repo-server component. To avoid this, you can set a jitter to the sync timeout, which will + # spread out the refreshes and give time to the repo-server to catch up. The jitter is the maximum duration that can be + # added to the sync timeout. So, if the sync timeout is 3 minutes and the jitter is 1 minute, then the actual timeout will + # be between 3 and 4 minutes. Disabled when the value is 0, defaults to 0. + timeout.reconciliation.jitter: 0 # cluster.inClusterEnabled indicates whether to allow in-cluster server address. This is enabled by default. cluster.inClusterEnabled: "true" diff --git a/docs/operator-manual/argocd-cmd-params-cm.yaml b/docs/operator-manual/argocd-cmd-params-cm.yaml index 7d38506d0b7ec..3cb79d85f3150 100644 --- a/docs/operator-manual/argocd-cmd-params-cm.yaml +++ b/docs/operator-manual/argocd-cmd-params-cm.yaml @@ -17,7 +17,11 @@ data: redis.db: # Open-Telemetry collector address: (e.g. "otel-collector:4317") - otlp.address: + otlp.address: "" + # Open-Telemetry collector insecure: (e.g. "true") + otlp.insecure: "true" + # Open-Telemetry collector headers: (e.g. "key1=value1,key2=value2") + otlp.headers: "" # List of additional namespaces where applications may be created in and # reconciled from. The namespace where Argo CD is installed to will always @@ -58,6 +62,16 @@ data: controller.sharding.algorithm: legacy # Number of allowed concurrent kubectl fork/execs. Any value less than 1 means no limit. controller.kubectl.parallelism.limit: "20" + # The maximum number of retries for each request + controller.k8sclient.retry.max: "0" + # The initial backoff delay on the first retry attempt in ms. Subsequent retries will double this backoff time up to a maximum threshold + controller.k8sclient.retry.base.backoff: "100" + # Grace period in seconds for ignoring consecutive errors while communicating with repo server. + controller.repo.error.grace.period.seconds: "180" + # Enables the server side diff feature at the application controller level. + # Diff calculation will be done by running a server side apply dryrun (when + # diff cache is unavailable). + controller.diff.server.side: "false" ## Server properties # Listen on given address for incoming connections (default "0.0.0.0") @@ -72,6 +86,13 @@ data: server.rootpath: "" # Directory path that contains additional static assets server.staticassets: "/shared/app" + # The maximum number of retries for each request + server.k8sclient.retry.max: "0" + # The initial backoff delay on the first retry attempt in ms. Subsequent retries will double this backoff time up to a maximum threshold + server.k8sclient.retry.base.backoff: "100" + # Semicolon-separated list of content types allowed on non-GET requests. Set an empty string to allow all. Be aware + # that allowing content types besides application/json may make your API more vulnerable to CSRF attacks. + server.api.content.types: "application/json" # Set the logging format. One of: text|json (default "text") server.log.format: "text" @@ -154,6 +175,10 @@ data: reposerver.streamed.manifest.max.extracted.size: "1G" # Enable git submodule support reposerver.enable.git.submodule: "true" + # Number of concurrent git ls-remote requests. Any value less than 1 means no limit. + reposerver.git.lsremote.parallelism.limit: "0" + # Git requests timeout. + reposerver.git.request.timeout: "15s" # Disable TLS on the HTTP endpoint dexserver.disable.tls: "false" @@ -192,3 +217,5 @@ data: notificationscontroller.log.level: "info" # Set the logging format. One of: text|json (default "text") notificationscontroller.log.format: "text" + # Enable self-service notifications config. Used in conjunction with apps-in-any-namespace. (default "false") + notificationscontroller.selfservice.enabled: "false" diff --git a/docs/operator-manual/cluster-management.md b/docs/operator-manual/cluster-management.md new file mode 100644 index 0000000000000..bd0d28e08dba7 --- /dev/null +++ b/docs/operator-manual/cluster-management.md @@ -0,0 +1,23 @@ +# Cluster Management + +This guide is for operators looking to manage clusters on the CLI. If you want to use Kubernetes resources for this, check out [Declarative Setup](./declarative-setup.md#clusters). + +Not all commands are described here, see the [argocd cluster Command Reference](../user-guide/commands/argocd_cluster.md) for all available commands. + +## Adding a cluster + +Run `argocd cluster add context-name`. + +If you're unsure about the context names, run `kubectl config get-contexts` to get them all listed. + +This will connect to the cluster and install the necessary resources for ArgoCD to connect to it. +Note that you will need privileged access to the cluster. + +## Removing a cluster + +Run `argocd cluster rm context-name`. + +This removes the cluster with the specified name. + +!!!note "in-cluster cannot be removed" + The `in-cluster` cluster cannot be removed with this. If you want to disable the `in-cluster` configuration, you need to update your `argocd-cm` ConfigMap. Set [`cluster.inClusterEnabled`](./argocd-cm-yaml.md) to `"false"` diff --git a/docs/operator-manual/config-management-plugins.md b/docs/operator-manual/config-management-plugins.md index ee805b71cd604..7c86075ff2f7f 100644 --- a/docs/operator-manual/config-management-plugins.md +++ b/docs/operator-manual/config-management-plugins.md @@ -34,6 +34,8 @@ metadata: # The name of the plugin must be unique within a given Argo CD instance. name: my-plugin spec: + # The version of your plugin. Optional. If specified, the Application's spec.source.plugin.name field + # must be -. version: v1.0 # The init command runs in the Application source directory at the beginning of each manifest generation. The init # command can output anything. A non-zero status code will fail manifest generation. @@ -44,6 +46,7 @@ spec: args: [-c, 'echo "Initializing..."'] # The generate command runs in the Application source directory each time manifests are generated. Standard output # must be ONLY valid Kubernetes Objects in either YAML or JSON. A non-zero exit code will fail manifest generation. + # To write log messages from the command, write them to stderr, it will always be displayed. # Error output will be sent to the UI, so avoid printing sensitive information (such as secrets). generate: command: [sh, -c] @@ -107,9 +110,9 @@ spec: # static parameter announcements list. command: [echo, '[{"name": "example-param", "string": "default-string-value"}]'] - # If set to `true` then the plugin receives repository files with original file mode. Dangerous since the repository - # might have executable files. Set to true only if you trust the CMP plugin authors. - preserveFileMode: false + # If set to `true` then the plugin receives repository files with original file mode. Dangerous since the repository + # might have executable files. Set to true only if you trust the CMP plugin authors. + preserveFileMode: false ``` !!! note @@ -333,6 +336,7 @@ If you are actively developing a sidecar-installed CMP, keep a few things in min 3. CMP errors are cached by the repo-server in Redis. Restarting the repo-server Pod will not clear the cache. Always do a "Hard Refresh" when actively developing a CMP so you have the latest output. 4. Verify your sidecar has started properly by viewing the Pod and seeing that two containers are running `kubectl get pod -l app.kubernetes.io/component=repo-server -n argocd` +5. Write log message to stderr and set the `--loglevel=info` flag in the sidecar. This will print everything written to stderr, even on successfull command execution. ### Other Common Errors diff --git a/docs/operator-manual/custom-styles.md b/docs/operator-manual/custom-styles.md index 8f2499a2d636a..6f68d5e23b128 100644 --- a/docs/operator-manual/custom-styles.md +++ b/docs/operator-manual/custom-styles.md @@ -21,7 +21,7 @@ metadata: ... name: argocd-cm data: - ui.cssurl: "https://www.myhost.com/my-styles.css" + ui.cssurl: "https://www.example.com/my-styles.css" ``` ## Adding Styles Via Volume Mounts @@ -100,7 +100,7 @@ experience, you may wish to build a separate project using the [Argo CD UI dev s ## Banners -Argo CD can optionally display a banner that can be used to notify your users of upcoming maintenance and operational changes. This feature can be enabled by specifying the banner message using the `ui.bannercontent` field in the `argocd-cm` ConfigMap and Argo CD will display this message at the top of every UI page. You can optionally add a link to this message by setting `ui.bannerurl`. You can also make the banner sticky (permanent) by setting `ui.bannerpermanent` to `true` and change it's position to the bottom by using `ui.bannerposition: "bottom"` +Argo CD can optionally display a banner that can be used to notify your users of upcoming maintenance and operational changes. This feature can be enabled by specifying the banner message using the `ui.bannercontent` field in the `argocd-cm` ConfigMap and Argo CD will display this message at the top of every UI page. You can optionally add a link to this message by setting `ui.bannerurl`. You can also make the banner sticky (permanent) by setting `ui.bannerpermanent` to true and change its position to "both" or "bottom" by using `ui.bannerposition: "both"`, allowing the banner to display on both the top and bottom, or `ui.bannerposition: "bottom"` to display it exclusively at the bottom. ### argocd-cm ```yaml diff --git a/docs/operator-manual/declarative-setup.md b/docs/operator-manual/declarative-setup.md index 5353f70cf14ef..4d87ae9f80286 100644 --- a/docs/operator-manual/declarative-setup.md +++ b/docs/operator-manual/declarative-setup.md @@ -266,7 +266,7 @@ metadata: argocd.argoproj.io/secret-type: repository stringData: type: git - repo: https://source.developers.google.com/p/my-google-project/r/my-repo + url: https://source.developers.google.com/p/my-google-project/r/my-repo gcpServiceAccountKey: | { "type": "service_account", @@ -490,7 +490,7 @@ stringData: ### Legacy behaviour -In Argo CD version 2.0 and earlier, repositories where stored as part of the `argocd-cm` config map. For +In Argo CD version 2.0 and earlier, repositories were stored as part of the `argocd-cm` config map. For backward-compatibility, Argo CD will still honor repositories in the config map, but this style of repository configuration is deprecated and support for it will be removed in a future version. @@ -549,6 +549,7 @@ bearerToken: string awsAuthConfig: clusterName: string roleARN: string + profile: string # Configure external command to supply client credentials # See https://godoc.org/k8s.io/client-go/tools/clientcmd/api#ExecConfig execProviderConfig: @@ -590,8 +591,8 @@ metadata: argocd.argoproj.io/secret-type: cluster type: Opaque stringData: - name: mycluster.com - server: https://mycluster.com + name: mycluster.example.com + server: https://mycluster.example.com config: | { "bearerToken": "", @@ -615,8 +616,8 @@ metadata: argocd.argoproj.io/secret-type: cluster type: Opaque stringData: - name: "mycluster.com" - server: "https://mycluster.com" + name: "mycluster.example.com" + server: "https://mycluster.example.com" config: | { "awsAuthConfig": { @@ -676,8 +677,10 @@ extended to allow assumption of multiple roles, either as an explicit array of r } ``` -Example service account configs for `argocd-application-controller` and `argocd-server`. Note that once the annotations -have been set on the service accounts, both the application controller and server pods need to be restarted. +Example service account configs for `argocd-application-controller` and `argocd-server`. + +!!! warning + Once the annotations have been set on the service accounts, both the application controller and server pods need to be restarted. ```yaml apiVersion: v1 @@ -742,8 +745,8 @@ metadata: argocd.argoproj.io/secret-type: cluster type: Opaque stringData: - name: mycluster.com - server: https://mycluster.com + name: mycluster.example.com + server: https://mycluster.example.com config: | { "execProviderConfig": { @@ -795,8 +798,8 @@ metadata: argocd.argoproj.io/secret-type: cluster type: Opaque stringData: - name: mycluster.com - server: https://mycluster.com + name: mycluster.example.com + server: https://mycluster.example.com config: | { "execProviderConfig": { @@ -830,8 +833,8 @@ metadata: argocd.argoproj.io/secret-type: cluster type: Opaque stringData: - name: mycluster.com - server: https://mycluster.com + name: mycluster.example.com + server: https://mycluster.example.com config: | { "execProviderConfig": { diff --git a/docs/operator-manual/dynamic-cluster-distribution.md b/docs/operator-manual/dynamic-cluster-distribution.md index a32258c3f2f0a..9d5d2104a1795 100644 --- a/docs/operator-manual/dynamic-cluster-distribution.md +++ b/docs/operator-manual/dynamic-cluster-distribution.md @@ -17,16 +17,10 @@ which does not require a restart of the application controller pods. ## Enabling Dynamic Distribution of Clusters -This feature is disabled by default while it is in alpha. To enable it, you must set the environment `ARGOCD_ENABLE_DYNAMIC_CLUSTER_DISTRIBUTION` to true when running the Application Controller. - -In order to utilize the feature, the manifests `manifests/ha/base/controller-deployment/` can be applied as a Kustomize -overlay. This overlay sets the StatefulSet replicas to `0` and deploys the application controller as a Deployment. The -dynamic distribution code automatically kicks in when the controller is deployed as a Deployment. +This feature is disabled by default while it is in alpha. In order to utilize the feature, the manifests `manifests/ha/base/controller-deployment/` can be applied as a Kustomize overlay. This overlay sets the StatefulSet replicas to `0` and deploys the application controller as a Deployment. Also, you must set the environment `ARGOCD_ENABLE_DYNAMIC_CLUSTER_DISTRIBUTION` to true when running the Application Controller as a deployment. !!! important - The use of a Deployment instead of a StatefulSet is an implementation detail which may change in future versions of - this feature. Therefore, the directory name of the Kustomize overlay may change as well. Monitor the release notes - to avoid issues. + The use of a Deployment instead of a StatefulSet is an implementation detail which may change in future versions of this feature. Therefore, the directory name of the Kustomize overlay may change as well. Monitor the release notes to avoid issues. Note the introduction of new environment variable `ARGOCD_CONTROLLER_HEARTBEAT_TIME`. The environment variable is explained in [working of Dynamic Distribution Heartbeat Process](#working-of-dynamic-distribution) diff --git a/docs/operator-manual/health.md b/docs/operator-manual/health.md index 5cc80de6538c5..8566d6460e6db 100644 --- a/docs/operator-manual/health.md +++ b/docs/operator-manual/health.md @@ -3,7 +3,7 @@ ## Overview Argo CD provides built-in health assessment for several standard Kubernetes types, which is then surfaced to the overall Application health status as a whole. The following checks are made for -specific types of kubernetes resources: +specific types of Kubernetes resources: ### Deployment, ReplicaSet, StatefulSet, DaemonSet * Observed generation is equal to desired generation. diff --git a/docs/operator-manual/high_availability.md b/docs/operator-manual/high_availability.md index ac59c333ba7cb..0a011104967f1 100644 --- a/docs/operator-manual/high_availability.md +++ b/docs/operator-manual/high_availability.md @@ -57,7 +57,7 @@ performance. For performance reasons the controller monitors and caches only the preferred version into a version of the resource stored in Git. If `kubectl convert` fails because the conversion is not supported then the controller falls back to Kubernetes API query which slows down reconciliation. In this case, we advise to use the preferred resource version in Git. -* The controller polls Git every 3m by default. You can change this duration using the `timeout.reconciliation` setting in the `argocd-cm` ConfigMap. The value of `timeout.reconciliation` is a duration string e.g `60s`, `1m`, `1h` or `1d`. +* The controller polls Git every 3m by default. You can change this duration using the `timeout.reconciliation` and `timeout.reconciliation.jitter` setting in the `argocd-cm` ConfigMap. The value of the fields is a duration string e.g `60s`, `1m`, `1h` or `1d`. * If the controller is managing too many clusters and uses too much memory then you can shard clusters across multiple controller replicas. To enable sharding, increase the number of replicas in `argocd-application-controller` `StatefulSet` @@ -98,8 +98,8 @@ metadata: type: Opaque stringData: shard: 1 - name: mycluster.com - server: https://mycluster.com + name: mycluster.example.com + server: https://mycluster.example.com config: | { "bearerToken": "", @@ -243,3 +243,102 @@ spec: path: my-application # ... ``` + +### Application Sync Timeout & Jitter + +Argo CD has a timeout for application syncs. It will trigger a refresh for each application periodically when the timeout expires. +With a large number of applications, this will cause a spike in the refresh queue and can cause a spike to the repo-server component. To avoid this, you can set a jitter to the sync timeout which will spread out the refreshes and give time to the repo-server to catch up. + +The jitter is the maximum duration that can be added to the sync timeout, so if the sync timeout is 5 minutes and the jitter is 1 minute, then the actual timeout will be between 5 and 6 minutes. + +To configure the jitter you can set the following environment variables: + +* `ARGOCD_RECONCILIATION_JITTER` - The jitter to apply to the sync timeout. Disabled when value is 0. Defaults to 0. + +## Rate Limiting Application Reconciliations + +To prevent high controller resource usage or sync loops caused either due to misbehaving apps or other environment specific factors, +we can configure rate limits on the workqueues used by the application controller. There are two types of rate limits that can be configured: + + * Global rate limits + * Per item rate limits + +The final rate limiter uses a combination of both and calculates the final backoff as `max(globalBackoff, perItemBackoff)`. + +### Global rate limits + + This is enabled by default, it is a simple bucket based rate limiter that limits the number of items that can be queued per second. +This is useful to prevent a large number of apps from being queued at the same time. + +To configure the bucket limiter you can set the following environment variables: + + * `WORKQUEUE_BUCKET_SIZE` - The number of items that can be queued in a single burst. Defaults to 500. + * `WORKQUEUE_BUCKET_QPS` - The number of items that can be queued per second. Defaults to 50. + +### Per item rate limits + + This by default returns a fixed base delay/backoff value but can be configured to return exponential values. +Per item rate limiter limits the number of times a particular item can be queued. This is based on exponential backoff where the backoff time for an item keeps increasing exponentially +if it is queued multiple times in a short period, but the backoff is reset automatically if a configured `cool down` period has elapsed since the last time the item was queued. + +To configure the per item limiter you can set the following environment variables: + + * `WORKQUEUE_FAILURE_COOLDOWN_NS` : The cool down period in nanoseconds, once period has elapsed for an item the backoff is reset. Exponential backoff is disabled if set to 0(default), eg. values : 10 * 10^9 (=10s) + * `WORKQUEUE_BASE_DELAY_NS` : The base delay in nanoseconds, this is the initial backoff used in the exponential backoff formula. Defaults to 1000 (=1μs) + * `WORKQUEUE_MAX_DELAY_NS` : The max delay in nanoseconds, this is the max backoff limit. Defaults to 3 * 10^9 (=3s) + * `WORKQUEUE_BACKOFF_FACTOR` : The backoff factor, this is the factor by which the backoff is increased for each retry. Defaults to 1.5 + +The formula used to calculate the backoff time for an item, where `numRequeue` is the number of times the item has been queued +and `lastRequeueTime` is the time at which the item was last queued: + +- When `WORKQUEUE_FAILURE_COOLDOWN_NS` != 0 : + +``` +backoff = time.Since(lastRequeueTime) >= WORKQUEUE_FAILURE_COOLDOWN_NS ? + WORKQUEUE_BASE_DELAY_NS : + min( + WORKQUEUE_MAX_DELAY_NS, + WORKQUEUE_BASE_DELAY_NS * WORKQUEUE_BACKOFF_FACTOR ^ (numRequeue) + ) +``` + +- When `WORKQUEUE_FAILURE_COOLDOWN_NS` = 0 : + +``` +backoff = WORKQUEUE_BASE_DELAY_NS +``` + +## HTTP Request Retry Strategy + +In scenarios where network instability or transient server errors occur, the retry strategy ensures the robustness of HTTP communication by automatically resending failed requests. It uses a combination of maximum retries and backoff intervals to prevent overwhelming the server or thrashing the network. + +### Configuring Retries + +The retry logic can be fine-tuned with the following environment variables: + +* `ARGOCD_K8SCLIENT_RETRY_MAX` - The maximum number of retries for each request. The request will be dropped after this count is reached. Defaults to 0 (no retries). +* `ARGOCD_K8SCLIENT_RETRY_BASE_BACKOFF` - The initial backoff delay on the first retry attempt in ms. Subsequent retries will double this backoff time up to a maximum threshold. Defaults to 100ms. + +### Backoff Strategy + +The backoff strategy employed is a simple exponential backoff without jitter. The backoff time increases exponentially with each retry attempt until a maximum backoff duration is reached. + +The formula for calculating the backoff time is: + +``` +backoff = min(retryWaitMax, baseRetryBackoff * (2 ^ retryAttempt)) +``` +Where `retryAttempt` starts at 0 and increments by 1 for each subsequent retry. + +### Maximum Wait Time + +There is a cap on the backoff time to prevent excessive wait times between retries. This cap is defined by: + +`retryWaitMax` - The maximum duration to wait before retrying. This ensures that retries happen within a reasonable timeframe. Defaults to 10 seconds. + +### Non-Retriable Conditions + +Not all HTTP responses are eligible for retries. The following conditions will not trigger a retry: + +* Responses with a status code indicating client errors (4xx) except for 429 Too Many Requests. +* Responses with the status code 501 Not Implemented. diff --git a/docs/operator-manual/ingress.md b/docs/operator-manual/ingress.md index 84b2bcaf34a67..aad2208c21873 100644 --- a/docs/operator-manual/ingress.md +++ b/docs/operator-manual/ingress.md @@ -166,6 +166,43 @@ The argocd-server Service needs to be annotated with `projectcontour.io/upstream The API server should then be run with TLS disabled. Edit the `argocd-server` deployment to add the `--insecure` flag to the argocd-server command, or simply set `server.insecure: "true"` in the `argocd-cmd-params-cm` ConfigMap [as described here](server-commands/additional-configuration-method.md). +Contour httpproxy CRD: + +Using a contour httpproxy CRD allows you to use the same hostname for the GRPC and REST api. + +```yaml +apiVersion: projectcontour.io/v1 +kind: HTTPProxy +metadata: + name: argocd-server + namespace: argocd +spec: + ingressClassName: contour + virtualhost: + fqdn: path.to.argocd.io + tls: + secretName: wildcard-tls + routes: + - conditions: + - prefix: / + - header: + name: Content-Type + contains: application/grpc + services: + - name: argocd-server + port: 80 + protocol: h2c # allows for unencrypted http2 connections + timeoutPolicy: + response: 1h + idle: 600s + idleConnection: 600s + - conditions: + - prefix: / + services: + - name: argocd-server + port: 80 +``` + ## [kubernetes/ingress-nginx](https://github.com/kubernetes/ingress-nginx) ### Option 1: SSL-Passthrough @@ -661,9 +698,9 @@ metadata: networking.gke.io/v1beta1.FrontendConfig: argocd-frontend-config spec: tls: - - secretName: secret-yourdomain-com + - secretName: secret-example-com rules: - - host: argocd.yourdomain.com + - host: argocd.example.com http: paths: - pathType: ImplementationSpecific @@ -686,9 +723,9 @@ metadata: networking.gke.io/v1beta1.FrontendConfig: argocd-frontend-config spec: tls: - - secretName: secret-yourdomain-com + - secretName: secret-example-com rules: - - host: argocd.yourdomain.com + - host: argocd.example.com http: paths: - pathType: Prefix @@ -700,7 +737,7 @@ spec: number: 80 ``` -As you may know already, it can take some minutes to deploy the load balancer and become ready to accept connections. Once it's ready, get the public IP address for your Load Balancer, go to your DNS server (Google or third party) and point your domain or subdomain (i.e. argocd.yourdomain.com) to that IP address. +As you may know already, it can take some minutes to deploy the load balancer and become ready to accept connections. Once it's ready, get the public IP address for your Load Balancer, go to your DNS server (Google or third party) and point your domain or subdomain (i.e. argocd.example.com) to that IP address. You can get that IP address describing the Ingress object like this: diff --git a/docs/operator-manual/metrics.md b/docs/operator-manual/metrics.md index 174b08fd75c2c..634684a430045 100644 --- a/docs/operator-manual/metrics.md +++ b/docs/operator-manual/metrics.md @@ -8,12 +8,12 @@ Metrics about applications. Scraped at the `argocd-metrics:8082/metrics` endpoin | Metric | Type | Description | |--------|:----:|-------------| | `argocd_app_info` | gauge | Information about Applications. It contains labels such as `sync_status` and `health_status` that reflect the application state in Argo CD. | -| `argocd_app_k8s_request_total` | counter | Number of kubernetes requests executed during application reconciliation | +| `argocd_app_k8s_request_total` | counter | Number of Kubernetes requests executed during application reconciliation | | `argocd_app_labels` | gauge | Argo Application labels converted to Prometheus labels. Disabled by default. See section below about how to enable it. | | `argocd_app_reconcile` | histogram | Application reconciliation performance. | | `argocd_app_sync_total` | counter | Counter for application sync history | | `argocd_cluster_api_resource_objects` | gauge | Number of k8s resource objects in the cache. | -| `argocd_cluster_api_resources` | gauge | Number of monitored kubernetes API resources. | +| `argocd_cluster_api_resources` | gauge | Number of monitored Kubernetes API resources. | | `argocd_cluster_cache_age_seconds` | gauge | Cluster cache age in seconds. | | `argocd_cluster_connection_status` | gauge | The k8s cluster current connection status. | | `argocd_cluster_events_total` | counter | Number of processes k8s resource events. | @@ -67,9 +67,11 @@ Scraped at the `argocd-server-metrics:8083/metrics` endpoint. | Metric | Type | Description | |--------|:----:|-------------| | `argocd_redis_request_duration` | histogram | Redis requests duration. | -| `argocd_redis_request_total` | counter | Number of kubernetes requests executed during application reconciliation. | +| `argocd_redis_request_total` | counter | Number of Kubernetes requests executed during application reconciliation. | | `grpc_server_handled_total` | counter | Total number of RPCs completed on the server, regardless of success or failure. | | `grpc_server_msg_sent_total` | counter | Total number of gRPC stream messages sent by the server. | +| `argocd_proxy_extension_request_total` | counter | Number of requests sent to the configured proxy extensions. | +| `argocd_proxy_extension_request_duration_seconds` | histogram | Request duration in seconds between the Argo CD API server and the proxy extension backend. | ## Repo Server Metrics Metrics about the Repo Server. @@ -80,13 +82,13 @@ Scraped at the `argocd-repo-server:8084/metrics` endpoint. | `argocd_git_request_duration_seconds` | histogram | Git requests duration seconds. | | `argocd_git_request_total` | counter | Number of git requests performed by repo server | | `argocd_redis_request_duration_seconds` | histogram | Redis requests duration seconds. | -| `argocd_redis_request_total` | counter | Number of kubernetes requests executed during application reconciliation. | +| `argocd_redis_request_total` | counter | Number of Kubernetes requests executed during application reconciliation. | | `argocd_repo_pending_request_total` | gauge | Number of pending requests requiring repository lock | ## Prometheus Operator If using Prometheus Operator, the following ServiceMonitor example manifests can be used. -Change `metadata.labels.release` to the name of label selected by your Prometheus. +Add a namespace where Argo CD is installed and change `metadata.labels.release` to the name of label selected by your Prometheus. ```yaml apiVersion: monitoring.coreos.com/v1 @@ -148,6 +150,52 @@ spec: - port: metrics ``` +```yaml +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: argocd-dex-server + labels: + release: prometheus-operator +spec: + selector: + matchLabels: + app.kubernetes.io/name: argocd-dex-server + endpoints: + - port: metrics +``` + +```yaml +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: argocd-redis-haproxy-metrics +spec: + selector: + matchLabels: + app.kubernetes.io/name: argocd-redis-ha-haproxy + endpoints: + - port: http-exporter-port +``` + +For notifications controller, you need to additionally add following: + +```yaml +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: argocd-notifications-controller + labels: + release: prometheus-operator +spec: + selector: + matchLabels: + app.kubernetes.io/name: argocd-notifications-controller-metrics + endpoints: + - port: metrics +``` + + ## Dashboards You can find an example Grafana dashboard [here](https://github.com/argoproj/argo-cd/blob/master/examples/dashboard.json) or check demo instance diff --git a/docs/operator-manual/notifications/functions.md b/docs/operator-manual/notifications/functions.md index 3d614e4e53a55..c50d122024b76 100644 --- a/docs/operator-manual/notifications/functions.md +++ b/docs/operator-manual/notifications/functions.md @@ -48,6 +48,16 @@ Transforms given GIT URL into HTTPs format. Returns repository URL full name `(/)`. Currently supports only Github, GitLab and Bitbucket. +
+**`repo.QueryEscape(s string) string`** + +QueryEscape escapes the string, so it can be safely placed inside a URL + +Example: +``` +/projects/{{ call .repo.QueryEscape (call .repo.FullNameByRepoURL .app.status.RepoURL) }}/merge_requests +``` +
**`repo.GetCommitMetadata(sha string) CommitMetadata`** diff --git a/docs/operator-manual/notifications/index.md b/docs/operator-manual/notifications/index.md index c719d10e7611c..eccca906ae91b 100644 --- a/docs/operator-manual/notifications/index.md +++ b/docs/operator-manual/notifications/index.md @@ -45,3 +45,71 @@ So you can just use them instead of reinventing new ones. ``` Try syncing an application to get notified when the sync is completed. + +## Namespace based configuration + +A common installation method for Argo CD Notifications is to install it in a dedicated namespace to manage a whole cluster. In this case, the administrator is the only +person who can configure notifications in that namespace generally. However, in some cases, it is required to allow end-users to configure notifications +for their Argo CD applications. For example, the end-user can configure notifications for their Argo CD application in the namespace where they have access to and their Argo CD application is running in. + +This feature is based on applications in any namespace. See [applications in any namespace](../app-any-namespace.md) page for more information. + +In order to enable this feature, the Argo CD administrator must reconfigure the argocd-notification-controller workloads to add `--application-namespaces` and `--self-service-notification-enabled` parameters to the container's startup command. +`--application-namespaces` controls the list of namespaces that Argo CD applications are in. `--self-service-notification-enabled` turns on this feature. + +The startup parameters for both can also be conveniently set up and kept in sync by specifying +the `application.namespaces` and `notificationscontroller.selfservice.enabled` in the argocd-cmd-params-cm ConfigMap instead of changing the manifests for the respective workloads. For example: + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: argocd-cmd-params-cm +data: + application.namespaces: app-team-one, app-team-two + notificationscontroller.selfservice.enabled: "true" +``` + +To use this feature, you can deploy configmap named `argocd-notifications-cm` and possibly a secret `argocd-notifications-secret` in the namespace where the Argo CD application lives. + +When it is configured this way the controller will send notifications using both the controller level configuration (the configmap located in the same namespaces as the controller) as well as +the configuration located in the same namespace where the Argo CD application is at. + +Example: Application team wants to receive notifications using PagerDutyV2, when the controller level configuration is only supporting Slack. + +The following two resources are deployed in the namespace where the Argo CD application lives. +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: argocd-notifications-cm +data: + service.pagerdutyv2: | + serviceKeys: + my-service: $pagerduty-key-my-service +... +``` +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: argo-cd-notification-secret +type: Opaque +data: + pagerduty-key-my-service: +``` + +When an Argo CD application has the following subscriptions, user receives application sync failure message from pager duty. +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + annotations: + notifications.argoproj.io/subscribe.on-sync-failed.pagerdutyv2: "" +``` + +!!! note + When the same notification service and trigger are defined in controller level configuration and application level configuration, + both notifications will be sent according to its own configuration. + +[Defining and using secrets within notification templates](templates.md/#defining-and-using-secrets-within-notification-templates) function is not available when flag `--self-service-notification-enable` is on. diff --git a/docs/operator-manual/notifications/services/alertmanager.md b/docs/operator-manual/notifications/services/alertmanager.md index e0f9d7e4e7889..033a76a29ea65 100755 --- a/docs/operator-manual/notifications/services/alertmanager.md +++ b/docs/operator-manual/notifications/services/alertmanager.md @@ -43,7 +43,7 @@ You should turn off "send_resolved" or you will receive unnecessary recovery not apiVersion: v1 kind: ConfigMap metadata: - name: + name: argocd-notifications-cm data: service.alertmanager: | targets: @@ -58,7 +58,7 @@ If your alertmanager has changed the default api, you can customize "apiPath". apiVersion: v1 kind: ConfigMap metadata: - name: + name: argocd-notifications-cm data: service.alertmanager: | targets: @@ -89,7 +89,7 @@ stringData: apiVersion: v1 kind: ConfigMap metadata: - name: + name: argocd-notifications-cm data: service.alertmanager: | targets: @@ -110,7 +110,7 @@ data: apiVersion: v1 kind: ConfigMap metadata: - name: + name: argocd-notifications-cm data: service.alertmanager: | targets: diff --git a/docs/operator-manual/notifications/services/awssqs.md b/docs/operator-manual/notifications/services/awssqs.md index 6bbc47cbbc0b5..5331533826348 100755 --- a/docs/operator-manual/notifications/services/awssqs.md +++ b/docs/operator-manual/notifications/services/awssqs.md @@ -1,13 +1,13 @@ -# AWS SQS +# AWS SQS ## Parameters -This notification service is capable of sending simple messages to AWS SQS queue. +This notification service is capable of sending simple messages to AWS SQS queue. -* `queue` - name of the queue you are intending to send messages to. Can be overwriten with target destination annotation. +* `queue` - name of the queue you are intending to send messages to. Can be overridden with target destination annotation. * `region` - region of the sqs queue can be provided via env variable AWS_DEFAULT_REGION * `key` - optional, aws access key must be either referenced from a secret via variable or via env variable AWS_ACCESS_KEY_ID -* `secret` - optional, aws access secret must be either referenced from a secret via variableor via env variable AWS_SECRET_ACCESS_KEY +* `secret` - optional, aws access secret must be either referenced from a secret via variable or via env variable AWS_SECRET_ACCESS_KEY * `account` optional, external accountId of the queue * `endpointUrl` optional, useful for development with localstack @@ -30,7 +30,7 @@ metadata: apiVersion: v1 kind: ConfigMap metadata: - name: + name: argocd-notifications-cm data: service.awssqs: | region: "us-east-2" @@ -63,7 +63,7 @@ stringData: ### Minimal configuration using AWS Env variables -Ensure following list of enviromental variable is injected via OIDC, or other method. And assuming SQS is local to the account. +Ensure the following list of environment variables are injected via OIDC, or another method. And assuming SQS is local to the account. You may skip usage of secret for sensitive data and omit other parameters. (Setting parameters via ConfigMap takes precedent.) Variables: @@ -89,7 +89,7 @@ metadata: apiVersion: v1 kind: ConfigMap metadata: - name: + name: argocd-notifications-cm data: service.awssqs: | queue: "myqueue" @@ -104,3 +104,16 @@ data: - oncePer: obj.metadata.annotations["generation"] ``` + +## FIFO SQS Queues + +FIFO queues require a [MessageGroupId](https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html#SQS-SendMessage-request-MessageGroupId) to be sent along with every message, every message with a matching MessageGroupId will be processed one by one in order. + +To send to a FIFO SQS Queue you must include a `messageGroupId` in the template such as in the example below: + +```yaml +template.deployment-ready: | + message: | + Deployment {{.obj.metadata.name}} is ready! + messageGroupId: {{.obj.metadata.name}}-deployment +``` diff --git a/docs/operator-manual/notifications/services/email.md b/docs/operator-manual/notifications/services/email.md index b81ab6cde8b4c..7fd3f0e22379c 100755 --- a/docs/operator-manual/notifications/services/email.md +++ b/docs/operator-manual/notifications/services/email.md @@ -20,7 +20,7 @@ The following snippet contains sample Gmail service configuration: apiVersion: v1 kind: ConfigMap metadata: - name: + name: argocd-notifications-cm data: service.email.gmail: | username: $email-username @@ -36,7 +36,7 @@ Without authentication: apiVersion: v1 kind: ConfigMap metadata: - name: + name: argocd-notifications-cm data: service.email.example: | host: smtp.example.com @@ -52,7 +52,7 @@ data: apiVersion: v1 kind: ConfigMap metadata: - name: + name: argocd-notifications-cm data: template.app-sync-succeeded: | email: diff --git a/docs/operator-manual/notifications/services/github.md b/docs/operator-manual/notifications/services/github.md index a3f89f8c87ef0..1fa1a985d2682 100755 --- a/docs/operator-manual/notifications/services/github.md +++ b/docs/operator-manual/notifications/services/github.md @@ -12,7 +12,7 @@ The GitHub notification service changes commit status using [GitHub Apps](https: ## Configuration 1. Create a GitHub Apps using https://github.com/settings/apps/new -2. Change repository permissions to enable write commit statuses and/or deployments +2. Change repository permissions to enable write commit statuses and/or deployments and/or pull requests comments ![2](https://user-images.githubusercontent.com/18019529/108397381-3ca57980-725b-11eb-8d17-5b8992dc009e.png) 3. Generate a private key, and download it automatically ![3](https://user-images.githubusercontent.com/18019529/108397926-d4a36300-725b-11eb-83fe-74795c8c3e03.png) @@ -24,7 +24,7 @@ in `argocd-notifications-cm` ConfigMap apiVersion: v1 kind: ConfigMap metadata: - name: + name: argocd-notifications-cm data: service.github: | appID: @@ -76,6 +76,11 @@ template.app-deployed: | logURL: "{{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true" requiredContexts: [] autoMerge: true + transientEnvironment: false + pullRequestComment: + content: | + Application {{.app.metadata.name}} is now running new version of deployments manifests. + See more here: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true ``` **Notes**: @@ -83,4 +88,5 @@ template.app-deployed: | - If `github.repoURLPath` and `github.revisionPath` are same as above, they can be omitted. - Automerge is optional and `true` by default for github deployments to ensure the requested ref is up to date with the default branch. Setting this option to `false` is required if you would like to deploy older refs in your default branch. - For more information see the [Github Deployment API Docs](https://docs.github.com/en/rest/deployments/deployments?apiVersion=2022-11-28#create-a-deployment). + For more information see the [GitHub Deployment API Docs](https://docs.github.com/en/rest/deployments/deployments?apiVersion=2022-11-28#create-a-deployment). +- If `github.pullRequestComment.content` is set to 65536 characters or more, it will be truncated. diff --git a/docs/operator-manual/notifications/services/googlechat.md b/docs/operator-manual/notifications/services/googlechat.md index 041ea6e022ef5..821c23023e863 100755 --- a/docs/operator-manual/notifications/services/googlechat.md +++ b/docs/operator-manual/notifications/services/googlechat.md @@ -19,7 +19,7 @@ The Google Chat notification service send message notifications to a google chat apiVersion: v1 kind: ConfigMap metadata: - name: + name: argocd-notifications-cm data: service.googlechat: | webhooks: @@ -59,24 +59,27 @@ A card message can be defined as follows: ```yaml template.app-sync-succeeded: | googlechat: - cards: | + cardsV2: | - header: title: ArgoCD Bot Notification sections: - widgets: - - textParagraph: + - decoratedText: text: The app {{ .app.metadata.name }} has successfully synced! - widgets: - - keyValue: + - decoratedText: topLabel: Repository - content: {{ call .repo.RepoURLToHTTPS .app.spec.source.repoURL }} - - keyValue: + text: {{ call .repo.RepoURLToHTTPS .app.spec.source.repoURL }} + - decoratedText: topLabel: Revision - content: {{ .app.spec.source.targetRevision }} - - keyValue: + text: {{ .app.spec.source.targetRevision }} + - decoratedText: topLabel: Author - content: {{ (call .repo.GetCommitMetadata .app.status.sync.revision).Author }} + text: {{ (call .repo.GetCommitMetadata .app.status.sync.revision).Author }} ``` +All [Card fields](https://developers.google.com/chat/api/reference/rest/v1/cards#Card_1) are supported and can be used +in notifications. It is also possible to use the previous (now deprecated) `cards` key to use the legacy card fields, +but this is not recommended as Google has deprecated this field and recommends using the newer `cardsV2`. The card message can be written in JSON too. @@ -86,7 +89,7 @@ It is possible send both simple text and card messages in a chat thread by speci ```yaml template.app-sync-succeeded: | - message: The app {{ .app.metadata.name }} has succesfully synced! + message: The app {{ .app.metadata.name }} has successfully synced! googlechat: threadKey: {{ .app.metadata.name }} ``` diff --git a/docs/operator-manual/notifications/services/grafana.md b/docs/operator-manual/notifications/services/grafana.md index a36672d0fa423..1f3e77701f044 100755 --- a/docs/operator-manual/notifications/services/grafana.md +++ b/docs/operator-manual/notifications/services/grafana.md @@ -21,7 +21,7 @@ Available parameters : apiVersion: v1 kind: ConfigMap metadata: - name: + name: argocd-notifications-cm data: service.grafana: | apiUrl: https://grafana.example.com/api diff --git a/docs/operator-manual/notifications/services/mattermost.md b/docs/operator-manual/notifications/services/mattermost.md index 98e0d0fd7b82f..d1f187e955b9c 100755 --- a/docs/operator-manual/notifications/services/mattermost.md +++ b/docs/operator-manual/notifications/services/mattermost.md @@ -19,7 +19,7 @@ in `argocd-notifications-cm` ConfigMap apiVersion: v1 kind: ConfigMap metadata: - name: + name: argocd-notifications-cm data: service.mattermost: | apiURL: diff --git a/docs/operator-manual/notifications/services/newrelic.md b/docs/operator-manual/notifications/services/newrelic.md index d98288a846422..b0c7e340c9b28 100755 --- a/docs/operator-manual/notifications/services/newrelic.md +++ b/docs/operator-manual/notifications/services/newrelic.md @@ -14,7 +14,7 @@ apiVersion: v1 kind: ConfigMap metadata: - name: + name: argocd-notifications-cm data: service.newrelic: | apiURL: diff --git a/docs/operator-manual/notifications/services/opsgenie.md b/docs/operator-manual/notifications/services/opsgenie.md index 665d0081e7c73..e92ee99756ab8 100755 --- a/docs/operator-manual/notifications/services/opsgenie.md +++ b/docs/operator-manual/notifications/services/opsgenie.md @@ -12,14 +12,15 @@ To be able to send notifications with argocd-notifications you have to create an 8. Give your integration a name, copy the "API key" and safe it somewhere for later 9. Make sure the checkboxes for "Create and Update Access" and "enable" are selected, disable the other checkboxes to remove unnecessary permissions 10. Click "Safe Integration" at the bottom -11. Check your browser for the correct server apiURL. If it is "app.opsgenie.com" then use the us/international api url `api.opsgenie.com` in the next step, otherwise use `api.eu.opsgenie.com` (european api). -12. You are finished with configuring opsgenie. Now you need to configure argocd-notifications. Use the apiUrl, the team name and the apiKey to configure the opsgenie integration in the `argocd-notifications-secret` secret. +11. Check your browser for the correct server apiURL. If it is "app.opsgenie.com" then use the US/international api url `api.opsgenie.com` in the next step, otherwise use `api.eu.opsgenie.com` (European API). +12. You are finished with configuring Opsgenie. Now you need to configure argocd-notifications. Use the apiUrl, the team name and the apiKey to configure the Opsgenie integration in the `argocd-notifications-secret` secret. + ```yaml apiVersion: v1 kind: ConfigMap metadata: - name: + name: argocd-notifications-cm data: service.opsgenie: | apiUrl: diff --git a/docs/operator-manual/notifications/services/pagerduty.md b/docs/operator-manual/notifications/services/pagerduty.md index 0e1ab965332e1..c6e1e41dac81d 100755 --- a/docs/operator-manual/notifications/services/pagerduty.md +++ b/docs/operator-manual/notifications/services/pagerduty.md @@ -1,17 +1,17 @@ -# Pagerduty +# PagerDuty ## Parameters -The Pagerduty notification service is used to create pagerduty incidents and requires specifying the following settings: +The PagerDuty notification service is used to create PagerDuty incidents and requires specifying the following settings: -* `pagerdutyToken` - the pagerduty auth token +* `pagerdutyToken` - the PagerDuty auth token * `from` - email address of a valid user associated with the account making the request. * `serviceID` - The ID of the resource. ## Example -The following snippet contains sample Pagerduty service configuration: +The following snippet contains sample PagerDuty service configuration: ```yaml apiVersion: v1 @@ -26,7 +26,7 @@ stringData: apiVersion: v1 kind: ConfigMap metadata: - name: + name: argocd-notifications-cm data: service.pagerduty: | token: $pagerdutyToken @@ -35,13 +35,13 @@ data: ## Template -[Notification templates](../templates.md) support specifying subject for pagerduty notifications: +[Notification templates](../templates.md) support specifying subject for PagerDuty notifications: ```yaml apiVersion: v1 kind: ConfigMap metadata: - name: + name: argocd-notifications-cm data: template.rollout-aborted: | message: Rollout {{.rollout.metadata.name}} is aborted. @@ -62,5 +62,5 @@ apiVersion: argoproj.io/v1alpha1 kind: Rollout metadata: annotations: - notifications.argoproj.io/subscribe.on-rollout-aborted.pagerduty: "" + notifications.argoproj.io/subscribe.on-rollout-aborted.pagerduty: "" ``` diff --git a/docs/operator-manual/notifications/services/pagerduty_v2.md b/docs/operator-manual/notifications/services/pagerduty_v2.md index 21e8d942e4e93..549cdc937b150 100755 --- a/docs/operator-manual/notifications/services/pagerduty_v2.md +++ b/docs/operator-manual/notifications/services/pagerduty_v2.md @@ -28,7 +28,7 @@ stringData: apiVersion: v1 kind: ConfigMap metadata: - name: + name: argocd-notifications-cm data: service.pagerdutyv2: | serviceKeys: @@ -43,7 +43,7 @@ data: apiVersion: v1 kind: ConfigMap metadata: - name: + name: argocd-notifications-cm data: template.rollout-aborted: | message: Rollout {{.rollout.metadata.name}} is aborted. @@ -74,5 +74,5 @@ apiVersion: argoproj.io/v1alpha1 kind: Rollout metadata: annotations: - notifications.argoproj.io/subscribe.on-rollout-aborted.pagerdutyv2: "" + notifications.argoproj.io/subscribe.on-rollout-aborted.pagerdutyv2: "" ``` diff --git a/docs/operator-manual/notifications/services/pushover.md b/docs/operator-manual/notifications/services/pushover.md index 37cb20b277dcc..a09b3660f9233 100755 --- a/docs/operator-manual/notifications/services/pushover.md +++ b/docs/operator-manual/notifications/services/pushover.md @@ -1,13 +1,13 @@ # Pushover 1. Create an app at [pushover.net](https://pushover.net/apps/build). -2. Store the API key in `` Secret and define the secret name in `` ConfigMap: +2. Store the API key in `` Secret and define the secret name in `argocd-notifications-cm` ConfigMap: ```yaml apiVersion: v1 kind: ConfigMap metadata: - name: + name: argocd-notifications-cm data: service.pushover: | token: $pushover-token diff --git a/docs/operator-manual/notifications/services/rocketchat.md b/docs/operator-manual/notifications/services/rocketchat.md index f1157050139d0..20aaa405c80d0 100755 --- a/docs/operator-manual/notifications/services/rocketchat.md +++ b/docs/operator-manual/notifications/services/rocketchat.md @@ -43,7 +43,7 @@ stringData: apiVersion: v1 kind: ConfigMap metadata: - name: + name: argocd-notifications-cm data: service.rocketchat: | email: $rocketchat-email diff --git a/docs/operator-manual/notifications/services/slack.md b/docs/operator-manual/notifications/services/slack.md index 15937597c19f2..41bdddd7617c4 100755 --- a/docs/operator-manual/notifications/services/slack.md +++ b/docs/operator-manual/notifications/services/slack.md @@ -6,11 +6,16 @@ If you want to send message using incoming webhook, you can use [webhook](./webh The Slack notification service configuration includes following settings: -* `token` - the app token -* `apiURL` - optional, the server url, e.g. https://example.com/api -* `username` - optional, the app username -* `icon` - optional, the app icon, e.g. :robot_face: or https://example.com/image.png -* `insecureSkipVerify` - optional bool, true or false +| **Option** | **Required** | **Type** | **Description** | **Example** | +| -------------------- | ------------ | -------------- | --------------- | ----------- | +| `apiURL` | False | `string` | The server URL. | `https://example.com/api` | +| `channels` | False | `list[string]` | | `["my-channel-1", "my-channel-2"]` | +| `icon` | False | `string` | The app icon. | `:robot_face:` or `https://example.com/image.png` | +| `insecureSkipVerify` | False | `bool` | | `true` | +| `signingSecret` | False | `string` | | `8f742231b10e8888abcd99yyyzzz85a5` | +| `token` | **True** | `string` | The app's OAuth access token. | `xoxb-1234567890-1234567890123-5n38u5ed63fgzqlvuyxvxcx6` | +| `username` | False | `string` | The app username. | `argocd` | +| `disableUnfurl` | False | `bool` | Disable slack unfurling links in messages | `true` | ## Configuration @@ -44,7 +49,7 @@ The Slack notification service configuration includes following settings: apiVersion: v1 kind: ConfigMap metadata: - name: + name: argocd-notifications-cm data: service.slack: | token: $slack-token diff --git a/docs/operator-manual/notifications/services/teams.md b/docs/operator-manual/notifications/services/teams.md index b5b9a228c43eb..0e44456d4de19 100755 --- a/docs/operator-manual/notifications/services/teams.md +++ b/docs/operator-manual/notifications/services/teams.md @@ -18,7 +18,7 @@ The Teams notification service send message notifications using Teams bot and re apiVersion: v1 kind: ConfigMap metadata: - name: + name: argocd-notifications-cm data: service.teams: | recipientUrls: @@ -113,7 +113,7 @@ template.app-sync-succeeded: | ### summary field -You can set a summary of the message that will be shown on Notifcation & Activity Feed +You can set a summary of the message that will be shown on Notification & Activity Feed ![](https://user-images.githubusercontent.com/6957724/116587921-84c4d480-a94d-11eb-9da4-f365151a12e7.jpg) diff --git a/docs/operator-manual/notifications/services/telegram.md b/docs/operator-manual/notifications/services/telegram.md index 953c2a9fca0bf..8612a09d1ca84 100755 --- a/docs/operator-manual/notifications/services/telegram.md +++ b/docs/operator-manual/notifications/services/telegram.md @@ -2,13 +2,13 @@ 1. Get an API token using [@Botfather](https://t.me/Botfather). 2. Store token in `` Secret and configure telegram integration -in `` ConfigMap: +in `argocd-notifications-cm` ConfigMap: ```yaml apiVersion: v1 kind: ConfigMap metadata: - name: + name: argocd-notifications-cm data: service.telegram: | token: $telegram-token diff --git a/docs/operator-manual/notifications/services/webex.md b/docs/operator-manual/notifications/services/webex.md index 440ed1ddc738f..eba4c5e11b8dc 100755 --- a/docs/operator-manual/notifications/services/webex.md +++ b/docs/operator-manual/notifications/services/webex.md @@ -24,7 +24,7 @@ The Webex Teams notification service configuration includes following settings: apiVersion: v1 kind: ConfigMap metadata: - name: + name: argocd-notifications-cm data: service.webex: | token: $webex-token diff --git a/docs/operator-manual/notifications/services/webhook.md b/docs/operator-manual/notifications/services/webhook.md index bd45b1f69e40b..4b8ca38a685ad 100755 --- a/docs/operator-manual/notifications/services/webhook.md +++ b/docs/operator-manual/notifications/services/webhook.md @@ -1,7 +1,7 @@ # Webhook The webhook notification service allows sending a generic HTTP request using the templatized request body and URL. -Using Webhook you might trigger a Jenkins job, update Github commit status. +Using Webhook you might trigger a Jenkins job, update GitHub commit status. ## Parameters @@ -9,8 +9,17 @@ The Webhook notification service configuration includes following settings: - `url` - the url to send the webhook to - `headers` - optional, the headers to pass along with the webhook -- `basicAuth` - optional, the basic authentication to pass along with the webook +- `basicAuth` - optional, the basic authentication to pass along with the webhook - `insecureSkipVerify` - optional bool, true or false +- `retryWaitMin` - Optional, the minimum wait time between retries. Default value: 1s. +- `retryWaitMax` - Optional, the maximum wait time between retries. Default value: 5s. +- `retryMax` - Optional, the maximum number of retries. Default value: 3. + +## Retry Behavior + +The webhook service will automatically retry the request if it fails due to network errors or if the server returns a 5xx status code. The number of retries and the wait time between retries can be configured using the `retryMax`, `retryWaitMin`, and `retryWaitMax` parameters. + +The wait time between retries is between `retryWaitMin` and `retryWaitMax`. If all retries fail, the `Send` method will return an error. ## Configuration @@ -22,7 +31,7 @@ Use the following steps to configure webhook: apiVersion: v1 kind: ConfigMap metadata: - name: + name: argocd-notifications-cm data: service.webhook.: | url: https:/// @@ -41,7 +50,7 @@ data: apiVersion: v1 kind: ConfigMap metadata: - name: + name: argocd-notifications-cm data: template.github-commit-status: | webhook: @@ -67,13 +76,13 @@ metadata: ## Examples -### Set Github commit status +### Set GitHub commit status ```yaml apiVersion: v1 kind: ConfigMap metadata: - name: + name: argocd-notifications-cm data: service.webhook.github: | url: https://api.github.com @@ -88,7 +97,7 @@ data: apiVersion: v1 kind: ConfigMap metadata: - name: + name: argocd-notifications-cm data: service.webhook.github: | url: https://api.github.com @@ -119,7 +128,7 @@ data: apiVersion: v1 kind: ConfigMap metadata: - name: + name: argocd-notifications-cm data: service.webhook.jenkins: | url: http:///job//build?token= @@ -136,7 +145,7 @@ type: Opaque apiVersion: v1 kind: ConfigMap metadata: - name: + name: argocd-notifications-cm data: service.webhook.form: | url: https://form.example.com @@ -157,7 +166,7 @@ data: apiVersion: v1 kind: ConfigMap metadata: - name: + name: argocd-notifications-cm data: service.webhook.slack_webhook: | url: https://hooks.slack.com/services/xxxxx diff --git a/docs/operator-manual/notifications/templates.md b/docs/operator-manual/notifications/templates.md index f865229e12835..1d80f20953b24 100644 --- a/docs/operator-manual/notifications/templates.md +++ b/docs/operator-manual/notifications/templates.md @@ -20,6 +20,7 @@ Each template has access to the following fields: - `app` holds the application object. - `context` is a user-defined string map and might include any string keys and values. +- `secrets` provides access to sensitive data stored in `argocd-notifications-secret` - `serviceType` holds the notification service type name (such as "slack" or "email). The field can be used to conditionally render service-specific fields. - `recipient` holds the recipient name. @@ -43,6 +44,39 @@ data: message: "Something happened in {{ .context.environmentName }} in the {{ .context.region }} data center!" ``` +## Defining and using secrets within notification templates + +Some notification service use cases will require the use of secrets within templates. This can be achieved with the use of +the `secrets` data variable available within the templates. + +Given that we have the following `argocd-notifications-secret`: + +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: argocd-notifications-secret +stringData: + sampleWebhookToken: secret-token +type: Opaque +``` + +We can use the defined `sampleWebhookToken` in a template as such: + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: argocd-notifications-cm +data: + template.trigger-webhook: | + webhook: + sample-webhook: + method: POST + path: 'webhook/endpoint/with/auth' + body: 'token={{ .secrets.sampleWebhookToken }}&variables[APP_SOURCE_PATH]={{ .app.spec.source.path }} +``` + ## Notification Service Specific Fields The `message` field of the template definition allows creating a basic notification for any notification service. You can leverage notification service-specific diff --git a/docs/operator-manual/notifications/triggers.md b/docs/operator-manual/notifications/triggers.md index c3e2dc601296b..02d0228c40997 100644 --- a/docs/operator-manual/notifications/triggers.md +++ b/docs/operator-manual/notifications/triggers.md @@ -1,7 +1,7 @@ The trigger defines the condition when the notification should be sent. The definition includes name, condition and notification templates reference. The condition is a predicate expression that returns true if the notification should be sent. The trigger condition evaluation is powered by [antonmedv/expr](https://github.com/antonmedv/expr). -The condition language syntax is described at [Language-Definition.md](https://github.com/antonmedv/expr/blob/master/docs/Language-Definition.md). +The condition language syntax is described at [language-definition.md](https://github.com/antonmedv/expr/blob/master/docs/language-definition.md). The trigger is configured in the `argocd-notifications-cm` ConfigMap. For example the following trigger sends a notification when application sync status changes to `Unknown` using the `app-sync-status` template: diff --git a/docs/operator-manual/notifications/troubleshooting-commands.md b/docs/operator-manual/notifications/troubleshooting-commands.md index 633eb47d71690..8674e9677c1eb 100644 --- a/docs/operator-manual/notifications/troubleshooting-commands.md +++ b/docs/operator-manual/notifications/troubleshooting-commands.md @@ -39,6 +39,7 @@ argocd admin notifications template get app-sync-succeeded -o=yaml --cluster string The name of the kubeconfig cluster to use --config-map string argocd-notifications-cm.yaml file path --context string The name of the kubeconfig context to use + --disable-compression If true, opt-out of response compression for all requests to the server --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure --kubeconfig string Path to a kube config. Only required if out-of-cluster -n, --namespace string If present, the namespace scope for this CLI request @@ -95,6 +96,7 @@ argocd admin notifications template notify app-sync-succeeded guestbook --cluster string The name of the kubeconfig cluster to use --config-map string argocd-notifications-cm.yaml file path --context string The name of the kubeconfig context to use + --disable-compression If true, opt-out of response compression for all requests to the server --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure --kubeconfig string Path to a kube config. Only required if out-of-cluster -n, --namespace string If present, the namespace scope for this CLI request @@ -150,6 +152,7 @@ argocd admin notifications trigger get on-sync-failed -o=yaml --cluster string The name of the kubeconfig cluster to use --config-map string argocd-notifications-cm.yaml file path --context string The name of the kubeconfig context to use + --disable-compression If true, opt-out of response compression for all requests to the server --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure --kubeconfig string Path to a kube config. Only required if out-of-cluster -n, --namespace string If present, the namespace scope for this CLI request @@ -205,6 +208,7 @@ argocd admin notifications trigger run on-sync-status-unknown ./sample-app.yaml --cluster string The name of the kubeconfig cluster to use --config-map string argocd-notifications-cm.yaml file path --context string The name of the kubeconfig context to use + --disable-compression If true, opt-out of response compression for all requests to the server --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure --kubeconfig string Path to a kube config. Only required if out-of-cluster -n, --namespace string If present, the namespace scope for this CLI request diff --git a/docs/operator-manual/rbac.md b/docs/operator-manual/rbac.md index 0f15a18be1973..b1d386fb5eb8e 100644 --- a/docs/operator-manual/rbac.md +++ b/docs/operator-manual/rbac.md @@ -159,6 +159,7 @@ data: g, your-github-org:your-team, role:org-admin ``` + ---- Another `policy.csv` example might look as follows: diff --git a/docs/operator-manual/secret-management.md b/docs/operator-manual/secret-management.md index ab06a46014b20..aa224e20ff742 100644 --- a/docs/operator-manual/secret-management.md +++ b/docs/operator-manual/secret-management.md @@ -10,7 +10,7 @@ Here are some ways people are doing GitOps secrets: * [Bitnami Sealed Secrets](https://github.com/bitnami-labs/sealed-secrets) * [External Secrets Operator](https://github.com/external-secrets/external-secrets) * [Hashicorp Vault](https://www.vaultproject.io) -* [Bank-Vaults]((https://bank-vaults.dev/)) +* [Bank-Vaults](https://bank-vaults.dev/) * [Helm Secrets](https://github.com/jkroepke/helm-secrets) * [Kustomize secret generator plugins](https://github.com/kubernetes-sigs/kustomize/blob/fd7a353df6cece4629b8e8ad56b71e30636f38fc/examples/kvSourceGoPlugin.md#secret-values-from-anywhere) * [aws-secret-operator](https://github.com/mumoshu/aws-secret-operator) diff --git a/docs/operator-manual/security.md b/docs/operator-manual/security.md index 3ba9fdfe39363..47c5d3aa1accc 100644 --- a/docs/operator-manual/security.md +++ b/docs/operator-manual/security.md @@ -45,7 +45,7 @@ Communication with Redis is performed over plain HTTP by default. TLS can be set Git and helm repositories are managed by a stand-alone service, called the repo-server. The repo-server does not carry any Kubernetes privileges and does not store credentials to any services (including git). The repo-server is responsible for cloning repositories which have been permitted -and trusted by Argo CD operators, and generating kubernetes manifests at a given path in the +and trusted by Argo CD operators, and generating Kubernetes manifests at a given path in the repository. For performance and bandwidth efficiency, the repo-server maintains local clones of these repositories so that subsequent commits to the repository are efficiently downloaded. @@ -109,7 +109,7 @@ The information is used to reconstruct a REST config and kubeconfig to the clust services. To rotate the bearer token used by Argo CD, the token can be deleted (e.g. using kubectl) which -causes kubernetes to generate a new secret with a new bearer token. The new token can be re-inputted +causes Kubernetes to generate a new secret with a new bearer token. The new token can be re-inputted to Argo CD by re-running `argocd cluster add`. Run the following commands against the *_managed_* cluster: diff --git a/docs/operator-manual/server-commands/argocd-application-controller.md b/docs/operator-manual/server-commands/argocd-application-controller.md index 21d26b29c572e..f4057bf7b04cc 100644 --- a/docs/operator-manual/server-commands/argocd-application-controller.md +++ b/docs/operator-manual/server-commands/argocd-application-controller.md @@ -17,6 +17,7 @@ argocd-application-controller [flags] ``` --app-hard-resync int Time period in seconds for application hard resync. --app-resync int Time period in seconds for application resync. (default 180) + --app-resync-jitter int Maximum time period in seconds to add as a delay jitter for application resync. --app-state-cache-expiration duration Cache expiration for app state (default 1h0m0s) --application-namespaces strings List of additional namespaces that applications are allowed to be reconciled from --as string Username to impersonate for the operation @@ -28,6 +29,7 @@ argocd-application-controller [flags] --cluster string The name of the kubeconfig cluster to use --context string The name of the kubeconfig context to use --default-cache-expiration duration Cache expiration default (default 24h0m0s) + --disable-compression If true, opt-out of response compression for all requests to the server --dynamic-cluster-distribution-enabled Enables dynamic cluster distribution. --gloglevel int Set the glog logging level -h, --help help for argocd-application-controller @@ -43,6 +45,8 @@ argocd-application-controller [flags] --operation-processors int Number of application operation processors (default 10) --otlp-address string OpenTelemetry collector address to send traces to --otlp-attrs strings List of OpenTelemetry collector extra attrs when send traces, each attribute is separated by a colon(e.g. key:value) + --otlp-headers stringToString List of OpenTelemetry collector extra headers sent with traces, headers are comma-separated key-value pairs(e.g. key1=value1,key2=value2) (default []) + --otlp-insecure OpenTelemetry collector insecure mode (default true) --password string Password for basic authentication to the API server --persist-resource-health Enables storing the managed resources health in the Application CRD (default true) --proxy-url string If provided, this URL will be used to connect via proxy @@ -54,6 +58,7 @@ argocd-application-controller [flags] --redis-insecure-skip-tls-verify Skip Redis server certificate validation. --redis-use-tls Use TLS when connecting to Redis. --redisdb int Redis database. + --repo-error-grace-period-seconds int Grace period in seconds for ignoring consecutive errors while communicating with repo server. (default 180) --repo-server string Repo server address. (default "argocd-repo-server:8081") --repo-server-plaintext Disable TLS on connections to repo server --repo-server-strict-tls Whether to use strict validation of the TLS cert presented by the repo server @@ -63,11 +68,18 @@ argocd-application-controller [flags] --sentinel stringArray Redis sentinel hostname and port (e.g. argocd-redis-ha-announce-0:6379). --sentinelmaster string Redis sentinel master group name. (default "master") --server string The address and port of the Kubernetes API server + --server-side-diff-enabled Feature flag to enable ServerSide diff. Default ("false") --sharding-method string Enables choice of sharding method. Supported sharding methods are : [legacy, round-robin] (default "legacy") --status-processors int Number of application status processors (default 20) --tls-server-name string If provided, this name will be used to validate server certificate. If this is not provided, hostname used to contact the server is used. --token string Bearer token for authentication to the API server --user string The name of the kubeconfig user to use --username string Username for basic authentication to the API server + --wq-backoff-factor float Set Workqueue Per Item Rate Limiter Backoff Factor, default is 1.5 (default 1.5) + --wq-basedelay-ns duration Set Workqueue Per Item Rate Limiter Base Delay duration in nanoseconds, default 1000000 (1ms) (default 1ms) + --wq-bucket-qps int Set Workqueue Rate Limiter Bucket QPS, default 50 (default 50) + --wq-bucket-size int Set Workqueue Rate Limiter Bucket Size, default 500 (default 500) + --wq-cooldown-ns duration Set Workqueue Per Item Rate Limiter Cooldown duration in ns, default 0(per item rate limiter disabled) + --wq-maxdelay-ns duration Set Workqueue Per Item Rate Limiter Max Delay duration in nanoseconds, default 1000000000 (1s) (default 1s) ``` diff --git a/docs/operator-manual/server-commands/argocd-dex_gendexcfg.md b/docs/operator-manual/server-commands/argocd-dex_gendexcfg.md index 1e784e94a2620..a889b64133a93 100644 --- a/docs/operator-manual/server-commands/argocd-dex_gendexcfg.md +++ b/docs/operator-manual/server-commands/argocd-dex_gendexcfg.md @@ -19,6 +19,7 @@ argocd-dex gendexcfg [flags] --client-key string Path to a client key file for TLS --cluster string The name of the kubeconfig cluster to use --context string The name of the kubeconfig context to use + --disable-compression If true, opt-out of response compression for all requests to the server --disable-tls Disable TLS on the HTTP endpoint -h, --help help for gendexcfg --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure diff --git a/docs/operator-manual/server-commands/argocd-dex_rundex.md b/docs/operator-manual/server-commands/argocd-dex_rundex.md index 16e2b15abbece..b2d453feba613 100644 --- a/docs/operator-manual/server-commands/argocd-dex_rundex.md +++ b/docs/operator-manual/server-commands/argocd-dex_rundex.md @@ -19,6 +19,7 @@ argocd-dex rundex [flags] --client-key string Path to a client key file for TLS --cluster string The name of the kubeconfig cluster to use --context string The name of the kubeconfig context to use + --disable-compression If true, opt-out of response compression for all requests to the server --disable-tls Disable TLS on the HTTP endpoint -h, --help help for rundex --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure diff --git a/docs/operator-manual/server-commands/argocd-repo-server.md b/docs/operator-manual/server-commands/argocd-repo-server.md index 33ecaf7c76dd4..7be45fe18d26f 100644 --- a/docs/operator-manual/server-commands/argocd-repo-server.md +++ b/docs/operator-manual/server-commands/argocd-repo-server.md @@ -29,6 +29,8 @@ argocd-repo-server [flags] --metrics-port int Start metrics server on given port (default 8084) --otlp-address string OpenTelemetry collector address to send traces to --otlp-attrs strings List of OpenTelemetry collector extra attrs when send traces, each attribute is separated by a colon(e.g. key:value) + --otlp-headers stringToString List of OpenTelemetry collector extra headers sent with traces, headers are comma-separated key-value pairs(e.g. key1=value1,key2=value2) (default []) + --otlp-insecure OpenTelemetry collector insecure mode (default true) --parallelismlimit int Limit on number of concurrent manifests generate requests. Any value less the 1 means no limit. --plugin-tar-exclude stringArray Globs to filter when sending tarballs to plugins. --port int Listen on given port for incoming connections (default 8081) diff --git a/docs/operator-manual/server-commands/argocd-server.md b/docs/operator-manual/server-commands/argocd-server.md index d39459ad181d6..a72cc041299ad 100644 --- a/docs/operator-manual/server-commands/argocd-server.md +++ b/docs/operator-manual/server-commands/argocd-server.md @@ -12,73 +12,100 @@ The API server is a gRPC/REST server which exposes the API consumed by the Web U argocd-server [flags] ``` +### Examples + +``` + # Start the Argo CD API server with default settings + $ argocd-server + + # Start the Argo CD API server on a custom port and enable tracing + $ argocd-server --port 8888 --otlp-address localhost:4317 +``` + ### Options ``` - --address string Listen on given address (default "0.0.0.0") - --app-state-cache-expiration duration Cache expiration for app state (default 1h0m0s) - --application-namespaces strings List of additional namespaces where application resources can be managed in - --as string Username to impersonate for the operation - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation - --basehref string Value for base href in index.html. Used if Argo CD is running behind reverse proxy under subpath different from / (default "/") - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use - --connection-status-cache-expiration duration Cache expiration for cluster/repo connection status (default 1h0m0s) - --content-security-policy value Set Content-Security-Policy header in HTTP responses to value. To disable, set to "". (default "frame-ancestors 'self';") - --context string The name of the kubeconfig context to use - --default-cache-expiration duration Cache expiration default (default 24h0m0s) - --dex-server string Dex server address (default "argocd-dex-server:5556") - --dex-server-plaintext Use a plaintext client (non-TLS) to connect to dex server - --dex-server-strict-tls Perform strict validation of TLS certificates when connecting to dex server - --disable-auth Disable client authentication - --enable-gzip Enable GZIP compression (default true) - --enable-proxy-extension Enable Proxy Extension feature - --gloglevel int Set the glog logging level - -h, --help help for argocd-server - --insecure Run server without TLS - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - --kubeconfig string Path to a kube config. Only required if out-of-cluster - --logformat string Set the logging format. One of: text|json (default "text") - --login-attempts-expiration duration Cache expiration for failed login attempts (default 24h0m0s) - --loglevel string Set the logging level. One of: debug|info|warn|error (default "info") - --metrics-address string Listen for metrics on given address (default "0.0.0.0") - --metrics-port int Start metrics on given port (default 8083) - -n, --namespace string If present, the namespace scope for this CLI request - --oidc-cache-expiration duration Cache expiration for OIDC state (default 3m0s) - --otlp-address string OpenTelemetry collector address to send traces to - --otlp-attrs strings List of OpenTelemetry collector extra attrs when send traces, each attribute is separated by a colon(e.g. key:value) - --password string Password for basic authentication to the API server - --port int Listen on given port (default 8080) - --proxy-url string If provided, this URL will be used to connect via proxy - --redis string Redis server hostname and port (e.g. argocd-redis:6379). - --redis-ca-certificate string Path to Redis server CA certificate (e.g. /etc/certs/redis/ca.crt). If not specified, system trusted CAs will be used for server certificate validation. - --redis-client-certificate string Path to Redis client certificate (e.g. /etc/certs/redis/client.crt). - --redis-client-key string Path to Redis client key (e.g. /etc/certs/redis/client.crt). - --redis-compress string Enable compression for data sent to Redis with the required compression algorithm. (possible values: gzip, none) (default "gzip") - --redis-insecure-skip-tls-verify Skip Redis server certificate validation. - --redis-use-tls Use TLS when connecting to Redis. - --redisdb int Redis database. - --repo-server string Repo server address (default "argocd-repo-server:8081") - --repo-server-plaintext Use a plaintext client (non-TLS) to connect to repository server - --repo-server-strict-tls Perform strict validation of TLS certificates when connecting to repo server - --repo-server-timeout-seconds int Repo server RPC call timeout seconds. (default 60) - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - --rootpath string Used if Argo CD is running behind reverse proxy under subpath different from / - --sentinel stringArray Redis sentinel hostname and port (e.g. argocd-redis-ha-announce-0:6379). - --sentinelmaster string Redis sentinel master group name. (default "master") - --server string The address and port of the Kubernetes API server - --staticassets string Directory path that contains additional static assets (default "/shared/app") - --tls-server-name string If provided, this name will be used to validate server certificate. If this is not provided, hostname used to contact the server is used. - --tlsciphers string The list of acceptable ciphers to be used when establishing TLS connections. Use 'list' to list available ciphers. (default "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:TLS_RSA_WITH_AES_256_GCM_SHA384") - --tlsmaxversion string The maximum SSL/TLS version that is acceptable (one of: 1.0|1.1|1.2|1.3) (default "1.3") - --tlsminversion string The minimum SSL/TLS version that is acceptable (one of: 1.0|1.1|1.2|1.3) (default "1.2") - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use - --username string Username for basic authentication to the API server - --x-frame-options value Set X-Frame-Options header in HTTP responses to value. To disable, set to "". (default "sameorigin") + --address string Listen on given address (default "0.0.0.0") + --api-content-types string Semicolon separated list of allowed content types for non GET api requests. Any content type is allowed if empty. (default "application/json") + --app-state-cache-expiration duration Cache expiration for app state (default 1h0m0s) + --application-namespaces strings List of additional namespaces where application resources can be managed in + --as string Username to impersonate for the operation + --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. + --as-uid string UID to impersonate for the operation + --basehref string Value for base href in index.html. Used if Argo CD is running behind reverse proxy under subpath different from / (default "/") + --certificate-authority string Path to a cert file for the certificate authority + --client-certificate string Path to a client certificate file for TLS + --client-key string Path to a client key file for TLS + --cluster string The name of the kubeconfig cluster to use + --connection-status-cache-expiration duration Cache expiration for cluster/repo connection status (default 1h0m0s) + --content-security-policy value Set Content-Security-Policy header in HTTP responses to value. To disable, set to "". (default "frame-ancestors 'self';") + --context string The name of the kubeconfig context to use + --default-cache-expiration duration Cache expiration default (default 24h0m0s) + --dex-server string Dex server address (default "argocd-dex-server:5556") + --dex-server-plaintext Use a plaintext client (non-TLS) to connect to dex server + --dex-server-strict-tls Perform strict validation of TLS certificates when connecting to dex server + --disable-auth Disable client authentication + --disable-compression If true, opt-out of response compression for all requests to the server + --enable-gzip Enable GZIP compression (default true) + --enable-proxy-extension Enable Proxy Extension feature + --gloglevel int Set the glog logging level + -h, --help help for argocd-server + --insecure Run server without TLS + --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure + --kubeconfig string Path to a kube config. Only required if out-of-cluster + --logformat string Set the logging format. One of: text|json (default "text") + --login-attempts-expiration duration Cache expiration for failed login attempts (default 24h0m0s) + --loglevel string Set the logging level. One of: debug|info|warn|error (default "info") + --metrics-address string Listen for metrics on given address (default "0.0.0.0") + --metrics-port int Start metrics on given port (default 8083) + -n, --namespace string If present, the namespace scope for this CLI request + --oidc-cache-expiration duration Cache expiration for OIDC state (default 3m0s) + --otlp-address string OpenTelemetry collector address to send traces to + --otlp-attrs strings List of OpenTelemetry collector extra attrs when send traces, each attribute is separated by a colon(e.g. key:value) + --otlp-headers stringToString List of OpenTelemetry collector extra headers sent with traces, headers are comma-separated key-value pairs(e.g. key1=value1,key2=value2) (default []) + --otlp-insecure OpenTelemetry collector insecure mode (default true) + --password string Password for basic authentication to the API server + --port int Listen on given port (default 8080) + --proxy-url string If provided, this URL will be used to connect via proxy + --redis string Redis server hostname and port (e.g. argocd-redis:6379). + --redis-ca-certificate string Path to Redis server CA certificate (e.g. /etc/certs/redis/ca.crt). If not specified, system trusted CAs will be used for server certificate validation. + --redis-client-certificate string Path to Redis client certificate (e.g. /etc/certs/redis/client.crt). + --redis-client-key string Path to Redis client key (e.g. /etc/certs/redis/client.crt). + --redis-compress string Enable compression for data sent to Redis with the required compression algorithm. (possible values: gzip, none) (default "gzip") + --redis-insecure-skip-tls-verify Skip Redis server certificate validation. + --redis-use-tls Use TLS when connecting to Redis. + --redisdb int Redis database. + --repo-cache-expiration duration Cache expiration for repo state, incl. app lists, app details, manifest generation, revision meta-data (default 24h0m0s) + --repo-server string Repo server address (default "argocd-repo-server:8081") + --repo-server-default-cache-expiration duration Cache expiration default (default 24h0m0s) + --repo-server-plaintext Use a plaintext client (non-TLS) to connect to repository server + --repo-server-redis string Redis server hostname and port (e.g. argocd-redis:6379). + --repo-server-redis-ca-certificate string Path to Redis server CA certificate (e.g. /etc/certs/redis/ca.crt). If not specified, system trusted CAs will be used for server certificate validation. + --repo-server-redis-client-certificate string Path to Redis client certificate (e.g. /etc/certs/redis/client.crt). + --repo-server-redis-client-key string Path to Redis client key (e.g. /etc/certs/redis/client.crt). + --repo-server-redis-compress string Enable compression for data sent to Redis with the required compression algorithm. (possible values: gzip, none) (default "gzip") + --repo-server-redis-insecure-skip-tls-verify Skip Redis server certificate validation. + --repo-server-redis-use-tls Use TLS when connecting to Redis. + --repo-server-redisdb int Redis database. + --repo-server-sentinel stringArray Redis sentinel hostname and port (e.g. argocd-redis-ha-announce-0:6379). + --repo-server-sentinelmaster string Redis sentinel master group name. (default "master") + --repo-server-strict-tls Perform strict validation of TLS certificates when connecting to repo server + --repo-server-timeout-seconds int Repo server RPC call timeout seconds. (default 60) + --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") + --revision-cache-expiration duration Cache expiration for cached revision (default 3m0s) + --rootpath string Used if Argo CD is running behind reverse proxy under subpath different from / + --sentinel stringArray Redis sentinel hostname and port (e.g. argocd-redis-ha-announce-0:6379). + --sentinelmaster string Redis sentinel master group name. (default "master") + --server string The address and port of the Kubernetes API server + --staticassets string Directory path that contains additional static assets (default "/shared/app") + --tls-server-name string If provided, this name will be used to validate server certificate. If this is not provided, hostname used to contact the server is used. + --tlsciphers string The list of acceptable ciphers to be used when establishing TLS connections. Use 'list' to list available ciphers. (default "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:TLS_RSA_WITH_AES_256_GCM_SHA384") + --tlsmaxversion string The maximum SSL/TLS version that is acceptable (one of: 1.0|1.1|1.2|1.3) (default "1.3") + --tlsminversion string The minimum SSL/TLS version that is acceptable (one of: 1.0|1.1|1.2|1.3) (default "1.2") + --token string Bearer token for authentication to the API server + --user string The name of the kubeconfig user to use + --username string Username for basic authentication to the API server + --x-frame-options value Set X-Frame-Options header in HTTP responses to value. To disable, set to "". (default "sameorigin") ``` ### SEE ALSO diff --git a/docs/operator-manual/server-commands/argocd-server_version.md b/docs/operator-manual/server-commands/argocd-server_version.md index 2d7d9d1151e8a..2659c99e87219 100644 --- a/docs/operator-manual/server-commands/argocd-server_version.md +++ b/docs/operator-manual/server-commands/argocd-server_version.md @@ -26,6 +26,7 @@ argocd-server version [flags] --client-key string Path to a client key file for TLS --cluster string The name of the kubeconfig cluster to use --context string The name of the kubeconfig context to use + --disable-compression If true, opt-out of response compression for all requests to the server --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure --kubeconfig string Path to a kube config. Only required if out-of-cluster -n, --namespace string If present, the namespace scope for this CLI request diff --git a/docs/operator-manual/signed-release-assets.md b/docs/operator-manual/signed-release-assets.md index 9aec6bb071047..b4e4f3fc97418 100644 --- a/docs/operator-manual/signed-release-assets.md +++ b/docs/operator-manual/signed-release-assets.md @@ -92,7 +92,7 @@ The attestation payload contains a non-forgeable provenance which is base64 enco ```bash slsa-verifier verify-image "$IMAGE" \ --source-uri github.com/argoproj/argo-cd \ - --source-tag v2.7.0 + --source-tag v2.7.0 \ --print-provenance | jq ``` diff --git a/docs/operator-manual/troubleshooting.md b/docs/operator-manual/troubleshooting.md index 884045410b0b8..0e0159e5def4f 100644 --- a/docs/operator-manual/troubleshooting.md +++ b/docs/operator-manual/troubleshooting.md @@ -25,7 +25,7 @@ argocd admin settings resource-overrides ignore-differences ./deploy.yaml --argo **Health Assessment** -Argo CD provides built-in [health assessment](./health.md) for several kubernetes resources which can be further +Argo CD provides built-in [health assessment](./health.md) for several Kubernetes resources which can be further customized by writing your own health checks in [Lua](https://www.lua.org/). The health checks are configured in the `resource.customizations` field of `argocd-cm` ConfigMap. diff --git a/docs/operator-manual/upgrading/2.10-2.11.md b/docs/operator-manual/upgrading/2.10-2.11.md new file mode 100644 index 0000000000000..4cf5c8ed02b0b --- /dev/null +++ b/docs/operator-manual/upgrading/2.10-2.11.md @@ -0,0 +1,5 @@ +# v2.10 to 2.11 + +## initiatedBy added in Application CRD + +In order to address [argoproj/argo-cd#16612](https://github.com/argoproj/argo-cd/issues/16612), initiatedBy has been added in the Application CRD. \ No newline at end of file diff --git a/docs/operator-manual/upgrading/2.7-2.8.md b/docs/operator-manual/upgrading/2.7-2.8.md index 1e403bf981ab4..c42a97a1f429c 100644 --- a/docs/operator-manual/upgrading/2.7-2.8.md +++ b/docs/operator-manual/upgrading/2.7-2.8.md @@ -11,7 +11,7 @@ to upgrade your plugin. With the 2.8 release `entrypoint.sh` will be removed from the containers, because starting with 2.7, the implicit entrypoint is set to `tini` in the -`Dockerfile` explicitly, and the kubernetes manifests has been updated to use +`Dockerfile` explicitly, and the Kubernetes manifests has been updated to use it. Simply updating the containers without updating the deployment manifests will result in pod startup failures, as the old manifests are relying on `entrypoint.sh` instead of `tini`. Please make sure the manifests are updated diff --git a/docs/operator-manual/upgrading/2.8-2.9.md b/docs/operator-manual/upgrading/2.8-2.9.md new file mode 100644 index 0000000000000..ef99e09587814 --- /dev/null +++ b/docs/operator-manual/upgrading/2.8-2.9.md @@ -0,0 +1,5 @@ +# v2.8 to 2.9 + +## Upgraded Kustomize Version + +Note that bundled Kustomize version has been upgraded from 5.1.0 to 5.2.1. diff --git a/docs/operator-manual/upgrading/2.9-2.10.md b/docs/operator-manual/upgrading/2.9-2.10.md new file mode 100644 index 0000000000000..cfb3e286649ac --- /dev/null +++ b/docs/operator-manual/upgrading/2.9-2.10.md @@ -0,0 +1,16 @@ +# v2.9 to 2.10 + +## `managedNamespaceMetadata` no longer preserves client-side-applied labels or annotations + +Argo CD 2.10 upgraded kubectl from 1.24 to 1.26. This upgrade introduced a change where client-side-applied labels and +annotations are no longer preserved when using a server-side kubectl apply. This change affects the +`managedNamespaceMetadata` field of the `Application` CRD. Previously, labels and annotations applied via a client-side +apply would be preserved when `managedNamespaceMetadata` was enabled. Now, those existing labels and annotation will be +removed. + +To avoid unexpected behavior, follow the [client-side to server-side resource upgrade guide](https://kubernetes.io/docs/reference/using-api/server-side-apply/#upgrading-from-client-side-apply-to-server-side-apply) +before enabling `managedNamespaceMetadata` on an existing namespace. + +## Upgraded Helm Version + +Note that bundled Helm version has been upgraded from 3.13.2 to 3.14.0. diff --git a/docs/operator-manual/upgrading/overview.md b/docs/operator-manual/upgrading/overview.md index 419fc7bbb1353..742c7b191b57a 100644 --- a/docs/operator-manual/upgrading/overview.md +++ b/docs/operator-manual/upgrading/overview.md @@ -37,6 +37,8 @@ kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/ +* [v2.9 to v2.10](./2.9-2.10.md) +* [v2.8 to v2.9](./2.8-2.9.md) * [v2.7 to v2.8](./2.7-2.8.md) * [v2.6 to v2.7](./2.6-2.7.md) * [v2.5 to v2.6](./2.5-2.6.md) diff --git a/docs/operator-manual/user-management/identity-center.md b/docs/operator-manual/user-management/identity-center.md new file mode 100644 index 0000000000000..0fd78b1aaf62f --- /dev/null +++ b/docs/operator-manual/user-management/identity-center.md @@ -0,0 +1,79 @@ +# Identity Center (AWS SSO) + +!!! note "Are you using this? Please contribute!" + If you're using this IdP please consider [contributing](../../developer-guide/site.md) to this document. + +A working Single Sign-On configuration using Identity Center (AWS SSO) has been achieved using the following method: + +* [SAML (with Dex)](#saml-with-dex) + +## SAML (with Dex) + +1. Create a new SAML application in Identity Center and download the certificate. + * ![Identity Center SAML App 1](../../assets/identity-center-1.png) + * ![Identity Center SAML App 2](../../assets/identity-center-2.png) +2. Click `Assign Users` after creating the application in Identity Center, and select the users or user groups you wish to grant access to this application. + * ![Identity Center SAML App 3](../../assets/identity-center-3.png) +3. Copy the Argo CD URL into the `data.url` field in the `argocd-cm` ConfigMap. + + data: + url: https://argocd.example.com + +4. Configure Attribute mappings. + + !!! note "Group attribute mapping is not officially!" + Group attribute mapping is not officially supported in the AWS docs, however the workaround is currently working. + + * ![Identity Center SAML App 4](../../assets/identity-center-4.png) + * ![Identity Center SAML App 5](../../assets/identity-center-5.png) + + + +5. Download the CA certificate to use in the `argocd-cm` configuration. + * If using the `caData` field, you'll need to base64-encode the entire certificate, including the `-----BEGIN CERTIFICATE-----` and `-----END CERTIFICATE-----` stanzas (e.g., `base64 my_cert.pem`). + * If using the `ca` field and storing the CA certificate separately as a secret, you will need to mount the secret onto the `dex` container in the `argocd-dex-server` Deployment. + * ![Identity Center SAML App 6](../../assets/identity-center-6.png) +6. Edit the `argocd-cm` and configure the `data.dex.config` section: + + +```yaml +dex.config: | + logger: + level: debug + format: json + connectors: + - type: saml + id: aws + name: "AWS IAM Identity Center" + config: + # You need value of Identity Center APP SAML (IAM Identity Center sign-in URL) + ssoURL: https://portal.sso.yourregion.amazonaws.com/saml/assertion/id + # You need `caData` _OR_ `ca`, but not both. + caData: + # Path to mount the secret to the dex container + entityIssuer: https://external.path.to.argocd.io/api/dex/callback + redirectURI: https://external.path.to.argocd.io/api/dex/callback + usernameAttr: email + emailAttr: email + groupsAttr: groups +``` + + +### Connect Identity Center Groups to Argo CD Roles +Argo CD recognizes user memberships in Identity Center groups that match the **Group Attribute Statements** regex. + + In the example above, the regex `argocd-*` is used, making Argo CD aware of a group named `argocd-admins`. + +Modify the `argocd-rbac-cm` ConfigMap to connect the `ArgoCD-administrators` Identity Center group to the builtin Argo CD `admin` role. + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: argocd-rbac-cm +data: + policy.csv: | + g, , role:admin + scopes: '[groups, email]' +``` + diff --git a/docs/operator-manual/user-management/index.md b/docs/operator-manual/user-management/index.md index 8c3f2e169597c..496dd17a83e9f 100644 --- a/docs/operator-manual/user-management/index.md +++ b/docs/operator-manual/user-management/index.md @@ -201,7 +201,7 @@ data: id: acme-github name: Acme GitHub config: - hostName: github.acme.com + hostName: github.acme.example.com clientID: abcdefghijklmnopqrst clientSecret: $dex.acme.clientSecret # Alternatively $:dex.acme.clientSecret orgs: @@ -242,7 +242,7 @@ data: id: oidc name: OIDC config: - issuer: https://example-OIDC-provider.com + issuer: https://example-OIDC-provider.example.com clientID: aaaabbbbccccddddeee clientSecret: $dex.oidc.clientSecret ``` @@ -264,7 +264,7 @@ data: id: oidc name: OIDC config: - issuer: https://example-OIDC-provider.com + issuer: https://example-OIDC-provider.example.com clientID: aaaabbbbccccddddeee clientSecret: $dex.oidc.clientSecret insecureEnableGroups: true @@ -294,7 +294,7 @@ data: id: oidc name: OIDC config: - issuer: https://example-OIDC-provider.com + issuer: https://example-OIDC-provider.example.com clientID: aaaabbbbccccddddeee clientSecret: $dex.oidc.clientSecret insecureEnableGroups: true @@ -344,6 +344,12 @@ data: # for the 'localhost' (CLI) client to Dex. This field is optional. If omitted, the CLI will # use the same clientID as the Argo CD server cliClientID: vvvvwwwwxxxxyyyyzzzz + + # PKCE authentication flow processes authorization flow from browser only - default false + # uses the clientID + # make sure the Identity Provider (IdP) is public and doesn't need clientSecret + # make sure the Identity Provider (IdP) has this redirect URI registered: https://argocd.example.com/pkce/verify + enablePKCEAuthentication: true ``` !!! note @@ -381,6 +387,20 @@ For a simple case this can be: oidc.config: | requestedIDTokenClaims: {"groups": {"essential": true}} ``` + +### Retrieving group claims when not in the token + +Some OIDC providers don't return the group information for a user in the ID token, even if explicitly requested using the `requestedIDTokenClaims` setting (Okta for example). They instead provide the groups on the user info endpoint. With the following config, Argo CD queries the user info endpoint during login for groups information of a user: + +```yaml +oidc.config: | + enableUserInfoGroups: true + userInfoPath: /userinfo + userInfoCacheExpiration: "5m" +``` + +**Note: If you omit the `userInfoCacheExpiration` setting or if it's greater than the expiration of the ID token, the argocd-server will cache group information as long as the ID token is valid!** + ### Configuring a custom logout URL for your OIDC provider Optionally, if your OIDC provider exposes a logout API and you wish to configure a custom logout URL for the purposes of invalidating @@ -389,18 +409,18 @@ any active session post logout, you can do so by specifying it as follows: ```yaml oidc.config: | name: example-OIDC-provider - issuer: https://example-OIDC-provider.com + issuer: https://example-OIDC-provider.example.com clientID: xxxxxxxxx clientSecret: xxxxxxxxx requestedScopes: ["openid", "profile", "email", "groups"] requestedIDTokenClaims: {"groups": {"essential": true}} - logoutURL: https://example-OIDC-provider.com/logout?id_token_hint={{token}} + logoutURL: https://example-OIDC-provider.example.com/logout?id_token_hint={{token}} ``` By default, this would take the user to their OIDC provider's login page after logout. If you also wish to redirect the user back to Argo CD after logout, you can specify the logout URL as follows: ```yaml ... - logoutURL: https://example-OIDC-provider.com/logout?id_token_hint={{token}}&post_logout_redirect_uri={{logoutRedirectURL}} + logoutURL: https://example-OIDC-provider.example.com/logout?id_token_hint={{token}}&post_logout_redirect_uri={{logoutRedirectURL}} ``` You are not required to specify a logoutRedirectURL as this is automatically generated by ArgoCD as your base ArgoCD url + Rootpath @@ -436,7 +456,7 @@ Add a `rootCA` to your `oidc.config` which contains the PEM encoded root certifi #### Example -SSO `clientSecret` can thus be stored as a kubernetes secret with the following manifests +SSO `clientSecret` can thus be stored as a Kubernetes secret with the following manifests `argocd-secret`: ```yaml diff --git a/docs/operator-manual/user-management/microsoft.md b/docs/operator-manual/user-management/microsoft.md index 33a6b3e945940..486d647fde3d0 100644 --- a/docs/operator-manual/user-management/microsoft.md +++ b/docs/operator-manual/user-management/microsoft.md @@ -1,13 +1,16 @@ # Microsoft -* [Azure AD SAML Enterprise App Auth using Dex](#azure-ad-saml-enterprise-app-auth-using-dex) -* [Azure AD App Registration Auth using OIDC](#azure-ad-app-registration-auth-using-oidc) -* [Azure AD App Registration Auth using Dex](#azure-ad-app-registration-auth-using-dex) +!!! note "" + Entra ID was formerly known as Azure AD. -## Azure AD SAML Enterprise App Auth using Dex -### Configure a new Azure AD Enterprise App +* [Entra ID SAML Enterprise App Auth using Dex](#entra-id-saml-enterprise-app-auth-using-dex) +* [Entra ID App Registration Auth using OIDC](#entra-id-app-registration-auth-using-oidc) +* [Entra ID App Registration Auth using Dex](#entra-id-app-registration-auth-using-dex) -1. From the `Azure Active Directory` > `Enterprise applications` menu, choose `+ New application` +## Entra ID SAML Enterprise App Auth using Dex +### Configure a new Entra ID Enterprise App + +1. From the `Microsoft Entra ID` > `Enterprise applications` menu, choose `+ New application` 2. Select `Non-gallery application` 3. Enter a `Name` for the application (e.g. `Argo CD`), then choose `Add` 4. Once the application is created, open it from the `Enterprise applications` menu. @@ -31,9 +34,9 @@ - *Keep a copy of the encoded output to be used in the next section.* 9. From the `Single sign-on` menu, copy the `Login URL` parameter, to be used in the next section. -### Configure Argo to use the new Azure AD Enterprise App +### Configure Argo to use the new Entra ID Enterprise App -1. Edit `argocd-cm` and add the following `dex.config` to the data section, replacing the `caData`, `my-argo-cd-url` and `my-login-url` your values from the Azure AD App: +1. Edit `argocd-cm` and add the following `dex.config` to the data section, replacing the `caData`, `my-argo-cd-url` and `my-login-url` your values from the Entra ID App: data: url: https://my-argo-cd-url @@ -56,7 +59,7 @@ groupsAttr: Group 2. Edit `argocd-rbac-cm` to configure permissions, similar to example below. - - Use Azure AD `Group IDs` for assigning roles. + - Use Entra ID `Group IDs` for assigning roles. - See [RBAC Configurations](../rbac.md) for more detailed scenarios. # example policy @@ -70,11 +73,11 @@ p, role:org-admin, repositories, delete, *, allow g, "84ce98d1-e359-4f3b-85af-985b458de3c6", role:org-admin # (azure group assigned to role) -## Azure AD App Registration Auth using OIDC -### Configure a new Azure AD App registration -#### Add a new Azure AD App registration +## Entra ID App Registration Auth using OIDC +### Configure a new Entra ID App registration +#### Add a new Entra ID App registration -1. From the `Azure Active Directory` > `App registrations` menu, choose `+ New registration` +1. From the `Microsoft Entra ID` > `App registrations` menu, choose `+ New registration` 2. Enter a `Name` for the application (e.g. `Argo CD`). 3. Specify who can use the application (e.g. `Accounts in this organizational directory only`). 4. Enter Redirect URI (optional) as follows (replacing `my-argo-cd-url` with your Argo URL), then choose `Add`. @@ -92,29 +95,29 @@ - **Redirect URI:** `http://localhost:8085/auth/callback` ![Azure App registration's Authentication](../../assets/azure-app-registration-authentication.png "Azure App registration's Authentication") -#### Add credentials a new Azure AD App registration +#### Add credentials a new Entra ID App registration 1. From the `Certificates & secrets` menu, choose `+ New client secret` 2. Enter a `Name` for the secret (e.g. `ArgoCD-SSO`). - Make sure to copy and save generated value. This is a value for the `client_secret`. ![Azure App registration's Secret](../../assets/azure-app-registration-secret.png "Azure App registration's Secret") -#### Setup permissions for Azure AD Application +#### Setup permissions for Entra ID Application 1. From the `API permissions` menu, choose `+ Add a permission` 2. Find `User.Read` permission (under `Microsoft Graph`) and grant it to the created application: - ![Azure AD API permissions](../../assets/azure-api-permissions.png "Azure AD API permissions") + ![Entra ID API permissions](../../assets/azure-api-permissions.png "Entra ID API permissions") 3. From the `Token Configuration` menu, choose `+ Add groups claim` - ![Azure AD token configuration](../../assets/azure-token-configuration.png "Azure AD token configuration") + ![Entra ID token configuration](../../assets/azure-token-configuration.png "Entra ID token configuration") -### Associate an Azure AD group to your Azure AD App registration +### Associate an Entra ID group to your Entra ID App registration -1. From the `Azure Active Directory` > `Enterprise applications` menu, search the App that you created (e.g. `Argo CD`). - - An Enterprise application with the same name of the Azure AD App registration is created when you add a new Azure AD App registration. +1. From the `Microsoft Entra ID` > `Enterprise applications` menu, search the App that you created (e.g. `Argo CD`). + - An Enterprise application with the same name of the Entra ID App registration is created when you add a new Entra ID App registration. 2. From the `Users and groups` menu of the app, add any users or groups requiring access to the service. ![Azure Enterprise SAML Users](../../assets/azure-enterprise-users.png "Azure Enterprise SAML Users") -### Configure Argo to use the new Azure AD App registration +### Configure Argo to use the new Entra ID App registration 1. Edit `argocd-cm` and configure the `data.oidc.config` and `data.url` section: @@ -173,7 +176,7 @@ Refer to [operator-manual/argocd-rbac-cm.yaml](https://github.com/argoproj/argo-cd/blob/master/docs/operator-manual/argocd-rbac-cm.yaml) for all of the available variables. -## Azure AD App Registration Auth using Dex +## Entra ID App Registration Auth using Dex Configure a new AD App Registration, as above. Then, add the `dex.config` to `argocd-cm`: @@ -200,9 +203,9 @@ data: 1. Open a new browser tab and enter your ArgoCD URI: https://`` ![Azure SSO Web Log In](../../assets/azure-sso-web-log-in-via-azure.png "Azure SSO Web Log In") -3. Click `LOGIN VIA AZURE` button to log in with your Azure Active Directory account. You’ll see the ArgoCD applications screen. +3. Click `LOGIN VIA AZURE` button to log in with your Microsoft Entra ID account. You’ll see the ArgoCD applications screen. ![Azure SSO Web Application](../../assets/azure-sso-web-application.png "Azure SSO Web Application") -4. Navigate to User Info and verify Group ID. Groups will have your group’s Object ID that you added in the `Setup permissions for Azure AD Application` step. +4. Navigate to User Info and verify Group ID. Groups will have your group’s Object ID that you added in the `Setup permissions for Entra ID Application` step. ![Azure SSO Web User Info](../../assets/azure-sso-web-user-info.png "Azure SSO Web User Info") ### Log in to ArgoCD using CLI diff --git a/docs/operator-manual/user-management/okta.md b/docs/operator-manual/user-management/okta.md index 09d7099d19954..308254759de6e 100644 --- a/docs/operator-manual/user-management/okta.md +++ b/docs/operator-manual/user-management/okta.md @@ -118,34 +118,81 @@ data: ## OIDC (without Dex) -!!! warning "Do you want groups for RBAC later?" - If you want `groups` scope returned from Okta you need to unfortunately contact support to enable [API Access Management with Okta](https://developer.okta.com/docs/concepts/api-access-management/) or [_just use SAML above!_](#saml-with-dex) +!!! warning "Okta groups for RBAC" + If you want `groups` scope returned from Okta, you will need to enable [API Access Management with Okta](https://developer.okta.com/docs/concepts/api-access-management/). This addon is free, and automatically enabled, on Okta developer edition. However, it's an optional add-on for production environments, with an additional associated cost. - Next you may need the API Access Management feature, which the support team can enable for your OktaPreview domain for testing, to enable "custom scopes" and a separate endpoint to use instead of the "public" `/oauth2/v1/authorize` API Access Management endpoint. This might be a paid feature if you want OIDC unfortunately. The free alternative I found was SAML. + You may alternately add a "groups" scope and claim to the default authorization server, and then filter the claim in the Okta application configuration. It's not clear if this requires the Authorization Server add-on. + + If this is not an option for you, use the [SAML (with Dex)](#saml-with-dex) option above instead. + +!!! note + These instructions and screenshots are of Okta version 2023.05.2 E. You can find the current version in the Okta website footer. + +First, create the OIDC integration: + +1. On the `Okta Admin` page, navigate to the Okta Applications at `Applications > Applications.` +1. Choose `Create App Integration`, and choose `OIDC`, and then `Web Application` in the resulting dialogues. + ![Okta OIDC app dialogue](../../assets/okta-create-oidc-app.png) +1. Update the following: + 1. `App Integration name` and `Logo` - set these to suit your needs; they'll be displayed in the Okta catalogue. + 1. `Sign-in redirect URLs`: Add `https://argocd.example.com/auth/callback`; replacing `argocd.example.com` with your ArgoCD web interface URL. Also add `http://localhost:8085/auth/callback` if you would like to be able to login with the CLI. + 1. `Sign-out redirect URIs`: Add `https://argocd.example.com`; substituting the correct domain name as above. + 1. Either assign groups, or choose to skip this step for now. + 1. Leave the rest of the options as-is, and save the integration. + ![Okta app settings](../../assets/okta-app.png) +1. Copy the `Client ID` and the `Client Secret` from the newly created app; you will need these later. + +Next, create a custom Authorization server: 1. On the `Okta Admin` page, navigate to the Okta API Management at `Security > API`. - ![Okta API Management](../../assets/api-management.png) -1. Choose your `default` authorization server. -1. Click `Scopes > Add Scope` - 1. Add a scope called `groups`. - ![Groups Scope](../../assets/groups-scope.png) -1. Click `Claims > Add Claim.` - 1. Add a claim called `groups` - 1. Choose the matching options you need, one example is: - * e.g. to match groups starting with `argocd-` you'd return an `ID Token` using your scope name from step 3 (e.g. `groups`) where the groups name `matches` the `regex` `argocd-.*` - ![Groups Claim](../../assets/groups-claim.png) -1. Edit the `argocd-cm` and configure the `data.oidc.config` section: +1. Click `Add Authorization Server`, and assign it a name and a description. The `Audience` should match your ArgoCD URL - `https://argocd.example.com` +1. Click `Scopes > Add Scope`: + 1. Add a scope called `groups`. Leave the rest of the options as default. + ![Groups Scope](../../assets/okta-groups-scope.png) +1. Click `Claims > Add Claim`: + 1. Add a claim called `groups`. + 1. Adjust the `Include in token type` to `ID Token`, `Always`. + 1. Adjust the `Value type` to `Groups`. + 1. Add a filter that will match the Okta groups you want passed on to ArgoCD; for example `Regex: argocd-.*`. + 1. Set `Include in` to `groups` (the scope you created above). + ![Groups Claim](../../assets/okta-groups-claim.png) +1. Click on `Access Policies` > `Add Policy.` This policy will restrict how this authorization server is used. + 1. Add a name and description. + 1. Assign the policy to the client (application integration) you created above. The field should auto-complete as you type. + 1. Create the policy. + ![Auth Policy](../../assets/okta-auth-policy.png) +1. Add a rule to the policy: + 1. Add a name; `default` is a reasonable name for this rule. + 1. Fine-tune the settings to suit your organization's security posture. Some ideas: + 1. uncheck all the grant types except the Authorization Code. + 1. Adjust the token lifetime to govern how long a session can last. + 1. Restrict refresh token lifetime, or completely disable it. + ![Default rule](../../assets/okta-auth-rule.png) +1. Finally, click `Back to Authorization Servers`, and copy the `Issuer URI`. You will need this later. + +If you haven't yet created Okta groups, and assigned them to the application integration, you should do that now: + +1. Go to `Directory > Groups` +1. For each group you wish to add: + 1. Click `Add Group`, and choose a meaningful name. It should match the regex or pattern you added to your custom `group` claim. + 1. Click on the group (refresh the page if the new group didn't show up in the list). + 1. Assign Okta users to the group. + 1. Click on `Applications` and assign the OIDC application integration you created to this group. + 1. Repeat as needed. + +Finally, configure ArgoCD itself. Edit the `argocd-cm` configmap: ```yaml +url: https://argocd.example.com oidc.config: | name: Okta - issuer: https://yourorganization.oktapreview.com - clientID: 0oaltaqg3oAIf2NOa0h3 - clientSecret: ZXF_CfUc-rtwNfzFecGquzdeJ_MxM4sGc8pDT2Tg6t + # this is the authorization server URI + issuer: https://example.okta.com/oauth2/aus9abcdefgABCDEFGd7 + clientID: 0oa9abcdefgh123AB5d7 + clientSecret: ABCDEFG1234567890abcdefg requestedScopes: ["openid", "profile", "email", "groups"] requestedIDTokenClaims: {"groups": {"essential": true}} ``` - - +You may want to store the `clientSecret` in a Kubernetes secret; see [how to deal with SSO secrets](./index.md/#sensitive-data-and-sso-client-secrets ) for more details. diff --git a/docs/operator-manual/webhook.md b/docs/operator-manual/webhook.md index 1d5ad5ec79c96..eb15c4cb02369 100644 --- a/docs/operator-manual/webhook.md +++ b/docs/operator-manual/webhook.md @@ -41,7 +41,7 @@ the contents of webhook payloads are considered untrusted, and will only result application (a process which already occurs at three-minute intervals). If Argo CD is publicly accessible, then configuring a webhook secret is recommended to prevent a DDoS attack. -In the `argocd-secret` kubernetes secret, configure one of the following keys with the Git +In the `argocd-secret` Kubernetes secret, configure one of the following keys with the Git provider's webhook secret configured in step 1. | Provider | K8s Secret Key | @@ -54,13 +54,13 @@ provider's webhook secret configured in step 1. | Azure DevOps | `webhook.azuredevops.username` | | | `webhook.azuredevops.password` | -Edit the Argo CD kubernetes secret: +Edit the Argo CD Kubernetes secret: ```bash kubectl edit secret argocd-secret -n argocd ``` -TIP: for ease of entering secrets, kubernetes supports inputting secrets in the `stringData` field, +TIP: for ease of entering secrets, Kubernetes supports inputting secrets in the `stringData` field, which saves you the trouble of base64 encoding the values and copying it to the `data` field. Simply copy the shared webhook secret created in step 1, to the corresponding GitHub/GitLab/BitBucket key under the `stringData` field: diff --git a/docs/proposals/config-management-plugin-v2.md b/docs/proposals/config-management-plugin-v2.md index d5d68cc0af942..549ed3967ef49 100644 --- a/docs/proposals/config-management-plugin-v2.md +++ b/docs/proposals/config-management-plugin-v2.md @@ -291,7 +291,7 @@ There aren't any major drawbacks to this proposal. Also, the advantages supersed However following are few minor drawbacks, * With addition of plugin.yaml, there will be more yamls to manage -* Operators need to be aware of the modified kubernetes manifests in the subsequent version. +* Operators need to be aware of the modified Kubernetes manifests in the subsequent version. * The format of the CMP manifest is a new "contract" that would need to adhere the usual Argo CD compatibility promises in future. diff --git a/docs/proposals/decouple-application-sync-user-using-impersonation.md b/docs/proposals/decouple-application-sync-user-using-impersonation.md new file mode 100644 index 0000000000000..e7e459a7059c0 --- /dev/null +++ b/docs/proposals/decouple-application-sync-user-using-impersonation.md @@ -0,0 +1,592 @@ +--- +title: Decouple Control plane and Application Sync privileges +authors: + - "@anandf" +sponsors: + - Red Hat +reviewers: + - "@blakepettersson" + - "@crenshaw-dev" + - "@jannfis" +approvers: + - "@alexmt" + - "@crenshaw-dev" + - "@jannfis" + +creation-date: 2023-06-23 +last-updated: 2024-02-06 +--- + +# Decouple Application Sync using Impersonation + +Application syncs in Argo CD have the same privileges as the Argo CD control plane. As a consequence, in a multi-tenant setup, the Argo CD control plane privileges needs to match the tenant that needs the highest privileges. As an example, if an Argo CD instance has 10 Applications and only one of them requires admin privileges, then the Argo CD control plane must have admin privileges in order to be able to sync that one Application. Argo CD provides a multi-tenancy model to restrict what each Application can do using `AppProjects`, even though the control plane has higher privileges, however that creates a large attack surface since if Argo CD is compromised, attackers would have cluster-admin access to the cluster. + +The goal of this proposal is to perform the Application sync as a different user using impersonation and use the service account provided in the cluster config purely for control plane operations. + +### What is Impersonation + +Impersonation is a feature in Kubernetes and enabled in the `kubectl` CLI client, using which, a user can act as another user through impersonation headers. For example, an admin could use this feature to debug an authorization policy by temporarily impersonating another user and seeing if a request was denied. + +Impersonation requests first authenticate as the requesting user, then switch to the impersonated user info. + +``` +kubectl --as ... +kubectl --as --as-group ... +``` + +## Open Questions [optional] + +- Should the restrictions imposed as part of the `AppProjects` be honored if the impersonation feature is enabled ? +>Yes, other restrictions implemented by `AppProject` related to whitelisting/blacklisting resources must continue to be honoured. +- Can an Application refer to a service account with elevated privileges like say `cluster-admin`, `admin`, and service accounts used for running the ArgoCD controllers itself ? +>Yes, this is possible as long as the ArgoCD admin user explicitly allows it through the `AppProject` configuration. +- Among the destinations configured in the `AppProject`, if there are multiple matches for a given destination, which destination option should be used ? +>If there are more than one matching destination, either with a glob pattern match or an exact match, then we use the first valid match to determine the service account to be used for the sync operation. +- Can the kubernetes audit trail events capture the impersonation. +>Yes, kubernetes audit trail events capture both the actual user and the impersonating user details and hence its possible to track who executed the commands and as which user permissions using the audit trails. +- Would the Sync hooks be using the impersonation service account. +>Yes, if the impersonation feature is enabled and customers use Sync hooks, then impersonation service account would be used for executing the hook jobs as well. +- If application resources have hardcoded namespaces in the git repository, would different service accounts be used for each resource during the sync operation ? +>The service account to be used for impersonation is determined on a per Application level rather than on per resource level. The value specified in `Application.spec.destination.namespace` would be used to determine the service account to be used for the sync operation of all resources present in the `Application`. + +## Summary + +In a multi team/multi tenant environment, an application team is typically granted access to a namespace to self-manage their Applications in a declarative way. Current implementation of ArgoCD requires the ArgoCD Administrator to create an `AppProject` with access settings configured to replicate the RBAC resources that are configured for each team. This approach requires duplication of effort and also requires syncing the access between both to maintain the security posture. It would be desirable for users to use the existing RBAC rules without having to revert to Argo CD API to create and manage these Applications. One namespace per team, or even one namespace per application is what we are looking to address as part of this proposal. + +## Motivation + +This proposal would allow ArgoCD administrators to manage the cluster permissions using kubernetes native RBAC implementation rather than using complex configurations in `AppProjects` to restrict access to individual applications. By decoupling the privileges required for application sync from the privileges required for ArgoCD control plane operations, the security requirement of providing least privileges can be achieved there by improving the security posture of ArgoCD. For implementing multi team/tenant use cases, this decoupling would be greatly beneficial. + +### Assumptions + +- Namespaces are pre-populated with one or more `ServiceAccounts` that define the permissions for each `AppProject`. +- Many users prefer to control access to kubernetes resources through kubernetes RBAC constructs instead of Argo specific constructs. +- Each tenant is generally given access to a specific namespace along with a service account, role or cluster role and role binding to control access to that namespace. +- `Applications` created by a tenant manage namespaced resources. +- An `AppProject` can either be mapped to a single tenant or multiple related tenants and the respective destinations that needs to be managed via the `AppProject`, needs to be configured. + + +### Goals +- Applications may only impersonate ServiceAccounts that live in the same namespace as the destination namespace configured in the application.If the service account is created in a different namespace, then the user can provide the service account name in the format `:` . ServiceAccount to be used for syncing each application is determined by the target destination configured in the `AppProject` associated with the `Application`. +- If impersonation feature is enabled, and no service account name is provided in the associated `AppProject`, then the default service account of the destination namespace of the `Application` should be used. +- Access restrictions implemented through properties in AppProject (if done) must have the existing behavior. From a security standpoint, any restrictions that were available before switching to a service account based approach should continue to exist even when the impersonation feature is enabled. + +### Non-Goals + +None + +## Proposal + +As part of this proposal, it would be possible for an ArgoCD Admin to specify a service account name in `AppProjects` CR for a single or a group of destinations. A destination is uniquely identified by a target cluster and a namespace combined. + +When applications gets synced, based on its destination (target cluster and namespace combination), the `defaultServiceAccount` configured in the `AppProject` will be selected and used for impersonation when executing the kubectl commands for the sync operation. + +We would be introducing a new element `destinationServiceAccounts` in `AppProject.spec`. This element is used for the sole purpose of specifying the impersonation configuration. The `defaultServiceAccount` configured for the `AppProject` would be used for the sync operation for a particular destination cluster and namespace. If impersonation feature is enabled and no specific service account is provided in the `AppProject` CR, then the `default` service account in the destination namespace would be used for impersonation. + +``` +apiVersion: argoproj.io/v1alpha1 +kind: AppProject +metadata: + name: my-project + namespace: argocd + finalizers: + - resources-finalizer.argocd.argoproj.io +spec: + description: Example Project + # Allow manifests to deploy from any Git repos + sourceRepos: + - '*' + destinations: + - * + destinationServiceAccounts: + - server: https://kubernetes.default.svc + namespace: guestbook + defaultServiceAccount: guestbook-deployer + - server: https://kubernetes.default.svc + namespace: guestbook-dev + defaultServiceAccount: guestbook-dev-deployer + - server: https://kubernetes.default.svc + namespace: guestbook-stage + defaultServiceAccount: guestbook-stage-deployer +``` + +### Structure of DestinationServiceAccount: +|Parameter| Type | Required/Optional| Description| +| ------ | ------ | ------- | -------- | +| server | string | Required | Server specifies the URL of the target cluster's Kubernetes control plane API. Glob patterns are supported. | +| namespace | string | Required | Namespace specifies the target namespace for the application's resources. Glob patterns are supported. | +| defaultServiceAccount | string | Required| DefaultServiceAccount specifies the service account to be impersonated when performing the `Application` sync operation.| + +**Note:** Only server URL for the target cluster is supported and target cluster name is not supported. + +### Future enhancements + +In a future release, we plan to support overriding of service accounts at the application level. In that case, we would be adding an element called `allowedServiceAccounts` to `AppProject.spec.destinationServiceAccounts[*]` + +### Use cases + +#### Use case 1: + +As a user, I would like to use kubernetes security constructs to restrict user access for application sync +So that, I can provide granular permissions based on the principle of least privilege required for syncing an application. + +#### Use case 2: + +As a user, I would like to configure a common service account for all applications associated to an AppProject +So that, I can use a generic convention of naming service accounts and avoid associating the service account per application. + +### Design considerations + +- Extending the `destinations` field under `AppProjects` was an option that was considered. But since the intent of it was to restrict the destinations that an associated `Application` can use, it was not used. Also the destination fields allowed negation operator (`!`) which would complicate the service account matching logic. The decision to create a new struct under `AppProject.Spec` for specifying the service account for each destination was considered a better alternative. + +- The field name `defaultServiceAccount` was chosen instead of `serviceAccount` as we wanted to support overriding of the service account at an `Application` at a later point in time and wanted to reserve the name `serviceAccount` for future extension. + +- Not supporting all impersonation options at the moment to keep the initial design to a minimum. Based on the need and feedback, support to impersonate users or groups can be added in future. + +### Implementation Details/Notes/Constraints + +#### Component : GitOps Engine + +- Fix GitOps Engine code to honor Impersonate configuration set in the Application sync context for all kubectl commands that are being executed. + +#### Component: ArgoCD API + +- Create a new struct type `DestinationServiceAccount` having fields `namespace`, `server` and `defaultServiceAccount` +- Create a new field `DestinationServiceAccounts` under a `AppProject.Spec` that takes in a list of `DestinationServiceAccount` objects. +- Add Documentation for newly introduced struct and its fields for `DestinationServiceAccount` and `DestinationServiceAccounts` under `AppProject.Spec` + +#### Component: ArgoCD Application Controller + +- Provide a configuration in `argocd-cm` which can be modified to enable the Impersonation feature. Set `applicationcontroller.enable.impersonation: true` in the Argo CD ConfigMap. Default value of `applicationcontroller.enable.impersonation` would be `false` and user has to explicitly override it to use this feature. +- Provide an option to override the Impersonation feature using environment variables. +Set `ARGOCD_APPLICATION_CONTROLLER_ENABLE_IMPERSONATION=true` in the Application controller environment variables. Default value of the environment variable must be `false` and user has to explicitly set it to `true` to use this feature. +- Provide an option to enable this feature using a command line flag `--enable-impersonation`. This new argument option needs to be added to the Application controller args. +- Fix Application Controller `sync.go` to set the Impersonate configuration from the AppProject CR to the `SyncContext` Object (rawConfig and restConfig field, need to understand which config is used for the actual sync and if both configs need to be impersonated.) + +#### Component: ArgoCD UI + +- Provide option to create `DestinationServiceAccount` with fields `namespace`, `server` and `defaultServiceAccount`. +- Provide option to add multiple `DestinationServiceAccounts` to an `AppProject` created/updated via the web console. +- Update the User Guide documentation on how to use these newly added fields from the web console. + +#### Component: ArgoCD CLI + +- Provide option to create `DestinationServiceAccount` with fields `namespace`, `server` and `defaultServiceAccount`. +- Provide option to add multiple `DestinationServiceAccounts` to an `AppProject` created/updated via the web console. +- Update the User Guide and other documentation where the CLI option usages are explained. + +#### Component: Documentation + +- Add note that this is a Beta feature in the documentation. +- Add a separate section for this feature under user-guide section. +- Update the ArgoCD CLI command reference documentation. +- Update the ArgoCD UI command reference documentation. + +### Detailed examples + +#### Example 1: Service account for application sync specified at the AppProject level for all namespaces + +In this specific scenario, service account name `generic-deployer` will get used for the application sync as the namespace `guestbook` matches the glob pattern `*`. + +- Install ArgoCD in the `argocd` namespace. +``` +kubectl apply -f https://raw.githubusercontent.com/argoproj/argo-cd/master/manifests/install.yaml -n argocd +``` + +- Enable the impersonation feature in ArgoCD. +``` +kubectl set env statefulset/argocd-application-controller ARGOCD_APPLICATION_CONTROLLER_ENABLE_IMPERSONATION=true +``` + +- Create a namespace called `guestbook` and a service account called `guestbook-deployer`. +``` +kubectl create namespace guestbook +kubectl create serviceaccount guestbook-deployer +``` + +- Create Role and RoleBindings and configure RBAC access for creating `Service` and `Deployment` objects in namespace `guestbook` for service account `guestbook-deployer`. +``` +kubectl create role guestbook-deployer-role --verb get,list,update,delete --resource pods,deployment,service +kubectl create rolebinding guestbook-deployer-rb --serviceaccount guestbook-deployer --role guestbook-deployer-role +``` + +- Create the `Application` in the `argocd` namespace and the required `AppProject` as below +``` +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: guestbook + namespace: argocd +spec: + project: my-project + source: + repoURL: https://github.com/argoproj/argocd-example-apps.git + targetRevision: HEAD + path: guestbook + destination: + server: https://kubernetes.default.svc + namespace: guestbook +--- +apiVersion: argoproj.io/v1alpha1 +kind: AppProject +metadata: + name: my-project + namespace: argocd + finalizers: + - resources-finalizer.argocd.argoproj.io +spec: + description: Example Project + # Allow manifests to deploy from any Git repos + sourceRepos: + - '*' + destinations: + - namespace: * + server: https://kubernetes.default.svc + destinationServiceAccounts: + - namespace: * + server: https://kubernetes.default.svc + defaultServiceAccount: generic-deployer +``` + +#### Example 2: Service account for application sync specified at the AppProject level for specific namespaces + +In this specific scenario, service account name `guestbook-deployer` will get used for the application sync as the namespace `guestbook` matches the target namespace `guestbook`. + +- Install ArgoCD in the `argocd` namespace. +``` +kubectl apply -f https://raw.githubusercontent.com/argoproj/argo-cd/master/manifests/install.yaml -n argocd +``` + +- Enable the impersonation feature in ArgoCD. +``` +kubectl set env statefulset/argocd-application-controller ARGOCD_APPLICATION_CONTROLLER_ENABLE_IMPERSONATION=true +``` + +- Create a namespace called `guestbook` and a service account called `guestbook-deployer`. +``` +kubectl create namespace guestbook +kubectl create serviceaccount guestbook-deployer +``` +- Create Role and RoleBindings and configure RBAC access for creating `Service` and `Deployment` objects in namespace `guestbook` for service account `guestbook-deployer`. +``` +kubectl create role guestbook-deployer-role --verb get,list,update,delete --resource pods,deployment,service +kubectl create rolebinding guestbook-deployer-rb --serviceaccount guestbook-deployer --role guestbook-deployer-role +``` + +In this specific scenario, service account name `guestbook-deployer` will get used as it matches to the specific namespace `guestbook`. +``` +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: guestbook + namespace: argocd +spec: + project: my-project + source: + repoURL: https://github.com/argoproj/argocd-example-apps.git + targetRevision: HEAD + path: guestbook + destination: + server: https://kubernetes.default.svc + namespace: guestbook +--- +apiVersion: argoproj.io/v1alpha1 +kind: AppProject +metadata: + name: my-project + namespace: argocd + finalizers: + - resources-finalizer.argocd.argoproj.io +spec: + description: Example Project + # Allow manifests to deploy from any Git repos + sourceRepos: + - '*' + destinations: + - namespace: guestbook + server: https://kubernetes.default.svc + - namespace: guestbook-ui + server: https://kubernetes.default.svc + destinationServiceAccounts: + - namespace: guestbook + server: https://kubernetes.default.svc + defaultServiceAccount: guestbook-deployer + - namespace: guestbook-ui + server: https://kubernetes.default.svc + defaultServiceAccount: guestbook-ui-deployer +``` + +#### Example 3: Remote destination with cluster-admin access and using different service account for the sync operation + +**Note**: In this example, we are relying on the default service account `argocd-manager` with `cluster-admin` privileges which gets created when adding a remote cluster destination using the ArgoCD CLI. + +- Install ArgoCD in the `argocd` namespace. +``` +kubectl apply -f https://raw.githubusercontent.com/argoproj/argo-cd/master/manifests/install.yaml -n argocd +``` + +- Enable the impersonation feature in ArgoCD. +``` +kubectl set env statefulset/argocd-application-controller ARGOCD_APPLICATION_CONTROLLER_ENABLE_IMPERSONATION=true +``` + +- Add the remote cluster as a destination to argocd +``` +argocd cluster add remote-cluster --name remote-cluster +``` +**Note:** The above command would create a service account named `argocd-manager` in `kube-system` namespace and `ClusterRole` named `argocd-manager-role` with full cluster admin access and a `ClusterRoleBinding` named `argocd-manager-role-binding` mapping the `argocd-manager-role` to the service account `remote-cluster` + +- In the remote cluster, create a namespace called `guestbook` and a service account called `guestbook-deployer`. +``` +kubectl ctx remote-cluster +kubectl create namespace guestbook +kubectl create serviceaccount guestbook-deployer +``` + +- In the remote cluster, create `Role` and `RoleBindings` and configure RBAC access for creating `Service` and `Deployment` objects in namespace `guestbook` for service account `guestbook-deployer`. + +``` +kubectl ctx remote-cluster +kubectl create role guestbook-deployer-role --verb get,list,update,delete --resource pods,deployment,service +kubectl create rolebinding guestbook-deployer-rb --serviceaccount guestbook-deployer --role guestbook-deployer-role +``` + +- Create the `Application` and `AppProject` for the `guestbook` application. +``` +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: guestbook + namespace: argocd +spec: + project: my-project + source: + repoURL: https://github.com/argoproj/argocd-example-apps.git + targetRevision: HEAD + path: guestbook + destination: + server: https://kubernetes.default.svc + namespace: guestbook +--- +apiVersion: argoproj.io/v1alpha1 +kind: AppProject +metadata: + name: my-project + namespace: argocd + finalizers: + - resources-finalizer.argocd.argoproj.io +spec: + description: Example Project + # Allow manifests to deploy from any Git repos + sourceRepos: + - '*' + destinations: + - namespace: guestbook + server: https://kubernetes.default.svc + serviceAccountName: guestbook-deployer + destinationServiceAccounts: + - namespace: guestbook + server: https://kubernetes.default.svc + defaultServiceAccount: guestbook-deployer +``` + +#### Example 4: Remote destination with a custom service account for the sync operation + +**Note**: In this example, we are relying on a non default service account `guestbook` created in the target cluster and namespace for the sync operation. This use case is for handling scenarios where the remote cluster is managed by a different administrator and providing a service account with `cluster-admin` level access is not feasible. + +- Install ArgoCD in the `argocd` namespace. +``` +kubectl apply -f https://raw.githubusercontent.com/argoproj/argo-cd/master/manifests/install.yaml -n argocd +``` + +- Enable the impersonation feature in ArgoCD. +``` +kubectl set env statefulset/argocd-application-controller ARGOCD_APPLICATION_CONTROLLER_ENABLE_IMPERSONATION=true +``` + +- In the remote cluster, create a service account called `argocd-admin` +``` +kubectl ctx remote-cluster +kubectl create serviceaccount argocd-admin +kubectl create clusterrole argocd-admin-role --verb=impersonate --resource="users,groups,serviceaccounts" +kubectl create clusterrole argocd-admin-role-access-review --verb=create --resource="selfsubjectaccessreviews" +kubectl create clusterrolebinding argocd-admin-role-binding --serviceaccount argocd-admin --clusterrole argocd-admin-role +kubectl create clusterrolebinding argocd-admin-access-review-role-binding --serviceaccount argocd-admin --clusterrole argocd-admin-role +``` + +- In the remote cluster, create a namespace called `guestbook` and a service account called `guestbook-deployer`. +``` +kubectl ctx remote-cluster +kubectl create namespace guestbook +kubectl create serviceaccount guestbook-deployer +``` + +- In the remote cluster, create `Role` and `RoleBindings` and configure RBAC access for creating `Service` and `Deployment` objects in namespace `guestbook` for service account `guestbook-deployer`. +``` +kubectl create role guestbook-deployer-role --verb get,list,update,delete --resource pods,deployment,service +kubectl create rolebinding guestbook-deployer-rb --serviceaccount guestbook-deployer --role guestbook-deployer-role +``` + +In this specific scenario, service account name `guestbook-deployer` will get used as it matches to the specific namespace `guestbook`. +``` +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: guestbook + namespace: argocd +spec: + project: my-project + source: + repoURL: https://github.com/argoproj/argocd-example-apps.git + targetRevision: HEAD + path: guestbook + destination: + server: https://kubernetes.default.svc + namespace: guestbook +--- +apiVersion: argoproj.io/v1alpha1 +kind: AppProject +metadata: + name: my-project + namespace: argocd + finalizers: + - resources-finalizer.argocd.argoproj.io +spec: + description: Example Project + # Allow manifests to deploy from any Git repos + sourceRepos: + - '*' + destinations: + - namespace: guestbook + server: https://kubernetes.default.svc + - namespace: guestbook-ui + server: https://kubernetes.default.svc + destinationServiceAccounts: + - namespace: guestbook + server: https://kubernetes.default.svc + defaultServiceAccount: guestbook-deployer + - namespace: guestbook-ui + server: https://kubernetes.default.svc + defaultServiceAccount: guestbook-ui-deployer +``` + +### Special cases + +#### Specifying service account in a different namespace + +By default, the service account would be looked up in the Application's destination namespace configured through `Application.Spec.Destination.Namespace` field. If the service account is in a different namespace, then users can provide the namespace of the service account explicitly in the format : +eg: +``` + ... + destinationServiceAccounts: + - server: https://kubernetes.default.svc + namespace: * + defaultServiceAccount: mynamespace:guestbook-deployer + ... +``` + +#### Multiple matches of destinations + +If there are multiple matches for a given destination, the first valid match in the list of `destinationServiceAccounts` would be used. + +eg: +Lets assume that the `AppProject` has the below `destinationServiceAccounts` configured. +``` + ... + destinationServiceAccounts: + - server: https://kubernetes.default.svc + namespace: guestbook-prod + defaultServiceAccount: guestbook-prod-deployer + - server: https://kubernetes.default.svc + namespace: guestbook-* + defaultServiceAccount: guestbook-generic-deployer + - server: https://kubernetes.default.svc + namespace: * + defaultServiceAccount: generic-deployer + ... +``` +- If the application destination namespace is `myns`, then the service account `generic-deployer` would be used as the first valid match is the glob pattern `*` and there are no other valid matches in the list. +- If the application destination namespace is `guestbook-dev` or `guestbook-stage`, then both glob patterns `*` and `guestbook-*` are valid matches, however `guestbook-*` pattern appears first and hence, the service account `guestbook-generic-deployer` would be used for the impersonation. +- If the application destination namespace is `guestbook-prod`, then there are three candidates, however the first valid match in the list is the one with service account `guestbook-prod-deployer` and that would be used for the impersonation. + +#### Application resources referring to multiple namespaces +If application resources have hardcoded namespaces in the git repository, would different service accounts be used for each resource during the sync operation ? + +The service account to be used for impersonation is determined on a per Application level rather than on per resource level. The value specified in `Application.spec.destination.namespace` would be used to determine the service account to be used for the sync operation of all resources present in the `Application`. + +### Security Considerations + +* How does this proposal impact the security aspects of Argo CD workloads ? +* Are there any unresolved follow-ups that need to be done to make the enhancement more robust ? + +### Risks and Mitigations + +#### Privilege Escalation + +There could be an issue of privilege escalation, if we allow users to impersonate without restrictions. This is mitigated by only allowing admin users to configure service account used for the sync operation at the `AppProject` level. + +Instead of allowing users to impersonate all possible users, administrators can restrict the users a particular service account can impersonate using the `resourceNames` field in the RBAC spec. + + +### Upgrade / Downgrade Strategy + +If applicable, how will the component be upgraded and downgraded? Make sure this is in the test +plan. + +Consider the following in developing an upgrade/downgrade strategy for this enhancement: + +- What changes (in invocations, configurations, API use, etc.) is an existing cluster required to + make on upgrade in order to keep previous behavior? +- What changes (in invocations, configurations, API use, etc.) is an existing cluster required to + make on upgrade in order to make use of the enhancement? + +- This feature would be implemented on an `opt-in` based on a feature flag and disabled by default. +- The new struct being added to `AppProject.Spec` would be introduced as an optional field and would be enabled only if the feature is enabled explicitly by a feature flag. If new property is used in the CR, but the feature flag is not enabled, then a warning message would be displayed during reconciliation of such CRs. + + +## Drawbacks + +- When using this feature, there is an overhead in creating namespaces, service accounts and the required RBAC policies and mapping the service accounts with the corresponding `AppProject` configuration. + +## Alternatives + +### Option 1 +Allow all options available in the `ImpersonationConfig` available to the user through the `AppProject` CRs. + +``` +apiVersion: argoproj.io/v1alpha1 +kind: AppProject +metadata: + name: my-project + namespace: argocd +spec: + description: Example Project + # Allow manifests to deploy from any Git repos + sourceRepos: + - '*' + destinations: + - namespace: * + server: https://kubernetes.default.svc + namespace: guestbook + impersonate: + user: system:serviceaccount:dev_ns:admin + uid: 1234 + groups: + - admin + - view + - edit +``` + +### Related issue + +https://github.com/argoproj/argo-cd/issues/7689 + + +### Related links + +https://kubernetes.io/docs/reference/access-authn-authz/authentication/#user-impersonation + +### Prior art + +https://github.com/argoproj/argo-cd/pull/3377 +https://github.com/argoproj/argo-cd/pull/7651 \ No newline at end of file diff --git a/docs/proposals/feature-bounties/hide-annotations.md b/docs/proposals/feature-bounties/hide-annotations.md new file mode 100644 index 0000000000000..47c9b943b8f71 --- /dev/null +++ b/docs/proposals/feature-bounties/hide-annotations.md @@ -0,0 +1,23 @@ +# Proposal: Allow Hiding Certain Annotations in the Argo CD Web UI + +Based on this issue: https://github.com/argoproj/argo-cd/issues/15693 + +Award amount: $100 + +## Solution + +!!! note + This is the proposed solution. The accepted PR may differ from this proposal. + +Add a new config item in argocd-cm: + +```yaml +hide.secret.annotations: | +- openshift.io/token-secret.value +``` + +This will hide the `openshift.io/token-secret.value` annotation from the UI. Behind the scenes, it would likely work the +same way as the `last-applied-configuration` annotation hiding works: https://github.com/argoproj/gitops-engine/blob/b0fffe419a0f0a40f9f2c0b6346b752ed6537385/pkg/diff/diff.go#L897 + +I considered whether we'd want to support hiding things besides annotations and in resources besides secrets, but +having reviewed existing issues, I think this narrow feature is sufficient. diff --git a/docs/proposals/native-ocp-support.md b/docs/proposals/native-oci-support.md similarity index 99% rename from docs/proposals/native-ocp-support.md rename to docs/proposals/native-oci-support.md index 64918fde8904e..7ec0053729c2e 100644 --- a/docs/proposals/native-ocp-support.md +++ b/docs/proposals/native-oci-support.md @@ -126,10 +126,10 @@ Consider the following in developing an upgrade/downgrade strategy for this enha ## Drawbacks -* Sourcing content from an OCI registry may be perceived to be against GitOps principles as content is not sourced from a Git repository. This concern could be mitigated by attaching additional details related to the content (such as original Git source [URL, revision]). Though it should be noted that the GitOps principles only require a source of truth to be visioned and immutable which OCI registires support. +* Sourcing content from an OCI registry may be perceived to be against GitOps principles as content is not sourced from a Git repository. This concern could be mitigated by attaching additional details related to the content (such as original Git source [URL, revision]). Though it should be noted that the GitOps principles only require a source of truth to be visioned and immutable which OCI registries support. ## Alternatives ### Config Management Plugin -Content stored within OCI artifacts could be sourced using a Config Management Plugin which would not require changes to the core capabilities provided by Argo CD. However, this would be hacky and not represent itself within the Argo CD UI. \ No newline at end of file +Content stored within OCI artifacts could be sourced using a Config Management Plugin which would not require changes to the core capabilities provided by Argo CD. However, this would be hacky and not represent itself within the Argo CD UI. diff --git a/docs/proposals/parameterized-config-management-plugins.md b/docs/proposals/parameterized-config-management-plugins.md index fa3061b2c3686..749f4efe63687 100644 --- a/docs/proposals/parameterized-config-management-plugins.md +++ b/docs/proposals/parameterized-config-management-plugins.md @@ -256,7 +256,7 @@ spec: array: [values.yaml] - name: helm-parameters map: - image.repository: my.company.com/gcr-proxy/heptio-images/ks-guestbook-demo + image.repository: my.example.com/gcr-proxy/heptio-images/ks-guestbook-demo image.tag: "0.1" ``` @@ -283,7 +283,7 @@ That command, when run by a CMP with the above Application manifest, will print { "name": "helm-parameters", "map": { - "image.repository": "my.company.com/gcr-proxy/heptio-images/ks-guestbook-demo", + "image.repository": "my.example.com/gcr-proxy/heptio-images/ks-guestbook-demo", "image.tag": "0.1" } } @@ -398,7 +398,7 @@ like this: "title": "Helm Parameters", "tooltip": "Parameters to override when generating manifests with Helm", "map": { - "image.repository": "my.company.com/gcr-proxy/heptio-images/ks-guestbook-demo", + "image.repository": "my.example.com/gcr-proxy/heptio-images/ks-guestbook-demo", "image.tag": "0.1" } } @@ -423,7 +423,7 @@ readability.) "title": "Helm Parameters", "tooltip": "Parameters to override when generating manifests with Helm", "map": { - "image.repository": "my.company.com/gcr-proxy/heptio-images/ks-guestbook-demo", + "image.repository": "my.example.com/gcr-proxy/heptio-images/ks-guestbook-demo", "image.tag": "0.1" } } @@ -493,11 +493,11 @@ type ParametersAnnouncement []ParameterAnnouncement - name: images collectionType: map array: # this gets ignored because collectionType is 'map' - - ubuntu:latest=docker.company.com/proxy/ubuntu:latest - - guestbook:v0.1=docker.company.com/proxy/guestbook:v0.1 + - ubuntu:latest=docker.example.com/proxy/ubuntu:latest + - guestbook:v0.1=docker.example.com/proxy/guestbook:v0.1 map: - ubuntu:latest: docker.company.com/proxy/ubuntu:latest - guestbook:v0.1: docker.company.com/proxy/guestbook:v0.1 + ubuntu:latest: docker.example.com/proxy/ubuntu:latest + guestbook:v0.1: docker.example.com/proxy/guestbook:v0.1 ``` 2. **Question**: What do we do if the CMP user sets more than one of `value`/`array`/`map` in the Application spec? @@ -513,11 +513,11 @@ type ParametersAnnouncement []ParameterAnnouncement parameters: - name: images array: # this gets sent to the CMP, but the CMP should ignore it - - ubuntu:latest=docker.company.com/proxy/ubuntu:latest - - guestbook:v0.1=docker.company.com/proxy/guestbook:v0.1 + - ubuntu:latest=docker.example.com/proxy/ubuntu:latest + - guestbook:v0.1=docker.example.com/proxy/guestbook:v0.1 map: - ubuntu:latest: docker.company.com/proxy/ubuntu:latest - guestbook:v0.1: docker.company.com/proxy/guestbook:v0.1 + ubuntu:latest: docker.example.com/proxy/ubuntu:latest + guestbook:v0.1: docker.example.com/proxy/guestbook:v0.1 ``` 3. **Question**: How will the UI know that adding more items to an array or a map is allowed? @@ -528,17 +528,17 @@ type ParametersAnnouncement []ParameterAnnouncement - name: images collectionType: map # users will be allowed to add new items, because this is a map map: - ubuntu:latest: docker.company.com/proxy/ubuntu:latest - guestbook:v0.1: docker.company.com/proxy/guestbook:v0.1 + ubuntu:latest: docker.example.com/proxy/ubuntu:latest + guestbook:v0.1: docker.example.com/proxy/guestbook:v0.1 ``` If the CMP author wants an immutable array or map, they should just break it into individual parameters. ```yaml - name: ubuntu:latest - string: docker.company.com/proxy/ubuntu:latest + string: docker.example.com/proxy/ubuntu:latest - name: guestbook:v0.1 - string: docker.company.com/proxy/guestbook:v0.1 + string: docker.example.com/proxy/guestbook:v0.1 ``` 4. **Question**: What do we do if a CMP announcement doesn't include a `collectionType`? @@ -799,8 +799,8 @@ spec: "title": "Image Overrides", "collectionType": "map", "map": { - "quay.io/argoproj/argocd": "docker.company.com/proxy/argoproj/argocd", - "ubuntu:latest": "docker.company.com/proxy/argoproj/argocd" + "quay.io/argoproj/argocd": "docker.example.com/proxy/argoproj/argocd", + "ubuntu:latest": "docker.example.com/proxy/argoproj/argocd" } } ] diff --git a/docs/proposals/project-repos-and-clusters.md b/docs/proposals/project-repos-and-clusters.md index 1f8258f47a72b..514c389048218 100644 --- a/docs/proposals/project-repos-and-clusters.md +++ b/docs/proposals/project-repos-and-clusters.md @@ -102,7 +102,7 @@ p, proj:my-project:admin, repositories, update, my-project/*, allow This provides extra flexibility so that admin can have stricter rules. e.g.: ``` -p, proj:my-project:admin, repositories, update, my-project/"https://github.my-company.com/*", allow +p, proj:my-project:admin, repositories, update, my-project/"https://github.example.com/*", allow ``` #### UI/CLI Changes diff --git a/docs/snyk/index.md b/docs/snyk/index.md index 0803b8ab69ef0..984cd3460c17d 100644 --- a/docs/snyk/index.md +++ b/docs/snyk/index.md @@ -13,38 +13,51 @@ recent minor releases. | | Critical | High | Medium | Low | |---:|:--------:|:----:|:------:|:---:| -| [go.mod](master/argocd-test.html) | 0 | 0 | 5 | 0 | +| [go.mod](master/argocd-test.html) | 0 | 0 | 6 | 0 | | [ui/yarn.lock](master/argocd-test.html) | 0 | 0 | 0 | 0 | -| [dex:v2.37.0](master/ghcr.io_dexidp_dex_v2.37.0.html) | 1 | 0 | 3 | 0 | -| [haproxy:2.6.14-alpine](master/haproxy_2.6.14-alpine.html) | 0 | 0 | 0 | 0 | -| [argocd:latest](master/quay.io_argoproj_argocd_latest.html) | 0 | 0 | 3 | 17 | -| [redis:7.0.11-alpine](master/redis_7.0.11-alpine.html) | 1 | 0 | 3 | 0 | +| [dex:v2.37.0](master/ghcr.io_dexidp_dex_v2.37.0.html) | 1 | 0 | 3 | 1 | +| [haproxy:2.6.14-alpine](master/haproxy_2.6.14-alpine.html) | 0 | 0 | 0 | 1 | +| [argocd:latest](master/quay.io_argoproj_argocd_latest.html) | 0 | 0 | 4 | 16 | +| [redis:7.0.11-alpine](master/redis_7.0.11-alpine.html) | 1 | 0 | 3 | 1 | | [install.yaml](master/argocd-iac-install.html) | - | - | - | - | | [namespace-install.yaml](master/argocd-iac-namespace-install.html) | - | - | - | - | -### v2.8.4 +### v2.9.0-rc3 | | Critical | High | Medium | Low | |---:|:--------:|:----:|:------:|:---:| -| [go.mod](v2.8.4/argocd-test.html) | 0 | 0 | 5 | 0 | -| [ui/yarn.lock](v2.8.4/argocd-test.html) | 0 | 0 | 0 | 0 | -| [dex:v2.37.0](v2.8.4/ghcr.io_dexidp_dex_v2.37.0.html) | 1 | 0 | 3 | 0 | -| [haproxy:2.6.14-alpine](v2.8.4/haproxy_2.6.14-alpine.html) | 0 | 0 | 0 | 0 | -| [argocd:v2.8.4](v2.8.4/quay.io_argoproj_argocd_v2.8.4.html) | 0 | 0 | 3 | 17 | -| [redis:7.0.11-alpine](v2.8.4/redis_7.0.11-alpine.html) | 1 | 0 | 3 | 0 | -| [install.yaml](v2.8.4/argocd-iac-install.html) | - | - | - | - | -| [namespace-install.yaml](v2.8.4/argocd-iac-namespace-install.html) | - | - | - | - | +| [go.mod](v2.9.0-rc3/argocd-test.html) | 0 | 2 | 6 | 0 | +| [ui/yarn.lock](v2.9.0-rc3/argocd-test.html) | 0 | 0 | 0 | 0 | +| [dex:v2.37.0](v2.9.0-rc3/ghcr.io_dexidp_dex_v2.37.0.html) | 1 | 0 | 3 | 1 | +| [haproxy:2.6.14-alpine](v2.9.0-rc3/haproxy_2.6.14-alpine.html) | 0 | 0 | 0 | 1 | +| [argocd:v2.9.0-rc3](v2.9.0-rc3/quay.io_argoproj_argocd_v2.9.0-rc3.html) | 0 | 0 | 4 | 16 | +| [redis:7.0.11-alpine](v2.9.0-rc3/redis_7.0.11-alpine.html) | 1 | 0 | 3 | 1 | +| [install.yaml](v2.9.0-rc3/argocd-iac-install.html) | - | - | - | - | +| [namespace-install.yaml](v2.9.0-rc3/argocd-iac-namespace-install.html) | - | - | - | - | + +### v2.8.5 + +| | Critical | High | Medium | Low | +|---:|:--------:|:----:|:------:|:---:| +| [go.mod](v2.8.5/argocd-test.html) | 0 | 0 | 6 | 0 | +| [ui/yarn.lock](v2.8.5/argocd-test.html) | 0 | 0 | 0 | 0 | +| [dex:v2.37.0](v2.8.5/ghcr.io_dexidp_dex_v2.37.0.html) | 1 | 0 | 3 | 1 | +| [haproxy:2.6.14-alpine](v2.8.5/haproxy_2.6.14-alpine.html) | 0 | 0 | 0 | 1 | +| [argocd:v2.8.5](v2.8.5/quay.io_argoproj_argocd_v2.8.5.html) | 0 | 0 | 4 | 16 | +| [redis:7.0.11-alpine](v2.8.5/redis_7.0.11-alpine.html) | 1 | 0 | 3 | 1 | +| [install.yaml](v2.8.5/argocd-iac-install.html) | - | - | - | - | +| [namespace-install.yaml](v2.8.5/argocd-iac-namespace-install.html) | - | - | - | - | ### v2.7.14 | | Critical | High | Medium | Low | |---:|:--------:|:----:|:------:|:---:| -| [go.mod](v2.7.14/argocd-test.html) | 0 | 1 | 5 | 0 | +| [go.mod](v2.7.14/argocd-test.html) | 0 | 3 | 5 | 0 | | [ui/yarn.lock](v2.7.14/argocd-test.html) | 0 | 1 | 0 | 0 | -| [dex:v2.37.0](v2.7.14/ghcr.io_dexidp_dex_v2.37.0.html) | 1 | 0 | 3 | 0 | -| [haproxy:2.6.14-alpine](v2.7.14/haproxy_2.6.14-alpine.html) | 0 | 0 | 0 | 0 | -| [argocd:v2.7.14](v2.7.14/quay.io_argoproj_argocd_v2.7.14.html) | 0 | 0 | 3 | 17 | -| [redis:7.0.11-alpine](v2.7.14/redis_7.0.11-alpine.html) | 1 | 0 | 3 | 0 | +| [dex:v2.37.0](v2.7.14/ghcr.io_dexidp_dex_v2.37.0.html) | 1 | 0 | 3 | 1 | +| [haproxy:2.6.14-alpine](v2.7.14/haproxy_2.6.14-alpine.html) | 0 | 0 | 0 | 1 | +| [argocd:v2.7.14](v2.7.14/quay.io_argoproj_argocd_v2.7.14.html) | 0 | 2 | 8 | 20 | +| [redis:7.0.11-alpine](v2.7.14/redis_7.0.11-alpine.html) | 1 | 0 | 3 | 1 | | [install.yaml](v2.7.14/argocd-iac-install.html) | - | - | - | - | | [namespace-install.yaml](v2.7.14/argocd-iac-namespace-install.html) | - | - | - | - | @@ -52,11 +65,11 @@ recent minor releases. | | Critical | High | Medium | Low | |---:|:--------:|:----:|:------:|:---:| -| [go.mod](v2.6.15/argocd-test.html) | 0 | 1 | 5 | 0 | +| [go.mod](v2.6.15/argocd-test.html) | 0 | 3 | 5 | 0 | | [ui/yarn.lock](v2.6.15/argocd-test.html) | 0 | 1 | 0 | 0 | -| [dex:v2.37.0](v2.6.15/ghcr.io_dexidp_dex_v2.37.0.html) | 1 | 0 | 3 | 0 | -| [haproxy:2.6.14-alpine](v2.6.15/haproxy_2.6.14-alpine.html) | 0 | 0 | 0 | 0 | -| [argocd:v2.6.15](v2.6.15/quay.io_argoproj_argocd_v2.6.15.html) | 0 | 0 | 3 | 17 | -| [redis:7.0.11-alpine](v2.6.15/redis_7.0.11-alpine.html) | 1 | 0 | 3 | 0 | +| [dex:v2.37.0](v2.6.15/ghcr.io_dexidp_dex_v2.37.0.html) | 1 | 0 | 3 | 1 | +| [haproxy:2.6.14-alpine](v2.6.15/haproxy_2.6.14-alpine.html) | 0 | 0 | 0 | 1 | +| [argocd:v2.6.15](v2.6.15/quay.io_argoproj_argocd_v2.6.15.html) | 0 | 2 | 8 | 20 | +| [redis:7.0.11-alpine](v2.6.15/redis_7.0.11-alpine.html) | 1 | 0 | 3 | 1 | | [install.yaml](v2.6.15/argocd-iac-install.html) | - | - | - | - | | [namespace-install.yaml](v2.6.15/argocd-iac-namespace-install.html) | - | - | - | - | diff --git a/docs/snyk/master/argocd-iac-install.html b/docs/snyk/master/argocd-iac-install.html index 3fb0b8186141a..28be7b9bb102b 100644 --- a/docs/snyk/master/argocd-iac-install.html +++ b/docs/snyk/master/argocd-iac-install.html @@ -456,7 +456,7 @@

Snyk test report

-

September 17th 2023, 12:18:15 am (UTC+00:00)

+

October 29th 2023, 12:17:42 am (UTC+00:00)

Scanned the following path: @@ -507,7 +507,7 @@

Role with dangerous permissions

  • - Line number: 18488 + Line number: 20316
  • @@ -553,7 +553,7 @@

    Role with dangerous permissions

  • - Line number: 18565 + Line number: 20393
  • @@ -599,7 +599,7 @@

    Role with dangerous permissions

  • - Line number: 18593 + Line number: 20421
  • @@ -645,7 +645,7 @@

    Role with dangerous permissions

  • - Line number: 18641 + Line number: 20469
  • @@ -691,7 +691,7 @@

    Role with dangerous permissions

  • - Line number: 18623 + Line number: 20451
  • @@ -737,7 +737,7 @@

    Role with dangerous permissions

  • - Line number: 18657 + Line number: 20485
  • @@ -789,7 +789,7 @@

    Container could be running with outdated image

  • - Line number: 19790 + Line number: 21642
  • @@ -847,7 +847,7 @@

    Container has no CPU limit

  • - Line number: 19141 + Line number: 20969
  • @@ -905,7 +905,7 @@

    Container has no CPU limit

  • - Line number: 19386 + Line number: 21220
  • @@ -963,7 +963,7 @@

    Container has no CPU limit

  • - Line number: 19352 + Line number: 21186
  • @@ -1021,7 +1021,7 @@

    Container has no CPU limit

  • - Line number: 19446 + Line number: 21280
  • @@ -1079,7 +1079,7 @@

    Container has no CPU limit

  • - Line number: 19533 + Line number: 21373
  • @@ -1137,7 +1137,7 @@

    Container has no CPU limit

  • - Line number: 19790 + Line number: 21642
  • @@ -1195,7 +1195,7 @@

    Container has no CPU limit

  • - Line number: 19590 + Line number: 21430
  • @@ -1253,7 +1253,7 @@

    Container has no CPU limit

  • - Line number: 19875 + Line number: 21727
  • @@ -1311,7 +1311,7 @@

    Container has no CPU limit

  • - Line number: 20191 + Line number: 22043
  • @@ -1363,7 +1363,7 @@

    Container is running with multiple open ports

  • - Line number: 19366 + Line number: 21200
  • @@ -1415,7 +1415,7 @@

    Container is running without liveness probe

  • - Line number: 19141 + Line number: 20969
  • @@ -1460,14 +1460,14 @@

    Container is running without liveness probe

    spec - containers[dex] + initContainers[copyutil] livenessProbe
  • - Line number: 19352 + Line number: 21220
  • @@ -1512,14 +1512,14 @@

    Container is running without liveness probe

    spec - initContainers[copyutil] + containers[dex] livenessProbe
  • - Line number: 19386 + Line number: 21186
  • @@ -1571,7 +1571,7 @@

    Container is running without liveness probe

  • - Line number: 19533 + Line number: 21373
  • @@ -1623,7 +1623,7 @@

    Container is running without liveness probe

  • - Line number: 19790 + Line number: 21642
  • @@ -1681,7 +1681,7 @@

    Container is running without memory limit

  • - Line number: 19141 + Line number: 20969
  • @@ -1739,7 +1739,7 @@

    Container is running without memory limit

  • - Line number: 19352 + Line number: 21186
  • @@ -1797,7 +1797,7 @@

    Container is running without memory limit

  • - Line number: 19386 + Line number: 21220
  • @@ -1855,7 +1855,7 @@

    Container is running without memory limit

  • - Line number: 19446 + Line number: 21280
  • @@ -1913,7 +1913,7 @@

    Container is running without memory limit

  • - Line number: 19533 + Line number: 21373
  • @@ -1971,7 +1971,7 @@

    Container is running without memory limit

  • - Line number: 19790 + Line number: 21642
  • @@ -2029,7 +2029,7 @@

    Container is running without memory limit

  • - Line number: 19590 + Line number: 21430
  • @@ -2087,7 +2087,7 @@

    Container is running without memory limit

  • - Line number: 19875 + Line number: 21727
  • @@ -2145,7 +2145,7 @@

    Container is running without memory limit

  • - Line number: 20191 + Line number: 22043
  • @@ -2201,7 +2201,7 @@

    Container's or Pod's UID could clash with hos
  • - Line number: 19276 + Line number: 21110
  • @@ -2257,7 +2257,7 @@

    Container's or Pod's UID could clash with hos
  • - Line number: 19394 + Line number: 21228
  • @@ -2313,7 +2313,7 @@

    Container's or Pod's UID could clash with hos
  • - Line number: 19369 + Line number: 21203
  • @@ -2369,7 +2369,7 @@

    Container's or Pod's UID could clash with hos
  • - Line number: 19467 + Line number: 21307
  • @@ -2425,7 +2425,7 @@

    Container's or Pod's UID could clash with hos
  • - Line number: 19543 + Line number: 21383
  • @@ -2481,7 +2481,7 @@

    Container's or Pod's UID could clash with hos
  • - Line number: 19797 + Line number: 21649
  • @@ -2537,7 +2537,7 @@

    Container's or Pod's UID could clash with hos
  • - Line number: 19763 + Line number: 21615
  • @@ -2593,7 +2593,7 @@

    Container's or Pod's UID could clash with hos
  • - Line number: 20101 + Line number: 21953
  • @@ -2649,7 +2649,7 @@

    Container's or Pod's UID could clash with hos
  • - Line number: 20339 + Line number: 22191
  • diff --git a/docs/snyk/master/argocd-iac-namespace-install.html b/docs/snyk/master/argocd-iac-namespace-install.html index 389ef692caaa1..e043d126f446c 100644 --- a/docs/snyk/master/argocd-iac-namespace-install.html +++ b/docs/snyk/master/argocd-iac-namespace-install.html @@ -456,7 +456,7 @@

    Snyk test report

    -

    September 17th 2023, 12:18:27 am (UTC+00:00)

    +

    October 29th 2023, 12:17:54 am (UTC+00:00)

    Scanned the following path: @@ -789,7 +789,7 @@

    Container could be running with outdated image

  • - Line number: 1274 + Line number: 1298
  • @@ -905,7 +905,7 @@

    Container has no CPU limit

  • - Line number: 870 + Line number: 876
  • @@ -963,7 +963,7 @@

    Container has no CPU limit

  • - Line number: 836 + Line number: 842
  • @@ -1021,7 +1021,7 @@

    Container has no CPU limit

  • - Line number: 930 + Line number: 936
  • @@ -1079,7 +1079,7 @@

    Container has no CPU limit

  • - Line number: 1017 + Line number: 1029
  • @@ -1137,7 +1137,7 @@

    Container has no CPU limit

  • - Line number: 1274 + Line number: 1298
  • @@ -1195,7 +1195,7 @@

    Container has no CPU limit

  • - Line number: 1074 + Line number: 1086
  • @@ -1253,7 +1253,7 @@

    Container has no CPU limit

  • - Line number: 1359 + Line number: 1383
  • @@ -1311,7 +1311,7 @@

    Container has no CPU limit

  • - Line number: 1675 + Line number: 1699
  • @@ -1363,7 +1363,7 @@

    Container is running with multiple open ports

  • - Line number: 850 + Line number: 856
  • @@ -1460,14 +1460,14 @@

    Container is running without liveness probe

    spec - containers[dex] + initContainers[copyutil] livenessProbe
  • - Line number: 836 + Line number: 876
  • @@ -1512,14 +1512,14 @@

    Container is running without liveness probe

    spec - initContainers[copyutil] + containers[dex] livenessProbe
  • - Line number: 870 + Line number: 842
  • @@ -1571,7 +1571,7 @@

    Container is running without liveness probe

  • - Line number: 1017 + Line number: 1029
  • @@ -1623,7 +1623,7 @@

    Container is running without liveness probe

  • - Line number: 1274 + Line number: 1298
  • @@ -1739,7 +1739,7 @@

    Container is running without memory limit

  • - Line number: 836 + Line number: 842
  • @@ -1797,7 +1797,7 @@

    Container is running without memory limit

  • - Line number: 870 + Line number: 876
  • @@ -1855,7 +1855,7 @@

    Container is running without memory limit

  • - Line number: 930 + Line number: 936
  • @@ -1913,7 +1913,7 @@

    Container is running without memory limit

  • - Line number: 1017 + Line number: 1029
  • @@ -1971,7 +1971,7 @@

    Container is running without memory limit

  • - Line number: 1274 + Line number: 1298
  • @@ -2029,7 +2029,7 @@

    Container is running without memory limit

  • - Line number: 1074 + Line number: 1086
  • @@ -2087,7 +2087,7 @@

    Container is running without memory limit

  • - Line number: 1359 + Line number: 1383
  • @@ -2145,7 +2145,7 @@

    Container is running without memory limit

  • - Line number: 1675 + Line number: 1699
  • @@ -2201,7 +2201,7 @@

    Container's or Pod's UID could clash with hos
  • - Line number: 760 + Line number: 766
  • @@ -2257,7 +2257,7 @@

    Container's or Pod's UID could clash with hos
  • - Line number: 878 + Line number: 884
  • @@ -2313,7 +2313,7 @@

    Container's or Pod's UID could clash with hos
  • - Line number: 853 + Line number: 859
  • @@ -2369,7 +2369,7 @@

    Container's or Pod's UID could clash with hos
  • - Line number: 951 + Line number: 963
  • @@ -2425,7 +2425,7 @@

    Container's or Pod's UID could clash with hos
  • - Line number: 1027 + Line number: 1039
  • @@ -2481,7 +2481,7 @@

    Container's or Pod's UID could clash with hos
  • - Line number: 1281 + Line number: 1305
  • @@ -2537,7 +2537,7 @@

    Container's or Pod's UID could clash with hos
  • - Line number: 1247 + Line number: 1271
  • @@ -2593,7 +2593,7 @@

    Container's or Pod's UID could clash with hos
  • - Line number: 1585 + Line number: 1609
  • @@ -2649,7 +2649,7 @@

    Container's or Pod's UID could clash with hos
  • - Line number: 1823 + Line number: 1847
  • diff --git a/docs/snyk/master/argocd-test.html b/docs/snyk/master/argocd-test.html index 4f0797405d6bb..1b2486932df9e 100644 --- a/docs/snyk/master/argocd-test.html +++ b/docs/snyk/master/argocd-test.html @@ -7,7 +7,7 @@ Snyk test report - + @@ -456,7 +456,7 @@

    Snyk test report

    -

    September 17th 2023, 12:15:18 am (UTC+00:00)

    +

    October 29th 2023, 12:14:38 am (UTC+00:00)

    Scanned the following paths: @@ -466,9 +466,9 @@

    Snyk test report

    -
    5 known vulnerabilities
    -
    18 vulnerable dependency paths
    -
    1919 dependencies
    +
    6 known vulnerabilities
    +
    19 vulnerable dependency paths
    +
    1965 dependencies

    @@ -476,6 +476,65 @@

    Snyk test report

    +
    +

    LGPL-3.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Module: + + gopkg.in/retry.v1 +
    • + +
    • Introduced through: + + + github.com/argoproj/argo-cd/v2@0.0.0, github.com/Azure/kubelogin/pkg/token@0.0.20 and others +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/Azure/kubelogin/pkg/token@0.0.20 + + gopkg.in/retry.v1@1.0.3 + + + +
    • +
    + +
    + +
    + +

    LGPL-3.0 license

    + +
    + + + +

    MPL-2.0 license

    @@ -662,7 +721,7 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/notifications-engine/pkg/cmd@#9dcecdc3eebf + github.com/argoproj/notifications-engine/pkg/subscriptions@#9dcecdc3eebf github.com/argoproj/notifications-engine/pkg/services@#9dcecdc3eebf @@ -677,7 +736,7 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/notifications-engine/pkg/subscriptions@#9dcecdc3eebf + github.com/argoproj/notifications-engine/pkg/cmd@#9dcecdc3eebf github.com/argoproj/notifications-engine/pkg/services@#9dcecdc3eebf @@ -824,7 +883,7 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/notifications-engine/pkg/cmd@#9dcecdc3eebf + github.com/argoproj/notifications-engine/pkg/subscriptions@#9dcecdc3eebf github.com/argoproj/notifications-engine/pkg/services@#9dcecdc3eebf @@ -841,7 +900,7 @@

    Detailed paths

    Introduced through: github.com/argoproj/argo-cd/v2@0.0.0 - github.com/argoproj/notifications-engine/pkg/subscriptions@#9dcecdc3eebf + github.com/argoproj/notifications-engine/pkg/cmd@#9dcecdc3eebf github.com/argoproj/notifications-engine/pkg/services@#9dcecdc3eebf diff --git a/docs/snyk/master/ghcr.io_dexidp_dex_v2.37.0.html b/docs/snyk/master/ghcr.io_dexidp_dex_v2.37.0.html index 5362d9f1153db..167a203368fb3 100644 --- a/docs/snyk/master/ghcr.io_dexidp_dex_v2.37.0.html +++ b/docs/snyk/master/ghcr.io_dexidp_dex_v2.37.0.html @@ -7,7 +7,7 @@ Snyk test report - + @@ -456,7 +456,7 @@

    Snyk test report

    -

    September 17th 2023, 12:15:34 am (UTC+00:00)

    +

    October 29th 2023, 12:14:53 am (UTC+00:00)

    Scanned the following paths: @@ -466,8 +466,8 @@

    Snyk test report

    -
    25 known vulnerabilities
    -
    68 vulnerable dependency paths
    +
    28 known vulnerabilities
    +
    79 vulnerable dependency paths
    786 dependencies
    @@ -583,6 +583,178 @@

    References

    More about this vulnerability

    +
    +
    +

    Denial of Service (DoS)

    +
    + +
    + high severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + google.golang.org/grpc +
    • + +
    • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and google.golang.org/grpc@v1.46.2 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + google.golang.org/grpc@v1.46.2 + + + +
    • +
    • + Introduced through: + github.com/dexidp/dex@* + + google.golang.org/grpc@v1.56.1 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    google.golang.org/grpc is a Go implementation of gRPC

    +

    Affected versions of this package are vulnerable to Denial of Service (DoS) in the implementation of the HTTP/2 protocol. An attacker can cause a denial of service (including via DDoS) by rapidly resetting many streams through request cancellation.

    +

    Remediation

    +

    Upgrade google.golang.org/grpc to version 1.56.3, 1.57.1, 1.58.3 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Denial of Service (DoS)

    +
    + +
    + high severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + golang.org/x/net/http2 +
    • + +
    • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and golang.org/x/net/http2@v0.7.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + golang.org/x/net/http2@v0.7.0 + + + +
    • +
    • + Introduced through: + github.com/dexidp/dex@* + + golang.org/x/net/http2@v0.11.0 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    golang.org/x/net/http2 is a work-in-progress HTTP/2 implementation for Go.

    +

    Affected versions of this package are vulnerable to Denial of Service (DoS) in the implementation of the HTTP/2 protocol. An attacker can cause a denial of service (including via DDoS) by rapidly resetting many streams through request cancellation.

    +

    Remediation

    +

    Upgrade golang.org/x/net/http2 to version 0.17.0 or higher.

    +

    References

    + + +
    + + +

    Improper Authentication

    @@ -852,7 +1024,7 @@

    Detailed paths


    NVD Description

    -

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine:3.18. +

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine. See How to fix? for Alpine:3.18 relevant fixed versions and status.

    Issue summary: Checking excessively long DH keys or parameters may be very slow.

    Impact summary: Applications that use the functions DH_check(), DH_check_ex() @@ -1015,7 +1187,7 @@

    Detailed paths


    NVD Description

    -

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine:3.18. +

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine. See How to fix? for Alpine:3.18 relevant fixed versions and status.

    Issue summary: Checking excessively long DH keys or parameters may be very slow.

    Impact summary: Applications that use the functions DH_check(), DH_check_ex() @@ -1050,6 +1222,9 @@

    References

  • openssl-security@openssl.org
  • openssl-security@openssl.org
  • openssl-security@openssl.org
  • +
  • openssl-security@openssl.org
  • +
  • openssl-security@openssl.org
  • +
  • openssl-security@openssl.org

  • @@ -2511,6 +2686,174 @@

    Detailed paths

    +
    +

    CVE-2023-5363

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Package Manager: alpine:3.18 +
    • +
    • + Vulnerable module: + + openssl/libcrypto3 +
    • + +
    • Introduced through: + + docker-image|ghcr.io/dexidp/dex@v2.37.0 and openssl/libcrypto3@3.1.1-r1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + busybox/ssl_client@1.36.1-r0 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libssl3@3.1.1-r1 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + busybox/ssl_client@1.36.1-r0 + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine. + See How to fix? for Alpine:3.18 relevant fixed versions and status.

    +

    Issue summary: A bug has been identified in the processing of key and + initialisation vector (IV) lengths. This can lead to potential truncation + or overruns during the initialisation of some symmetric ciphers.

    +

    Impact summary: A truncation in the IV can result in non-uniqueness, + which could result in loss of confidentiality for some cipher modes.

    +

    When calling EVP_EncryptInit_ex2(), EVP_DecryptInit_ex2() or + EVP_CipherInit_ex2() the provided OSSL_PARAM array is processed after + the key and IV have been established. Any alterations to the key length, + via the "keylen" parameter or the IV length, via the "ivlen" parameter, + within the OSSL_PARAM array will not take effect as intended, potentially + causing truncation or overreading of these values. The following ciphers + and cipher modes are impacted: RC2, RC4, RC5, CCM, GCM and OCB.

    +

    For the CCM, GCM and OCB cipher modes, truncation of the IV can result in + loss of confidentiality. For example, when following NIST's SP 800-38D + section 8.2.1 guidance for constructing a deterministic IV for AES in + GCM mode, truncation of the counter portion could lead to IV reuse.

    +

    Both truncations and overruns of the key and overruns of the IV will + produce incorrect results and could, in some cases, trigger a memory + exception. However, these issues are not currently assessed as security + critical.

    +

    Changing the key and/or IV lengths is not considered to be a common operation + and the vulnerable API was recently introduced. Furthermore it is likely that + application developers will have spotted this problem during testing since + decryption would fail unless both peers in the communication were similarly + vulnerable. For these reasons we expect the probability of an application being + vulnerable to this to be quite low. However if an application is vulnerable then + this issue is considered very serious. For these reasons we have assessed this + issue as Moderate severity overall.

    +

    The OpenSSL SSL/TLS implementation is not affected by this issue.

    +

    The OpenSSL 3.0 and 3.1 FIPS providers are not affected by this because + the issue lies outside of the FIPS provider boundary.

    +

    OpenSSL 3.1 and 3.0 are vulnerable to this issue.

    +

    Remediation

    +

    Upgrade Alpine:3.18 openssl to version 3.1.4-r0 or higher.

    +

    References

    + + +
    + + + +
    diff --git a/docs/snyk/master/haproxy_2.6.14-alpine.html b/docs/snyk/master/haproxy_2.6.14-alpine.html index 6ba6ea51ffc0a..19c8202ec7564 100644 --- a/docs/snyk/master/haproxy_2.6.14-alpine.html +++ b/docs/snyk/master/haproxy_2.6.14-alpine.html @@ -7,7 +7,7 @@ Snyk test report - + @@ -456,7 +456,7 @@

    Snyk test report

    -

    September 17th 2023, 12:15:44 am (UTC+00:00)

    +

    October 29th 2023, 12:15:02 am (UTC+00:00)

    Scanned the following path: @@ -466,8 +466,8 @@

    Snyk test report

    -
    0 known vulnerabilities
    -
    0 vulnerable dependency paths
    +
    1 known vulnerabilities
    +
    9 vulnerable dependency paths
    18 dependencies
    @@ -484,7 +484,198 @@

    Snyk test report

    - No known vulnerabilities detected. +
    +
    +

    CVE-2023-5363

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Package Manager: alpine:3.18 +
    • +
    • + Vulnerable module: + + openssl/libcrypto3 +
    • + +
    • Introduced through: + + docker-image|haproxy@2.6.14-alpine and openssl/libcrypto3@3.1.2-r0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|haproxy@2.6.14-alpine + + openssl/libcrypto3@3.1.2-r0 + + + +
    • +
    • + Introduced through: + docker-image|haproxy@2.6.14-alpine + + .haproxy-rundeps@20230809.001942 + + openssl/libcrypto3@3.1.2-r0 + + + +
    • +
    • + Introduced through: + docker-image|haproxy@2.6.14-alpine + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libcrypto3@3.1.2-r0 + + + +
    • +
    • + Introduced through: + docker-image|haproxy@2.6.14-alpine + + busybox/ssl_client@1.36.1-r2 + + openssl/libcrypto3@3.1.2-r0 + + + +
    • +
    • + Introduced through: + docker-image|haproxy@2.6.14-alpine + + .haproxy-rundeps@20230809.001942 + + openssl/libssl3@3.1.2-r0 + + openssl/libcrypto3@3.1.2-r0 + + + +
    • +
    • + Introduced through: + docker-image|haproxy@2.6.14-alpine + + openssl/libssl3@3.1.2-r0 + + + +
    • +
    • + Introduced through: + docker-image|haproxy@2.6.14-alpine + + .haproxy-rundeps@20230809.001942 + + openssl/libssl3@3.1.2-r0 + + + +
    • +
    • + Introduced through: + docker-image|haproxy@2.6.14-alpine + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libssl3@3.1.2-r0 + + + +
    • +
    • + Introduced through: + docker-image|haproxy@2.6.14-alpine + + busybox/ssl_client@1.36.1-r2 + + openssl/libssl3@3.1.2-r0 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine. + See How to fix? for Alpine:3.18 relevant fixed versions and status.

    +

    Issue summary: A bug has been identified in the processing of key and + initialisation vector (IV) lengths. This can lead to potential truncation + or overruns during the initialisation of some symmetric ciphers.

    +

    Impact summary: A truncation in the IV can result in non-uniqueness, + which could result in loss of confidentiality for some cipher modes.

    +

    When calling EVP_EncryptInit_ex2(), EVP_DecryptInit_ex2() or + EVP_CipherInit_ex2() the provided OSSL_PARAM array is processed after + the key and IV have been established. Any alterations to the key length, + via the "keylen" parameter or the IV length, via the "ivlen" parameter, + within the OSSL_PARAM array will not take effect as intended, potentially + causing truncation or overreading of these values. The following ciphers + and cipher modes are impacted: RC2, RC4, RC5, CCM, GCM and OCB.

    +

    For the CCM, GCM and OCB cipher modes, truncation of the IV can result in + loss of confidentiality. For example, when following NIST's SP 800-38D + section 8.2.1 guidance for constructing a deterministic IV for AES in + GCM mode, truncation of the counter portion could lead to IV reuse.

    +

    Both truncations and overruns of the key and overruns of the IV will + produce incorrect results and could, in some cases, trigger a memory + exception. However, these issues are not currently assessed as security + critical.

    +

    Changing the key and/or IV lengths is not considered to be a common operation + and the vulnerable API was recently introduced. Furthermore it is likely that + application developers will have spotted this problem during testing since + decryption would fail unless both peers in the communication were similarly + vulnerable. For these reasons we expect the probability of an application being + vulnerable to this to be quite low. However if an application is vulnerable then + this issue is considered very serious. For these reasons we have assessed this + issue as Moderate severity overall.

    +

    The OpenSSL SSL/TLS implementation is not affected by this issue.

    +

    The OpenSSL 3.0 and 3.1 FIPS providers are not affected by this because + the issue lies outside of the FIPS provider boundary.

    +

    OpenSSL 3.1 and 3.0 are vulnerable to this issue.

    +

    Remediation

    +

    Upgrade Alpine:3.18 openssl to version 3.1.4-r0 or higher.

    +

    References

    + + +
    + + + +
    +
    diff --git a/docs/snyk/master/quay.io_argoproj_argocd_latest.html b/docs/snyk/master/quay.io_argoproj_argocd_latest.html index dac774d0f0d30..c9b59ef5e997f 100644 --- a/docs/snyk/master/quay.io_argoproj_argocd_latest.html +++ b/docs/snyk/master/quay.io_argoproj_argocd_latest.html @@ -7,7 +7,7 @@ Snyk test report - + @@ -456,19 +456,19 @@

    Snyk test report

    -

    September 17th 2023, 12:16:14 am (UTC+00:00)

    +

    October 29th 2023, 12:15:33 am (UTC+00:00)

    Scanned the following paths:
      -
    • quay.io/argoproj/argocd:latest/argoproj/argocd (deb)
    • quay.io/argoproj/argocd:latest/argoproj/argo-cd/v2 (gomodules)
    • quay.io/argoproj/argocd:latest/kustomize/kustomize/v5 (gomodules)
    • quay.io/argoproj/argocd:latest/helm/v3 (gomodules)
    • quay.io/argoproj/argocd:latest/git-lfs/git-lfs (gomodules)
    • +
    • quay.io/argoproj/argocd:latest/argoproj/argocd (deb)
    • quay.io/argoproj/argocd:latest/argoproj/argo-cd/v2 (gomodules)
    • quay.io/argoproj/argocd:latest (gomodules)
    • quay.io/argoproj/argocd:latest/helm/v3 (gomodules)
    • quay.io/argoproj/argocd:latest/git-lfs/git-lfs (gomodules)
    -
    27 known vulnerabilities
    -
    102 vulnerable dependency paths
    -
    2170 dependencies
    +
    28 known vulnerabilities
    +
    96 vulnerable dependency paths
    +
    2235 dependencies
    @@ -477,7 +477,7 @@

    Snyk test report

    -

    Directory Traversal

    +

    Denial of Service (DoS)

    @@ -493,12 +493,12 @@

    Directory Traversal

  • Vulnerable module: - github.com/cyphar/filepath-securejoin + golang.org/x/net/http2
  • Introduced through: - helm.sh/helm/v3@* and github.com/cyphar/filepath-securejoin@v0.2.3 + helm.sh/helm/v3@* and golang.org/x/net/http2@v0.13.0
  • @@ -513,7 +513,7 @@

    Detailed paths

    Introduced through: helm.sh/helm/v3@* - github.com/cyphar/filepath-securejoin@v0.2.3 + golang.org/x/net/http2@v0.13.0 @@ -525,41 +525,31 @@

    Detailed paths


    Overview

    -

    Affected versions of this package are vulnerable to Directory Traversal via the filepath.FromSlash() function, allwoing attackers to generate paths that were outside of the provided rootfs.

    -

    Note: - This vulnerability is only exploitable on Windows OS.

    -

    Details

    -

    A Directory Traversal attack (also known as path traversal) aims to access files and directories that are stored outside the intended folder. By manipulating files with "dot-dot-slash (../)" sequences and its variations, or by using absolute file paths, it may be possible to access arbitrary files and directories stored on file system, including application source code, configuration, and other critical system files.

    -

    Directory Traversal vulnerabilities can be generally divided into two types:

    -
      -
    • Information Disclosure: Allows the attacker to gain information about the folder structure or read the contents of sensitive files on the system.
    • -
    -

    st is a module for serving static files on web pages, and contains a vulnerability of this type. In our example, we will serve files from the public route.

    -

    If an attacker requests the following URL from our server, it will in turn leak the sensitive private key of the root user.

    -
    curl http://localhost:8080/public/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/root/.ssh/id_rsa
    -        
    -

    Note %2e is the URL encoded version of . (dot).

    -
      -
    • Writing arbitrary files: Allows the attacker to create or replace existing files. This type of vulnerability is also known as Zip-Slip.
    • -
    -

    One way to achieve this is by using a malicious zip archive that holds path traversal filenames. When each filename in the zip archive gets concatenated to the target extraction folder, without validation, the final path ends up outside of the target folder. If an executable or a configuration file is overwritten with a file containing malicious code, the problem can turn into an arbitrary code execution issue quite easily.

    -

    The following is an example of a zip archive with one benign file and one malicious file. Extracting the malicious file will result in traversing out of the target folder, ending up in /root/.ssh/ overwriting the authorized_keys file:

    -
    2018-04-15 22:04:29 .....           19           19  good.txt
    -        2018-04-15 22:04:42 .....           20           20  ../../../../../../root/.ssh/authorized_keys
    -        
    +

    golang.org/x/net/http2 is a work-in-progress HTTP/2 implementation for Go.

    +

    Affected versions of this package are vulnerable to Denial of Service (DoS) in the implementation of the HTTP/2 protocol. An attacker can cause a denial of service (including via DDoS) by rapidly resetting many streams through request cancellation.

    Remediation

    -

    Upgrade github.com/cyphar/filepath-securejoin to version 0.2.4 or higher.

    +

    Upgrade golang.org/x/net/http2 to version 0.17.0 or higher.

    References


    @@ -614,7 +604,7 @@

    Detailed paths

    NVD Description

    Note: Versions mentioned in the description apply only to the upstream xz-utils package and not the xz-utils package as distributed by Ubuntu. See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    -

    An issue discovered in XZ 5.2.5 allows attackers to cause a denial of service via decompression of a crafted file. NOTE: the software maintainers are unable to reproduce this as of 2023-09-12 because the example crafted file is temporarily offline.

    +

    ** DISPUTED ** An issue discovered in XZ 5.2.5 allows attackers to cause a denial of service via decompression of a crafted file. NOTE: the vendor disputes the claims of "endless output" and "denial of service" because decompression of the 17,486 bytes always results in 114,881,179 bytes, which is often a reasonable size increase.

    Remediation

    There is no fixed version for Ubuntu:22.04 xz-utils.

    References

    @@ -626,6 +616,7 @@

    References

  • cve@mitre.org
  • cve@mitre.org
  • cve@mitre.org
  • +
  • cve@mitre.org

  • @@ -897,7 +888,7 @@

    Detailed paths

    git@1:2.34.1-1ubuntu1.10 - curl/libcurl3-gnutls@7.81.0-1ubuntu1.13 + curl/libcurl3-gnutls@7.81.0-1ubuntu1.14 krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.2 @@ -910,7 +901,7 @@

    Detailed paths

    git@1:2.34.1-1ubuntu1.10 - curl/libcurl3-gnutls@7.81.0-1ubuntu1.13 + curl/libcurl3-gnutls@7.81.0-1ubuntu1.14 libssh/libssh-4@0.9.6-2ubuntu0.22.04.1 @@ -967,6 +958,7 @@

    References

  • cve@mitre.org
  • cve@mitre.org
  • cve@mitre.org
  • +
  • cve@mitre.org

  • @@ -975,6 +967,146 @@

    References

    More about this vulnerability

    +
    +
    +

    LGPL-3.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Module: + + gopkg.in/retry.v1 +
    • + +
    • Introduced through: + + github.com/argoproj/argo-cd/v2@* and gopkg.in/retry.v1@v1.0.3 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@* + + gopkg.in/retry.v1@v1.0.3 + + + +
    • +
    + +
    + +
    + +

    LGPL-3.0 license

    + +
    + + + +
    +
    +

    Memory Leak

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + glibc/libc-bin +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@latest and glibc/libc-bin@2.35-0ubuntu3.4 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + glibc/libc-bin@2.35-0ubuntu3.4 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@latest + + glibc/libc6@2.35-0ubuntu3.4 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream glibc package and not the glibc package as distributed by Ubuntu. + See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    +

    A flaw was found in the GNU C Library. A recent fix for CVE-2023-4806 introduced the potential for a memory leak, which may result in an application crash.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 glibc.

    +

    References

    + + +
    + + +

    MPL-2.0 license

    @@ -1801,198 +1933,6 @@

    References

    More about this vulnerability

    -
    -
    -

    Improper Authentication

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:22.04 -
    • -
    • - Vulnerable module: - - openssl/libssl3 -
    • - -
    • Introduced through: - - docker-image|quay.io/argoproj/argocd@latest and openssl/libssl3@3.0.2-0ubuntu1.10 - -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@latest - - openssl/libssl3@3.0.2-0ubuntu1.10 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@latest - - cyrus-sasl2/libsasl2-modules@2.1.27+dfsg2-3ubuntu1.2 - - openssl/libssl3@3.0.2-0ubuntu1.10 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@latest - - libfido2/libfido2-1@1.10.0-1 - - openssl/libssl3@3.0.2-0ubuntu1.10 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@latest - - openssh/openssh-client@1:8.9p1-3ubuntu0.4 - - openssl/libssl3@3.0.2-0ubuntu1.10 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@latest - - ca-certificates@20230311ubuntu0.22.04.1 - - openssl@3.0.2-0ubuntu1.10 - - openssl/libssl3@3.0.2-0ubuntu1.10 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@latest - - git@1:2.34.1-1ubuntu1.10 - - curl/libcurl3-gnutls@7.81.0-1ubuntu1.13 - - libssh/libssh-4@0.9.6-2ubuntu0.22.04.1 - - openssl/libssl3@3.0.2-0ubuntu1.10 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@latest - - adduser@3.118ubuntu5 - - shadow/passwd@1:4.8.1-2ubuntu2.1 - - pam/libpam-modules@1.4.0-11ubuntu2.3 - - libnsl/libnsl2@1.3.0-2build2 - - libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - - krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.2 - - krb5/libkrb5-3@1.19.2-2ubuntu0.2 - - openssl/libssl3@3.0.2-0ubuntu1.10 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@latest - - openssl@3.0.2-0ubuntu1.10 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@latest - - ca-certificates@20230311ubuntu0.22.04.1 - - openssl@3.0.2-0ubuntu1.10 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Ubuntu:22.04. - See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    -

    Issue summary: The AES-SIV cipher implementation contains a bug that causes - it to ignore empty associated data entries which are unauthenticated as - a consequence.

    -

    Impact summary: Applications that use the AES-SIV algorithm and want to - authenticate empty data entries as associated data can be mislead by removing - adding or reordering such empty entries as these are ignored by the OpenSSL - implementation. We are currently unaware of any such applications.

    -

    The AES-SIV algorithm allows for authentication of multiple associated - data entries along with the encryption. To authenticate empty data the - application has to call EVP_EncryptUpdate() (or EVP_CipherUpdate()) with - NULL pointer as the output buffer and 0 as the input buffer length. - The AES-SIV implementation in OpenSSL just returns success for such a call - instead of performing the associated data authentication operation. - The empty data thus will not be authenticated.

    -

    As this issue does not affect non-empty associated data authentication and - we expect it to be rare for an application to use empty associated data - entries this is qualified as Low severity issue.

    -

    Remediation

    -

    There is no fixed version for Ubuntu:22.04 openssl.

    -

    References

    - - -
    - - -

    CVE-2023-28531

    @@ -2113,7 +2053,7 @@

    Detailed paths

    git@1:2.34.1-1ubuntu1.10 - curl/libcurl3-gnutls@7.81.0-1ubuntu1.13 + curl/libcurl3-gnutls@7.81.0-1ubuntu1.14 openldap/libldap-2.5-0@2.5.16+dfsg-0ubuntu0.22.04.1 @@ -2375,7 +2315,7 @@

    Detailed paths

    git@1:2.34.1-1ubuntu1.10 - curl/libcurl3-gnutls@7.81.0-1ubuntu1.13 + curl/libcurl3-gnutls@7.81.0-1ubuntu1.14 krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.2 @@ -2388,7 +2328,7 @@

    Detailed paths

    git@1:2.34.1-1ubuntu1.10 - curl/libcurl3-gnutls@7.81.0-1ubuntu1.13 + curl/libcurl3-gnutls@7.81.0-1ubuntu1.14 libssh/libssh-4@0.9.6-2ubuntu0.22.04.1 @@ -2851,7 +2791,7 @@

    Allocation of Resources Without Limits or Throttling

    Introduced through: - docker-image|quay.io/argoproj/argocd@latest and glibc/libc-bin@2.35-0ubuntu3.3 + docker-image|quay.io/argoproj/argocd@latest and glibc/libc-bin@2.35-0ubuntu3.4 @@ -2866,7 +2806,7 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@latest - glibc/libc-bin@2.35-0ubuntu3.3 + glibc/libc-bin@2.35-0ubuntu3.4 @@ -2875,7 +2815,7 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@latest - glibc/libc6@2.35-0ubuntu3.3 + glibc/libc6@2.35-0ubuntu3.4 diff --git a/docs/snyk/master/redis_7.0.11-alpine.html b/docs/snyk/master/redis_7.0.11-alpine.html index 3c8e68ad964d9..5409d26e74695 100644 --- a/docs/snyk/master/redis_7.0.11-alpine.html +++ b/docs/snyk/master/redis_7.0.11-alpine.html @@ -7,7 +7,7 @@ Snyk test report - + @@ -456,7 +456,7 @@

    Snyk test report

    -

    September 17th 2023, 12:16:22 am (UTC+00:00)

    +

    October 29th 2023, 12:15:46 am (UTC+00:00)

    Scanned the following path: @@ -466,8 +466,8 @@

    Snyk test report

    -
    4 known vulnerabilities
    -
    32 vulnerable dependency paths
    +
    5 known vulnerabilities
    +
    41 vulnerable dependency paths
    18 dependencies
    @@ -905,7 +905,7 @@

    Detailed paths


    NVD Description

    -

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine:3.18. +

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine. See How to fix? for Alpine:3.18 relevant fixed versions and status.

    Issue summary: Checking excessively long DH keys or parameters may be very slow.

    Impact summary: Applications that use the functions DH_check(), DH_check_ex() @@ -1090,7 +1090,7 @@

    Detailed paths


    NVD Description

    -

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine:3.18. +

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine. See How to fix? for Alpine:3.18 relevant fixed versions and status.

    Issue summary: Checking excessively long DH keys or parameters may be very slow.

    Impact summary: Applications that use the functions DH_check(), DH_check_ex() @@ -1125,6 +1125,9 @@

    References

  • openssl-security@openssl.org
  • openssl-security@openssl.org
  • openssl-security@openssl.org
  • +
  • openssl-security@openssl.org
  • +
  • openssl-security@openssl.org
  • +
  • openssl-security@openssl.org

  • @@ -1134,6 +1137,196 @@

    References

    +
    +

    CVE-2023-5363

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Package Manager: alpine:3.18 +
    • +
    • + Vulnerable module: + + openssl/libcrypto3 +
    • + +
    • Introduced through: + + docker-image|redis@7.0.11-alpine and openssl/libcrypto3@3.1.1-r1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + .redis-rundeps@20230614.215749 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + busybox/ssl_client@1.36.1-r0 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + .redis-rundeps@20230614.215749 + + openssl/libssl3@3.1.1-r1 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + .redis-rundeps@20230614.215749 + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + busybox/ssl_client@1.36.1-r0 + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine. + See How to fix? for Alpine:3.18 relevant fixed versions and status.

    +

    Issue summary: A bug has been identified in the processing of key and + initialisation vector (IV) lengths. This can lead to potential truncation + or overruns during the initialisation of some symmetric ciphers.

    +

    Impact summary: A truncation in the IV can result in non-uniqueness, + which could result in loss of confidentiality for some cipher modes.

    +

    When calling EVP_EncryptInit_ex2(), EVP_DecryptInit_ex2() or + EVP_CipherInit_ex2() the provided OSSL_PARAM array is processed after + the key and IV have been established. Any alterations to the key length, + via the "keylen" parameter or the IV length, via the "ivlen" parameter, + within the OSSL_PARAM array will not take effect as intended, potentially + causing truncation or overreading of these values. The following ciphers + and cipher modes are impacted: RC2, RC4, RC5, CCM, GCM and OCB.

    +

    For the CCM, GCM and OCB cipher modes, truncation of the IV can result in + loss of confidentiality. For example, when following NIST's SP 800-38D + section 8.2.1 guidance for constructing a deterministic IV for AES in + GCM mode, truncation of the counter portion could lead to IV reuse.

    +

    Both truncations and overruns of the key and overruns of the IV will + produce incorrect results and could, in some cases, trigger a memory + exception. However, these issues are not currently assessed as security + critical.

    +

    Changing the key and/or IV lengths is not considered to be a common operation + and the vulnerable API was recently introduced. Furthermore it is likely that + application developers will have spotted this problem during testing since + decryption would fail unless both peers in the communication were similarly + vulnerable. For these reasons we expect the probability of an application being + vulnerable to this to be quite low. However if an application is vulnerable then + this issue is considered very serious. For these reasons we have assessed this + issue as Moderate severity overall.

    +

    The OpenSSL SSL/TLS implementation is not affected by this issue.

    +

    The OpenSSL 3.0 and 3.1 FIPS providers are not affected by this because + the issue lies outside of the FIPS provider boundary.

    +

    OpenSSL 3.1 and 3.0 are vulnerable to this issue.

    +

    Remediation

    +

    Upgrade Alpine:3.18 openssl to version 3.1.4-r0 or higher.

    +

    References

    + + +
    + + + +
    diff --git a/docs/snyk/v2.6.15/argocd-iac-install.html b/docs/snyk/v2.6.15/argocd-iac-install.html index bf9ee4f20bde5..6867e68c4bd18 100644 --- a/docs/snyk/v2.6.15/argocd-iac-install.html +++ b/docs/snyk/v2.6.15/argocd-iac-install.html @@ -456,7 +456,7 @@

    Snyk test report

    -

    September 17th 2023, 12:28:14 am (UTC+00:00)

    +

    October 29th 2023, 12:30:07 am (UTC+00:00)

    Scanned the following path: @@ -1514,14 +1514,14 @@

    Container is running without liveness probe

    spec - containers[dex] + initContainers[copyutil] livenessProbe
  • - Line number: 15951 + Line number: 15985
  • @@ -1566,14 +1566,14 @@

    Container is running without liveness probe

    spec - initContainers[copyutil] + containers[dex] livenessProbe
  • - Line number: 15985 + Line number: 15951
  • diff --git a/docs/snyk/v2.6.15/argocd-iac-namespace-install.html b/docs/snyk/v2.6.15/argocd-iac-namespace-install.html index 3b6b2fbd7b92b..a0dbfd5315336 100644 --- a/docs/snyk/v2.6.15/argocd-iac-namespace-install.html +++ b/docs/snyk/v2.6.15/argocd-iac-namespace-install.html @@ -456,7 +456,7 @@

    Snyk test report

    -

    September 17th 2023, 12:28:28 am (UTC+00:00)

    +

    October 29th 2023, 12:30:19 am (UTC+00:00)

    Scanned the following path: @@ -1514,14 +1514,14 @@

    Container is running without liveness probe

    spec - containers[dex] + initContainers[copyutil] livenessProbe
  • - Line number: 755 + Line number: 789
  • @@ -1566,14 +1566,14 @@

    Container is running without liveness probe

    spec - initContainers[copyutil] + containers[dex] livenessProbe
  • - Line number: 789 + Line number: 755
  • diff --git a/docs/snyk/v2.6.15/argocd-test.html b/docs/snyk/v2.6.15/argocd-test.html index b643763bc9443..cbf674fc20222 100644 --- a/docs/snyk/v2.6.15/argocd-test.html +++ b/docs/snyk/v2.6.15/argocd-test.html @@ -7,7 +7,7 @@ Snyk test report - + @@ -456,7 +456,7 @@

    Snyk test report

    -

    September 17th 2023, 12:25:21 am (UTC+00:00)

    +

    October 29th 2023, 12:27:33 am (UTC+00:00)

    Scanned the following paths: @@ -466,8 +466,8 @@

    Snyk test report

    -
    7 known vulnerabilities
    -
    20 vulnerable dependency paths
    +
    9 known vulnerabilities
    +
    157 vulnerable dependency paths
    1727 dependencies
    @@ -627,6 +627,2587 @@

    References

    More about this vulnerability

    + +
    +

    Denial of Service (DoS)

    +
    + +
    + high severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + google.golang.org/grpc +
    • + +
    • Introduced through: + + github.com/argoproj/argo-cd/v2@0.0.0 and google.golang.org/grpc@1.51.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc@1.51.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/go-grpc-middleware@1.3.0 + + google.golang.org/grpc@1.51.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc/health@1.51.0 + + google.golang.org/grpc@1.51.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc/reflection@1.51.0 + + google.golang.org/grpc@1.51.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/go-grpc-middleware/auth@1.3.0 + + google.golang.org/grpc@1.51.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/go-grpc-middleware/retry@1.3.0 + + google.golang.org/grpc@1.51.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/go-grpc-prometheus@1.2.0 + + google.golang.org/grpc@1.51.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc/health/grpc_health_v1@1.51.0 + + google.golang.org/grpc@1.51.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus@1.3.0 + + google.golang.org/grpc@1.51.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/improbable-eng/grpc-web/go/grpcweb@#16092bd1d58a + + google.golang.org/grpc@1.51.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc@0.31.0 + + google.golang.org/grpc@1.51.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.11.1 + + google.golang.org/grpc@1.51.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/go-grpc-middleware/auth@1.3.0 + + github.com/grpc-ecosystem/go-grpc-middleware@1.3.0 + + google.golang.org/grpc@1.51.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.11.1 + + go.opentelemetry.io/otel/exporters/otlp/otlptrace/internal/otlpconfig@1.11.1 + + google.golang.org/grpc@1.51.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.11.1 + + go.opentelemetry.io/proto/otlp/collector/trace/v1@0.19.0 + + google.golang.org/grpc@1.51.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc/reflection@1.51.0 + + google.golang.org/grpc/reflection/grpc_reflection_v1alpha@1.51.0 + + google.golang.org/grpc@1.51.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc/health@1.51.0 + + google.golang.org/grpc/health/grpc_health_v1@1.51.0 + + google.golang.org/grpc@1.51.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus@1.3.0 + + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus@1.3.0 + + github.com/grpc-ecosystem/go-grpc-middleware/tags@1.3.0 + + google.golang.org/grpc@1.51.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/go-grpc-middleware/tags/logrus@1.3.0 + + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus@1.3.0 + + github.com/grpc-ecosystem/go-grpc-middleware/tags@1.3.0 + + google.golang.org/grpc@1.51.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus@1.3.0 + + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus@1.3.0 + + github.com/grpc-ecosystem/go-grpc-middleware/tags@1.3.0 + + github.com/grpc-ecosystem/go-grpc-middleware@1.3.0 + + google.golang.org/grpc@1.51.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/go-grpc-middleware/tags/logrus@1.3.0 + + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus@1.3.0 + + github.com/grpc-ecosystem/go-grpc-middleware/tags@1.3.0 + + github.com/grpc-ecosystem/go-grpc-middleware@1.3.0 + + google.golang.org/grpc@1.51.0 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    google.golang.org/grpc is a Go implementation of gRPC

    +

    Affected versions of this package are vulnerable to Denial of Service (DoS) in the implementation of the HTTP/2 protocol. An attacker can cause a denial of service (including via DDoS) by rapidly resetting many streams through request cancellation.

    +

    Remediation

    +

    Upgrade google.golang.org/grpc to version 1.56.3, 1.57.1, 1.58.3 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Denial of Service (DoS)

    +
    + +
    + high severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + golang.org/x/net/http2 +
    • + +
    • Introduced through: + + + github.com/argoproj/argo-cd/v2@0.0.0, k8s.io/apimachinery/pkg/util/net@0.24.2 and others +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/soheilhy/cmux@0.1.5 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/improbable-eng/grpc-web/go/grpcweb@#16092bd1d58a + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc@1.51.0 + + google.golang.org/grpc/internal/transport@1.51.0 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/tools/cache@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/transport/spdy@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/pkg/kubeclientmetrics@#a4dd357b057e + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/testing@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/dynamic@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/plugin/pkg/client/auth/azure@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/plugin/pkg/client/auth/gcp@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/plugin/pkg/client/auth/oidc@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/tools/record@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/rest@0.24.2 + + k8s.io/client-go/transport@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/go-grpc-middleware@1.3.0 + + google.golang.org/grpc@1.51.0 + + google.golang.org/grpc/internal/transport@1.51.0 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/go-grpc-middleware/auth@1.3.0 + + google.golang.org/grpc@1.51.0 + + google.golang.org/grpc/internal/transport@1.51.0 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/go-grpc-middleware/retry@1.3.0 + + google.golang.org/grpc@1.51.0 + + google.golang.org/grpc/internal/transport@1.51.0 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/go-grpc-prometheus@1.2.0 + + google.golang.org/grpc@1.51.0 + + google.golang.org/grpc/internal/transport@1.51.0 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc/health/grpc_health_v1@1.51.0 + + google.golang.org/grpc@1.51.0 + + google.golang.org/grpc/internal/transport@1.51.0 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc@0.31.0 + + google.golang.org/grpc@1.51.0 + + google.golang.org/grpc/internal/transport@1.51.0 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.11.1 + + google.golang.org/grpc@1.51.0 + + google.golang.org/grpc/internal/transport@1.51.0 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus@1.3.0 + + google.golang.org/grpc@1.51.0 + + google.golang.org/grpc/internal/transport@1.51.0 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/improbable-eng/grpc-web/go/grpcweb@#16092bd1d58a + + google.golang.org/grpc@1.51.0 + + google.golang.org/grpc/internal/transport@1.51.0 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/kubectl/pkg/util/openapi@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/listers/core/v1@0.24.2 + + k8s.io/client-go/tools/cache@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/informers@0.24.2 + + k8s.io/client-go/tools/cache@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/tools/clientcmd@0.24.2 + + k8s.io/client-go/tools/auth@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/controller@#f754726f03da + + k8s.io/client-go/tools/cache@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/discovery/fake@0.24.2 + + k8s.io/client-go/testing@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/kubernetes/fake@0.24.2 + + k8s.io/client-go/testing@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/tools/remotecommand@0.24.2 + + k8s.io/client-go/transport/spdy@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/api/rbac/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/pkg/apis/clientauthentication/v1beta1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/apimachinery/pkg/api/errors@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/sync/common@#b4dd8b8c3976 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/apimachinery/pkg/api/equality@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/transport/spdy@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + k8s.io/client-go/transport@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/pkg/kubeclientmetrics@#a4dd357b057e + + k8s.io/client-go/rest@0.24.2 + + k8s.io/client-go/transport@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/testing@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + k8s.io/client-go/transport@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/plugin/pkg/client/auth/azure@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + k8s.io/client-go/transport@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/plugin/pkg/client/auth/gcp@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + k8s.io/client-go/transport@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/plugin/pkg/client/auth/oidc@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + k8s.io/client-go/transport@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc/reflection@1.51.0 + + google.golang.org/grpc/reflection/grpc_reflection_v1alpha@1.51.0 + + google.golang.org/grpc@1.51.0 + + google.golang.org/grpc/internal/transport@1.51.0 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc/health@1.51.0 + + google.golang.org/grpc/health/grpc_health_v1@1.51.0 + + google.golang.org/grpc@1.51.0 + + google.golang.org/grpc/internal/transport@1.51.0 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/cache@#b4dd8b8c3976 + + k8s.io/kubectl/pkg/util/openapi@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/sync@#b4dd8b8c3976 + + k8s.io/kubectl/pkg/util/openapi@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/utils/kube@#b4dd8b8c3976 + + k8s.io/kubectl/pkg/util/openapi@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/api@#f754726f03da + + k8s.io/client-go/listers/core/v1@0.24.2 + + k8s.io/client-go/tools/cache@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/informers/core/v1@0.24.2 + + k8s.io/client-go/listers/core/v1@0.24.2 + + k8s.io/client-go/tools/cache@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/cmd@#f754726f03da + + k8s.io/client-go/tools/clientcmd@0.24.2 + + k8s.io/client-go/tools/auth@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/kubectl/pkg/util/term@0.24.2 + + k8s.io/client-go/tools/remotecommand@0.24.2 + + k8s.io/client-go/transport/spdy@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/kubectl/pkg/util/resource@0.24.2 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/health@#b4dd8b8c3976 + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/sync/resource@#b4dd8b8c3976 + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/dynamic@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/sync/ignore@#b4dd8b8c3976 + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/sync/syncwaves@#b4dd8b8c3976 + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/utils/testing@#b4dd8b8c3976 + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/apimachinery/pkg/util/managedfields@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/tools/cache@0.24.2 + + k8s.io/client-go/tools/pager@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/scheme@0.11.0 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/util/retry@0.24.2 + + k8s.io/apimachinery/pkg/api/errors@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/tools/portforward@0.24.2 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1@0.24.2 + + k8s.io/apimachinery/pkg/api/equality@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/controller/controllerutil@0.11.0 + + k8s.io/apimachinery/pkg/api/equality@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/apimachinery/pkg/api/validation@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1/validation@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/discovery/fake@0.24.2 + + k8s.io/client-go/testing@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + k8s.io/client-go/transport@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/kubernetes/fake@0.24.2 + + k8s.io/client-go/testing@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + k8s.io/client-go/transport@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/tools/remotecommand@0.24.2 + + k8s.io/client-go/transport/spdy@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + k8s.io/client-go/transport@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/health@#b4dd8b8c3976 + + github.com/argoproj/gitops-engine/pkg/utils/kube@#b4dd8b8c3976 + + k8s.io/kubectl/pkg/util/openapi@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/sync/common@#b4dd8b8c3976 + + github.com/argoproj/gitops-engine/pkg/utils/kube@#b4dd8b8c3976 + + k8s.io/kubectl/pkg/util/openapi@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/controller/controllerutil@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/client/apiutil@0.11.0 + + k8s.io/client-go/restmapper@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/envtest@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane@0.11.0 + + k8s.io/client-go/tools/clientcmd@0.24.2 + + k8s.io/client-go/tools/auth@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/kubernetes/scheme@0.24.2 + + k8s.io/api/storage/v1beta1@0.24.2 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/tools/record@0.24.2 + + k8s.io/client-go/tools/reference@0.24.2 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/sync/hook@#b4dd8b8c3976 + + github.com/argoproj/gitops-engine/pkg/sync/resource@#b4dd8b8c3976 + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/apimachinery/pkg/runtime/serializer@0.24.2 + + k8s.io/apimachinery/pkg/runtime/serializer/versioning@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/listers/core/v1@0.24.2 + + k8s.io/client-go/tools/cache@0.24.2 + + k8s.io/client-go/tools/pager@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/informers@0.24.2 + + k8s.io/client-go/tools/cache@0.24.2 + + k8s.io/client-go/tools/pager@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/controller@#f754726f03da + + k8s.io/client-go/tools/cache@0.24.2 + + k8s.io/client-go/tools/pager@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/utils/kube/scheme@#b4dd8b8c3976 + + k8s.io/apimachinery/pkg/util/managedfields@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/kubectl/pkg/util/term@0.24.2 + + k8s.io/client-go/tools/remotecommand@0.24.2 + + k8s.io/client-go/transport/spdy@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + k8s.io/client-go/transport@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/go-grpc-middleware/tags/logrus@1.3.0 + + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus@1.3.0 + + github.com/grpc-ecosystem/go-grpc-middleware/tags@1.3.0 + + github.com/grpc-ecosystem/go-grpc-middleware@1.3.0 + + google.golang.org/grpc@1.51.0 + + google.golang.org/grpc/internal/transport@1.51.0 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/client@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/internal/objectutil@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/client/apiutil@0.11.0 + + k8s.io/client-go/restmapper@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/cache@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/internal/objectutil@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/client/apiutil@0.11.0 + + k8s.io/client-go/restmapper@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/kubernetes@0.24.2 + + k8s.io/client-go/kubernetes/typed/storage/v1beta1@0.24.2 + + k8s.io/client-go/applyconfigurations/storage/v1beta1@0.24.2 + + k8s.io/client-go/applyconfigurations/meta/v1@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/kubernetes/scheme@0.24.2 + + k8s.io/api/storage/v1beta1@0.24.2 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/tools/clientcmd@0.24.2 + + k8s.io/client-go/tools/clientcmd/api/latest@0.24.2 + + k8s.io/apimachinery/pkg/runtime/serializer/versioning@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/api@#f754726f03da + + k8s.io/client-go/listers/core/v1@0.24.2 + + k8s.io/client-go/tools/cache@0.24.2 + + k8s.io/client-go/tools/pager@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/informers/core/v1@0.24.2 + + k8s.io/client-go/listers/core/v1@0.24.2 + + k8s.io/client-go/tools/cache@0.24.2 + + k8s.io/client-go/tools/pager@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/diff@#b4dd8b8c3976 + + github.com/argoproj/gitops-engine/pkg/utils/kube/scheme@#b4dd8b8c3976 + + k8s.io/apimachinery/pkg/util/managedfields@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/sync/hook@#b4dd8b8c3976 + + github.com/argoproj/gitops-engine/pkg/sync/hook/helm@#b4dd8b8c3976 + + github.com/argoproj/gitops-engine/pkg/sync/common@#b4dd8b8c3976 + + github.com/argoproj/gitops-engine/pkg/utils/kube@#b4dd8b8c3976 + + k8s.io/kubectl/pkg/util/openapi@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/sync/syncwaves@#b4dd8b8c3976 + + github.com/argoproj/gitops-engine/pkg/sync/hook/helm@#b4dd8b8c3976 + + github.com/argoproj/gitops-engine/pkg/sync/common@#b4dd8b8c3976 + + github.com/argoproj/gitops-engine/pkg/utils/kube@#b4dd8b8c3976 + + k8s.io/kubectl/pkg/util/openapi@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/event@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/client@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/internal/objectutil@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/client/apiutil@0.11.0 + + k8s.io/client-go/restmapper@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/manager@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/webhook@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/webhook/internal/metrics@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/metrics@0.11.0 + + k8s.io/client-go/tools/cache@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/kubectl/pkg/util/openapi@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/kubernetes/scheme@0.24.2 + + k8s.io/api/storage/v1beta1@0.24.2 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/kubernetes@0.24.2 + + k8s.io/client-go/kubernetes/typed/storage/v1beta1@0.24.2 + + k8s.io/client-go/kubernetes/scheme@0.24.2 + + k8s.io/api/storage/v1beta1@0.24.2 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/cmd@#f754726f03da + + k8s.io/client-go/tools/clientcmd@0.24.2 + + k8s.io/client-go/tools/clientcmd/api/latest@0.24.2 + + k8s.io/apimachinery/pkg/runtime/serializer/versioning@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/envtest@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/webhook/conversion@0.11.0 + + k8s.io/apimachinery/pkg/runtime/serializer@0.24.2 + + k8s.io/apimachinery/pkg/runtime/serializer/versioning@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/sync/ignore@#b4dd8b8c3976 + + github.com/argoproj/gitops-engine/pkg/sync/hook@#b4dd8b8c3976 + + github.com/argoproj/gitops-engine/pkg/sync/hook/helm@#b4dd8b8c3976 + + github.com/argoproj/gitops-engine/pkg/sync/common@#b4dd8b8c3976 + + github.com/argoproj/gitops-engine/pkg/utils/kube@#b4dd8b8c3976 + + k8s.io/kubectl/pkg/util/openapi@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/handler@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/runtime/inject@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/cache@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/internal/objectutil@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/client/apiutil@0.11.0 + + k8s.io/client-go/restmapper@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/cache@#b4dd8b8c3976 + + k8s.io/kubectl/pkg/util/openapi@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/kubernetes/scheme@0.24.2 + + k8s.io/api/storage/v1beta1@0.24.2 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/sync@#b4dd8b8c3976 + + k8s.io/kubectl/pkg/util/openapi@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/kubernetes/scheme@0.24.2 + + k8s.io/api/storage/v1beta1@0.24.2 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/utils/kube@#b4dd8b8c3976 + + k8s.io/kubectl/pkg/util/openapi@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/kubernetes/scheme@0.24.2 + + k8s.io/api/storage/v1beta1@0.24.2 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/source@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/source/internal@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/predicate@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/event@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/client@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/internal/objectutil@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/client/apiutil@0.11.0 + + k8s.io/client-go/restmapper@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/client@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/internal/objectutil@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/client/apiutil@0.11.0 + + k8s.io/client-go/restmapper@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/kubernetes/scheme@0.24.2 + + k8s.io/api/storage/v1beta1@0.24.2 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/cache@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/internal/objectutil@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/client/apiutil@0.11.0 + + k8s.io/client-go/restmapper@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/kubernetes/scheme@0.24.2 + + k8s.io/api/storage/v1beta1@0.24.2 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/event@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/client@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/internal/objectutil@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/client/apiutil@0.11.0 + + k8s.io/client-go/restmapper@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/kubernetes/scheme@0.24.2 + + k8s.io/api/storage/v1beta1@0.24.2 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/handler@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/runtime/inject@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/cache@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/internal/objectutil@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/client/apiutil@0.11.0 + + k8s.io/client-go/restmapper@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/kubernetes/scheme@0.24.2 + + k8s.io/api/storage/v1beta1@0.24.2 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/source@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/source/internal@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/predicate@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/event@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/client@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/internal/objectutil@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/client/apiutil@0.11.0 + + k8s.io/client-go/restmapper@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/kubernetes/scheme@0.24.2 + + k8s.io/api/storage/v1beta1@0.24.2 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    golang.org/x/net/http2 is a work-in-progress HTTP/2 implementation for Go.

    +

    Affected versions of this package are vulnerable to Denial of Service (DoS) in the implementation of the HTTP/2 protocol. An attacker can cause a denial of service (including via DDoS) by rapidly resetting many streams through request cancellation.

    +

    Remediation

    +

    Upgrade golang.org/x/net/http2 to version 0.17.0 or higher.

    +

    References

    + + +
    + + +

    Directory Traversal

    diff --git a/docs/snyk/v2.6.15/ghcr.io_dexidp_dex_v2.37.0.html b/docs/snyk/v2.6.15/ghcr.io_dexidp_dex_v2.37.0.html index cbb0ecd603903..5cac66bfdc642 100644 --- a/docs/snyk/v2.6.15/ghcr.io_dexidp_dex_v2.37.0.html +++ b/docs/snyk/v2.6.15/ghcr.io_dexidp_dex_v2.37.0.html @@ -7,7 +7,7 @@ Snyk test report - + @@ -456,7 +456,7 @@

    Snyk test report

    -

    September 17th 2023, 12:25:29 am (UTC+00:00)

    +

    October 29th 2023, 12:27:42 am (UTC+00:00)

    Scanned the following paths: @@ -466,8 +466,8 @@

    Snyk test report

    -
    25 known vulnerabilities
    -
    68 vulnerable dependency paths
    +
    28 known vulnerabilities
    +
    79 vulnerable dependency paths
    786 dependencies
    @@ -583,6 +583,178 @@

    References

    More about this vulnerability

    + +
    +

    Denial of Service (DoS)

    +
    + +
    + high severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + google.golang.org/grpc +
    • + +
    • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and google.golang.org/grpc@v1.46.2 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + google.golang.org/grpc@v1.46.2 + + + +
    • +
    • + Introduced through: + github.com/dexidp/dex@* + + google.golang.org/grpc@v1.56.1 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    google.golang.org/grpc is a Go implementation of gRPC

    +

    Affected versions of this package are vulnerable to Denial of Service (DoS) in the implementation of the HTTP/2 protocol. An attacker can cause a denial of service (including via DDoS) by rapidly resetting many streams through request cancellation.

    +

    Remediation

    +

    Upgrade google.golang.org/grpc to version 1.56.3, 1.57.1, 1.58.3 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Denial of Service (DoS)

    +
    + +
    + high severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + golang.org/x/net/http2 +
    • + +
    • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and golang.org/x/net/http2@v0.7.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + golang.org/x/net/http2@v0.7.0 + + + +
    • +
    • + Introduced through: + github.com/dexidp/dex@* + + golang.org/x/net/http2@v0.11.0 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    golang.org/x/net/http2 is a work-in-progress HTTP/2 implementation for Go.

    +

    Affected versions of this package are vulnerable to Denial of Service (DoS) in the implementation of the HTTP/2 protocol. An attacker can cause a denial of service (including via DDoS) by rapidly resetting many streams through request cancellation.

    +

    Remediation

    +

    Upgrade golang.org/x/net/http2 to version 0.17.0 or higher.

    +

    References

    + + +
    + + +

    Improper Authentication

    @@ -852,7 +1024,7 @@

    Detailed paths


    NVD Description

    -

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine:3.18. +

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine. See How to fix? for Alpine:3.18 relevant fixed versions and status.

    Issue summary: Checking excessively long DH keys or parameters may be very slow.

    Impact summary: Applications that use the functions DH_check(), DH_check_ex() @@ -1015,7 +1187,7 @@

    Detailed paths


    NVD Description

    -

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine:3.18. +

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine. See How to fix? for Alpine:3.18 relevant fixed versions and status.

    Issue summary: Checking excessively long DH keys or parameters may be very slow.

    Impact summary: Applications that use the functions DH_check(), DH_check_ex() @@ -1050,6 +1222,9 @@

    References

  • openssl-security@openssl.org
  • openssl-security@openssl.org
  • openssl-security@openssl.org
  • +
  • openssl-security@openssl.org
  • +
  • openssl-security@openssl.org
  • +
  • openssl-security@openssl.org

  • @@ -2511,6 +2686,174 @@

    Detailed paths

    +
    +

    CVE-2023-5363

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Package Manager: alpine:3.18 +
    • +
    • + Vulnerable module: + + openssl/libcrypto3 +
    • + +
    • Introduced through: + + docker-image|ghcr.io/dexidp/dex@v2.37.0 and openssl/libcrypto3@3.1.1-r1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + busybox/ssl_client@1.36.1-r0 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libssl3@3.1.1-r1 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + busybox/ssl_client@1.36.1-r0 + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine. + See How to fix? for Alpine:3.18 relevant fixed versions and status.

    +

    Issue summary: A bug has been identified in the processing of key and + initialisation vector (IV) lengths. This can lead to potential truncation + or overruns during the initialisation of some symmetric ciphers.

    +

    Impact summary: A truncation in the IV can result in non-uniqueness, + which could result in loss of confidentiality for some cipher modes.

    +

    When calling EVP_EncryptInit_ex2(), EVP_DecryptInit_ex2() or + EVP_CipherInit_ex2() the provided OSSL_PARAM array is processed after + the key and IV have been established. Any alterations to the key length, + via the "keylen" parameter or the IV length, via the "ivlen" parameter, + within the OSSL_PARAM array will not take effect as intended, potentially + causing truncation or overreading of these values. The following ciphers + and cipher modes are impacted: RC2, RC4, RC5, CCM, GCM and OCB.

    +

    For the CCM, GCM and OCB cipher modes, truncation of the IV can result in + loss of confidentiality. For example, when following NIST's SP 800-38D + section 8.2.1 guidance for constructing a deterministic IV for AES in + GCM mode, truncation of the counter portion could lead to IV reuse.

    +

    Both truncations and overruns of the key and overruns of the IV will + produce incorrect results and could, in some cases, trigger a memory + exception. However, these issues are not currently assessed as security + critical.

    +

    Changing the key and/or IV lengths is not considered to be a common operation + and the vulnerable API was recently introduced. Furthermore it is likely that + application developers will have spotted this problem during testing since + decryption would fail unless both peers in the communication were similarly + vulnerable. For these reasons we expect the probability of an application being + vulnerable to this to be quite low. However if an application is vulnerable then + this issue is considered very serious. For these reasons we have assessed this + issue as Moderate severity overall.

    +

    The OpenSSL SSL/TLS implementation is not affected by this issue.

    +

    The OpenSSL 3.0 and 3.1 FIPS providers are not affected by this because + the issue lies outside of the FIPS provider boundary.

    +

    OpenSSL 3.1 and 3.0 are vulnerable to this issue.

    +

    Remediation

    +

    Upgrade Alpine:3.18 openssl to version 3.1.4-r0 or higher.

    +

    References

    + + +
    + + + +
    diff --git a/docs/snyk/v2.6.15/haproxy_2.6.14-alpine.html b/docs/snyk/v2.6.15/haproxy_2.6.14-alpine.html index 4f717f2c05aab..605a7d8b7d5bd 100644 --- a/docs/snyk/v2.6.15/haproxy_2.6.14-alpine.html +++ b/docs/snyk/v2.6.15/haproxy_2.6.14-alpine.html @@ -7,7 +7,7 @@ Snyk test report - + @@ -456,7 +456,7 @@

    Snyk test report

    -

    September 17th 2023, 12:25:35 am (UTC+00:00)

    +

    October 29th 2023, 12:27:48 am (UTC+00:00)

    Scanned the following path: @@ -466,8 +466,8 @@

    Snyk test report

    -
    0 known vulnerabilities
    -
    0 vulnerable dependency paths
    +
    1 known vulnerabilities
    +
    9 vulnerable dependency paths
    18 dependencies
    @@ -484,7 +484,198 @@

    Snyk test report

    - No known vulnerabilities detected. +
    +
    +

    CVE-2023-5363

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Package Manager: alpine:3.18 +
    • +
    • + Vulnerable module: + + openssl/libcrypto3 +
    • + +
    • Introduced through: + + docker-image|haproxy@2.6.14-alpine and openssl/libcrypto3@3.1.2-r0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|haproxy@2.6.14-alpine + + openssl/libcrypto3@3.1.2-r0 + + + +
    • +
    • + Introduced through: + docker-image|haproxy@2.6.14-alpine + + .haproxy-rundeps@20230809.001942 + + openssl/libcrypto3@3.1.2-r0 + + + +
    • +
    • + Introduced through: + docker-image|haproxy@2.6.14-alpine + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libcrypto3@3.1.2-r0 + + + +
    • +
    • + Introduced through: + docker-image|haproxy@2.6.14-alpine + + busybox/ssl_client@1.36.1-r2 + + openssl/libcrypto3@3.1.2-r0 + + + +
    • +
    • + Introduced through: + docker-image|haproxy@2.6.14-alpine + + .haproxy-rundeps@20230809.001942 + + openssl/libssl3@3.1.2-r0 + + openssl/libcrypto3@3.1.2-r0 + + + +
    • +
    • + Introduced through: + docker-image|haproxy@2.6.14-alpine + + openssl/libssl3@3.1.2-r0 + + + +
    • +
    • + Introduced through: + docker-image|haproxy@2.6.14-alpine + + .haproxy-rundeps@20230809.001942 + + openssl/libssl3@3.1.2-r0 + + + +
    • +
    • + Introduced through: + docker-image|haproxy@2.6.14-alpine + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libssl3@3.1.2-r0 + + + +
    • +
    • + Introduced through: + docker-image|haproxy@2.6.14-alpine + + busybox/ssl_client@1.36.1-r2 + + openssl/libssl3@3.1.2-r0 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine. + See How to fix? for Alpine:3.18 relevant fixed versions and status.

    +

    Issue summary: A bug has been identified in the processing of key and + initialisation vector (IV) lengths. This can lead to potential truncation + or overruns during the initialisation of some symmetric ciphers.

    +

    Impact summary: A truncation in the IV can result in non-uniqueness, + which could result in loss of confidentiality for some cipher modes.

    +

    When calling EVP_EncryptInit_ex2(), EVP_DecryptInit_ex2() or + EVP_CipherInit_ex2() the provided OSSL_PARAM array is processed after + the key and IV have been established. Any alterations to the key length, + via the "keylen" parameter or the IV length, via the "ivlen" parameter, + within the OSSL_PARAM array will not take effect as intended, potentially + causing truncation or overreading of these values. The following ciphers + and cipher modes are impacted: RC2, RC4, RC5, CCM, GCM and OCB.

    +

    For the CCM, GCM and OCB cipher modes, truncation of the IV can result in + loss of confidentiality. For example, when following NIST's SP 800-38D + section 8.2.1 guidance for constructing a deterministic IV for AES in + GCM mode, truncation of the counter portion could lead to IV reuse.

    +

    Both truncations and overruns of the key and overruns of the IV will + produce incorrect results and could, in some cases, trigger a memory + exception. However, these issues are not currently assessed as security + critical.

    +

    Changing the key and/or IV lengths is not considered to be a common operation + and the vulnerable API was recently introduced. Furthermore it is likely that + application developers will have spotted this problem during testing since + decryption would fail unless both peers in the communication were similarly + vulnerable. For these reasons we expect the probability of an application being + vulnerable to this to be quite low. However if an application is vulnerable then + this issue is considered very serious. For these reasons we have assessed this + issue as Moderate severity overall.

    +

    The OpenSSL SSL/TLS implementation is not affected by this issue.

    +

    The OpenSSL 3.0 and 3.1 FIPS providers are not affected by this because + the issue lies outside of the FIPS provider boundary.

    +

    OpenSSL 3.1 and 3.0 are vulnerable to this issue.

    +

    Remediation

    +

    Upgrade Alpine:3.18 openssl to version 3.1.4-r0 or higher.

    +

    References

    + + +
    + + + +
    +
    diff --git a/docs/snyk/v2.6.15/quay.io_argoproj_argocd_v2.6.15.html b/docs/snyk/v2.6.15/quay.io_argoproj_argocd_v2.6.15.html index 71e5552f26c97..759d3b81c634b 100644 --- a/docs/snyk/v2.6.15/quay.io_argoproj_argocd_v2.6.15.html +++ b/docs/snyk/v2.6.15/quay.io_argoproj_argocd_v2.6.15.html @@ -7,7 +7,7 @@ Snyk test report - + @@ -456,7 +456,7 @@

    Snyk test report

    -

    September 17th 2023, 12:26:27 am (UTC+00:00)

    +

    October 29th 2023, 12:28:36 am (UTC+00:00)

    Scanned the following paths: @@ -466,8 +466,8 @@

    Snyk test report

    -
    36 known vulnerabilities
    -
    114 vulnerable dependency paths
    +
    48 known vulnerabilities
    +
    168 vulnerable dependency paths
    2063 dependencies
    @@ -643,6 +643,83 @@

    References

    More about this vulnerability

    + +
    +

    Denial of Service (DoS)

    +
    + +
    + high severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + google.golang.org/grpc +
    • + +
    • Introduced through: + + github.com/argoproj/argo-cd/v2@* and google.golang.org/grpc@v1.51.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@* + + google.golang.org/grpc@v1.51.0 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    google.golang.org/grpc is a Go implementation of gRPC

    +

    Affected versions of this package are vulnerable to Denial of Service (DoS) in the implementation of the HTTP/2 protocol. An attacker can cause a denial of service (including via DDoS) by rapidly resetting many streams through request cancellation.

    +

    Remediation

    +

    Upgrade google.golang.org/grpc to version 1.56.3, 1.57.1, 1.58.3 or higher.

    +

    References

    + + +
    + + +

    Denial of Service (DoS)

    @@ -731,6 +808,92 @@

    References

    More about this vulnerability

    + +
    +

    Denial of Service (DoS)

    +
    + +
    + high severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + golang.org/x/net/http2 +
    • + +
    • Introduced through: + + github.com/argoproj/argo-cd/v2@* and golang.org/x/net/http2@v0.11.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@* + + golang.org/x/net/http2@v0.11.0 + + + +
    • +
    • + Introduced through: + helm.sh/helm/v3@* + + golang.org/x/net/http2@v0.0.0-20220722155237-a158d28d115b + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    golang.org/x/net/http2 is a work-in-progress HTTP/2 implementation for Go.

    +

    Affected versions of this package are vulnerable to Denial of Service (DoS) in the implementation of the HTTP/2 protocol. An attacker can cause a denial of service (including via DDoS) by rapidly resetting many streams through request cancellation.

    +

    Remediation

    +

    Upgrade golang.org/x/net/http2 to version 0.17.0 or higher.

    +

    References

    + + +
    + + +

    Denial of Service

    @@ -862,45 +1025,722 @@

    Details

    Remediation

    -

    Upgrade golang.org/x/net/http2 to version 0.7.0 or higher.

    +

    Upgrade golang.org/x/net/http2 to version 0.7.0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Out-of-bounds Write

    +
    + +
    + high severity +
    + +
    + +
      +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + glibc/libc-bin +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.6.15 and glibc/libc-bin@2.35-0ubuntu3.1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 + + glibc/libc-bin@2.35-0ubuntu3.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 + + glibc/libc6@2.35-0ubuntu3.1 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream glibc package and not the glibc package as distributed by Ubuntu. + See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    +

    A buffer overflow was discovered in the GNU C Library's dynamic loader ld.so while processing the GLIBC_TUNABLES environment variable. This issue could allow a local attacker to use maliciously crafted GLIBC_TUNABLES environment variables when launching binaries with SUID permission to execute code with elevated privileges.

    +

    Remediation

    +

    Upgrade Ubuntu:22.04 glibc to version 2.35-0ubuntu3.4 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Directory Traversal

    +
    + +
    + high severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + github.com/cyphar/filepath-securejoin +
    • + +
    • Introduced through: + + github.com/argoproj/argo-cd/v2@* and github.com/cyphar/filepath-securejoin@v0.2.3 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@* + + github.com/cyphar/filepath-securejoin@v0.2.3 + + + +
    • +
    • + Introduced through: + helm.sh/helm/v3@* + + github.com/cyphar/filepath-securejoin@v0.2.3 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    Affected versions of this package are vulnerable to Directory Traversal via the filepath.FromSlash() function, allwoing attackers to generate paths that were outside of the provided rootfs.

    +

    Note: + This vulnerability is only exploitable on Windows OS.

    +

    Details

    +

    A Directory Traversal attack (also known as path traversal) aims to access files and directories that are stored outside the intended folder. By manipulating files with "dot-dot-slash (../)" sequences and its variations, or by using absolute file paths, it may be possible to access arbitrary files and directories stored on file system, including application source code, configuration, and other critical system files.

    +

    Directory Traversal vulnerabilities can be generally divided into two types:

    +
      +
    • Information Disclosure: Allows the attacker to gain information about the folder structure or read the contents of sensitive files on the system.
    • +
    +

    st is a module for serving static files on web pages, and contains a vulnerability of this type. In our example, we will serve files from the public route.

    +

    If an attacker requests the following URL from our server, it will in turn leak the sensitive private key of the root user.

    +
    curl http://localhost:8080/public/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/root/.ssh/id_rsa
    +        
    +

    Note %2e is the URL encoded version of . (dot).

    +
      +
    • Writing arbitrary files: Allows the attacker to create or replace existing files. This type of vulnerability is also known as Zip-Slip.
    • +
    +

    One way to achieve this is by using a malicious zip archive that holds path traversal filenames. When each filename in the zip archive gets concatenated to the target extraction folder, without validation, the final path ends up outside of the target folder. If an executable or a configuration file is overwritten with a file containing malicious code, the problem can turn into an arbitrary code execution issue quite easily.

    +

    The following is an example of a zip archive with one benign file and one malicious file. Extracting the malicious file will result in traversing out of the target folder, ending up in /root/.ssh/ overwriting the authorized_keys file:

    +
    2018-04-15 22:04:29 .....           19           19  good.txt
    +        2018-04-15 22:04:42 .....           20           20  ../../../../../../root/.ssh/authorized_keys
    +        
    +

    Remediation

    +

    Upgrade github.com/cyphar/filepath-securejoin to version 0.2.4 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Out-of-bounds Write

    +
    + +
    + high severity +
    + +
    + +
      +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + curl/libcurl3-gnutls +
    • + +
    • Introduced through: + + + docker-image|quay.io/argoproj/argocd@v2.6.15, git@1:2.34.1-1ubuntu1.10 and others +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.13 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream curl package and not the curl package as distributed by Ubuntu. + See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    +

    This flaw makes curl overflow a heap based buffer in the SOCKS5 proxy + handshake.

    +

    When curl is asked to pass along the host name to the SOCKS5 proxy to allow + that to resolve the address instead of it getting done by curl itself, the + maximum length that host name can be is 255 bytes.

    +

    If the host name is detected to be longer, curl switches to local name + resolving and instead passes on the resolved address only. Due to this bug, + the local variable that means "let the host resolve the name" could get the + wrong value during a slow SOCKS5 handshake, and contrary to the intention, + copy the too long host name to the target buffer instead of copying just the + resolved address there.

    +

    The target buffer being a heap based buffer, and the host name coming from the + URL that curl has been told to operate with.

    +

    Remediation

    +

    Upgrade Ubuntu:22.04 curl to version 7.81.0-1ubuntu1.14 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    CVE-2020-22916

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + xz-utils/liblzma5 +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.6.15 and xz-utils/liblzma5@5.2.5-2ubuntu1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 + + xz-utils/liblzma5@5.2.5-2ubuntu1 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream xz-utils package and not the xz-utils package as distributed by Ubuntu. + See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    +

    ** DISPUTED ** An issue discovered in XZ 5.2.5 allows attackers to cause a denial of service via decompression of a crafted file. NOTE: the vendor disputes the claims of "endless output" and "denial of service" because decompression of the 17,486 bytes always results in 114,881,179 bytes, which is often a reasonable size increase.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 xz-utils.

    +

    References

    + + +
    + + + +
    +
    +

    Out-of-bounds Write

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + perl/perl-modules-5.34 +
    • + +
    • Introduced through: + + + docker-image|quay.io/argoproj/argocd@v2.6.15, git@1:2.34.1-1ubuntu1.10 and others +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 + + git@1:2.34.1-1ubuntu1.10 + + perl@5.34.0-3ubuntu1.2 + + perl/perl-modules-5.34@5.34.0-3ubuntu1.2 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 + + git@1:2.34.1-1ubuntu1.10 + + perl@5.34.0-3ubuntu1.2 + + perl/libperl5.34@5.34.0-3ubuntu1.2 + + perl/perl-modules-5.34@5.34.0-3ubuntu1.2 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 + + git@1:2.34.1-1ubuntu1.10 + + perl@5.34.0-3ubuntu1.2 + + perl/libperl5.34@5.34.0-3ubuntu1.2 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 + + git@1:2.34.1-1ubuntu1.10 + + perl@5.34.0-3ubuntu1.2 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 + + perl/perl-base@5.34.0-3ubuntu1.2 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream perl package and not the perl package as distributed by Ubuntu. + See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    +

    In Perl 5.34.0, function S_find_uninit_var in sv.c has a stack-based crash that can lead to remote code execution or local privilege escalation.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 perl.

    +

    References

    + + +
    + + + +
    +
    +

    CVE-2023-5363

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + openssl/libssl3 +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.6.15 and openssl/libssl3@3.0.2-0ubuntu1.10 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 + + openssl/libssl3@3.0.2-0ubuntu1.10 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 + + cyrus-sasl2/libsasl2-modules@2.1.27+dfsg2-3ubuntu1.2 + + openssl/libssl3@3.0.2-0ubuntu1.10 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 + + libfido2/libfido2-1@1.10.0-1 + + openssl/libssl3@3.0.2-0ubuntu1.10 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 + + openssh/openssh-client@1:8.9p1-3ubuntu0.3 + + openssl/libssl3@3.0.2-0ubuntu1.10 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 + + ca-certificates@20230311ubuntu0.22.04.1 + + openssl@3.0.2-0ubuntu1.10 + + openssl/libssl3@3.0.2-0ubuntu1.10 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.13 + + libssh/libssh-4@0.9.6-2ubuntu0.22.04.1 + + openssl/libssl3@3.0.2-0ubuntu1.10 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.1 + + pam/libpam-modules@1.4.0-11ubuntu2.3 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.2 + + krb5/libkrb5-3@1.19.2-2ubuntu0.2 + + openssl/libssl3@3.0.2-0ubuntu1.10 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 + + openssl@3.0.2-0ubuntu1.10 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 + + ca-certificates@20230311ubuntu0.22.04.1 + + openssl@3.0.2-0ubuntu1.10 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Ubuntu. + See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    +

    Issue summary: A bug has been identified in the processing of key and + initialisation vector (IV) lengths. This can lead to potential truncation + or overruns during the initialisation of some symmetric ciphers.

    +

    Impact summary: A truncation in the IV can result in non-uniqueness, + which could result in loss of confidentiality for some cipher modes.

    +

    When calling EVP_EncryptInit_ex2(), EVP_DecryptInit_ex2() or + EVP_CipherInit_ex2() the provided OSSL_PARAM array is processed after + the key and IV have been established. Any alterations to the key length, + via the "keylen" parameter or the IV length, via the "ivlen" parameter, + within the OSSL_PARAM array will not take effect as intended, potentially + causing truncation or overreading of these values. The following ciphers + and cipher modes are impacted: RC2, RC4, RC5, CCM, GCM and OCB.

    +

    For the CCM, GCM and OCB cipher modes, truncation of the IV can result in + loss of confidentiality. For example, when following NIST's SP 800-38D + section 8.2.1 guidance for constructing a deterministic IV for AES in + GCM mode, truncation of the counter portion could lead to IV reuse.

    +

    Both truncations and overruns of the key and overruns of the IV will + produce incorrect results and could, in some cases, trigger a memory + exception. However, these issues are not currently assessed as security + critical.

    +

    Changing the key and/or IV lengths is not considered to be a common operation + and the vulnerable API was recently introduced. Furthermore it is likely that + application developers will have spotted this problem during testing since + decryption would fail unless both peers in the communication were similarly + vulnerable. For these reasons we expect the probability of an application being + vulnerable to this to be quite low. However if an application is vulnerable then + this issue is considered very serious. For these reasons we have assessed this + issue as Moderate severity overall.

    +

    The OpenSSL SSL/TLS implementation is not affected by this issue.

    +

    The OpenSSL 3.0 and 3.1 FIPS providers are not affected by this because + the issue lies outside of the FIPS provider boundary.

    +

    OpenSSL 3.1 and 3.0 are vulnerable to this issue.

    +

    Remediation

    +

    Upgrade Ubuntu:22.04 openssl to version 3.0.2-0ubuntu1.12 or higher.

    References


    -
    -

    Directory Traversal

    +
    +

    Out-of-bounds Read

    -
    - high severity +
    + medium severity

    • - Package Manager: golang + Package Manager: ubuntu:22.04
    • Vulnerable module: - github.com/cyphar/filepath-securejoin + libx11/libx11-data
    • Introduced through: - github.com/argoproj/argo-cd/v2@* and github.com/cyphar/filepath-securejoin@v0.2.3 + docker-image|quay.io/argoproj/argocd@v2.6.15 and libx11/libx11-data@2:1.7.5-1ubuntu0.2
    @@ -913,18 +1753,62 @@

    Detailed paths

    • Introduced through: - github.com/argoproj/argo-cd/v2@* + docker-image|quay.io/argoproj/argocd@v2.6.15 - github.com/cyphar/filepath-securejoin@v0.2.3 + libx11/libx11-data@2:1.7.5-1ubuntu0.2
    • Introduced through: - helm.sh/helm/v3@* + docker-image|quay.io/argoproj/argocd@v2.6.15 - github.com/cyphar/filepath-securejoin@v0.2.3 + libx11/libx11-6@2:1.7.5-1ubuntu0.2 + + libx11/libx11-data@2:1.7.5-1ubuntu0.2 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 + + libx11/libx11-6@2:1.7.5-1ubuntu0.2 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 + + libxext/libxext6@2:1.3.4-1build1 + + libx11/libx11-6@2:1.7.5-1ubuntu0.2 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 + + libxmu/libxmuu1@2:1.1.3-3 + + libx11/libx11-6@2:1.7.5-1ubuntu0.2 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 + + xauth@1:1.1-1build2 + + libx11/libx11-6@2:1.7.5-1ubuntu0.2 @@ -935,47 +1819,28 @@

      Detailed paths


      -

      Overview

      -

      Affected versions of this package are vulnerable to Directory Traversal via the filepath.FromSlash() function, allwoing attackers to generate paths that were outside of the provided rootfs.

      -

      Note: - This vulnerability is only exploitable on Windows OS.

      -

      Details

      -

      A Directory Traversal attack (also known as path traversal) aims to access files and directories that are stored outside the intended folder. By manipulating files with "dot-dot-slash (../)" sequences and its variations, or by using absolute file paths, it may be possible to access arbitrary files and directories stored on file system, including application source code, configuration, and other critical system files.

      -

      Directory Traversal vulnerabilities can be generally divided into two types:

      -
        -
      • Information Disclosure: Allows the attacker to gain information about the folder structure or read the contents of sensitive files on the system.
      • -
      -

      st is a module for serving static files on web pages, and contains a vulnerability of this type. In our example, we will serve files from the public route.

      -

      If an attacker requests the following URL from our server, it will in turn leak the sensitive private key of the root user.

      -
      curl http://localhost:8080/public/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/root/.ssh/id_rsa
      -        
      -

      Note %2e is the URL encoded version of . (dot).

      -
        -
      • Writing arbitrary files: Allows the attacker to create or replace existing files. This type of vulnerability is also known as Zip-Slip.
      • -
      -

      One way to achieve this is by using a malicious zip archive that holds path traversal filenames. When each filename in the zip archive gets concatenated to the target extraction folder, without validation, the final path ends up outside of the target folder. If an executable or a configuration file is overwritten with a file containing malicious code, the problem can turn into an arbitrary code execution issue quite easily.

      -

      The following is an example of a zip archive with one benign file and one malicious file. Extracting the malicious file will result in traversing out of the target folder, ending up in /root/.ssh/ overwriting the authorized_keys file:

      -
      2018-04-15 22:04:29 .....           19           19  good.txt
      -        2018-04-15 22:04:42 .....           20           20  ../../../../../../root/.ssh/authorized_keys
      -        
      +

      NVD Description

      +

      Note: Versions mentioned in the description apply only to the upstream libx11 package and not the libx11 package as distributed by Ubuntu. + See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

      +

      A vulnerability was found in libX11 due to a boundary condition within the _XkbReadKeySyms() function. This flaw allows a local user to trigger an out-of-bounds read error and read the contents of memory on the system.

      Remediation

      -

      Upgrade github.com/cyphar/filepath-securejoin to version 0.2.4 or higher.

      +

      Upgrade Ubuntu:22.04 libx11 to version 2:1.7.5-1ubuntu0.3 or higher.

      References


    -

    CVE-2020-22916

    +

    Loop with Unreachable Exit Condition ('Infinite Loop')

    @@ -991,12 +1856,12 @@

    CVE-2020-22916

  • Vulnerable module: - xz-utils/liblzma5 + libx11/libx11-data
  • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.15 and xz-utils/liblzma5@5.2.5-2ubuntu1 + docker-image|quay.io/argoproj/argocd@v2.6.15 and libx11/libx11-data@2:1.7.5-1ubuntu0.2
  • @@ -1011,7 +1876,60 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@v2.6.15 - xz-utils/liblzma5@5.2.5-2ubuntu1 + libx11/libx11-data@2:1.7.5-1ubuntu0.2 + + + + +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 + + libx11/libx11-6@2:1.7.5-1ubuntu0.2 + + libx11/libx11-data@2:1.7.5-1ubuntu0.2 + + + +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 + + libx11/libx11-6@2:1.7.5-1ubuntu0.2 + + + +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 + + libxext/libxext6@2:1.3.4-1build1 + + libx11/libx11-6@2:1.7.5-1ubuntu0.2 + + + +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 + + libxmu/libxmuu1@2:1.1.3-3 + + libx11/libx11-6@2:1.7.5-1ubuntu0.2 + + + +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 + + xauth@1:1.1-1build2 + + libx11/libx11-6@2:1.7.5-1ubuntu0.2 @@ -1023,31 +1941,27 @@

    Detailed paths


    NVD Description

    -

    Note: Versions mentioned in the description apply only to the upstream xz-utils package and not the xz-utils package as distributed by Ubuntu. +

    Note: Versions mentioned in the description apply only to the upstream libx11 package and not the libx11 package as distributed by Ubuntu. See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    -

    An issue discovered in XZ 5.2.5 allows attackers to cause a denial of service via decompression of a crafted file. NOTE: the software maintainers are unable to reproduce this as of 2023-09-12 because the example crafted file is temporarily offline.

    +

    A vulnerability was found in libX11 due to an infinite loop within the PutSubImage() function. This flaw allows a local user to consume all available system resources and cause a denial of service condition.

    Remediation

    -

    There is no fixed version for Ubuntu:22.04 xz-utils.

    +

    Upgrade Ubuntu:22.04 libx11 to version 2:1.7.5-1ubuntu0.3 or higher.

    References


  • -

    Out-of-bounds Write

    +

    Integer Overflow or Wraparound

    @@ -1063,13 +1977,13 @@

    Out-of-bounds Write

  • Vulnerable module: - perl/perl-modules-5.34 + libx11/libx11-data
  • Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 and libx11/libx11-data@2:1.7.5-1ubuntu0.2 - docker-image|quay.io/argoproj/argocd@v2.6.15, git@1:2.34.1-1ubuntu1.10 and others
  • @@ -1083,11 +1997,7 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@v2.6.15 - git@1:2.34.1-1ubuntu1.10 - - perl@5.34.0-3ubuntu1.2 - - perl/perl-modules-5.34@5.34.0-3ubuntu1.2 + libx11/libx11-data@2:1.7.5-1ubuntu0.2 @@ -1096,13 +2006,9 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@v2.6.15 - git@1:2.34.1-1ubuntu1.10 - - perl@5.34.0-3ubuntu1.2 - - perl/libperl5.34@5.34.0-3ubuntu1.2 + libx11/libx11-6@2:1.7.5-1ubuntu0.2 - perl/perl-modules-5.34@5.34.0-3ubuntu1.2 + libx11/libx11-data@2:1.7.5-1ubuntu0.2 @@ -1111,11 +2017,18 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@v2.6.15 - git@1:2.34.1-1ubuntu1.10 + libx11/libx11-6@2:1.7.5-1ubuntu0.2 + + + + +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 - perl@5.34.0-3ubuntu1.2 + libxext/libxext6@2:1.3.4-1build1 - perl/libperl5.34@5.34.0-3ubuntu1.2 + libx11/libx11-6@2:1.7.5-1ubuntu0.2 @@ -1124,9 +2037,9 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@v2.6.15 - git@1:2.34.1-1ubuntu1.10 + libxmu/libxmuu1@2:1.1.3-3 - perl@5.34.0-3ubuntu1.2 + libx11/libx11-6@2:1.7.5-1ubuntu0.2 @@ -1135,7 +2048,9 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@v2.6.15 - perl/perl-base@5.34.0-3ubuntu1.2 + xauth@1:1.1-1build2 + + libx11/libx11-6@2:1.7.5-1ubuntu0.2 @@ -1147,22 +2062,22 @@

    Detailed paths


    NVD Description

    -

    Note: Versions mentioned in the description apply only to the upstream perl package and not the perl package as distributed by Ubuntu. +

    Note: Versions mentioned in the description apply only to the upstream libx11 package and not the libx11 package as distributed by Ubuntu. See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    -

    In Perl 5.34.0, function S_find_uninit_var in sv.c has a stack-based crash that can lead to remote code execution or local privilege escalation.

    +

    A vulnerability was found in libX11 due to an integer overflow within the XCreateImage() function. This flaw allows a local user to trigger an integer overflow and execute arbitrary code with elevated privileges.

    Remediation

    -

    There is no fixed version for Ubuntu:22.04 perl.

    +

    Upgrade Ubuntu:22.04 libx11 to version 2:1.7.5-1ubuntu0.3 or higher.

    References


  • @@ -1378,6 +2293,7 @@

    References

  • cve@mitre.org
  • cve@mitre.org
  • cve@mitre.org
  • +
  • cve@mitre.org

  • @@ -1641,12 +2557,87 @@

    Improper Verification of Cryptographic Signature

    Detailed paths

    -
      +
        +
      • + Introduced through: + helm.sh/helm/v3@* + + golang.org/x/crypto/openpgp/clearsign@v0.0.0-20220525230936-793ad666bf5e + + + +
      • +
      + +
    + +
    + +

    Overview

    +

    Affected versions of this package are vulnerable to Improper Verification of Cryptographic Signature via the crypto/openpgp/clearsign/clearsign.go component. An attacker can spoof the 'Hash' Armor Header, leading a victim to believe the signature was generated using a different message digest algorithm than what was actually used. Moreover, the attacker can prepend arbitrary text to cleartext messages without invalidating the signatures.

    +

    Remediation

    +

    Upgrade golang.org/x/crypto/openpgp/clearsign to version 0.1.0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Memory Leak

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + glibc/libc-bin +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.6.15 and glibc/libc-bin@2.35-0ubuntu3.1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 + + glibc/libc-bin@2.35-0ubuntu3.1 + + + +
    • Introduced through: - helm.sh/helm/v3@* + docker-image|quay.io/argoproj/argocd@v2.6.15 - golang.org/x/crypto/openpgp/clearsign@v0.0.0-20220525230936-793ad666bf5e + glibc/libc6@2.35-0ubuntu3.1 @@ -1657,21 +2648,29 @@

      Detailed paths


      -

      Overview

      -

      Affected versions of this package are vulnerable to Improper Verification of Cryptographic Signature via the crypto/openpgp/clearsign/clearsign.go component. An attacker can spoof the 'Hash' Armor Header, leading a victim to believe the signature was generated using a different message digest algorithm than what was actually used. Moreover, the attacker can prepend arbitrary text to cleartext messages without invalidating the signatures.

      +

      NVD Description

      +

      Note: Versions mentioned in the description apply only to the upstream glibc package and not the glibc package as distributed by Ubuntu. + See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

      +

      A flaw was found in the GNU C Library. A recent fix for CVE-2023-4806 introduced the potential for a memory leak, which may result in an application crash.

      Remediation

      -

      Upgrade golang.org/x/crypto/openpgp/clearsign to version 0.1.0 or higher.

      +

      There is no fixed version for Ubuntu:22.04 glibc.

      References


    @@ -2401,14 +3400,257 @@

    Release of Invalid Pointer or Reference


    -

    Detailed paths

    +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 + + patch@2.7.6-7build2 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream patch package and not the patch package as distributed by Ubuntu:22.04. + See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    +

    An Invalid Pointer vulnerability exists in GNU patch 2.7 via the another_hunk function, which causes a Denial of Service.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 patch.

    +

    References

    + + +
    + + + +
    +
    +

    Double Free

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + patch +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.6.15 and patch@2.7.6-7build2 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 + + patch@2.7.6-7build2 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream patch package and not the patch package as distributed by Ubuntu:22.04. + See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    +

    A double free exists in the another_hunk function in pch.c in GNU patch through 2.7.6.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 patch.

    +

    References

    + + +
    + + + +
    +
    +

    Improper Authentication

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + openssl/libssl3 +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.6.15 and openssl/libssl3@3.0.2-0ubuntu1.10 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 + + openssl/libssl3@3.0.2-0ubuntu1.10 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 + + cyrus-sasl2/libsasl2-modules@2.1.27+dfsg2-3ubuntu1.2 + + openssl/libssl3@3.0.2-0ubuntu1.10 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 + + libfido2/libfido2-1@1.10.0-1 + + openssl/libssl3@3.0.2-0ubuntu1.10 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 + + openssh/openssh-client@1:8.9p1-3ubuntu0.3 + + openssl/libssl3@3.0.2-0ubuntu1.10 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 + + ca-certificates@20230311ubuntu0.22.04.1 + + openssl@3.0.2-0ubuntu1.10 + + openssl/libssl3@3.0.2-0ubuntu1.10 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.13 + + libssh/libssh-4@0.9.6-2ubuntu0.22.04.1 + + openssl/libssl3@3.0.2-0ubuntu1.10 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.1 + + pam/libpam-modules@1.4.0-11ubuntu2.3 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.2 + + krb5/libkrb5-3@1.19.2-2ubuntu0.2 + + openssl/libssl3@3.0.2-0ubuntu1.10 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 + + openssl@3.0.2-0ubuntu1.10 + + -
        +
      • Introduced through: docker-image|quay.io/argoproj/argocd@v2.6.15 - patch@2.7.6-7build2 + ca-certificates@20230311ubuntu0.22.04.1 + + openssl@3.0.2-0ubuntu1.10 @@ -2420,26 +3662,47 @@

        Detailed paths


        NVD Description

        -

        Note: Versions mentioned in the description apply only to the upstream patch package and not the patch package as distributed by Ubuntu:22.04. +

        Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Ubuntu. See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

        -

        An Invalid Pointer vulnerability exists in GNU patch 2.7 via the another_hunk function, which causes a Denial of Service.

        +

        Issue summary: The AES-SIV cipher implementation contains a bug that causes + it to ignore empty associated data entries which are unauthenticated as + a consequence.

        +

        Impact summary: Applications that use the AES-SIV algorithm and want to + authenticate empty data entries as associated data can be mislead by removing + adding or reordering such empty entries as these are ignored by the OpenSSL + implementation. We are currently unaware of any such applications.

        +

        The AES-SIV algorithm allows for authentication of multiple associated + data entries along with the encryption. To authenticate empty data the + application has to call EVP_EncryptUpdate() (or EVP_CipherUpdate()) with + NULL pointer as the output buffer and 0 as the input buffer length. + The AES-SIV implementation in OpenSSL just returns success for such a call + instead of performing the associated data authentication operation. + The empty data thus will not be authenticated.

        +

        As this issue does not affect non-empty associated data authentication and + we expect it to be rare for an application to use empty associated data + entries this is qualified as Low severity issue.

        Remediation

        -

        There is no fixed version for Ubuntu:22.04 patch.

        +

        Upgrade Ubuntu:22.04 openssl to version 3.0.2-0ubuntu1.12 or higher.

        References


    -

    Double Free

    +

    Inefficient Regular Expression Complexity

    @@ -2455,12 +3718,12 @@

    Double Free

  • Vulnerable module: - patch + openssl/libssl3
  • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.6.15 and patch@2.7.6-7build2 + docker-image|quay.io/argoproj/argocd@v2.6.15 and openssl/libssl3@3.0.2-0ubuntu1.10
  • @@ -2475,7 +3738,111 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@v2.6.15 - patch@2.7.6-7build2 + openssl/libssl3@3.0.2-0ubuntu1.10 + + + + +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 + + cyrus-sasl2/libsasl2-modules@2.1.27+dfsg2-3ubuntu1.2 + + openssl/libssl3@3.0.2-0ubuntu1.10 + + + +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 + + libfido2/libfido2-1@1.10.0-1 + + openssl/libssl3@3.0.2-0ubuntu1.10 + + + +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 + + openssh/openssh-client@1:8.9p1-3ubuntu0.3 + + openssl/libssl3@3.0.2-0ubuntu1.10 + + + +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 + + ca-certificates@20230311ubuntu0.22.04.1 + + openssl@3.0.2-0ubuntu1.10 + + openssl/libssl3@3.0.2-0ubuntu1.10 + + + +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.13 + + libssh/libssh-4@0.9.6-2ubuntu0.22.04.1 + + openssl/libssl3@3.0.2-0ubuntu1.10 + + + +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.1 + + pam/libpam-modules@1.4.0-11ubuntu2.3 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.2 + + krb5/libkrb5-3@1.19.2-2ubuntu0.2 + + openssl/libssl3@3.0.2-0ubuntu1.10 + + + +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 + + openssl@3.0.2-0ubuntu1.10 + + + +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 + + ca-certificates@20230311ubuntu0.22.04.1 + + openssl@3.0.2-0ubuntu1.10 @@ -2487,31 +3854,57 @@

    Detailed paths


    NVD Description

    -

    Note: Versions mentioned in the description apply only to the upstream patch package and not the patch package as distributed by Ubuntu:22.04. +

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Ubuntu. See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    -

    A double free exists in the another_hunk function in pch.c in GNU patch through 2.7.6.

    +

    Issue summary: Checking excessively long DH keys or parameters may be very slow.

    +

    Impact summary: Applications that use the functions DH_check(), DH_check_ex() + or EVP_PKEY_param_check() to check a DH key or DH parameters may experience long + delays. Where the key or parameters that are being checked have been obtained + from an untrusted source this may lead to a Denial of Service.

    +

    The function DH_check() performs various checks on DH parameters. One of those + checks confirms that the modulus ('p' parameter) is not too large. Trying to use + a very large modulus is slow and OpenSSL will not normally use a modulus which + is over 10,000 bits in length.

    +

    However the DH_check() function checks numerous aspects of the key or parameters + that have been supplied. Some of those checks use the supplied modulus value + even if it has already been found to be too large.

    +

    An application that calls DH_check() and supplies a key or parameters obtained + from an untrusted source could be vulernable to a Denial of Service attack.

    +

    The function DH_check() is itself called by a number of other OpenSSL functions. + An application calling any of those other functions may similarly be affected. + The other functions affected by this are DH_check_ex() and + EVP_PKEY_param_check().

    +

    Also vulnerable are the OpenSSL dhparam and pkeyparam command line applications + when using the '-check' option.

    +

    The OpenSSL SSL/TLS implementation is not affected by this issue. + The OpenSSL 3.0 and 3.1 FIPS providers are not affected by this issue.

    Remediation

    -

    There is no fixed version for Ubuntu:22.04 patch.

    +

    Upgrade Ubuntu:22.04 openssl to version 3.0.2-0ubuntu1.12 or higher.

    References


  • -

    Improper Authentication

    +

    Excessive Iteration

    @@ -2663,42 +4056,51 @@

    Detailed paths


    NVD Description

    -

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Ubuntu:22.04. +

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Ubuntu. See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    -

    Issue summary: The AES-SIV cipher implementation contains a bug that causes - it to ignore empty associated data entries which are unauthenticated as - a consequence.

    -

    Impact summary: Applications that use the AES-SIV algorithm and want to - authenticate empty data entries as associated data can be mislead by removing - adding or reordering such empty entries as these are ignored by the OpenSSL - implementation. We are currently unaware of any such applications.

    -

    The AES-SIV algorithm allows for authentication of multiple associated - data entries along with the encryption. To authenticate empty data the - application has to call EVP_EncryptUpdate() (or EVP_CipherUpdate()) with - NULL pointer as the output buffer and 0 as the input buffer length. - The AES-SIV implementation in OpenSSL just returns success for such a call - instead of performing the associated data authentication operation. - The empty data thus will not be authenticated.

    -

    As this issue does not affect non-empty associated data authentication and - we expect it to be rare for an application to use empty associated data - entries this is qualified as Low severity issue.

    +

    Issue summary: Checking excessively long DH keys or parameters may be very slow.

    +

    Impact summary: Applications that use the functions DH_check(), DH_check_ex() + or EVP_PKEY_param_check() to check a DH key or DH parameters may experience long + delays. Where the key or parameters that are being checked have been obtained + from an untrusted source this may lead to a Denial of Service.

    +

    The function DH_check() performs various checks on DH parameters. After fixing + CVE-2023-3446 it was discovered that a large q parameter value can also trigger + an overly long computation during some of these checks. A correct q value, + if present, cannot be larger than the modulus p parameter, thus it is + unnecessary to perform these checks if q is larger than p.

    +

    An application that calls DH_check() and supplies a key or parameters obtained + from an untrusted source could be vulnerable to a Denial of Service attack.

    +

    The function DH_check() is itself called by a number of other OpenSSL functions. + An application calling any of those other functions may similarly be affected. + The other functions affected by this are DH_check_ex() and + EVP_PKEY_param_check().

    +

    Also vulnerable are the OpenSSL dhparam and pkeyparam command line applications + when using the "-check" option.

    +

    The OpenSSL SSL/TLS implementation is not affected by this issue.

    +

    The OpenSSL 3.0 and 3.1 FIPS providers are not affected by this issue.

    Remediation

    -

    There is no fixed version for Ubuntu:22.04 openssl.

    +

    Upgrade Ubuntu:22.04 openssl to version 3.0.2-0ubuntu1.12 or higher.

    References


    @@ -3815,6 +5217,90 @@

    References

    More about this vulnerability

    +
    +
    +

    CVE-2023-38546

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + curl/libcurl3-gnutls +
    • + +
    • Introduced through: + + + docker-image|quay.io/argoproj/argocd@v2.6.15, git@1:2.34.1-1ubuntu1.10 and others +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.6.15 + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.13 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream curl package and not the curl package as distributed by Ubuntu. + See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    +

    This flaw allows an attacker to insert cookies at will into a running program + using libcurl, if the specific series of conditions are met.

    +

    libcurl performs transfers. In its API, an application creates "easy handles" + that are the individual handles for single transfers.

    +

    libcurl provides a function call that duplicates en easy handle called + curl_easy_duphandle.

    +

    If a transfer has cookies enabled when the handle is duplicated, the + cookie-enable state is also cloned - but without cloning the actual + cookies. If the source handle did not read any cookies from a specific file on + disk, the cloned version of the handle would instead store the file name as + none (using the four ASCII letters, no quotes).

    +

    Subsequent use of the cloned handle that does not explicitly set a source to + load cookies from would then inadvertently load cookies from a file named + none - if such a file exists and is readable in the current directory of the + program using libcurl. And if using the correct file format of course.

    +

    Remediation

    +

    Upgrade Ubuntu:22.04 curl to version 7.81.0-1ubuntu1.14 or higher.

    +

    References

    + + +
    + + +

    Improper Input Validation

    diff --git a/docs/snyk/v2.6.15/redis_7.0.11-alpine.html b/docs/snyk/v2.6.15/redis_7.0.11-alpine.html index ec20676ee2756..ef98cc541da29 100644 --- a/docs/snyk/v2.6.15/redis_7.0.11-alpine.html +++ b/docs/snyk/v2.6.15/redis_7.0.11-alpine.html @@ -7,7 +7,7 @@ Snyk test report - + @@ -456,7 +456,7 @@

    Snyk test report

    -

    September 17th 2023, 12:26:33 am (UTC+00:00)

    +

    October 29th 2023, 12:28:42 am (UTC+00:00)

    Scanned the following path: @@ -466,8 +466,8 @@

    Snyk test report

    -
    4 known vulnerabilities
    -
    32 vulnerable dependency paths
    +
    5 known vulnerabilities
    +
    41 vulnerable dependency paths
    18 dependencies
    @@ -905,7 +905,7 @@

    Detailed paths


    NVD Description

    -

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine:3.18. +

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine. See How to fix? for Alpine:3.18 relevant fixed versions and status.

    Issue summary: Checking excessively long DH keys or parameters may be very slow.

    Impact summary: Applications that use the functions DH_check(), DH_check_ex() @@ -1090,7 +1090,7 @@

    Detailed paths


    NVD Description

    -

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine:3.18. +

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine. See How to fix? for Alpine:3.18 relevant fixed versions and status.

    Issue summary: Checking excessively long DH keys or parameters may be very slow.

    Impact summary: Applications that use the functions DH_check(), DH_check_ex() @@ -1125,6 +1125,9 @@

    References

  • openssl-security@openssl.org
  • openssl-security@openssl.org
  • openssl-security@openssl.org
  • +
  • openssl-security@openssl.org
  • +
  • openssl-security@openssl.org
  • +
  • openssl-security@openssl.org

  • @@ -1134,6 +1137,196 @@

    References

    +
    +

    CVE-2023-5363

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Package Manager: alpine:3.18 +
    • +
    • + Vulnerable module: + + openssl/libcrypto3 +
    • + +
    • Introduced through: + + docker-image|redis@7.0.11-alpine and openssl/libcrypto3@3.1.1-r1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + .redis-rundeps@20230614.215749 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + busybox/ssl_client@1.36.1-r0 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + .redis-rundeps@20230614.215749 + + openssl/libssl3@3.1.1-r1 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + .redis-rundeps@20230614.215749 + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + busybox/ssl_client@1.36.1-r0 + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine. + See How to fix? for Alpine:3.18 relevant fixed versions and status.

    +

    Issue summary: A bug has been identified in the processing of key and + initialisation vector (IV) lengths. This can lead to potential truncation + or overruns during the initialisation of some symmetric ciphers.

    +

    Impact summary: A truncation in the IV can result in non-uniqueness, + which could result in loss of confidentiality for some cipher modes.

    +

    When calling EVP_EncryptInit_ex2(), EVP_DecryptInit_ex2() or + EVP_CipherInit_ex2() the provided OSSL_PARAM array is processed after + the key and IV have been established. Any alterations to the key length, + via the "keylen" parameter or the IV length, via the "ivlen" parameter, + within the OSSL_PARAM array will not take effect as intended, potentially + causing truncation or overreading of these values. The following ciphers + and cipher modes are impacted: RC2, RC4, RC5, CCM, GCM and OCB.

    +

    For the CCM, GCM and OCB cipher modes, truncation of the IV can result in + loss of confidentiality. For example, when following NIST's SP 800-38D + section 8.2.1 guidance for constructing a deterministic IV for AES in + GCM mode, truncation of the counter portion could lead to IV reuse.

    +

    Both truncations and overruns of the key and overruns of the IV will + produce incorrect results and could, in some cases, trigger a memory + exception. However, these issues are not currently assessed as security + critical.

    +

    Changing the key and/or IV lengths is not considered to be a common operation + and the vulnerable API was recently introduced. Furthermore it is likely that + application developers will have spotted this problem during testing since + decryption would fail unless both peers in the communication were similarly + vulnerable. For these reasons we expect the probability of an application being + vulnerable to this to be quite low. However if an application is vulnerable then + this issue is considered very serious. For these reasons we have assessed this + issue as Moderate severity overall.

    +

    The OpenSSL SSL/TLS implementation is not affected by this issue.

    +

    The OpenSSL 3.0 and 3.1 FIPS providers are not affected by this because + the issue lies outside of the FIPS provider boundary.

    +

    OpenSSL 3.1 and 3.0 are vulnerable to this issue.

    +

    Remediation

    +

    Upgrade Alpine:3.18 openssl to version 3.1.4-r0 or higher.

    +

    References

    + + +
    + + + +
    diff --git a/docs/snyk/v2.7.14/argocd-iac-install.html b/docs/snyk/v2.7.14/argocd-iac-install.html index d516c063c3ba8..602c76a57c103 100644 --- a/docs/snyk/v2.7.14/argocd-iac-install.html +++ b/docs/snyk/v2.7.14/argocd-iac-install.html @@ -456,7 +456,7 @@

    Snyk test report

    -

    September 17th 2023, 12:24:49 am (UTC+00:00)

    +

    October 29th 2023, 12:27:04 am (UTC+00:00)

    Scanned the following path: @@ -1514,14 +1514,14 @@

    Container is running without liveness probe

    spec - containers[dex] + initContainers[copyutil] livenessProbe
  • - Line number: 17118 + Line number: 17152
  • @@ -1566,14 +1566,14 @@

    Container is running without liveness probe

    spec - initContainers[copyutil] + containers[dex] livenessProbe
  • - Line number: 17152 + Line number: 17118
  • diff --git a/docs/snyk/v2.7.14/argocd-iac-namespace-install.html b/docs/snyk/v2.7.14/argocd-iac-namespace-install.html index 4ce19418dbe92..937ce3343905e 100644 --- a/docs/snyk/v2.7.14/argocd-iac-namespace-install.html +++ b/docs/snyk/v2.7.14/argocd-iac-namespace-install.html @@ -456,7 +456,7 @@

    Snyk test report

    -

    September 17th 2023, 12:25:03 am (UTC+00:00)

    +

    October 29th 2023, 12:27:17 am (UTC+00:00)

    Scanned the following path: @@ -1514,14 +1514,14 @@

    Container is running without liveness probe

    spec - containers[dex] + initContainers[copyutil] livenessProbe
  • - Line number: 778 + Line number: 812
  • @@ -1566,14 +1566,14 @@

    Container is running without liveness probe

    spec - initContainers[copyutil] + containers[dex] livenessProbe
  • - Line number: 812 + Line number: 778
  • diff --git a/docs/snyk/v2.7.14/argocd-test.html b/docs/snyk/v2.7.14/argocd-test.html index 950fd6562d51b..342599913dab0 100644 --- a/docs/snyk/v2.7.14/argocd-test.html +++ b/docs/snyk/v2.7.14/argocd-test.html @@ -7,7 +7,7 @@ Snyk test report - + @@ -456,7 +456,7 @@

    Snyk test report

    -

    September 17th 2023, 12:22:14 am (UTC+00:00)

    +

    October 29th 2023, 12:24:41 am (UTC+00:00)

    Scanned the following paths: @@ -466,8 +466,8 @@

    Snyk test report

    -
    7 known vulnerabilities
    -
    20 vulnerable dependency paths
    +
    9 known vulnerabilities
    +
    161 vulnerable dependency paths
    1748 dependencies
    @@ -627,6 +627,2699 @@

    References

    More about this vulnerability

    +
    +
    +

    Denial of Service (DoS)

    +
    + +
    + high severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + google.golang.org/grpc +
    • + +
    • Introduced through: + + github.com/argoproj/argo-cd/v2@0.0.0 and google.golang.org/grpc@1.51.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc@1.51.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/go-grpc-middleware@1.3.0 + + google.golang.org/grpc@1.51.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc/health@1.51.0 + + google.golang.org/grpc@1.51.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc/reflection@1.51.0 + + google.golang.org/grpc@1.51.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/go-grpc-middleware/auth@1.3.0 + + google.golang.org/grpc@1.51.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/go-grpc-middleware/retry@1.3.0 + + google.golang.org/grpc@1.51.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/go-grpc-prometheus@1.2.0 + + google.golang.org/grpc@1.51.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc/health/grpc_health_v1@1.51.0 + + google.golang.org/grpc@1.51.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus@1.3.0 + + google.golang.org/grpc@1.51.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/improbable-eng/grpc-web/go/grpcweb@#16092bd1d58a + + google.golang.org/grpc@1.51.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc@0.31.0 + + google.golang.org/grpc@1.51.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.11.1 + + google.golang.org/grpc@1.51.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/go-grpc-middleware/auth@1.3.0 + + github.com/grpc-ecosystem/go-grpc-middleware@1.3.0 + + google.golang.org/grpc@1.51.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.11.1 + + go.opentelemetry.io/otel/exporters/otlp/otlptrace/internal/otlpconfig@1.11.1 + + google.golang.org/grpc@1.51.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.11.1 + + go.opentelemetry.io/proto/otlp/collector/trace/v1@0.19.0 + + google.golang.org/grpc@1.51.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc/reflection@1.51.0 + + google.golang.org/grpc/reflection/grpc_reflection_v1alpha@1.51.0 + + google.golang.org/grpc@1.51.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc/health@1.51.0 + + google.golang.org/grpc/health/grpc_health_v1@1.51.0 + + google.golang.org/grpc@1.51.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus@1.3.0 + + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus@1.3.0 + + github.com/grpc-ecosystem/go-grpc-middleware/tags@1.3.0 + + google.golang.org/grpc@1.51.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/go-grpc-middleware/tags/logrus@1.3.0 + + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus@1.3.0 + + github.com/grpc-ecosystem/go-grpc-middleware/tags@1.3.0 + + google.golang.org/grpc@1.51.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus@1.3.0 + + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus@1.3.0 + + github.com/grpc-ecosystem/go-grpc-middleware/tags@1.3.0 + + github.com/grpc-ecosystem/go-grpc-middleware@1.3.0 + + google.golang.org/grpc@1.51.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/go-grpc-middleware/tags/logrus@1.3.0 + + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus@1.3.0 + + github.com/grpc-ecosystem/go-grpc-middleware/tags@1.3.0 + + github.com/grpc-ecosystem/go-grpc-middleware@1.3.0 + + google.golang.org/grpc@1.51.0 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    google.golang.org/grpc is a Go implementation of gRPC

    +

    Affected versions of this package are vulnerable to Denial of Service (DoS) in the implementation of the HTTP/2 protocol. An attacker can cause a denial of service (including via DDoS) by rapidly resetting many streams through request cancellation.

    +

    Remediation

    +

    Upgrade google.golang.org/grpc to version 1.56.3, 1.57.1, 1.58.3 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Denial of Service (DoS)

    +
    + +
    + high severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + golang.org/x/net/http2 +
    • + +
    • Introduced through: + + + github.com/argoproj/argo-cd/v2@0.0.0, k8s.io/apimachinery/pkg/util/net@0.24.2 and others +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/soheilhy/cmux@0.1.5 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/improbable-eng/grpc-web/go/grpcweb@#16092bd1d58a + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc@1.51.0 + + google.golang.org/grpc/internal/transport@1.51.0 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/tools/cache@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/transport/spdy@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/pkg/kubeclientmetrics@#a4dd357b057e + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/testing@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/dynamic@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/plugin/pkg/client/auth/azure@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/plugin/pkg/client/auth/gcp@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/plugin/pkg/client/auth/oidc@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/tools/record@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/rest@0.24.2 + + k8s.io/client-go/transport@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/go-grpc-middleware@1.3.0 + + google.golang.org/grpc@1.51.0 + + google.golang.org/grpc/internal/transport@1.51.0 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/go-grpc-middleware/auth@1.3.0 + + google.golang.org/grpc@1.51.0 + + google.golang.org/grpc/internal/transport@1.51.0 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/go-grpc-middleware/retry@1.3.0 + + google.golang.org/grpc@1.51.0 + + google.golang.org/grpc/internal/transport@1.51.0 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/go-grpc-prometheus@1.2.0 + + google.golang.org/grpc@1.51.0 + + google.golang.org/grpc/internal/transport@1.51.0 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc/health/grpc_health_v1@1.51.0 + + google.golang.org/grpc@1.51.0 + + google.golang.org/grpc/internal/transport@1.51.0 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc@0.31.0 + + google.golang.org/grpc@1.51.0 + + google.golang.org/grpc/internal/transport@1.51.0 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.11.1 + + google.golang.org/grpc@1.51.0 + + google.golang.org/grpc/internal/transport@1.51.0 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus@1.3.0 + + google.golang.org/grpc@1.51.0 + + google.golang.org/grpc/internal/transport@1.51.0 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/improbable-eng/grpc-web/go/grpcweb@#16092bd1d58a + + google.golang.org/grpc@1.51.0 + + google.golang.org/grpc/internal/transport@1.51.0 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/kubectl/pkg/util/openapi@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/listers/core/v1@0.24.2 + + k8s.io/client-go/tools/cache@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/informers@0.24.2 + + k8s.io/client-go/tools/cache@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/tools/clientcmd@0.24.2 + + k8s.io/client-go/tools/auth@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/controller@#f754726f03da + + k8s.io/client-go/tools/cache@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/discovery/fake@0.24.2 + + k8s.io/client-go/testing@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/kubernetes/fake@0.24.2 + + k8s.io/client-go/testing@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/tools/remotecommand@0.24.2 + + k8s.io/client-go/transport/spdy@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/api/rbac/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/pkg/apis/clientauthentication/v1beta1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/apimachinery/pkg/api/errors@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/sync/common@#ad9a694fe4bc + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/apimachinery/pkg/api/equality@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/transport/spdy@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + k8s.io/client-go/transport@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/pkg/kubeclientmetrics@#a4dd357b057e + + k8s.io/client-go/rest@0.24.2 + + k8s.io/client-go/transport@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/testing@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + k8s.io/client-go/transport@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/plugin/pkg/client/auth/azure@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + k8s.io/client-go/transport@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/plugin/pkg/client/auth/gcp@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + k8s.io/client-go/transport@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/plugin/pkg/client/auth/oidc@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + k8s.io/client-go/transport@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc/reflection@1.51.0 + + google.golang.org/grpc/reflection/grpc_reflection_v1alpha@1.51.0 + + google.golang.org/grpc@1.51.0 + + google.golang.org/grpc/internal/transport@1.51.0 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc/health@1.51.0 + + google.golang.org/grpc/health/grpc_health_v1@1.51.0 + + google.golang.org/grpc@1.51.0 + + google.golang.org/grpc/internal/transport@1.51.0 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/cache@#ad9a694fe4bc + + k8s.io/kubectl/pkg/util/openapi@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/sync@#ad9a694fe4bc + + k8s.io/kubectl/pkg/util/openapi@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/utils/kube@#ad9a694fe4bc + + k8s.io/kubectl/pkg/util/openapi@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/api@#f754726f03da + + k8s.io/client-go/listers/core/v1@0.24.2 + + k8s.io/client-go/tools/cache@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/informers/core/v1@0.24.2 + + k8s.io/client-go/listers/core/v1@0.24.2 + + k8s.io/client-go/tools/cache@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/cmd@#f754726f03da + + k8s.io/client-go/tools/clientcmd@0.24.2 + + k8s.io/client-go/tools/auth@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/kubectl/pkg/util/term@0.24.2 + + k8s.io/client-go/tools/remotecommand@0.24.2 + + k8s.io/client-go/transport/spdy@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/kubectl/pkg/util/resource@0.24.2 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/health@#ad9a694fe4bc + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/sync/resource@#ad9a694fe4bc + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/dynamic@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/sync/ignore@#ad9a694fe4bc + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/sync/syncwaves@#ad9a694fe4bc + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/utils/testing@#ad9a694fe4bc + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/apimachinery/pkg/util/managedfields@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/tools/cache@0.24.2 + + k8s.io/client-go/tools/pager@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/scheme@0.11.0 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/util/retry@0.24.2 + + k8s.io/apimachinery/pkg/api/errors@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/tools/portforward@0.24.2 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1@0.24.2 + + k8s.io/apimachinery/pkg/api/equality@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/apimachinery/pkg/api/validation@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1/validation@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/discovery/fake@0.24.2 + + k8s.io/client-go/testing@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + k8s.io/client-go/transport@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/kubernetes/fake@0.24.2 + + k8s.io/client-go/testing@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + k8s.io/client-go/transport@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/tools/remotecommand@0.24.2 + + k8s.io/client-go/transport/spdy@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + k8s.io/client-go/transport@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/health@#ad9a694fe4bc + + github.com/argoproj/gitops-engine/pkg/utils/kube@#ad9a694fe4bc + + k8s.io/kubectl/pkg/util/openapi@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/sync/common@#ad9a694fe4bc + + github.com/argoproj/gitops-engine/pkg/utils/kube@#ad9a694fe4bc + + k8s.io/kubectl/pkg/util/openapi@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/controller/controllerutil@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/client/apiutil@0.11.0 + + k8s.io/client-go/restmapper@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/manager@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/recorder@0.11.0 + + k8s.io/client-go/tools/record@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/envtest@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane@0.11.0 + + k8s.io/client-go/tools/clientcmd@0.24.2 + + k8s.io/client-go/tools/auth@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/kubernetes/scheme@0.24.2 + + k8s.io/api/storage/v1beta1@0.24.2 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/tools/record@0.24.2 + + k8s.io/client-go/tools/reference@0.24.2 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/sync/hook@#ad9a694fe4bc + + github.com/argoproj/gitops-engine/pkg/sync/resource@#ad9a694fe4bc + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/apimachinery/pkg/runtime/serializer@0.24.2 + + k8s.io/apimachinery/pkg/runtime/serializer/versioning@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/listers/core/v1@0.24.2 + + k8s.io/client-go/tools/cache@0.24.2 + + k8s.io/client-go/tools/pager@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/informers@0.24.2 + + k8s.io/client-go/tools/cache@0.24.2 + + k8s.io/client-go/tools/pager@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/controller@#f754726f03da + + k8s.io/client-go/tools/cache@0.24.2 + + k8s.io/client-go/tools/pager@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/utils/kube/scheme@#ad9a694fe4bc + + k8s.io/apimachinery/pkg/util/managedfields@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/kubectl/pkg/util/term@0.24.2 + + k8s.io/client-go/tools/remotecommand@0.24.2 + + k8s.io/client-go/transport/spdy@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + k8s.io/client-go/transport@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/go-grpc-middleware/tags/logrus@1.3.0 + + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus@1.3.0 + + github.com/grpc-ecosystem/go-grpc-middleware/tags@1.3.0 + + github.com/grpc-ecosystem/go-grpc-middleware@1.3.0 + + google.golang.org/grpc@1.51.0 + + google.golang.org/grpc/internal/transport@1.51.0 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/client@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/internal/objectutil@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/client/apiutil@0.11.0 + + k8s.io/client-go/restmapper@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/cache@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/internal/objectutil@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/client/apiutil@0.11.0 + + k8s.io/client-go/restmapper@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/kubernetes@0.24.2 + + k8s.io/client-go/kubernetes/typed/storage/v1beta1@0.24.2 + + k8s.io/client-go/applyconfigurations/storage/v1beta1@0.24.2 + + k8s.io/client-go/applyconfigurations/meta/v1@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/builder@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/webhook/admission@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/webhook/internal/metrics@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/metrics@0.11.0 + + k8s.io/client-go/tools/cache@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/kubernetes/scheme@0.24.2 + + k8s.io/api/storage/v1beta1@0.24.2 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/tools/clientcmd@0.24.2 + + k8s.io/client-go/tools/clientcmd/api/latest@0.24.2 + + k8s.io/apimachinery/pkg/runtime/serializer/versioning@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/api@#f754726f03da + + k8s.io/client-go/listers/core/v1@0.24.2 + + k8s.io/client-go/tools/cache@0.24.2 + + k8s.io/client-go/tools/pager@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/informers/core/v1@0.24.2 + + k8s.io/client-go/listers/core/v1@0.24.2 + + k8s.io/client-go/tools/cache@0.24.2 + + k8s.io/client-go/tools/pager@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/diff@#ad9a694fe4bc + + github.com/argoproj/gitops-engine/pkg/utils/kube/scheme@#ad9a694fe4bc + + k8s.io/apimachinery/pkg/util/managedfields@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/sync/hook@#ad9a694fe4bc + + github.com/argoproj/gitops-engine/pkg/sync/hook/helm@#ad9a694fe4bc + + github.com/argoproj/gitops-engine/pkg/sync/common@#ad9a694fe4bc + + github.com/argoproj/gitops-engine/pkg/utils/kube@#ad9a694fe4bc + + k8s.io/kubectl/pkg/util/openapi@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/sync/syncwaves@#ad9a694fe4bc + + github.com/argoproj/gitops-engine/pkg/sync/hook/helm@#ad9a694fe4bc + + github.com/argoproj/gitops-engine/pkg/sync/common@#ad9a694fe4bc + + github.com/argoproj/gitops-engine/pkg/utils/kube@#ad9a694fe4bc + + k8s.io/kubectl/pkg/util/openapi@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/event@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/client@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/internal/objectutil@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/client/apiutil@0.11.0 + + k8s.io/client-go/restmapper@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/kubectl/pkg/util/openapi@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/kubernetes/scheme@0.24.2 + + k8s.io/api/storage/v1beta1@0.24.2 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/kubernetes@0.24.2 + + k8s.io/client-go/kubernetes/typed/storage/v1beta1@0.24.2 + + k8s.io/client-go/kubernetes/scheme@0.24.2 + + k8s.io/api/storage/v1beta1@0.24.2 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/builder@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/webhook/conversion@0.11.0 + + k8s.io/apimachinery/pkg/runtime/serializer@0.24.2 + + k8s.io/apimachinery/pkg/runtime/serializer/versioning@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/envtest@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/webhook/conversion@0.11.0 + + k8s.io/apimachinery/pkg/runtime/serializer@0.24.2 + + k8s.io/apimachinery/pkg/runtime/serializer/versioning@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/cmd@#f754726f03da + + k8s.io/client-go/tools/clientcmd@0.24.2 + + k8s.io/client-go/tools/clientcmd/api/latest@0.24.2 + + k8s.io/apimachinery/pkg/runtime/serializer/versioning@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/sync/ignore@#ad9a694fe4bc + + github.com/argoproj/gitops-engine/pkg/sync/hook@#ad9a694fe4bc + + github.com/argoproj/gitops-engine/pkg/sync/hook/helm@#ad9a694fe4bc + + github.com/argoproj/gitops-engine/pkg/sync/common@#ad9a694fe4bc + + github.com/argoproj/gitops-engine/pkg/utils/kube@#ad9a694fe4bc + + k8s.io/kubectl/pkg/util/openapi@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/predicate@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/event@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/client@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/internal/objectutil@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/client/apiutil@0.11.0 + + k8s.io/client-go/restmapper@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/handler@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/runtime/inject@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/cache@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/internal/objectutil@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/client/apiutil@0.11.0 + + k8s.io/client-go/restmapper@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/cache@#ad9a694fe4bc + + k8s.io/kubectl/pkg/util/openapi@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/kubernetes/scheme@0.24.2 + + k8s.io/api/storage/v1beta1@0.24.2 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/sync@#ad9a694fe4bc + + k8s.io/kubectl/pkg/util/openapi@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/kubernetes/scheme@0.24.2 + + k8s.io/api/storage/v1beta1@0.24.2 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/utils/kube@#ad9a694fe4bc + + k8s.io/kubectl/pkg/util/openapi@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/kubernetes/scheme@0.24.2 + + k8s.io/api/storage/v1beta1@0.24.2 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/controller/controllerutil@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/client/apiutil@0.11.0 + + k8s.io/client-go/restmapper@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/kubernetes/scheme@0.24.2 + + k8s.io/api/storage/v1beta1@0.24.2 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/source@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/source/internal@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/predicate@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/event@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/client@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/internal/objectutil@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/client/apiutil@0.11.0 + + k8s.io/client-go/restmapper@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/client@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/internal/objectutil@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/client/apiutil@0.11.0 + + k8s.io/client-go/restmapper@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/kubernetes/scheme@0.24.2 + + k8s.io/api/storage/v1beta1@0.24.2 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/cache@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/internal/objectutil@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/client/apiutil@0.11.0 + + k8s.io/client-go/restmapper@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/kubernetes/scheme@0.24.2 + + k8s.io/api/storage/v1beta1@0.24.2 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/event@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/client@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/internal/objectutil@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/client/apiutil@0.11.0 + + k8s.io/client-go/restmapper@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/kubernetes/scheme@0.24.2 + + k8s.io/api/storage/v1beta1@0.24.2 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/predicate@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/event@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/client@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/internal/objectutil@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/client/apiutil@0.11.0 + + k8s.io/client-go/restmapper@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/kubernetes/scheme@0.24.2 + + k8s.io/api/storage/v1beta1@0.24.2 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/handler@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/runtime/inject@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/cache@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/internal/objectutil@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/client/apiutil@0.11.0 + + k8s.io/client-go/restmapper@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/kubernetes/scheme@0.24.2 + + k8s.io/api/storage/v1beta1@0.24.2 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/source@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/source/internal@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/predicate@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/event@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/client@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/internal/objectutil@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/client/apiutil@0.11.0 + + k8s.io/client-go/restmapper@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/kubernetes/scheme@0.24.2 + + k8s.io/api/storage/v1beta1@0.24.2 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.11.0 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    golang.org/x/net/http2 is a work-in-progress HTTP/2 implementation for Go.

    +

    Affected versions of this package are vulnerable to Denial of Service (DoS) in the implementation of the HTTP/2 protocol. An attacker can cause a denial of service (including via DDoS) by rapidly resetting many streams through request cancellation.

    +

    Remediation

    +

    Upgrade golang.org/x/net/http2 to version 0.17.0 or higher.

    +

    References

    + + +
    + + +

    Directory Traversal

    diff --git a/docs/snyk/v2.7.14/ghcr.io_dexidp_dex_v2.37.0.html b/docs/snyk/v2.7.14/ghcr.io_dexidp_dex_v2.37.0.html index 4f8d2c4e4b4b7..57ebb7d952e52 100644 --- a/docs/snyk/v2.7.14/ghcr.io_dexidp_dex_v2.37.0.html +++ b/docs/snyk/v2.7.14/ghcr.io_dexidp_dex_v2.37.0.html @@ -7,7 +7,7 @@ Snyk test report - + @@ -456,7 +456,7 @@

    Snyk test report

    -

    September 17th 2023, 12:22:25 am (UTC+00:00)

    +

    October 29th 2023, 12:24:54 am (UTC+00:00)

    Scanned the following paths: @@ -466,8 +466,8 @@

    Snyk test report

    -
    25 known vulnerabilities
    -
    68 vulnerable dependency paths
    +
    28 known vulnerabilities
    +
    79 vulnerable dependency paths
    786 dependencies
    @@ -583,6 +583,178 @@

    References

    More about this vulnerability

    +
    +
    +

    Denial of Service (DoS)

    +
    + +
    + high severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + google.golang.org/grpc +
    • + +
    • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and google.golang.org/grpc@v1.46.2 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + google.golang.org/grpc@v1.46.2 + + + +
    • +
    • + Introduced through: + github.com/dexidp/dex@* + + google.golang.org/grpc@v1.56.1 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    google.golang.org/grpc is a Go implementation of gRPC

    +

    Affected versions of this package are vulnerable to Denial of Service (DoS) in the implementation of the HTTP/2 protocol. An attacker can cause a denial of service (including via DDoS) by rapidly resetting many streams through request cancellation.

    +

    Remediation

    +

    Upgrade google.golang.org/grpc to version 1.56.3, 1.57.1, 1.58.3 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Denial of Service (DoS)

    +
    + +
    + high severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + golang.org/x/net/http2 +
    • + +
    • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and golang.org/x/net/http2@v0.7.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + golang.org/x/net/http2@v0.7.0 + + + +
    • +
    • + Introduced through: + github.com/dexidp/dex@* + + golang.org/x/net/http2@v0.11.0 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    golang.org/x/net/http2 is a work-in-progress HTTP/2 implementation for Go.

    +

    Affected versions of this package are vulnerable to Denial of Service (DoS) in the implementation of the HTTP/2 protocol. An attacker can cause a denial of service (including via DDoS) by rapidly resetting many streams through request cancellation.

    +

    Remediation

    +

    Upgrade golang.org/x/net/http2 to version 0.17.0 or higher.

    +

    References

    + + +
    + + +

    Improper Authentication

    @@ -852,7 +1024,7 @@

    Detailed paths


    NVD Description

    -

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine:3.18. +

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine. See How to fix? for Alpine:3.18 relevant fixed versions and status.

    Issue summary: Checking excessively long DH keys or parameters may be very slow.

    Impact summary: Applications that use the functions DH_check(), DH_check_ex() @@ -1015,7 +1187,7 @@

    Detailed paths


    NVD Description

    -

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine:3.18. +

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine. See How to fix? for Alpine:3.18 relevant fixed versions and status.

    Issue summary: Checking excessively long DH keys or parameters may be very slow.

    Impact summary: Applications that use the functions DH_check(), DH_check_ex() @@ -1050,6 +1222,9 @@

    References

  • openssl-security@openssl.org
  • openssl-security@openssl.org
  • openssl-security@openssl.org
  • +
  • openssl-security@openssl.org
  • +
  • openssl-security@openssl.org
  • +
  • openssl-security@openssl.org

  • @@ -2511,6 +2686,174 @@

    Detailed paths

    +
    +

    CVE-2023-5363

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Package Manager: alpine:3.18 +
    • +
    • + Vulnerable module: + + openssl/libcrypto3 +
    • + +
    • Introduced through: + + docker-image|ghcr.io/dexidp/dex@v2.37.0 and openssl/libcrypto3@3.1.1-r1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + busybox/ssl_client@1.36.1-r0 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libssl3@3.1.1-r1 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + busybox/ssl_client@1.36.1-r0 + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine. + See How to fix? for Alpine:3.18 relevant fixed versions and status.

    +

    Issue summary: A bug has been identified in the processing of key and + initialisation vector (IV) lengths. This can lead to potential truncation + or overruns during the initialisation of some symmetric ciphers.

    +

    Impact summary: A truncation in the IV can result in non-uniqueness, + which could result in loss of confidentiality for some cipher modes.

    +

    When calling EVP_EncryptInit_ex2(), EVP_DecryptInit_ex2() or + EVP_CipherInit_ex2() the provided OSSL_PARAM array is processed after + the key and IV have been established. Any alterations to the key length, + via the "keylen" parameter or the IV length, via the "ivlen" parameter, + within the OSSL_PARAM array will not take effect as intended, potentially + causing truncation or overreading of these values. The following ciphers + and cipher modes are impacted: RC2, RC4, RC5, CCM, GCM and OCB.

    +

    For the CCM, GCM and OCB cipher modes, truncation of the IV can result in + loss of confidentiality. For example, when following NIST's SP 800-38D + section 8.2.1 guidance for constructing a deterministic IV for AES in + GCM mode, truncation of the counter portion could lead to IV reuse.

    +

    Both truncations and overruns of the key and overruns of the IV will + produce incorrect results and could, in some cases, trigger a memory + exception. However, these issues are not currently assessed as security + critical.

    +

    Changing the key and/or IV lengths is not considered to be a common operation + and the vulnerable API was recently introduced. Furthermore it is likely that + application developers will have spotted this problem during testing since + decryption would fail unless both peers in the communication were similarly + vulnerable. For these reasons we expect the probability of an application being + vulnerable to this to be quite low. However if an application is vulnerable then + this issue is considered very serious. For these reasons we have assessed this + issue as Moderate severity overall.

    +

    The OpenSSL SSL/TLS implementation is not affected by this issue.

    +

    The OpenSSL 3.0 and 3.1 FIPS providers are not affected by this because + the issue lies outside of the FIPS provider boundary.

    +

    OpenSSL 3.1 and 3.0 are vulnerable to this issue.

    +

    Remediation

    +

    Upgrade Alpine:3.18 openssl to version 3.1.4-r0 or higher.

    +

    References

    + + +
    + + + +
    diff --git a/docs/snyk/v2.7.14/haproxy_2.6.14-alpine.html b/docs/snyk/v2.7.14/haproxy_2.6.14-alpine.html index 09342f7d6f484..953bbbe0d1e05 100644 --- a/docs/snyk/v2.7.14/haproxy_2.6.14-alpine.html +++ b/docs/snyk/v2.7.14/haproxy_2.6.14-alpine.html @@ -7,7 +7,7 @@ Snyk test report - + @@ -456,7 +456,7 @@

    Snyk test report

    -

    September 17th 2023, 12:22:31 am (UTC+00:00)

    +

    October 29th 2023, 12:24:59 am (UTC+00:00)

    Scanned the following path: @@ -466,8 +466,8 @@

    Snyk test report

    -
    0 known vulnerabilities
    -
    0 vulnerable dependency paths
    +
    1 known vulnerabilities
    +
    9 vulnerable dependency paths
    18 dependencies
    @@ -484,7 +484,198 @@

    Snyk test report

    - No known vulnerabilities detected. +
    +
    +

    CVE-2023-5363

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Package Manager: alpine:3.18 +
    • +
    • + Vulnerable module: + + openssl/libcrypto3 +
    • + +
    • Introduced through: + + docker-image|haproxy@2.6.14-alpine and openssl/libcrypto3@3.1.2-r0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|haproxy@2.6.14-alpine + + openssl/libcrypto3@3.1.2-r0 + + + +
    • +
    • + Introduced through: + docker-image|haproxy@2.6.14-alpine + + .haproxy-rundeps@20230809.001942 + + openssl/libcrypto3@3.1.2-r0 + + + +
    • +
    • + Introduced through: + docker-image|haproxy@2.6.14-alpine + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libcrypto3@3.1.2-r0 + + + +
    • +
    • + Introduced through: + docker-image|haproxy@2.6.14-alpine + + busybox/ssl_client@1.36.1-r2 + + openssl/libcrypto3@3.1.2-r0 + + + +
    • +
    • + Introduced through: + docker-image|haproxy@2.6.14-alpine + + .haproxy-rundeps@20230809.001942 + + openssl/libssl3@3.1.2-r0 + + openssl/libcrypto3@3.1.2-r0 + + + +
    • +
    • + Introduced through: + docker-image|haproxy@2.6.14-alpine + + openssl/libssl3@3.1.2-r0 + + + +
    • +
    • + Introduced through: + docker-image|haproxy@2.6.14-alpine + + .haproxy-rundeps@20230809.001942 + + openssl/libssl3@3.1.2-r0 + + + +
    • +
    • + Introduced through: + docker-image|haproxy@2.6.14-alpine + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libssl3@3.1.2-r0 + + + +
    • +
    • + Introduced through: + docker-image|haproxy@2.6.14-alpine + + busybox/ssl_client@1.36.1-r2 + + openssl/libssl3@3.1.2-r0 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine. + See How to fix? for Alpine:3.18 relevant fixed versions and status.

    +

    Issue summary: A bug has been identified in the processing of key and + initialisation vector (IV) lengths. This can lead to potential truncation + or overruns during the initialisation of some symmetric ciphers.

    +

    Impact summary: A truncation in the IV can result in non-uniqueness, + which could result in loss of confidentiality for some cipher modes.

    +

    When calling EVP_EncryptInit_ex2(), EVP_DecryptInit_ex2() or + EVP_CipherInit_ex2() the provided OSSL_PARAM array is processed after + the key and IV have been established. Any alterations to the key length, + via the "keylen" parameter or the IV length, via the "ivlen" parameter, + within the OSSL_PARAM array will not take effect as intended, potentially + causing truncation or overreading of these values. The following ciphers + and cipher modes are impacted: RC2, RC4, RC5, CCM, GCM and OCB.

    +

    For the CCM, GCM and OCB cipher modes, truncation of the IV can result in + loss of confidentiality. For example, when following NIST's SP 800-38D + section 8.2.1 guidance for constructing a deterministic IV for AES in + GCM mode, truncation of the counter portion could lead to IV reuse.

    +

    Both truncations and overruns of the key and overruns of the IV will + produce incorrect results and could, in some cases, trigger a memory + exception. However, these issues are not currently assessed as security + critical.

    +

    Changing the key and/or IV lengths is not considered to be a common operation + and the vulnerable API was recently introduced. Furthermore it is likely that + application developers will have spotted this problem during testing since + decryption would fail unless both peers in the communication were similarly + vulnerable. For these reasons we expect the probability of an application being + vulnerable to this to be quite low. However if an application is vulnerable then + this issue is considered very serious. For these reasons we have assessed this + issue as Moderate severity overall.

    +

    The OpenSSL SSL/TLS implementation is not affected by this issue.

    +

    The OpenSSL 3.0 and 3.1 FIPS providers are not affected by this because + the issue lies outside of the FIPS provider boundary.

    +

    OpenSSL 3.1 and 3.0 are vulnerable to this issue.

    +

    Remediation

    +

    Upgrade Alpine:3.18 openssl to version 3.1.4-r0 or higher.

    +

    References

    + + +
    + + + +
    +
    diff --git a/docs/snyk/v2.7.14/quay.io_argoproj_argocd_v2.7.14.html b/docs/snyk/v2.7.14/quay.io_argoproj_argocd_v2.7.14.html index 4c1cb8f1d8e16..5b4ea7a6ff4d0 100644 --- a/docs/snyk/v2.7.14/quay.io_argoproj_argocd_v2.7.14.html +++ b/docs/snyk/v2.7.14/quay.io_argoproj_argocd_v2.7.14.html @@ -7,7 +7,7 @@ Snyk test report - + @@ -456,7 +456,7 @@

    Snyk test report

    -

    September 17th 2023, 12:22:58 am (UTC+00:00)

    +

    October 29th 2023, 12:25:22 am (UTC+00:00)

    Scanned the following paths: @@ -466,8 +466,8 @@

    Snyk test report

    -
    29 known vulnerabilities
    -
    105 vulnerable dependency paths
    +
    41 known vulnerabilities
    +
    159 vulnerable dependency paths
    2065 dependencies
    @@ -476,6 +476,83 @@

    Snyk test report

    +
    +

    Denial of Service (DoS)

    +
    + +
    + high severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + google.golang.org/grpc +
    • + +
    • Introduced through: + + github.com/argoproj/argo-cd/v2@* and google.golang.org/grpc@v1.51.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@* + + google.golang.org/grpc@v1.51.0 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    google.golang.org/grpc is a Go implementation of gRPC

    +

    Affected versions of this package are vulnerable to Denial of Service (DoS) in the implementation of the HTTP/2 protocol. An attacker can cause a denial of service (including via DDoS) by rapidly resetting many streams through request cancellation.

    +

    Remediation

    +

    Upgrade google.golang.org/grpc to version 1.56.3, 1.57.1, 1.58.3 or higher.

    +

    References

    + + +
    + + + +

    Denial of Service (DoS)

    @@ -554,6 +631,92 @@

    References

    More about this vulnerability

    +
    +
    +

    Denial of Service (DoS)

    +
    + +
    + high severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + golang.org/x/net/http2 +
    • + +
    • Introduced through: + + github.com/argoproj/argo-cd/v2@* and golang.org/x/net/http2@v0.11.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@* + + golang.org/x/net/http2@v0.11.0 + + + +
    • +
    • + Introduced through: + helm.sh/helm/v3@* + + golang.org/x/net/http2@v0.5.0 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    golang.org/x/net/http2 is a work-in-progress HTTP/2 implementation for Go.

    +

    Affected versions of this package are vulnerable to Denial of Service (DoS) in the implementation of the HTTP/2 protocol. An attacker can cause a denial of service (including via DDoS) by rapidly resetting many streams through request cancellation.

    +

    Remediation

    +

    Upgrade golang.org/x/net/http2 to version 0.17.0 or higher.

    +

    References

    + + +
    + + +

    Denial of Service (DoS)

    @@ -619,45 +782,722 @@

    Details

    Remediation

    -

    Upgrade golang.org/x/net/http2 to version 0.7.0 or higher.

    +

    Upgrade golang.org/x/net/http2 to version 0.7.0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Out-of-bounds Write

    +
    + +
    + high severity +
    + +
    + +
      +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + glibc/libc-bin +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.7.14 and glibc/libc-bin@2.35-0ubuntu3.1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 + + glibc/libc-bin@2.35-0ubuntu3.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 + + glibc/libc6@2.35-0ubuntu3.1 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream glibc package and not the glibc package as distributed by Ubuntu. + See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    +

    A buffer overflow was discovered in the GNU C Library's dynamic loader ld.so while processing the GLIBC_TUNABLES environment variable. This issue could allow a local attacker to use maliciously crafted GLIBC_TUNABLES environment variables when launching binaries with SUID permission to execute code with elevated privileges.

    +

    Remediation

    +

    Upgrade Ubuntu:22.04 glibc to version 2.35-0ubuntu3.4 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Directory Traversal

    +
    + +
    + high severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + github.com/cyphar/filepath-securejoin +
    • + +
    • Introduced through: + + github.com/argoproj/argo-cd/v2@* and github.com/cyphar/filepath-securejoin@v0.2.3 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@* + + github.com/cyphar/filepath-securejoin@v0.2.3 + + + +
    • +
    • + Introduced through: + helm.sh/helm/v3@* + + github.com/cyphar/filepath-securejoin@v0.2.3 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    Affected versions of this package are vulnerable to Directory Traversal via the filepath.FromSlash() function, allwoing attackers to generate paths that were outside of the provided rootfs.

    +

    Note: + This vulnerability is only exploitable on Windows OS.

    +

    Details

    +

    A Directory Traversal attack (also known as path traversal) aims to access files and directories that are stored outside the intended folder. By manipulating files with "dot-dot-slash (../)" sequences and its variations, or by using absolute file paths, it may be possible to access arbitrary files and directories stored on file system, including application source code, configuration, and other critical system files.

    +

    Directory Traversal vulnerabilities can be generally divided into two types:

    +
      +
    • Information Disclosure: Allows the attacker to gain information about the folder structure or read the contents of sensitive files on the system.
    • +
    +

    st is a module for serving static files on web pages, and contains a vulnerability of this type. In our example, we will serve files from the public route.

    +

    If an attacker requests the following URL from our server, it will in turn leak the sensitive private key of the root user.

    +
    curl http://localhost:8080/public/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/root/.ssh/id_rsa
    +        
    +

    Note %2e is the URL encoded version of . (dot).

    +
      +
    • Writing arbitrary files: Allows the attacker to create or replace existing files. This type of vulnerability is also known as Zip-Slip.
    • +
    +

    One way to achieve this is by using a malicious zip archive that holds path traversal filenames. When each filename in the zip archive gets concatenated to the target extraction folder, without validation, the final path ends up outside of the target folder. If an executable or a configuration file is overwritten with a file containing malicious code, the problem can turn into an arbitrary code execution issue quite easily.

    +

    The following is an example of a zip archive with one benign file and one malicious file. Extracting the malicious file will result in traversing out of the target folder, ending up in /root/.ssh/ overwriting the authorized_keys file:

    +
    2018-04-15 22:04:29 .....           19           19  good.txt
    +        2018-04-15 22:04:42 .....           20           20  ../../../../../../root/.ssh/authorized_keys
    +        
    +

    Remediation

    +

    Upgrade github.com/cyphar/filepath-securejoin to version 0.2.4 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Out-of-bounds Write

    +
    + +
    + high severity +
    + +
    + +
      +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + curl/libcurl3-gnutls +
    • + +
    • Introduced through: + + + docker-image|quay.io/argoproj/argocd@v2.7.14, git@1:2.34.1-1ubuntu1.10 and others +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.13 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream curl package and not the curl package as distributed by Ubuntu. + See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    +

    This flaw makes curl overflow a heap based buffer in the SOCKS5 proxy + handshake.

    +

    When curl is asked to pass along the host name to the SOCKS5 proxy to allow + that to resolve the address instead of it getting done by curl itself, the + maximum length that host name can be is 255 bytes.

    +

    If the host name is detected to be longer, curl switches to local name + resolving and instead passes on the resolved address only. Due to this bug, + the local variable that means "let the host resolve the name" could get the + wrong value during a slow SOCKS5 handshake, and contrary to the intention, + copy the too long host name to the target buffer instead of copying just the + resolved address there.

    +

    The target buffer being a heap based buffer, and the host name coming from the + URL that curl has been told to operate with.

    +

    Remediation

    +

    Upgrade Ubuntu:22.04 curl to version 7.81.0-1ubuntu1.14 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    CVE-2020-22916

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + xz-utils/liblzma5 +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.7.14 and xz-utils/liblzma5@5.2.5-2ubuntu1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 + + xz-utils/liblzma5@5.2.5-2ubuntu1 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream xz-utils package and not the xz-utils package as distributed by Ubuntu. + See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    +

    ** DISPUTED ** An issue discovered in XZ 5.2.5 allows attackers to cause a denial of service via decompression of a crafted file. NOTE: the vendor disputes the claims of "endless output" and "denial of service" because decompression of the 17,486 bytes always results in 114,881,179 bytes, which is often a reasonable size increase.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 xz-utils.

    +

    References

    + + +
    + + + +
    +
    +

    Out-of-bounds Write

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + perl/perl-modules-5.34 +
    • + +
    • Introduced through: + + + docker-image|quay.io/argoproj/argocd@v2.7.14, git@1:2.34.1-1ubuntu1.10 and others +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 + + git@1:2.34.1-1ubuntu1.10 + + perl@5.34.0-3ubuntu1.2 + + perl/perl-modules-5.34@5.34.0-3ubuntu1.2 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 + + git@1:2.34.1-1ubuntu1.10 + + perl@5.34.0-3ubuntu1.2 + + perl/libperl5.34@5.34.0-3ubuntu1.2 + + perl/perl-modules-5.34@5.34.0-3ubuntu1.2 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 + + git@1:2.34.1-1ubuntu1.10 + + perl@5.34.0-3ubuntu1.2 + + perl/libperl5.34@5.34.0-3ubuntu1.2 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 + + git@1:2.34.1-1ubuntu1.10 + + perl@5.34.0-3ubuntu1.2 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 + + perl/perl-base@5.34.0-3ubuntu1.2 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream perl package and not the perl package as distributed by Ubuntu. + See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    +

    In Perl 5.34.0, function S_find_uninit_var in sv.c has a stack-based crash that can lead to remote code execution or local privilege escalation.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 perl.

    +

    References

    + + +
    + + + +
    +
    +

    CVE-2023-5363

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + openssl/libssl3 +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.7.14 and openssl/libssl3@3.0.2-0ubuntu1.10 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 + + openssl/libssl3@3.0.2-0ubuntu1.10 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 + + cyrus-sasl2/libsasl2-modules@2.1.27+dfsg2-3ubuntu1.2 + + openssl/libssl3@3.0.2-0ubuntu1.10 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 + + libfido2/libfido2-1@1.10.0-1 + + openssl/libssl3@3.0.2-0ubuntu1.10 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 + + openssh/openssh-client@1:8.9p1-3ubuntu0.3 + + openssl/libssl3@3.0.2-0ubuntu1.10 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 + + ca-certificates@20230311ubuntu0.22.04.1 + + openssl@3.0.2-0ubuntu1.10 + + openssl/libssl3@3.0.2-0ubuntu1.10 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.13 + + libssh/libssh-4@0.9.6-2ubuntu0.22.04.1 + + openssl/libssl3@3.0.2-0ubuntu1.10 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.1 + + pam/libpam-modules@1.4.0-11ubuntu2.3 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.2 + + krb5/libkrb5-3@1.19.2-2ubuntu0.2 + + openssl/libssl3@3.0.2-0ubuntu1.10 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 + + openssl@3.0.2-0ubuntu1.10 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 + + ca-certificates@20230311ubuntu0.22.04.1 + + openssl@3.0.2-0ubuntu1.10 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Ubuntu. + See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    +

    Issue summary: A bug has been identified in the processing of key and + initialisation vector (IV) lengths. This can lead to potential truncation + or overruns during the initialisation of some symmetric ciphers.

    +

    Impact summary: A truncation in the IV can result in non-uniqueness, + which could result in loss of confidentiality for some cipher modes.

    +

    When calling EVP_EncryptInit_ex2(), EVP_DecryptInit_ex2() or + EVP_CipherInit_ex2() the provided OSSL_PARAM array is processed after + the key and IV have been established. Any alterations to the key length, + via the "keylen" parameter or the IV length, via the "ivlen" parameter, + within the OSSL_PARAM array will not take effect as intended, potentially + causing truncation or overreading of these values. The following ciphers + and cipher modes are impacted: RC2, RC4, RC5, CCM, GCM and OCB.

    +

    For the CCM, GCM and OCB cipher modes, truncation of the IV can result in + loss of confidentiality. For example, when following NIST's SP 800-38D + section 8.2.1 guidance for constructing a deterministic IV for AES in + GCM mode, truncation of the counter portion could lead to IV reuse.

    +

    Both truncations and overruns of the key and overruns of the IV will + produce incorrect results and could, in some cases, trigger a memory + exception. However, these issues are not currently assessed as security + critical.

    +

    Changing the key and/or IV lengths is not considered to be a common operation + and the vulnerable API was recently introduced. Furthermore it is likely that + application developers will have spotted this problem during testing since + decryption would fail unless both peers in the communication were similarly + vulnerable. For these reasons we expect the probability of an application being + vulnerable to this to be quite low. However if an application is vulnerable then + this issue is considered very serious. For these reasons we have assessed this + issue as Moderate severity overall.

    +

    The OpenSSL SSL/TLS implementation is not affected by this issue.

    +

    The OpenSSL 3.0 and 3.1 FIPS providers are not affected by this because + the issue lies outside of the FIPS provider boundary.

    +

    OpenSSL 3.1 and 3.0 are vulnerable to this issue.

    +

    Remediation

    +

    Upgrade Ubuntu:22.04 openssl to version 3.0.2-0ubuntu1.12 or higher.

    References


    -
    -

    Directory Traversal

    +
    +

    Out-of-bounds Read

    -
    - high severity +
    + medium severity

    • - Package Manager: golang + Package Manager: ubuntu:22.04
    • Vulnerable module: - github.com/cyphar/filepath-securejoin + libx11/libx11-data
    • Introduced through: - github.com/argoproj/argo-cd/v2@* and github.com/cyphar/filepath-securejoin@v0.2.3 + docker-image|quay.io/argoproj/argocd@v2.7.14 and libx11/libx11-data@2:1.7.5-1ubuntu0.2
    @@ -670,18 +1510,62 @@

    Detailed paths

    • Introduced through: - github.com/argoproj/argo-cd/v2@* + docker-image|quay.io/argoproj/argocd@v2.7.14 - github.com/cyphar/filepath-securejoin@v0.2.3 + libx11/libx11-data@2:1.7.5-1ubuntu0.2
    • Introduced through: - helm.sh/helm/v3@* + docker-image|quay.io/argoproj/argocd@v2.7.14 - github.com/cyphar/filepath-securejoin@v0.2.3 + libx11/libx11-6@2:1.7.5-1ubuntu0.2 + + libx11/libx11-data@2:1.7.5-1ubuntu0.2 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 + + libx11/libx11-6@2:1.7.5-1ubuntu0.2 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 + + libxext/libxext6@2:1.3.4-1build1 + + libx11/libx11-6@2:1.7.5-1ubuntu0.2 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 + + libxmu/libxmuu1@2:1.1.3-3 + + libx11/libx11-6@2:1.7.5-1ubuntu0.2 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 + + xauth@1:1.1-1build2 + + libx11/libx11-6@2:1.7.5-1ubuntu0.2 @@ -692,47 +1576,28 @@

      Detailed paths


      -

      Overview

      -

      Affected versions of this package are vulnerable to Directory Traversal via the filepath.FromSlash() function, allwoing attackers to generate paths that were outside of the provided rootfs.

      -

      Note: - This vulnerability is only exploitable on Windows OS.

      -

      Details

      -

      A Directory Traversal attack (also known as path traversal) aims to access files and directories that are stored outside the intended folder. By manipulating files with "dot-dot-slash (../)" sequences and its variations, or by using absolute file paths, it may be possible to access arbitrary files and directories stored on file system, including application source code, configuration, and other critical system files.

      -

      Directory Traversal vulnerabilities can be generally divided into two types:

      -
        -
      • Information Disclosure: Allows the attacker to gain information about the folder structure or read the contents of sensitive files on the system.
      • -
      -

      st is a module for serving static files on web pages, and contains a vulnerability of this type. In our example, we will serve files from the public route.

      -

      If an attacker requests the following URL from our server, it will in turn leak the sensitive private key of the root user.

      -
      curl http://localhost:8080/public/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/root/.ssh/id_rsa
      -        
      -

      Note %2e is the URL encoded version of . (dot).

      -
        -
      • Writing arbitrary files: Allows the attacker to create or replace existing files. This type of vulnerability is also known as Zip-Slip.
      • -
      -

      One way to achieve this is by using a malicious zip archive that holds path traversal filenames. When each filename in the zip archive gets concatenated to the target extraction folder, without validation, the final path ends up outside of the target folder. If an executable or a configuration file is overwritten with a file containing malicious code, the problem can turn into an arbitrary code execution issue quite easily.

      -

      The following is an example of a zip archive with one benign file and one malicious file. Extracting the malicious file will result in traversing out of the target folder, ending up in /root/.ssh/ overwriting the authorized_keys file:

      -
      2018-04-15 22:04:29 .....           19           19  good.txt
      -        2018-04-15 22:04:42 .....           20           20  ../../../../../../root/.ssh/authorized_keys
      -        
      +

      NVD Description

      +

      Note: Versions mentioned in the description apply only to the upstream libx11 package and not the libx11 package as distributed by Ubuntu. + See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

      +

      A vulnerability was found in libX11 due to a boundary condition within the _XkbReadKeySyms() function. This flaw allows a local user to trigger an out-of-bounds read error and read the contents of memory on the system.

      Remediation

      -

      Upgrade github.com/cyphar/filepath-securejoin to version 0.2.4 or higher.

      +

      Upgrade Ubuntu:22.04 libx11 to version 2:1.7.5-1ubuntu0.3 or higher.

      References


    -

    CVE-2020-22916

    +

    Loop with Unreachable Exit Condition ('Infinite Loop')

    @@ -748,12 +1613,12 @@

    CVE-2020-22916

  • Vulnerable module: - xz-utils/liblzma5 + libx11/libx11-data
  • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.7.14 and xz-utils/liblzma5@5.2.5-2ubuntu1 + docker-image|quay.io/argoproj/argocd@v2.7.14 and libx11/libx11-data@2:1.7.5-1ubuntu0.2
  • @@ -768,7 +1633,60 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@v2.7.14 - xz-utils/liblzma5@5.2.5-2ubuntu1 + libx11/libx11-data@2:1.7.5-1ubuntu0.2 + + + + +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 + + libx11/libx11-6@2:1.7.5-1ubuntu0.2 + + libx11/libx11-data@2:1.7.5-1ubuntu0.2 + + + +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 + + libx11/libx11-6@2:1.7.5-1ubuntu0.2 + + + +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 + + libxext/libxext6@2:1.3.4-1build1 + + libx11/libx11-6@2:1.7.5-1ubuntu0.2 + + + +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 + + libxmu/libxmuu1@2:1.1.3-3 + + libx11/libx11-6@2:1.7.5-1ubuntu0.2 + + + +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 + + xauth@1:1.1-1build2 + + libx11/libx11-6@2:1.7.5-1ubuntu0.2 @@ -780,31 +1698,27 @@

    Detailed paths


    NVD Description

    -

    Note: Versions mentioned in the description apply only to the upstream xz-utils package and not the xz-utils package as distributed by Ubuntu. +

    Note: Versions mentioned in the description apply only to the upstream libx11 package and not the libx11 package as distributed by Ubuntu. See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    -

    An issue discovered in XZ 5.2.5 allows attackers to cause a denial of service via decompression of a crafted file. NOTE: the software maintainers are unable to reproduce this as of 2023-09-12 because the example crafted file is temporarily offline.

    +

    A vulnerability was found in libX11 due to an infinite loop within the PutSubImage() function. This flaw allows a local user to consume all available system resources and cause a denial of service condition.

    Remediation

    -

    There is no fixed version for Ubuntu:22.04 xz-utils.

    +

    Upgrade Ubuntu:22.04 libx11 to version 2:1.7.5-1ubuntu0.3 or higher.

    References


  • -

    Out-of-bounds Write

    +

    Integer Overflow or Wraparound

    @@ -820,13 +1734,13 @@

    Out-of-bounds Write

  • Vulnerable module: - perl/perl-modules-5.34 + libx11/libx11-data
  • Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 and libx11/libx11-data@2:1.7.5-1ubuntu0.2 - docker-image|quay.io/argoproj/argocd@v2.7.14, git@1:2.34.1-1ubuntu1.10 and others
  • @@ -840,11 +1754,7 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@v2.7.14 - git@1:2.34.1-1ubuntu1.10 - - perl@5.34.0-3ubuntu1.2 - - perl/perl-modules-5.34@5.34.0-3ubuntu1.2 + libx11/libx11-data@2:1.7.5-1ubuntu0.2 @@ -853,13 +1763,9 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@v2.7.14 - git@1:2.34.1-1ubuntu1.10 - - perl@5.34.0-3ubuntu1.2 - - perl/libperl5.34@5.34.0-3ubuntu1.2 + libx11/libx11-6@2:1.7.5-1ubuntu0.2 - perl/perl-modules-5.34@5.34.0-3ubuntu1.2 + libx11/libx11-data@2:1.7.5-1ubuntu0.2 @@ -868,11 +1774,18 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@v2.7.14 - git@1:2.34.1-1ubuntu1.10 + libx11/libx11-6@2:1.7.5-1ubuntu0.2 + + + + +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 - perl@5.34.0-3ubuntu1.2 + libxext/libxext6@2:1.3.4-1build1 - perl/libperl5.34@5.34.0-3ubuntu1.2 + libx11/libx11-6@2:1.7.5-1ubuntu0.2 @@ -881,9 +1794,9 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@v2.7.14 - git@1:2.34.1-1ubuntu1.10 + libxmu/libxmuu1@2:1.1.3-3 - perl@5.34.0-3ubuntu1.2 + libx11/libx11-6@2:1.7.5-1ubuntu0.2 @@ -892,7 +1805,9 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@v2.7.14 - perl/perl-base@5.34.0-3ubuntu1.2 + xauth@1:1.1-1build2 + + libx11/libx11-6@2:1.7.5-1ubuntu0.2 @@ -904,22 +1819,22 @@

    Detailed paths


    NVD Description

    -

    Note: Versions mentioned in the description apply only to the upstream perl package and not the perl package as distributed by Ubuntu. +

    Note: Versions mentioned in the description apply only to the upstream libx11 package and not the libx11 package as distributed by Ubuntu. See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    -

    In Perl 5.34.0, function S_find_uninit_var in sv.c has a stack-based crash that can lead to remote code execution or local privilege escalation.

    +

    A vulnerability was found in libX11 due to an integer overflow within the XCreateImage() function. This flaw allows a local user to trigger an integer overflow and execute arbitrary code with elevated privileges.

    Remediation

    -

    There is no fixed version for Ubuntu:22.04 perl.

    +

    Upgrade Ubuntu:22.04 libx11 to version 2:1.7.5-1ubuntu0.3 or higher.

    References


  • @@ -1101,7 +2016,88 @@

    Detailed paths

    libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.2 + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.2 + + + + +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 + + krb5/libkrb5support0@1.19.2-2ubuntu0.2 + + + +
  • + + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream krb5 package and not the krb5 package as distributed by Ubuntu. + See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    +

    lib/kadm5/kadm_rpc_xdr.c in MIT Kerberos 5 (aka krb5) before 1.20.2 and 1.21.x before 1.21.1 frees an uninitialized pointer. A remote authenticated user can trigger a kadmind crash. This occurs because _xdr_kadm5_principal_ent_rec does not validate the relationship between n_key_data and the key_data array count.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 krb5.

    +

    References

    + + +
    + + + +
    +
    +

    Memory Leak

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + glibc/libc-bin +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.7.14 and glibc/libc-bin@2.35-0ubuntu3.1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 + + glibc/libc-bin@2.35-0ubuntu3.1 @@ -1110,7 +2106,7 @@

      Detailed paths

      Introduced through: docker-image|quay.io/argoproj/argocd@v2.7.14 - krb5/libkrb5support0@1.19.2-2ubuntu0.2 + glibc/libc6@2.35-0ubuntu3.1 @@ -1122,25 +2118,28 @@

      Detailed paths


      NVD Description

      -

      Note: Versions mentioned in the description apply only to the upstream krb5 package and not the krb5 package as distributed by Ubuntu. +

      Note: Versions mentioned in the description apply only to the upstream glibc package and not the glibc package as distributed by Ubuntu. See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

      -

      lib/kadm5/kadm_rpc_xdr.c in MIT Kerberos 5 (aka krb5) before 1.20.2 and 1.21.x before 1.21.1 frees an uninitialized pointer. A remote authenticated user can trigger a kadmind crash. This occurs because _xdr_kadm5_principal_ent_rec does not validate the relationship between n_key_data and the key_data array count.

      +

      A flaw was found in the GNU C Library. A recent fix for CVE-2023-4806 introduced the potential for a memory leak, which may result in an application crash.

      Remediation

      -

      There is no fixed version for Ubuntu:22.04 krb5.

      +

      There is no fixed version for Ubuntu:22.04 glibc.

      References


    @@ -1870,14 +2869,257 @@

    Release of Invalid Pointer or Reference


    -

    Detailed paths

    +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 + + patch@2.7.6-7build2 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream patch package and not the patch package as distributed by Ubuntu:22.04. + See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    +

    An Invalid Pointer vulnerability exists in GNU patch 2.7 via the another_hunk function, which causes a Denial of Service.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 patch.

    +

    References

    + + +
    + + + +
    +
    +

    Double Free

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + patch +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.7.14 and patch@2.7.6-7build2 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 + + patch@2.7.6-7build2 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream patch package and not the patch package as distributed by Ubuntu:22.04. + See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    +

    A double free exists in the another_hunk function in pch.c in GNU patch through 2.7.6.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 patch.

    +

    References

    + + +
    + + + +
    +
    +

    Improper Authentication

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + openssl/libssl3 +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.7.14 and openssl/libssl3@3.0.2-0ubuntu1.10 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 + + openssl/libssl3@3.0.2-0ubuntu1.10 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 + + cyrus-sasl2/libsasl2-modules@2.1.27+dfsg2-3ubuntu1.2 + + openssl/libssl3@3.0.2-0ubuntu1.10 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 + + libfido2/libfido2-1@1.10.0-1 + + openssl/libssl3@3.0.2-0ubuntu1.10 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 + + openssh/openssh-client@1:8.9p1-3ubuntu0.3 + + openssl/libssl3@3.0.2-0ubuntu1.10 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 + + ca-certificates@20230311ubuntu0.22.04.1 + + openssl@3.0.2-0ubuntu1.10 + + openssl/libssl3@3.0.2-0ubuntu1.10 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.13 + + libssh/libssh-4@0.9.6-2ubuntu0.22.04.1 + + openssl/libssl3@3.0.2-0ubuntu1.10 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.1 + + pam/libpam-modules@1.4.0-11ubuntu2.3 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.2 + + krb5/libkrb5-3@1.19.2-2ubuntu0.2 + + openssl/libssl3@3.0.2-0ubuntu1.10 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 + + openssl@3.0.2-0ubuntu1.10 + + -
        +
      • Introduced through: docker-image|quay.io/argoproj/argocd@v2.7.14 - patch@2.7.6-7build2 + ca-certificates@20230311ubuntu0.22.04.1 + + openssl@3.0.2-0ubuntu1.10 @@ -1889,26 +3131,47 @@

        Detailed paths


        NVD Description

        -

        Note: Versions mentioned in the description apply only to the upstream patch package and not the patch package as distributed by Ubuntu:22.04. +

        Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Ubuntu. See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

        -

        An Invalid Pointer vulnerability exists in GNU patch 2.7 via the another_hunk function, which causes a Denial of Service.

        +

        Issue summary: The AES-SIV cipher implementation contains a bug that causes + it to ignore empty associated data entries which are unauthenticated as + a consequence.

        +

        Impact summary: Applications that use the AES-SIV algorithm and want to + authenticate empty data entries as associated data can be mislead by removing + adding or reordering such empty entries as these are ignored by the OpenSSL + implementation. We are currently unaware of any such applications.

        +

        The AES-SIV algorithm allows for authentication of multiple associated + data entries along with the encryption. To authenticate empty data the + application has to call EVP_EncryptUpdate() (or EVP_CipherUpdate()) with + NULL pointer as the output buffer and 0 as the input buffer length. + The AES-SIV implementation in OpenSSL just returns success for such a call + instead of performing the associated data authentication operation. + The empty data thus will not be authenticated.

        +

        As this issue does not affect non-empty associated data authentication and + we expect it to be rare for an application to use empty associated data + entries this is qualified as Low severity issue.

        Remediation

        -

        There is no fixed version for Ubuntu:22.04 patch.

        +

        Upgrade Ubuntu:22.04 openssl to version 3.0.2-0ubuntu1.12 or higher.

        References


    -

    Double Free

    +

    Inefficient Regular Expression Complexity

    @@ -1924,12 +3187,12 @@

    Double Free

  • Vulnerable module: - patch + openssl/libssl3
  • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.7.14 and patch@2.7.6-7build2 + docker-image|quay.io/argoproj/argocd@v2.7.14 and openssl/libssl3@3.0.2-0ubuntu1.10
  • @@ -1944,7 +3207,111 @@

    Detailed paths

    Introduced through: docker-image|quay.io/argoproj/argocd@v2.7.14 - patch@2.7.6-7build2 + openssl/libssl3@3.0.2-0ubuntu1.10 + + + + +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 + + cyrus-sasl2/libsasl2-modules@2.1.27+dfsg2-3ubuntu1.2 + + openssl/libssl3@3.0.2-0ubuntu1.10 + + + +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 + + libfido2/libfido2-1@1.10.0-1 + + openssl/libssl3@3.0.2-0ubuntu1.10 + + + +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 + + openssh/openssh-client@1:8.9p1-3ubuntu0.3 + + openssl/libssl3@3.0.2-0ubuntu1.10 + + + +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 + + ca-certificates@20230311ubuntu0.22.04.1 + + openssl@3.0.2-0ubuntu1.10 + + openssl/libssl3@3.0.2-0ubuntu1.10 + + + +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.13 + + libssh/libssh-4@0.9.6-2ubuntu0.22.04.1 + + openssl/libssl3@3.0.2-0ubuntu1.10 + + + +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.1 + + pam/libpam-modules@1.4.0-11ubuntu2.3 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.2 + + krb5/libkrb5-3@1.19.2-2ubuntu0.2 + + openssl/libssl3@3.0.2-0ubuntu1.10 + + + +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 + + openssl@3.0.2-0ubuntu1.10 + + + +
  • +
  • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 + + ca-certificates@20230311ubuntu0.22.04.1 + + openssl@3.0.2-0ubuntu1.10 @@ -1956,31 +3323,57 @@

    Detailed paths


    NVD Description

    -

    Note: Versions mentioned in the description apply only to the upstream patch package and not the patch package as distributed by Ubuntu:22.04. +

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Ubuntu. See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    -

    A double free exists in the another_hunk function in pch.c in GNU patch through 2.7.6.

    +

    Issue summary: Checking excessively long DH keys or parameters may be very slow.

    +

    Impact summary: Applications that use the functions DH_check(), DH_check_ex() + or EVP_PKEY_param_check() to check a DH key or DH parameters may experience long + delays. Where the key or parameters that are being checked have been obtained + from an untrusted source this may lead to a Denial of Service.

    +

    The function DH_check() performs various checks on DH parameters. One of those + checks confirms that the modulus ('p' parameter) is not too large. Trying to use + a very large modulus is slow and OpenSSL will not normally use a modulus which + is over 10,000 bits in length.

    +

    However the DH_check() function checks numerous aspects of the key or parameters + that have been supplied. Some of those checks use the supplied modulus value + even if it has already been found to be too large.

    +

    An application that calls DH_check() and supplies a key or parameters obtained + from an untrusted source could be vulernable to a Denial of Service attack.

    +

    The function DH_check() is itself called by a number of other OpenSSL functions. + An application calling any of those other functions may similarly be affected. + The other functions affected by this are DH_check_ex() and + EVP_PKEY_param_check().

    +

    Also vulnerable are the OpenSSL dhparam and pkeyparam command line applications + when using the '-check' option.

    +

    The OpenSSL SSL/TLS implementation is not affected by this issue. + The OpenSSL 3.0 and 3.1 FIPS providers are not affected by this issue.

    Remediation

    -

    There is no fixed version for Ubuntu:22.04 patch.

    +

    Upgrade Ubuntu:22.04 openssl to version 3.0.2-0ubuntu1.12 or higher.

    References


  • -

    Improper Authentication

    +

    Excessive Iteration

    @@ -2132,42 +3525,51 @@

    Detailed paths


    NVD Description

    -

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Ubuntu:22.04. +

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Ubuntu. See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    -

    Issue summary: The AES-SIV cipher implementation contains a bug that causes - it to ignore empty associated data entries which are unauthenticated as - a consequence.

    -

    Impact summary: Applications that use the AES-SIV algorithm and want to - authenticate empty data entries as associated data can be mislead by removing - adding or reordering such empty entries as these are ignored by the OpenSSL - implementation. We are currently unaware of any such applications.

    -

    The AES-SIV algorithm allows for authentication of multiple associated - data entries along with the encryption. To authenticate empty data the - application has to call EVP_EncryptUpdate() (or EVP_CipherUpdate()) with - NULL pointer as the output buffer and 0 as the input buffer length. - The AES-SIV implementation in OpenSSL just returns success for such a call - instead of performing the associated data authentication operation. - The empty data thus will not be authenticated.

    -

    As this issue does not affect non-empty associated data authentication and - we expect it to be rare for an application to use empty associated data - entries this is qualified as Low severity issue.

    +

    Issue summary: Checking excessively long DH keys or parameters may be very slow.

    +

    Impact summary: Applications that use the functions DH_check(), DH_check_ex() + or EVP_PKEY_param_check() to check a DH key or DH parameters may experience long + delays. Where the key or parameters that are being checked have been obtained + from an untrusted source this may lead to a Denial of Service.

    +

    The function DH_check() performs various checks on DH parameters. After fixing + CVE-2023-3446 it was discovered that a large q parameter value can also trigger + an overly long computation during some of these checks. A correct q value, + if present, cannot be larger than the modulus p parameter, thus it is + unnecessary to perform these checks if q is larger than p.

    +

    An application that calls DH_check() and supplies a key or parameters obtained + from an untrusted source could be vulnerable to a Denial of Service attack.

    +

    The function DH_check() is itself called by a number of other OpenSSL functions. + An application calling any of those other functions may similarly be affected. + The other functions affected by this are DH_check_ex() and + EVP_PKEY_param_check().

    +

    Also vulnerable are the OpenSSL dhparam and pkeyparam command line applications + when using the "-check" option.

    +

    The OpenSSL SSL/TLS implementation is not affected by this issue.

    +

    The OpenSSL 3.0 and 3.1 FIPS providers are not affected by this issue.

    Remediation

    -

    There is no fixed version for Ubuntu:22.04 openssl.

    +

    Upgrade Ubuntu:22.04 openssl to version 3.0.2-0ubuntu1.12 or higher.

    References


    @@ -3284,6 +4686,90 @@

    References

    More about this vulnerability

    +
    +
    +

    CVE-2023-38546

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + curl/libcurl3-gnutls +
    • + +
    • Introduced through: + + + docker-image|quay.io/argoproj/argocd@v2.7.14, git@1:2.34.1-1ubuntu1.10 and others +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.7.14 + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.13 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream curl package and not the curl package as distributed by Ubuntu. + See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    +

    This flaw allows an attacker to insert cookies at will into a running program + using libcurl, if the specific series of conditions are met.

    +

    libcurl performs transfers. In its API, an application creates "easy handles" + that are the individual handles for single transfers.

    +

    libcurl provides a function call that duplicates en easy handle called + curl_easy_duphandle.

    +

    If a transfer has cookies enabled when the handle is duplicated, the + cookie-enable state is also cloned - but without cloning the actual + cookies. If the source handle did not read any cookies from a specific file on + disk, the cloned version of the handle would instead store the file name as + none (using the four ASCII letters, no quotes).

    +

    Subsequent use of the cloned handle that does not explicitly set a source to + load cookies from would then inadvertently load cookies from a file named + none - if such a file exists and is readable in the current directory of the + program using libcurl. And if using the correct file format of course.

    +

    Remediation

    +

    Upgrade Ubuntu:22.04 curl to version 7.81.0-1ubuntu1.14 or higher.

    +

    References

    + + +
    + + +

    Improper Input Validation

    diff --git a/docs/snyk/v2.7.14/redis_7.0.11-alpine.html b/docs/snyk/v2.7.14/redis_7.0.11-alpine.html index bf29e934c06db..bb89e05940bc5 100644 --- a/docs/snyk/v2.7.14/redis_7.0.11-alpine.html +++ b/docs/snyk/v2.7.14/redis_7.0.11-alpine.html @@ -7,7 +7,7 @@ Snyk test report - + @@ -456,7 +456,7 @@

    Snyk test report

    -

    September 17th 2023, 12:23:05 am (UTC+00:00)

    +

    October 29th 2023, 12:25:30 am (UTC+00:00)

    Scanned the following path: @@ -466,8 +466,8 @@

    Snyk test report

    -
    4 known vulnerabilities
    -
    32 vulnerable dependency paths
    +
    5 known vulnerabilities
    +
    41 vulnerable dependency paths
    18 dependencies
    @@ -905,7 +905,7 @@

    Detailed paths


    NVD Description

    -

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine:3.18. +

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine. See How to fix? for Alpine:3.18 relevant fixed versions and status.

    Issue summary: Checking excessively long DH keys or parameters may be very slow.

    Impact summary: Applications that use the functions DH_check(), DH_check_ex() @@ -1090,7 +1090,7 @@

    Detailed paths


    NVD Description

    -

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine:3.18. +

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine. See How to fix? for Alpine:3.18 relevant fixed versions and status.

    Issue summary: Checking excessively long DH keys or parameters may be very slow.

    Impact summary: Applications that use the functions DH_check(), DH_check_ex() @@ -1125,6 +1125,9 @@

    References

  • openssl-security@openssl.org
  • openssl-security@openssl.org
  • openssl-security@openssl.org
  • +
  • openssl-security@openssl.org
  • +
  • openssl-security@openssl.org
  • +
  • openssl-security@openssl.org

  • @@ -1134,6 +1137,196 @@

    References

    +
    +

    CVE-2023-5363

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Package Manager: alpine:3.18 +
    • +
    • + Vulnerable module: + + openssl/libcrypto3 +
    • + +
    • Introduced through: + + docker-image|redis@7.0.11-alpine and openssl/libcrypto3@3.1.1-r1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + .redis-rundeps@20230614.215749 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + busybox/ssl_client@1.36.1-r0 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + .redis-rundeps@20230614.215749 + + openssl/libssl3@3.1.1-r1 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + .redis-rundeps@20230614.215749 + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + busybox/ssl_client@1.36.1-r0 + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine. + See How to fix? for Alpine:3.18 relevant fixed versions and status.

    +

    Issue summary: A bug has been identified in the processing of key and + initialisation vector (IV) lengths. This can lead to potential truncation + or overruns during the initialisation of some symmetric ciphers.

    +

    Impact summary: A truncation in the IV can result in non-uniqueness, + which could result in loss of confidentiality for some cipher modes.

    +

    When calling EVP_EncryptInit_ex2(), EVP_DecryptInit_ex2() or + EVP_CipherInit_ex2() the provided OSSL_PARAM array is processed after + the key and IV have been established. Any alterations to the key length, + via the "keylen" parameter or the IV length, via the "ivlen" parameter, + within the OSSL_PARAM array will not take effect as intended, potentially + causing truncation or overreading of these values. The following ciphers + and cipher modes are impacted: RC2, RC4, RC5, CCM, GCM and OCB.

    +

    For the CCM, GCM and OCB cipher modes, truncation of the IV can result in + loss of confidentiality. For example, when following NIST's SP 800-38D + section 8.2.1 guidance for constructing a deterministic IV for AES in + GCM mode, truncation of the counter portion could lead to IV reuse.

    +

    Both truncations and overruns of the key and overruns of the IV will + produce incorrect results and could, in some cases, trigger a memory + exception. However, these issues are not currently assessed as security + critical.

    +

    Changing the key and/or IV lengths is not considered to be a common operation + and the vulnerable API was recently introduced. Furthermore it is likely that + application developers will have spotted this problem during testing since + decryption would fail unless both peers in the communication were similarly + vulnerable. For these reasons we expect the probability of an application being + vulnerable to this to be quite low. However if an application is vulnerable then + this issue is considered very serious. For these reasons we have assessed this + issue as Moderate severity overall.

    +

    The OpenSSL SSL/TLS implementation is not affected by this issue.

    +

    The OpenSSL 3.0 and 3.1 FIPS providers are not affected by this because + the issue lies outside of the FIPS provider boundary.

    +

    OpenSSL 3.1 and 3.0 are vulnerable to this issue.

    +

    Remediation

    +

    Upgrade Alpine:3.18 openssl to version 3.1.4-r0 or higher.

    +

    References

    + + +
    + + + +
    diff --git a/docs/snyk/v2.8.4/argocd-iac-install.html b/docs/snyk/v2.8.5/argocd-iac-install.html similarity index 99% rename from docs/snyk/v2.8.4/argocd-iac-install.html rename to docs/snyk/v2.8.5/argocd-iac-install.html index 5f74f2148397b..3d4dd5fd52b45 100644 --- a/docs/snyk/v2.8.4/argocd-iac-install.html +++ b/docs/snyk/v2.8.5/argocd-iac-install.html @@ -456,7 +456,7 @@

    Snyk test report

    -

    September 17th 2023, 12:21:35 am (UTC+00:00)

    +

    October 29th 2023, 12:24:06 am (UTC+00:00)

    Scanned the following path: @@ -789,7 +789,7 @@

    Container could be running with outdated image

  • - Line number: 19755 + Line number: 19761
  • @@ -1079,7 +1079,7 @@

    Container has no CPU limit

  • - Line number: 19498 + Line number: 19504
  • @@ -1137,7 +1137,7 @@

    Container has no CPU limit

  • - Line number: 19755 + Line number: 19761
  • @@ -1195,7 +1195,7 @@

    Container has no CPU limit

  • - Line number: 19555 + Line number: 19561
  • @@ -1253,7 +1253,7 @@

    Container has no CPU limit

  • - Line number: 19840 + Line number: 19846
  • @@ -1311,7 +1311,7 @@

    Container has no CPU limit

  • - Line number: 20156 + Line number: 20162
  • @@ -1460,14 +1460,14 @@

    Container is running without liveness probe

    spec - containers[dex] + initContainers[copyutil] livenessProbe
  • - Line number: 19317 + Line number: 19351
  • @@ -1512,14 +1512,14 @@

    Container is running without liveness probe

    spec - initContainers[copyutil] + containers[dex] livenessProbe
  • - Line number: 19351 + Line number: 19317
  • @@ -1571,7 +1571,7 @@

    Container is running without liveness probe

  • - Line number: 19498 + Line number: 19504
  • @@ -1623,7 +1623,7 @@

    Container is running without liveness probe

  • - Line number: 19755 + Line number: 19761
  • @@ -1913,7 +1913,7 @@

    Container is running without memory limit

  • - Line number: 19498 + Line number: 19504
  • @@ -1971,7 +1971,7 @@

    Container is running without memory limit

  • - Line number: 19755 + Line number: 19761
  • @@ -2029,7 +2029,7 @@

    Container is running without memory limit

  • - Line number: 19555 + Line number: 19561
  • @@ -2087,7 +2087,7 @@

    Container is running without memory limit

  • - Line number: 19840 + Line number: 19846
  • @@ -2145,7 +2145,7 @@

    Container is running without memory limit

  • - Line number: 20156 + Line number: 20162
  • @@ -2369,7 +2369,7 @@

    Container's or Pod's UID could clash with hos
  • - Line number: 19432 + Line number: 19438
  • @@ -2425,7 +2425,7 @@

    Container's or Pod's UID could clash with hos
  • - Line number: 19508 + Line number: 19514
  • @@ -2481,7 +2481,7 @@

    Container's or Pod's UID could clash with hos
  • - Line number: 19762 + Line number: 19768
  • @@ -2537,7 +2537,7 @@

    Container's or Pod's UID could clash with hos
  • - Line number: 19728 + Line number: 19734
  • @@ -2593,7 +2593,7 @@

    Container's or Pod's UID could clash with hos
  • - Line number: 20066 + Line number: 20072
  • @@ -2649,7 +2649,7 @@

    Container's or Pod's UID could clash with hos
  • - Line number: 20304 + Line number: 20310
  • diff --git a/docs/snyk/v2.8.4/argocd-iac-namespace-install.html b/docs/snyk/v2.8.5/argocd-iac-namespace-install.html similarity index 99% rename from docs/snyk/v2.8.4/argocd-iac-namespace-install.html rename to docs/snyk/v2.8.5/argocd-iac-namespace-install.html index cc0982d073c19..aae75827ee40d 100644 --- a/docs/snyk/v2.8.4/argocd-iac-namespace-install.html +++ b/docs/snyk/v2.8.5/argocd-iac-namespace-install.html @@ -456,7 +456,7 @@

    Snyk test report

    -

    September 17th 2023, 12:21:47 am (UTC+00:00)

    +

    October 29th 2023, 12:24:17 am (UTC+00:00)

    Scanned the following path: @@ -789,7 +789,7 @@

    Container could be running with outdated image

  • - Line number: 1261 + Line number: 1267
  • @@ -1079,7 +1079,7 @@

    Container has no CPU limit

  • - Line number: 1004 + Line number: 1010
  • @@ -1137,7 +1137,7 @@

    Container has no CPU limit

  • - Line number: 1261 + Line number: 1267
  • @@ -1195,7 +1195,7 @@

    Container has no CPU limit

  • - Line number: 1061 + Line number: 1067
  • @@ -1253,7 +1253,7 @@

    Container has no CPU limit

  • - Line number: 1346 + Line number: 1352
  • @@ -1311,7 +1311,7 @@

    Container has no CPU limit

  • - Line number: 1662 + Line number: 1668
  • @@ -1460,14 +1460,14 @@

    Container is running without liveness probe

    spec - containers[dex] + initContainers[copyutil] livenessProbe
  • - Line number: 823 + Line number: 857
  • @@ -1512,14 +1512,14 @@

    Container is running without liveness probe

    spec - initContainers[copyutil] + containers[dex] livenessProbe
  • - Line number: 857 + Line number: 823
  • @@ -1571,7 +1571,7 @@

    Container is running without liveness probe

  • - Line number: 1004 + Line number: 1010
  • @@ -1623,7 +1623,7 @@

    Container is running without liveness probe

  • - Line number: 1261 + Line number: 1267
  • @@ -1913,7 +1913,7 @@

    Container is running without memory limit

  • - Line number: 1004 + Line number: 1010
  • @@ -1971,7 +1971,7 @@

    Container is running without memory limit

  • - Line number: 1261 + Line number: 1267
  • @@ -2029,7 +2029,7 @@

    Container is running without memory limit

  • - Line number: 1061 + Line number: 1067
  • @@ -2087,7 +2087,7 @@

    Container is running without memory limit

  • - Line number: 1346 + Line number: 1352
  • @@ -2145,7 +2145,7 @@

    Container is running without memory limit

  • - Line number: 1662 + Line number: 1668
  • @@ -2369,7 +2369,7 @@

    Container's or Pod's UID could clash with hos
  • - Line number: 938 + Line number: 944
  • @@ -2425,7 +2425,7 @@

    Container's or Pod's UID could clash with hos
  • - Line number: 1014 + Line number: 1020
  • @@ -2481,7 +2481,7 @@

    Container's or Pod's UID could clash with hos
  • - Line number: 1268 + Line number: 1274
  • @@ -2537,7 +2537,7 @@

    Container's or Pod's UID could clash with hos
  • - Line number: 1234 + Line number: 1240
  • @@ -2593,7 +2593,7 @@

    Container's or Pod's UID could clash with hos
  • - Line number: 1572 + Line number: 1578
  • @@ -2649,7 +2649,7 @@

    Container's or Pod's UID could clash with hos
  • - Line number: 1810 + Line number: 1816
  • diff --git a/docs/snyk/v2.8.4/argocd-test.html b/docs/snyk/v2.8.5/argocd-test.html similarity index 93% rename from docs/snyk/v2.8.4/argocd-test.html rename to docs/snyk/v2.8.5/argocd-test.html index c231307e65854..3a5f08a08b860 100644 --- a/docs/snyk/v2.8.4/argocd-test.html +++ b/docs/snyk/v2.8.5/argocd-test.html @@ -7,7 +7,7 @@ Snyk test report - + @@ -456,7 +456,7 @@

    Snyk test report

    -

    September 17th 2023, 12:18:51 am (UTC+00:00)

    +

    October 29th 2023, 12:21:29 am (UTC+00:00)

    Scanned the following paths: @@ -466,9 +466,9 @@

    Snyk test report

    -
    5 known vulnerabilities
    -
    18 vulnerable dependency paths
    -
    1851 dependencies
    +
    6 known vulnerabilities
    +
    19 vulnerable dependency paths
    +
    1853 dependencies

    @@ -476,6 +476,65 @@

    Snyk test report

    +
    +

    LGPL-3.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Module: + + gopkg.in/retry.v1 +
    • + +
    • Introduced through: + + + github.com/argoproj/argo-cd/v2@0.0.0, github.com/Azure/kubelogin/pkg/token@0.0.20 and others +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/Azure/kubelogin/pkg/token@0.0.20 + + gopkg.in/retry.v1@1.0.3 + + + +
    • +
    + +
    + +
    + +

    LGPL-3.0 license

    + +
    + + + +

    MPL-2.0 license

    diff --git a/docs/snyk/v2.8.4/ghcr.io_dexidp_dex_v2.37.0.html b/docs/snyk/v2.8.5/ghcr.io_dexidp_dex_v2.37.0.html similarity index 84% rename from docs/snyk/v2.8.4/ghcr.io_dexidp_dex_v2.37.0.html rename to docs/snyk/v2.8.5/ghcr.io_dexidp_dex_v2.37.0.html index ba807896bd4af..74f7da7894829 100644 --- a/docs/snyk/v2.8.4/ghcr.io_dexidp_dex_v2.37.0.html +++ b/docs/snyk/v2.8.5/ghcr.io_dexidp_dex_v2.37.0.html @@ -7,7 +7,7 @@ Snyk test report - + @@ -456,7 +456,7 @@

    Snyk test report

    -

    September 17th 2023, 12:19:00 am (UTC+00:00)

    +

    October 29th 2023, 12:21:38 am (UTC+00:00)

    Scanned the following paths: @@ -466,8 +466,8 @@

    Snyk test report

    -
    25 known vulnerabilities
    -
    68 vulnerable dependency paths
    +
    28 known vulnerabilities
    +
    79 vulnerable dependency paths
    786 dependencies
    @@ -583,6 +583,178 @@

    References

    More about this vulnerability

    +
    +
    +

    Denial of Service (DoS)

    +
    + +
    + high severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + google.golang.org/grpc +
    • + +
    • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and google.golang.org/grpc@v1.46.2 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + google.golang.org/grpc@v1.46.2 + + + +
    • +
    • + Introduced through: + github.com/dexidp/dex@* + + google.golang.org/grpc@v1.56.1 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    google.golang.org/grpc is a Go implementation of gRPC

    +

    Affected versions of this package are vulnerable to Denial of Service (DoS) in the implementation of the HTTP/2 protocol. An attacker can cause a denial of service (including via DDoS) by rapidly resetting many streams through request cancellation.

    +

    Remediation

    +

    Upgrade google.golang.org/grpc to version 1.56.3, 1.57.1, 1.58.3 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Denial of Service (DoS)

    +
    + +
    + high severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + golang.org/x/net/http2 +
    • + +
    • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and golang.org/x/net/http2@v0.7.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + golang.org/x/net/http2@v0.7.0 + + + +
    • +
    • + Introduced through: + github.com/dexidp/dex@* + + golang.org/x/net/http2@v0.11.0 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    golang.org/x/net/http2 is a work-in-progress HTTP/2 implementation for Go.

    +

    Affected versions of this package are vulnerable to Denial of Service (DoS) in the implementation of the HTTP/2 protocol. An attacker can cause a denial of service (including via DDoS) by rapidly resetting many streams through request cancellation.

    +

    Remediation

    +

    Upgrade golang.org/x/net/http2 to version 0.17.0 or higher.

    +

    References

    + + +
    + + +

    Improper Authentication

    @@ -852,7 +1024,7 @@

    Detailed paths


    NVD Description

    -

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine:3.18. +

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine. See How to fix? for Alpine:3.18 relevant fixed versions and status.

    Issue summary: Checking excessively long DH keys or parameters may be very slow.

    Impact summary: Applications that use the functions DH_check(), DH_check_ex() @@ -1015,7 +1187,7 @@

    Detailed paths


    NVD Description

    -

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine:3.18. +

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine. See How to fix? for Alpine:3.18 relevant fixed versions and status.

    Issue summary: Checking excessively long DH keys or parameters may be very slow.

    Impact summary: Applications that use the functions DH_check(), DH_check_ex() @@ -1050,6 +1222,9 @@

    References

  • openssl-security@openssl.org
  • openssl-security@openssl.org
  • openssl-security@openssl.org
  • +
  • openssl-security@openssl.org
  • +
  • openssl-security@openssl.org
  • +
  • openssl-security@openssl.org

  • @@ -2511,6 +2686,174 @@

    Detailed paths

    +
    +

    CVE-2023-5363

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Package Manager: alpine:3.18 +
    • +
    • + Vulnerable module: + + openssl/libcrypto3 +
    • + +
    • Introduced through: + + docker-image|ghcr.io/dexidp/dex@v2.37.0 and openssl/libcrypto3@3.1.1-r1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + busybox/ssl_client@1.36.1-r0 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libssl3@3.1.1-r1 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + busybox/ssl_client@1.36.1-r0 + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine. + See How to fix? for Alpine:3.18 relevant fixed versions and status.

    +

    Issue summary: A bug has been identified in the processing of key and + initialisation vector (IV) lengths. This can lead to potential truncation + or overruns during the initialisation of some symmetric ciphers.

    +

    Impact summary: A truncation in the IV can result in non-uniqueness, + which could result in loss of confidentiality for some cipher modes.

    +

    When calling EVP_EncryptInit_ex2(), EVP_DecryptInit_ex2() or + EVP_CipherInit_ex2() the provided OSSL_PARAM array is processed after + the key and IV have been established. Any alterations to the key length, + via the "keylen" parameter or the IV length, via the "ivlen" parameter, + within the OSSL_PARAM array will not take effect as intended, potentially + causing truncation or overreading of these values. The following ciphers + and cipher modes are impacted: RC2, RC4, RC5, CCM, GCM and OCB.

    +

    For the CCM, GCM and OCB cipher modes, truncation of the IV can result in + loss of confidentiality. For example, when following NIST's SP 800-38D + section 8.2.1 guidance for constructing a deterministic IV for AES in + GCM mode, truncation of the counter portion could lead to IV reuse.

    +

    Both truncations and overruns of the key and overruns of the IV will + produce incorrect results and could, in some cases, trigger a memory + exception. However, these issues are not currently assessed as security + critical.

    +

    Changing the key and/or IV lengths is not considered to be a common operation + and the vulnerable API was recently introduced. Furthermore it is likely that + application developers will have spotted this problem during testing since + decryption would fail unless both peers in the communication were similarly + vulnerable. For these reasons we expect the probability of an application being + vulnerable to this to be quite low. However if an application is vulnerable then + this issue is considered very serious. For these reasons we have assessed this + issue as Moderate severity overall.

    +

    The OpenSSL SSL/TLS implementation is not affected by this issue.

    +

    The OpenSSL 3.0 and 3.1 FIPS providers are not affected by this because + the issue lies outside of the FIPS provider boundary.

    +

    OpenSSL 3.1 and 3.0 are vulnerable to this issue.

    +

    Remediation

    +

    Upgrade Alpine:3.18 openssl to version 3.1.4-r0 or higher.

    +

    References

    + + +
    + + + +
    diff --git a/docs/snyk/v2.8.4/haproxy_2.6.14-alpine.html b/docs/snyk/v2.8.5/haproxy_2.6.14-alpine.html similarity index 53% rename from docs/snyk/v2.8.4/haproxy_2.6.14-alpine.html rename to docs/snyk/v2.8.5/haproxy_2.6.14-alpine.html index 5d86d078e915f..020d8275f0dad 100644 --- a/docs/snyk/v2.8.4/haproxy_2.6.14-alpine.html +++ b/docs/snyk/v2.8.5/haproxy_2.6.14-alpine.html @@ -7,7 +7,7 @@ Snyk test report - + @@ -456,7 +456,7 @@

    Snyk test report

    -

    September 17th 2023, 12:19:05 am (UTC+00:00)

    +

    October 29th 2023, 12:21:43 am (UTC+00:00)

    Scanned the following path: @@ -466,8 +466,8 @@

    Snyk test report

    -
    0 known vulnerabilities
    -
    0 vulnerable dependency paths
    +
    1 known vulnerabilities
    +
    9 vulnerable dependency paths
    18 dependencies
    @@ -484,7 +484,198 @@

    Snyk test report

    - No known vulnerabilities detected. +
    +
    +

    CVE-2023-5363

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Package Manager: alpine:3.18 +
    • +
    • + Vulnerable module: + + openssl/libcrypto3 +
    • + +
    • Introduced through: + + docker-image|haproxy@2.6.14-alpine and openssl/libcrypto3@3.1.2-r0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|haproxy@2.6.14-alpine + + openssl/libcrypto3@3.1.2-r0 + + + +
    • +
    • + Introduced through: + docker-image|haproxy@2.6.14-alpine + + .haproxy-rundeps@20230809.001942 + + openssl/libcrypto3@3.1.2-r0 + + + +
    • +
    • + Introduced through: + docker-image|haproxy@2.6.14-alpine + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libcrypto3@3.1.2-r0 + + + +
    • +
    • + Introduced through: + docker-image|haproxy@2.6.14-alpine + + busybox/ssl_client@1.36.1-r2 + + openssl/libcrypto3@3.1.2-r0 + + + +
    • +
    • + Introduced through: + docker-image|haproxy@2.6.14-alpine + + .haproxy-rundeps@20230809.001942 + + openssl/libssl3@3.1.2-r0 + + openssl/libcrypto3@3.1.2-r0 + + + +
    • +
    • + Introduced through: + docker-image|haproxy@2.6.14-alpine + + openssl/libssl3@3.1.2-r0 + + + +
    • +
    • + Introduced through: + docker-image|haproxy@2.6.14-alpine + + .haproxy-rundeps@20230809.001942 + + openssl/libssl3@3.1.2-r0 + + + +
    • +
    • + Introduced through: + docker-image|haproxy@2.6.14-alpine + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libssl3@3.1.2-r0 + + + +
    • +
    • + Introduced through: + docker-image|haproxy@2.6.14-alpine + + busybox/ssl_client@1.36.1-r2 + + openssl/libssl3@3.1.2-r0 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine. + See How to fix? for Alpine:3.18 relevant fixed versions and status.

    +

    Issue summary: A bug has been identified in the processing of key and + initialisation vector (IV) lengths. This can lead to potential truncation + or overruns during the initialisation of some symmetric ciphers.

    +

    Impact summary: A truncation in the IV can result in non-uniqueness, + which could result in loss of confidentiality for some cipher modes.

    +

    When calling EVP_EncryptInit_ex2(), EVP_DecryptInit_ex2() or + EVP_CipherInit_ex2() the provided OSSL_PARAM array is processed after + the key and IV have been established. Any alterations to the key length, + via the "keylen" parameter or the IV length, via the "ivlen" parameter, + within the OSSL_PARAM array will not take effect as intended, potentially + causing truncation or overreading of these values. The following ciphers + and cipher modes are impacted: RC2, RC4, RC5, CCM, GCM and OCB.

    +

    For the CCM, GCM and OCB cipher modes, truncation of the IV can result in + loss of confidentiality. For example, when following NIST's SP 800-38D + section 8.2.1 guidance for constructing a deterministic IV for AES in + GCM mode, truncation of the counter portion could lead to IV reuse.

    +

    Both truncations and overruns of the key and overruns of the IV will + produce incorrect results and could, in some cases, trigger a memory + exception. However, these issues are not currently assessed as security + critical.

    +

    Changing the key and/or IV lengths is not considered to be a common operation + and the vulnerable API was recently introduced. Furthermore it is likely that + application developers will have spotted this problem during testing since + decryption would fail unless both peers in the communication were similarly + vulnerable. For these reasons we expect the probability of an application being + vulnerable to this to be quite low. However if an application is vulnerable then + this issue is considered very serious. For these reasons we have assessed this + issue as Moderate severity overall.

    +

    The OpenSSL SSL/TLS implementation is not affected by this issue.

    +

    The OpenSSL 3.0 and 3.1 FIPS providers are not affected by this because + the issue lies outside of the FIPS provider boundary.

    +

    OpenSSL 3.1 and 3.0 are vulnerable to this issue.

    +

    Remediation

    +

    Upgrade Alpine:3.18 openssl to version 3.1.4-r0 or higher.

    +

    References

    + + +
    + + + +
    +
    diff --git a/docs/snyk/v2.8.4/quay.io_argoproj_argocd_v2.8.4.html b/docs/snyk/v2.8.5/quay.io_argoproj_argocd_v2.8.5.html similarity index 92% rename from docs/snyk/v2.8.4/quay.io_argoproj_argocd_v2.8.4.html rename to docs/snyk/v2.8.5/quay.io_argoproj_argocd_v2.8.5.html index d2fabc64806b7..eb2bb47c67fc8 100644 --- a/docs/snyk/v2.8.4/quay.io_argoproj_argocd_v2.8.4.html +++ b/docs/snyk/v2.8.5/quay.io_argoproj_argocd_v2.8.5.html @@ -7,7 +7,7 @@ Snyk test report - + @@ -456,19 +456,19 @@

    Snyk test report

    -

    September 17th 2023, 12:19:32 am (UTC+00:00)

    +

    October 29th 2023, 12:22:15 am (UTC+00:00)

    Scanned the following paths:
      -
    • quay.io/argoproj/argocd:v2.8.4/argoproj/argocd (deb)
    • quay.io/argoproj/argocd:v2.8.4/argoproj/argo-cd/v2 (gomodules)
    • quay.io/argoproj/argocd:v2.8.4/kustomize/kustomize/v5 (gomodules)
    • quay.io/argoproj/argocd:v2.8.4/helm/v3 (gomodules)
    • quay.io/argoproj/argocd:v2.8.4/git-lfs/git-lfs (gomodules)
    • +
    • quay.io/argoproj/argocd:v2.8.5/argoproj/argocd (deb)
    • quay.io/argoproj/argocd:v2.8.5/argoproj/argo-cd/v2 (gomodules)
    • quay.io/argoproj/argocd:v2.8.5/kustomize/kustomize/v5 (gomodules)
    • quay.io/argoproj/argocd:v2.8.5/helm/v3 (gomodules)
    • quay.io/argoproj/argocd:v2.8.5/git-lfs/git-lfs (gomodules)
    -
    27 known vulnerabilities
    -
    102 vulnerable dependency paths
    -
    2116 dependencies
    +
    29 known vulnerabilities
    +
    97 vulnerable dependency paths
    +
    2117 dependencies
    @@ -476,6 +476,83 @@

    Snyk test report

    +
    +

    Denial of Service (DoS)

    +
    + +
    + high severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + golang.org/x/net/http2 +
    • + +
    • Introduced through: + + helm.sh/helm/v3@* and golang.org/x/net/http2@v0.8.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + helm.sh/helm/v3@* + + golang.org/x/net/http2@v0.8.0 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    golang.org/x/net/http2 is a work-in-progress HTTP/2 implementation for Go.

    +

    Affected versions of this package are vulnerable to Denial of Service (DoS) in the implementation of the HTTP/2 protocol. An attacker can cause a denial of service (including via DDoS) by rapidly resetting many streams through request cancellation.

    +

    Remediation

    +

    Upgrade golang.org/x/net/http2 to version 0.17.0 or higher.

    +

    References

    + + +
    + + + +

    Directory Traversal

    @@ -585,7 +662,7 @@

    CVE-2020-22916

  • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 and xz-utils/liblzma5@5.2.5-2ubuntu1 + docker-image|quay.io/argoproj/argocd@v2.8.5 and xz-utils/liblzma5@5.2.5-2ubuntu1
  • @@ -598,7 +675,7 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 xz-utils/liblzma5@5.2.5-2ubuntu1 @@ -614,7 +691,7 @@

      Detailed paths

      NVD Description

      Note: Versions mentioned in the description apply only to the upstream xz-utils package and not the xz-utils package as distributed by Ubuntu. See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

      -

      An issue discovered in XZ 5.2.5 allows attackers to cause a denial of service via decompression of a crafted file. NOTE: the software maintainers are unable to reproduce this as of 2023-09-12 because the example crafted file is temporarily offline.

      +

      ** DISPUTED ** An issue discovered in XZ 5.2.5 allows attackers to cause a denial of service via decompression of a crafted file. NOTE: the vendor disputes the claims of "endless output" and "denial of service" because decompression of the 17,486 bytes always results in 114,881,179 bytes, which is often a reasonable size increase.

      Remediation

      There is no fixed version for Ubuntu:22.04 xz-utils.

      References

      @@ -626,6 +703,7 @@

      References

    • cve@mitre.org
    • cve@mitre.org
    • cve@mitre.org
    • +
    • cve@mitre.org

    @@ -658,7 +736,7 @@

    Out-of-bounds Write

  • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4, git@1:2.34.1-1ubuntu1.10 and others + docker-image|quay.io/argoproj/argocd@v2.8.5, git@1:2.34.1-1ubuntu1.10 and others
  • @@ -670,7 +748,7 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 git@1:2.34.1-1ubuntu1.10 @@ -683,7 +761,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 git@1:2.34.1-1ubuntu1.10 @@ -698,7 +776,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 git@1:2.34.1-1ubuntu1.10 @@ -711,7 +789,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 git@1:2.34.1-1ubuntu1.10 @@ -722,7 +800,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 perl/perl-base@5.34.0-3ubuntu1.2 @@ -777,7 +855,7 @@

      Access of Uninitialized Pointer

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 and krb5/libk5crypto3@1.19.2-2ubuntu0.2 + docker-image|quay.io/argoproj/argocd@v2.8.5 and krb5/libk5crypto3@1.19.2-2ubuntu0.2
    @@ -790,7 +868,7 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 krb5/libk5crypto3@1.19.2-2ubuntu0.2 @@ -799,7 +877,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 adduser@3.118ubuntu5 @@ -820,7 +898,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 adduser@3.118ubuntu5 @@ -843,7 +921,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 krb5/libkrb5-3@1.19.2-2ubuntu0.2 @@ -852,7 +930,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 adduser@3.118ubuntu5 @@ -873,7 +951,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.2 @@ -882,9 +960,9 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 - openssh/openssh-client@1:8.9p1-3ubuntu0.3 + openssh/openssh-client@1:8.9p1-3ubuntu0.4 krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.2 @@ -893,11 +971,11 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 git@1:2.34.1-1ubuntu1.10 - curl/libcurl3-gnutls@7.81.0-1ubuntu1.13 + curl/libcurl3-gnutls@7.81.0-1ubuntu1.14 krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.2 @@ -906,11 +984,11 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 git@1:2.34.1-1ubuntu1.10 - curl/libcurl3-gnutls@7.81.0-1ubuntu1.13 + curl/libcurl3-gnutls@7.81.0-1ubuntu1.14 libssh/libssh-4@0.9.6-2ubuntu0.22.04.1 @@ -921,7 +999,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 adduser@3.118ubuntu5 @@ -940,7 +1018,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 krb5/libkrb5support0@1.19.2-2ubuntu0.2 @@ -967,6 +1045,7 @@

      References

    • cve@mitre.org
    • cve@mitre.org
    • cve@mitre.org
    • +
    • cve@mitre.org

    @@ -975,6 +1054,146 @@

    References

    More about this vulnerability

    +
    +
    +

    LGPL-3.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Module: + + gopkg.in/retry.v1 +
    • + +
    • Introduced through: + + github.com/argoproj/argo-cd/v2@* and gopkg.in/retry.v1@v1.0.3 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@* + + gopkg.in/retry.v1@v1.0.3 + + + +
    • +
    + +
    + +
    + +

    LGPL-3.0 license

    + +
    + + + +
    +
    +

    Memory Leak

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + glibc/libc-bin +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.8.5 and glibc/libc-bin@2.35-0ubuntu3.4 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.5 + + glibc/libc-bin@2.35-0ubuntu3.4 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.8.5 + + glibc/libc6@2.35-0ubuntu3.4 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream glibc package and not the glibc package as distributed by Ubuntu. + See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    +

    A flaw was found in the GNU C Library. A recent fix for CVE-2023-4806 introduced the potential for a memory leak, which may result in an application crash.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 glibc.

    +

    References

    + + +
    + + +

    MPL-2.0 license

    @@ -1341,7 +1560,7 @@

    CVE-2022-46908

  • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4, gnupg2/gpg@2.2.27-3ubuntu2.1 and others + docker-image|quay.io/argoproj/argocd@v2.8.5, gnupg2/gpg@2.2.27-3ubuntu2.1 and others
  • @@ -1353,7 +1572,7 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 gnupg2/gpg@2.2.27-3ubuntu2.1 @@ -1412,7 +1631,7 @@

      Arbitrary Code Injection

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 and shadow/passwd@1:4.8.1-2ubuntu2.1 + docker-image|quay.io/argoproj/argocd@v2.8.5 and shadow/passwd@1:4.8.1-2ubuntu2.1
    @@ -1425,7 +1644,7 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 shadow/passwd@1:4.8.1-2ubuntu2.1 @@ -1434,7 +1653,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 adduser@3.118ubuntu5 @@ -1445,9 +1664,9 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 - openssh/openssh-client@1:8.9p1-3ubuntu0.3 + openssh/openssh-client@1:8.9p1-3ubuntu0.4 shadow/passwd@1:4.8.1-2ubuntu2.1 @@ -1456,7 +1675,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 shadow/login@1:4.8.1-2ubuntu2.1 @@ -1513,7 +1732,7 @@

      Out-of-bounds Write

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 and procps/libprocps8@2:3.3.17-6ubuntu2 + docker-image|quay.io/argoproj/argocd@v2.8.5 and procps/libprocps8@2:3.3.17-6ubuntu2
    @@ -1526,7 +1745,7 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 procps/libprocps8@2:3.3.17-6ubuntu2 @@ -1535,7 +1754,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 procps@2:3.3.17-6ubuntu2 @@ -1546,7 +1765,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 procps@2:3.3.17-6ubuntu2 @@ -1601,7 +1820,7 @@

      Uncontrolled Recursion

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 and pcre3/libpcre3@2:8.39-13ubuntu0.22.04.1 + docker-image|quay.io/argoproj/argocd@v2.8.5 and pcre3/libpcre3@2:8.39-13ubuntu0.22.04.1
    @@ -1614,7 +1833,7 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 pcre3/libpcre3@2:8.39-13ubuntu0.22.04.1 @@ -1623,7 +1842,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 grep@3.7-1build1 @@ -1685,7 +1904,7 @@

      Release of Invalid Pointer or Reference

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 and patch@2.7.6-7build2 + docker-image|quay.io/argoproj/argocd@v2.8.5 and patch@2.7.6-7build2
    @@ -1698,7 +1917,7 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 patch@2.7.6-7build2 @@ -1752,7 +1971,7 @@

      Double Free

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 and patch@2.7.6-7build2 + docker-image|quay.io/argoproj/argocd@v2.8.5 and patch@2.7.6-7build2
    @@ -1765,7 +1984,7 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 patch@2.7.6-7build2 @@ -1801,198 +2020,6 @@

      References

      More about this vulnerability

    -
    -
    -

    Improper Authentication

    -
    - -
    - low severity -
    - -
    - -
      -
    • - Package Manager: ubuntu:22.04 -
    • -
    • - Vulnerable module: - - openssl/libssl3 -
    • - -
    • Introduced through: - - docker-image|quay.io/argoproj/argocd@v2.8.4 and openssl/libssl3@3.0.2-0ubuntu1.10 - -
    • -
    - -
    - - -

    Detailed paths

    - -
      -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 - - openssl/libssl3@3.0.2-0ubuntu1.10 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 - - cyrus-sasl2/libsasl2-modules@2.1.27+dfsg2-3ubuntu1.2 - - openssl/libssl3@3.0.2-0ubuntu1.10 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 - - libfido2/libfido2-1@1.10.0-1 - - openssl/libssl3@3.0.2-0ubuntu1.10 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 - - openssh/openssh-client@1:8.9p1-3ubuntu0.3 - - openssl/libssl3@3.0.2-0ubuntu1.10 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 - - ca-certificates@20230311ubuntu0.22.04.1 - - openssl@3.0.2-0ubuntu1.10 - - openssl/libssl3@3.0.2-0ubuntu1.10 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 - - git@1:2.34.1-1ubuntu1.10 - - curl/libcurl3-gnutls@7.81.0-1ubuntu1.13 - - libssh/libssh-4@0.9.6-2ubuntu0.22.04.1 - - openssl/libssl3@3.0.2-0ubuntu1.10 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 - - adduser@3.118ubuntu5 - - shadow/passwd@1:4.8.1-2ubuntu2.1 - - pam/libpam-modules@1.4.0-11ubuntu2.3 - - libnsl/libnsl2@1.3.0-2build2 - - libtirpc/libtirpc3@1.3.2-2ubuntu0.1 - - krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.2 - - krb5/libkrb5-3@1.19.2-2ubuntu0.2 - - openssl/libssl3@3.0.2-0ubuntu1.10 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 - - openssl@3.0.2-0ubuntu1.10 - - - -
    • -
    • - Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 - - ca-certificates@20230311ubuntu0.22.04.1 - - openssl@3.0.2-0ubuntu1.10 - - - -
    • -
    - -
    - -
    - -

    NVD Description

    -

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Ubuntu:22.04. - See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    -

    Issue summary: The AES-SIV cipher implementation contains a bug that causes - it to ignore empty associated data entries which are unauthenticated as - a consequence.

    -

    Impact summary: Applications that use the AES-SIV algorithm and want to - authenticate empty data entries as associated data can be mislead by removing - adding or reordering such empty entries as these are ignored by the OpenSSL - implementation. We are currently unaware of any such applications.

    -

    The AES-SIV algorithm allows for authentication of multiple associated - data entries along with the encryption. To authenticate empty data the - application has to call EVP_EncryptUpdate() (or EVP_CipherUpdate()) with - NULL pointer as the output buffer and 0 as the input buffer length. - The AES-SIV implementation in OpenSSL just returns success for such a call - instead of performing the associated data authentication operation. - The empty data thus will not be authenticated.

    -

    As this issue does not affect non-empty associated data authentication and - we expect it to be rare for an application to use empty associated data - entries this is qualified as Low severity issue.

    -

    Remediation

    -

    There is no fixed version for Ubuntu:22.04 openssl.

    -

    References

    - - -
    - - -

    CVE-2023-28531

    @@ -2016,7 +2043,7 @@

    CVE-2023-28531

  • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 and openssh/openssh-client@1:8.9p1-3ubuntu0.3 + docker-image|quay.io/argoproj/argocd@v2.8.5 and openssh/openssh-client@1:8.9p1-3ubuntu0.4
  • @@ -2029,9 +2056,9 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 - openssh/openssh-client@1:8.9p1-3ubuntu0.3 + openssh/openssh-client@1:8.9p1-3ubuntu0.4 @@ -2086,7 +2113,7 @@

      NULL Pointer Dereference

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4, gnupg2/dirmngr@2.2.27-3ubuntu2.1 and others + docker-image|quay.io/argoproj/argocd@v2.8.5, gnupg2/dirmngr@2.2.27-3ubuntu2.1 and others
    @@ -2098,7 +2125,7 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 gnupg2/dirmngr@2.2.27-3ubuntu2.1 @@ -2109,11 +2136,11 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 git@1:2.34.1-1ubuntu1.10 - curl/libcurl3-gnutls@7.81.0-1ubuntu1.13 + curl/libcurl3-gnutls@7.81.0-1ubuntu1.14 openldap/libldap-2.5-0@2.5.16+dfsg-0ubuntu0.22.04.1 @@ -2122,7 +2149,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 openldap/libldap-common@2.5.16+dfsg-0ubuntu0.22.04.1 @@ -2184,7 +2211,7 @@

      Resource Exhaustion

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 and libzstd/libzstd1@1.4.8+dfsg-3build1 + docker-image|quay.io/argoproj/argocd@v2.8.5 and libzstd/libzstd1@1.4.8+dfsg-3build1
    @@ -2197,7 +2224,7 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 libzstd/libzstd1@1.4.8+dfsg-3build1 @@ -2255,7 +2282,7 @@

      Integer Overflow or Wraparound

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 and krb5/libk5crypto3@1.19.2-2ubuntu0.2 + docker-image|quay.io/argoproj/argocd@v2.8.5 and krb5/libk5crypto3@1.19.2-2ubuntu0.2
    @@ -2268,7 +2295,7 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 krb5/libk5crypto3@1.19.2-2ubuntu0.2 @@ -2277,7 +2304,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 adduser@3.118ubuntu5 @@ -2298,7 +2325,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 adduser@3.118ubuntu5 @@ -2321,7 +2348,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 krb5/libkrb5-3@1.19.2-2ubuntu0.2 @@ -2330,7 +2357,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 adduser@3.118ubuntu5 @@ -2351,7 +2378,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.2 @@ -2360,9 +2387,9 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 - openssh/openssh-client@1:8.9p1-3ubuntu0.3 + openssh/openssh-client@1:8.9p1-3ubuntu0.4 krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.2 @@ -2371,11 +2398,11 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 git@1:2.34.1-1ubuntu1.10 - curl/libcurl3-gnutls@7.81.0-1ubuntu1.13 + curl/libcurl3-gnutls@7.81.0-1ubuntu1.14 krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.2 @@ -2384,11 +2411,11 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 git@1:2.34.1-1ubuntu1.10 - curl/libcurl3-gnutls@7.81.0-1ubuntu1.13 + curl/libcurl3-gnutls@7.81.0-1ubuntu1.14 libssh/libssh-4@0.9.6-2ubuntu0.22.04.1 @@ -2399,7 +2426,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 adduser@3.118ubuntu5 @@ -2418,7 +2445,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 krb5/libkrb5support0@1.19.2-2ubuntu0.2 @@ -2475,7 +2502,7 @@

      Out-of-bounds Write

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 and gnupg2/gpgv@2.2.27-3ubuntu2.1 + docker-image|quay.io/argoproj/argocd@v2.8.5 and gnupg2/gpgv@2.2.27-3ubuntu2.1
    @@ -2488,7 +2515,7 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 gnupg2/gpgv@2.2.27-3ubuntu2.1 @@ -2497,7 +2524,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 apt@2.4.10 @@ -2508,7 +2535,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 gnupg2/gnupg@2.2.27-3ubuntu2.1 @@ -2519,7 +2546,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 gnupg2/dirmngr@2.2.27-3ubuntu2.1 @@ -2530,7 +2557,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 gnupg2/gpg@2.2.27-3ubuntu2.1 @@ -2541,7 +2568,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 gnupg2/gnupg@2.2.27-3ubuntu2.1 @@ -2554,7 +2581,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 gnupg2/gnupg@2.2.27-3ubuntu2.1 @@ -2567,7 +2594,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 gnupg2/dirmngr@2.2.27-3ubuntu2.1 @@ -2576,7 +2603,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 gnupg2/gnupg@2.2.27-3ubuntu2.1 @@ -2587,7 +2614,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 gnupg2/gnupg@2.2.27-3ubuntu2.1 @@ -2600,7 +2627,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 gnupg2/gnupg-l10n@2.2.27-3ubuntu2.1 @@ -2609,7 +2636,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 gnupg2/gnupg@2.2.27-3ubuntu2.1 @@ -2620,7 +2647,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 gnupg2/gnupg-utils@2.2.27-3ubuntu2.1 @@ -2629,7 +2656,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 gnupg2/gnupg@2.2.27-3ubuntu2.1 @@ -2640,7 +2667,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 gnupg2/gpg@2.2.27-3ubuntu2.1 @@ -2649,7 +2676,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 gnupg2/gnupg@2.2.27-3ubuntu2.1 @@ -2660,7 +2687,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 gnupg2/gnupg@2.2.27-3ubuntu2.1 @@ -2673,7 +2700,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 gnupg2/gnupg@2.2.27-3ubuntu2.1 @@ -2686,7 +2713,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 gnupg2/gpg-agent@2.2.27-3ubuntu2.1 @@ -2695,7 +2722,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 gnupg2/gnupg@2.2.27-3ubuntu2.1 @@ -2706,7 +2733,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 gnupg2/gnupg@2.2.27-3ubuntu2.1 @@ -2719,7 +2746,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 gnupg2/gnupg@2.2.27-3ubuntu2.1 @@ -2732,7 +2759,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 gnupg2/gpg-wks-client@2.2.27-3ubuntu2.1 @@ -2741,7 +2768,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 gnupg2/gnupg@2.2.27-3ubuntu2.1 @@ -2752,7 +2779,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 gnupg2/gpg-wks-server@2.2.27-3ubuntu2.1 @@ -2761,7 +2788,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 gnupg2/gnupg@2.2.27-3ubuntu2.1 @@ -2772,7 +2799,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 gnupg2/gpgsm@2.2.27-3ubuntu2.1 @@ -2781,7 +2808,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 gnupg2/gnupg@2.2.27-3ubuntu2.1 @@ -2792,7 +2819,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 gnupg2/gnupg@2.2.27-3ubuntu2.1 @@ -2851,7 +2878,7 @@

      Allocation of Resources Without Limits or Throttling

      Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 and glibc/libc-bin@2.35-0ubuntu3.3 + docker-image|quay.io/argoproj/argocd@v2.8.5 and glibc/libc-bin@2.35-0ubuntu3.4
    @@ -2864,18 +2891,18 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 - glibc/libc-bin@2.35-0ubuntu3.3 + glibc/libc-bin@2.35-0ubuntu3.4
    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 - glibc/libc6@2.35-0ubuntu3.3 + glibc/libc6@2.35-0ubuntu3.4 @@ -2930,7 +2957,7 @@

      Improper Input Validation

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4, git@1:2.34.1-1ubuntu1.10 and others + docker-image|quay.io/argoproj/argocd@v2.8.5, git@1:2.34.1-1ubuntu1.10 and others
    @@ -2942,7 +2969,7 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 git@1:2.34.1-1ubuntu1.10 @@ -2953,7 +2980,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 git@1:2.34.1-1ubuntu1.10 @@ -2962,7 +2989,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 git-lfs@3.0.2-1ubuntu0.2 @@ -3019,7 +3046,7 @@

      Uncontrolled Recursion

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 and gcc-12/libstdc++6@12.3.0-1ubuntu1~22.04 + docker-image|quay.io/argoproj/argocd@v2.8.5 and gcc-12/libstdc++6@12.3.0-1ubuntu1~22.04
    @@ -3032,7 +3059,7 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 gcc-12/libstdc++6@12.3.0-1ubuntu1~22.04 @@ -3041,7 +3068,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 apt@2.4.10 @@ -3052,7 +3079,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 apt@2.4.10 @@ -3065,7 +3092,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 gcc-12/gcc-12-base@12.3.0-1ubuntu1~22.04 @@ -3074,7 +3101,7 @@

      Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 gcc-12/libgcc-s1@12.3.0-1ubuntu1~22.04 @@ -3130,7 +3157,7 @@

      Improper Input Validation

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 and coreutils@8.32-4.1ubuntu1 + docker-image|quay.io/argoproj/argocd@v2.8.5 and coreutils@8.32-4.1ubuntu1
    @@ -3143,7 +3170,7 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 coreutils@8.32-4.1ubuntu1 @@ -3200,7 +3227,7 @@

      Out-of-bounds Write

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 and bash@5.1-6ubuntu1 + docker-image|quay.io/argoproj/argocd@v2.8.5 and bash@5.1-6ubuntu1
    @@ -3213,7 +3240,7 @@

    Detailed paths

    • Introduced through: - docker-image|quay.io/argoproj/argocd@v2.8.4 + docker-image|quay.io/argoproj/argocd@v2.8.5 bash@5.1-6ubuntu1 diff --git a/docs/snyk/v2.8.4/redis_7.0.11-alpine.html b/docs/snyk/v2.8.5/redis_7.0.11-alpine.html similarity index 81% rename from docs/snyk/v2.8.4/redis_7.0.11-alpine.html rename to docs/snyk/v2.8.5/redis_7.0.11-alpine.html index e44d0b26fc925..20730eb214f1d 100644 --- a/docs/snyk/v2.8.4/redis_7.0.11-alpine.html +++ b/docs/snyk/v2.8.5/redis_7.0.11-alpine.html @@ -7,7 +7,7 @@ Snyk test report - + @@ -456,7 +456,7 @@

      Snyk test report

      -

      September 17th 2023, 12:19:39 am (UTC+00:00)

      +

      October 29th 2023, 12:22:23 am (UTC+00:00)

      Scanned the following path: @@ -466,8 +466,8 @@

      Snyk test report

      -
      4 known vulnerabilities
      -
      32 vulnerable dependency paths
      +
      5 known vulnerabilities
      +
      41 vulnerable dependency paths
      18 dependencies
    @@ -905,7 +905,7 @@

    Detailed paths


    NVD Description

    -

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine:3.18. +

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine. See How to fix? for Alpine:3.18 relevant fixed versions and status.

    Issue summary: Checking excessively long DH keys or parameters may be very slow.

    Impact summary: Applications that use the functions DH_check(), DH_check_ex() @@ -1090,7 +1090,7 @@

    Detailed paths


    NVD Description

    -

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine:3.18. +

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine. See How to fix? for Alpine:3.18 relevant fixed versions and status.

    Issue summary: Checking excessively long DH keys or parameters may be very slow.

    Impact summary: Applications that use the functions DH_check(), DH_check_ex() @@ -1125,6 +1125,9 @@

    References

  • openssl-security@openssl.org
  • openssl-security@openssl.org
  • openssl-security@openssl.org
  • +
  • openssl-security@openssl.org
  • +
  • openssl-security@openssl.org
  • +
  • openssl-security@openssl.org

  • @@ -1134,6 +1137,196 @@

    References

    +
    +

    CVE-2023-5363

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Package Manager: alpine:3.18 +
    • +
    • + Vulnerable module: + + openssl/libcrypto3 +
    • + +
    • Introduced through: + + docker-image|redis@7.0.11-alpine and openssl/libcrypto3@3.1.1-r1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + .redis-rundeps@20230614.215749 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + busybox/ssl_client@1.36.1-r0 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + .redis-rundeps@20230614.215749 + + openssl/libssl3@3.1.1-r1 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + .redis-rundeps@20230614.215749 + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + busybox/ssl_client@1.36.1-r0 + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine. + See How to fix? for Alpine:3.18 relevant fixed versions and status.

    +

    Issue summary: A bug has been identified in the processing of key and + initialisation vector (IV) lengths. This can lead to potential truncation + or overruns during the initialisation of some symmetric ciphers.

    +

    Impact summary: A truncation in the IV can result in non-uniqueness, + which could result in loss of confidentiality for some cipher modes.

    +

    When calling EVP_EncryptInit_ex2(), EVP_DecryptInit_ex2() or + EVP_CipherInit_ex2() the provided OSSL_PARAM array is processed after + the key and IV have been established. Any alterations to the key length, + via the "keylen" parameter or the IV length, via the "ivlen" parameter, + within the OSSL_PARAM array will not take effect as intended, potentially + causing truncation or overreading of these values. The following ciphers + and cipher modes are impacted: RC2, RC4, RC5, CCM, GCM and OCB.

    +

    For the CCM, GCM and OCB cipher modes, truncation of the IV can result in + loss of confidentiality. For example, when following NIST's SP 800-38D + section 8.2.1 guidance for constructing a deterministic IV for AES in + GCM mode, truncation of the counter portion could lead to IV reuse.

    +

    Both truncations and overruns of the key and overruns of the IV will + produce incorrect results and could, in some cases, trigger a memory + exception. However, these issues are not currently assessed as security + critical.

    +

    Changing the key and/or IV lengths is not considered to be a common operation + and the vulnerable API was recently introduced. Furthermore it is likely that + application developers will have spotted this problem during testing since + decryption would fail unless both peers in the communication were similarly + vulnerable. For these reasons we expect the probability of an application being + vulnerable to this to be quite low. However if an application is vulnerable then + this issue is considered very serious. For these reasons we have assessed this + issue as Moderate severity overall.

    +

    The OpenSSL SSL/TLS implementation is not affected by this issue.

    +

    The OpenSSL 3.0 and 3.1 FIPS providers are not affected by this because + the issue lies outside of the FIPS provider boundary.

    +

    OpenSSL 3.1 and 3.0 are vulnerable to this issue.

    +

    Remediation

    +

    Upgrade Alpine:3.18 openssl to version 3.1.4-r0 or higher.

    +

    References

    + + +
    + + + +
    diff --git a/docs/snyk/v2.9.0-rc3/argocd-iac-install.html b/docs/snyk/v2.9.0-rc3/argocd-iac-install.html new file mode 100644 index 0000000000000..207acd982d50e --- /dev/null +++ b/docs/snyk/v2.9.0-rc3/argocd-iac-install.html @@ -0,0 +1,2679 @@ + + + + + + + + + Snyk test report + + + + + + + + + +
    +
    +
    +
    + + + Snyk - Open Source Security + + + + + + + +
    +

    Snyk test report

    + +

    October 29th 2023, 12:20:57 am (UTC+00:00)

    +
    +
    + Scanned the following path: +
      +
    • /argo-cd/manifests/install.yaml (Kubernetes)
    • +
    +
    + +
    +
    40 total issues
    +
    +
    +
    +
    + +
    + + + + + + +
    Project manifests/install.yaml
    Path /argo-cd/manifests/install.yaml
    Project Type Kubernetes
    +
    +
    +
    +

    Role with dangerous permissions

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-47 +
    • + +
    • Introduced through: + [DocId: 10] + + rules[0] + + resources + +
    • + +
    • + Line number: 20316 +
    • +
    + +
    + +

    Impact

    +

    Using this role grants dangerous permissions

    + +

    Remediation

    +

    Consider removing this permissions

    + + +
    +
    + + + +
    +
    +

    Role with dangerous permissions

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-47 +
    • + +
    • Introduced through: + [DocId: 11] + + rules[4] + + resources + +
    • + +
    • + Line number: 20393 +
    • +
    + +
    + +

    Impact

    +

    Using this role grants dangerous permissions

    + +

    Remediation

    +

    Consider removing this permissions

    + + +
    +
    + + + +
    +
    +

    Role with dangerous permissions

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-47 +
    • + +
    • Introduced through: + [DocId: 12] + + rules[0] + + resources + +
    • + +
    • + Line number: 20421 +
    • +
    + +
    + +

    Impact

    +

    Using this role grants dangerous permissions

    + +

    Remediation

    +

    Consider removing this permissions

    + + +
    +
    + + + +
    +
    +

    Role with dangerous permissions

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-47 +
    • + +
    • Introduced through: + [DocId: 13] + + rules[3] + + resources + +
    • + +
    • + Line number: 20469 +
    • +
    + +
    + +

    Impact

    +

    Using this role grants dangerous permissions

    + +

    Remediation

    +

    Consider removing this permissions

    + + +
    +
    + + + +
    +
    +

    Role with dangerous permissions

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-47 +
    • + +
    • Introduced through: + [DocId: 13] + + rules[1] + + resources + +
    • + +
    • + Line number: 20451 +
    • +
    + +
    + +

    Impact

    +

    Using this role grants dangerous permissions

    + +

    Remediation

    +

    Consider removing this permissions

    + + +
    +
    + + + +
    +
    +

    Role with dangerous permissions

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-47 +
    • + +
    • Introduced through: + [DocId: 14] + + rules[0] + + resources + +
    • + +
    • + Line number: 20485 +
    • +
    + +
    + +

    Impact

    +

    Using this role grants dangerous permissions

    + +

    Remediation

    +

    Consider removing this permissions

    + + +
    +
    + + + +
    +
    +

    Container could be running with outdated image

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-42 +
    • + +
    • Introduced through: + [DocId: 45] + + spec + + template + + spec + + initContainers[copyutil] + + imagePullPolicy + +
    • + +
    • + Line number: 21618 +
    • +
    + +
    + +

    Impact

    +

    The container may run with outdated or unauthorized image

    + +

    Remediation

    +

    Set `imagePullPolicy` attribute to `Always`

    + + +
    +
    + + + +
    +
    +

    Container has no CPU limit

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-5 +
    • + +
    • Introduced through: + [DocId: 41] + + input + + spec + + template + + spec + + containers[argocd-applicationset-controller] + + resources + + limits + + cpu + +
    • + +
    • + Line number: 20969 +
    • +
    + +
    + +

    Impact

    +

    CPU limits can prevent containers from consuming valuable compute time for no benefit (e.g. inefficient code) that might lead to unnecessary costs. It is advisable to also configure CPU requests to ensure application stability.

    + +

    Remediation

    +

    Add `resources.limits.cpu` field with required CPU limit value

    + + +
    +
    + + + +
    +
    +

    Container has no CPU limit

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-5 +
    • + +
    • Introduced through: + [DocId: 42] + + input + + spec + + template + + spec + + initContainers[copyutil] + + resources + + limits + + cpu + +
    • + +
    • + Line number: 21214 +
    • +
    + +
    + +

    Impact

    +

    CPU limits can prevent containers from consuming valuable compute time for no benefit (e.g. inefficient code) that might lead to unnecessary costs. It is advisable to also configure CPU requests to ensure application stability.

    + +

    Remediation

    +

    Add `resources.limits.cpu` field with required CPU limit value

    + + +
    +
    + + + +
    +
    +

    Container has no CPU limit

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-5 +
    • + +
    • Introduced through: + [DocId: 42] + + input + + spec + + template + + spec + + containers[dex] + + resources + + limits + + cpu + +
    • + +
    • + Line number: 21180 +
    • +
    + +
    + +

    Impact

    +

    CPU limits can prevent containers from consuming valuable compute time for no benefit (e.g. inefficient code) that might lead to unnecessary costs. It is advisable to also configure CPU requests to ensure application stability.

    + +

    Remediation

    +

    Add `resources.limits.cpu` field with required CPU limit value

    + + +
    +
    + + + +
    +
    +

    Container has no CPU limit

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-5 +
    • + +
    • Introduced through: + [DocId: 43] + + input + + spec + + template + + spec + + containers[argocd-notifications-controller] + + resources + + limits + + cpu + +
    • + +
    • + Line number: 21274 +
    • +
    + +
    + +

    Impact

    +

    CPU limits can prevent containers from consuming valuable compute time for no benefit (e.g. inefficient code) that might lead to unnecessary costs. It is advisable to also configure CPU requests to ensure application stability.

    + +

    Remediation

    +

    Add `resources.limits.cpu` field with required CPU limit value

    + + +
    +
    + + + +
    +
    +

    Container has no CPU limit

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-5 +
    • + +
    • Introduced through: + [DocId: 44] + + input + + spec + + template + + spec + + containers[redis] + + resources + + limits + + cpu + +
    • + +
    • + Line number: 21361 +
    • +
    + +
    + +

    Impact

    +

    CPU limits can prevent containers from consuming valuable compute time for no benefit (e.g. inefficient code) that might lead to unnecessary costs. It is advisable to also configure CPU requests to ensure application stability.

    + +

    Remediation

    +

    Add `resources.limits.cpu` field with required CPU limit value

    + + +
    +
    + + + +
    +
    +

    Container has no CPU limit

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-5 +
    • + +
    • Introduced through: + [DocId: 45] + + input + + spec + + template + + spec + + initContainers[copyutil] + + resources + + limits + + cpu + +
    • + +
    • + Line number: 21618 +
    • +
    + +
    + +

    Impact

    +

    CPU limits can prevent containers from consuming valuable compute time for no benefit (e.g. inefficient code) that might lead to unnecessary costs. It is advisable to also configure CPU requests to ensure application stability.

    + +

    Remediation

    +

    Add `resources.limits.cpu` field with required CPU limit value

    + + +
    +
    + + + +
    +
    +

    Container has no CPU limit

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-5 +
    • + +
    • Introduced through: + [DocId: 45] + + input + + spec + + template + + spec + + containers[argocd-repo-server] + + resources + + limits + + cpu + +
    • + +
    • + Line number: 21418 +
    • +
    + +
    + +

    Impact

    +

    CPU limits can prevent containers from consuming valuable compute time for no benefit (e.g. inefficient code) that might lead to unnecessary costs. It is advisable to also configure CPU requests to ensure application stability.

    + +

    Remediation

    +

    Add `resources.limits.cpu` field with required CPU limit value

    + + +
    +
    + + + +
    +
    +

    Container has no CPU limit

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-5 +
    • + +
    • Introduced through: + [DocId: 46] + + input + + spec + + template + + spec + + containers[argocd-server] + + resources + + limits + + cpu + +
    • + +
    • + Line number: 21703 +
    • +
    + +
    + +

    Impact

    +

    CPU limits can prevent containers from consuming valuable compute time for no benefit (e.g. inefficient code) that might lead to unnecessary costs. It is advisable to also configure CPU requests to ensure application stability.

    + +

    Remediation

    +

    Add `resources.limits.cpu` field with required CPU limit value

    + + +
    +
    + + + +
    +
    +

    Container has no CPU limit

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-5 +
    • + +
    • Introduced through: + [DocId: 47] + + input + + spec + + template + + spec + + containers[argocd-application-controller] + + resources + + limits + + cpu + +
    • + +
    • + Line number: 22019 +
    • +
    + +
    + +

    Impact

    +

    CPU limits can prevent containers from consuming valuable compute time for no benefit (e.g. inefficient code) that might lead to unnecessary costs. It is advisable to also configure CPU requests to ensure application stability.

    + +

    Remediation

    +

    Add `resources.limits.cpu` field with required CPU limit value

    + + +
    +
    + + + +
    +
    +

    Container is running with multiple open ports

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-36 +
    • + +
    • Introduced through: + [DocId: 42] + + spec + + template + + spec + + containers[dex] + + ports + +
    • + +
    • + Line number: 21194 +
    • +
    + +
    + +

    Impact

    +

    Increases the attack surface of the application and the container.

    + +

    Remediation

    +

    Reduce `ports` count to 2

    + + +
    +
    + + + +
    +
    +

    Container is running without liveness probe

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-41 +
    • + +
    • Introduced through: + [DocId: 41] + + spec + + template + + spec + + containers[argocd-applicationset-controller] + + livenessProbe + +
    • + +
    • + Line number: 20969 +
    • +
    + +
    + +

    Impact

    +

    Kubernetes will not be able to detect if application is able to service requests, and will not restart unhealthy pods

    + +

    Remediation

    +

    Add `livenessProbe` attribute

    + + +
    +
    + + + +
    +
    +

    Container is running without liveness probe

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-41 +
    • + +
    • Introduced through: + [DocId: 42] + + spec + + template + + spec + + initContainers[copyutil] + + livenessProbe + +
    • + +
    • + Line number: 21214 +
    • +
    + +
    + +

    Impact

    +

    Kubernetes will not be able to detect if application is able to service requests, and will not restart unhealthy pods

    + +

    Remediation

    +

    Add `livenessProbe` attribute

    + + +
    +
    + + + +
    +
    +

    Container is running without liveness probe

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-41 +
    • + +
    • Introduced through: + [DocId: 42] + + spec + + template + + spec + + containers[dex] + + livenessProbe + +
    • + +
    • + Line number: 21180 +
    • +
    + +
    + +

    Impact

    +

    Kubernetes will not be able to detect if application is able to service requests, and will not restart unhealthy pods

    + +

    Remediation

    +

    Add `livenessProbe` attribute

    + + +
    +
    + + + +
    +
    +

    Container is running without liveness probe

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-41 +
    • + +
    • Introduced through: + [DocId: 44] + + spec + + template + + spec + + containers[redis] + + livenessProbe + +
    • + +
    • + Line number: 21361 +
    • +
    + +
    + +

    Impact

    +

    Kubernetes will not be able to detect if application is able to service requests, and will not restart unhealthy pods

    + +

    Remediation

    +

    Add `livenessProbe` attribute

    + + +
    +
    + + + +
    +
    +

    Container is running without liveness probe

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-41 +
    • + +
    • Introduced through: + [DocId: 45] + + spec + + template + + spec + + initContainers[copyutil] + + livenessProbe + +
    • + +
    • + Line number: 21618 +
    • +
    + +
    + +

    Impact

    +

    Kubernetes will not be able to detect if application is able to service requests, and will not restart unhealthy pods

    + +

    Remediation

    +

    Add `livenessProbe` attribute

    + + +
    +
    + + + +
    +
    +

    Container is running without memory limit

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-4 +
    • + +
    • Introduced through: + [DocId: 41] + + input + + spec + + template + + spec + + containers[argocd-applicationset-controller] + + resources + + limits + + memory + +
    • + +
    • + Line number: 20969 +
    • +
    + +
    + +

    Impact

    +

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    + +

    Remediation

    +

    Set `resources.limits.memory` value

    + + +
    +
    + + + +
    +
    +

    Container is running without memory limit

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-4 +
    • + +
    • Introduced through: + [DocId: 42] + + input + + spec + + template + + spec + + containers[dex] + + resources + + limits + + memory + +
    • + +
    • + Line number: 21180 +
    • +
    + +
    + +

    Impact

    +

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    + +

    Remediation

    +

    Set `resources.limits.memory` value

    + + +
    +
    + + + +
    +
    +

    Container is running without memory limit

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-4 +
    • + +
    • Introduced through: + [DocId: 42] + + input + + spec + + template + + spec + + initContainers[copyutil] + + resources + + limits + + memory + +
    • + +
    • + Line number: 21214 +
    • +
    + +
    + +

    Impact

    +

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    + +

    Remediation

    +

    Set `resources.limits.memory` value

    + + +
    +
    + + + +
    +
    +

    Container is running without memory limit

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-4 +
    • + +
    • Introduced through: + [DocId: 43] + + input + + spec + + template + + spec + + containers[argocd-notifications-controller] + + resources + + limits + + memory + +
    • + +
    • + Line number: 21274 +
    • +
    + +
    + +

    Impact

    +

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    + +

    Remediation

    +

    Set `resources.limits.memory` value

    + + +
    +
    + + + +
    +
    +

    Container is running without memory limit

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-4 +
    • + +
    • Introduced through: + [DocId: 44] + + input + + spec + + template + + spec + + containers[redis] + + resources + + limits + + memory + +
    • + +
    • + Line number: 21361 +
    • +
    + +
    + +

    Impact

    +

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    + +

    Remediation

    +

    Set `resources.limits.memory` value

    + + +
    +
    + + + +
    +
    +

    Container is running without memory limit

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-4 +
    • + +
    • Introduced through: + [DocId: 45] + + input + + spec + + template + + spec + + initContainers[copyutil] + + resources + + limits + + memory + +
    • + +
    • + Line number: 21618 +
    • +
    + +
    + +

    Impact

    +

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    + +

    Remediation

    +

    Set `resources.limits.memory` value

    + + +
    +
    + + + +
    +
    +

    Container is running without memory limit

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-4 +
    • + +
    • Introduced through: + [DocId: 45] + + input + + spec + + template + + spec + + containers[argocd-repo-server] + + resources + + limits + + memory + +
    • + +
    • + Line number: 21418 +
    • +
    + +
    + +

    Impact

    +

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    + +

    Remediation

    +

    Set `resources.limits.memory` value

    + + +
    +
    + + + +
    +
    +

    Container is running without memory limit

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-4 +
    • + +
    • Introduced through: + [DocId: 46] + + input + + spec + + template + + spec + + containers[argocd-server] + + resources + + limits + + memory + +
    • + +
    • + Line number: 21703 +
    • +
    + +
    + +

    Impact

    +

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    + +

    Remediation

    +

    Set `resources.limits.memory` value

    + + +
    +
    + + + +
    +
    +

    Container is running without memory limit

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-4 +
    • + +
    • Introduced through: + [DocId: 47] + + input + + spec + + template + + spec + + containers[argocd-application-controller] + + resources + + limits + + memory + +
    • + +
    • + Line number: 22019 +
    • +
    + +
    + +

    Impact

    +

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    + +

    Remediation

    +

    Set `resources.limits.memory` value

    + + +
    +
    + + + +
    +
    +

    Container's or Pod's UID could clash with host's UID

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-11 +
    • + +
    • Introduced through: + [DocId: 41] + + input + + spec + + template + + spec + + containers[argocd-applicationset-controller] + + securityContext + + runAsUser + +
    • + +
    • + Line number: 21104 +
    • +
    + +
    + +

    Impact

    +

    UID of the container processes could clash with host's UIDs and lead to unintentional authorization bypass

    + +

    Remediation

    +

    Set `securityContext.runAsUser` value to greater or equal than 10'000. SecurityContext can be set on both `pod` and `container` level. If both are set, then the container level takes precedence

    + + +
    +
    + + + +
    +
    +

    Container's or Pod's UID could clash with host's UID

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-11 +
    • + +
    • Introduced through: + [DocId: 42] + + input + + spec + + template + + spec + + initContainers[copyutil] + + securityContext + + runAsUser + +
    • + +
    • + Line number: 21222 +
    • +
    + +
    + +

    Impact

    +

    UID of the container processes could clash with host's UIDs and lead to unintentional authorization bypass

    + +

    Remediation

    +

    Set `securityContext.runAsUser` value to greater or equal than 10'000. SecurityContext can be set on both `pod` and `container` level. If both are set, then the container level takes precedence

    + + +
    +
    + + + +
    +
    +

    Container's or Pod's UID could clash with host's UID

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-11 +
    • + +
    • Introduced through: + [DocId: 42] + + input + + spec + + template + + spec + + containers[dex] + + securityContext + + runAsUser + +
    • + +
    • + Line number: 21197 +
    • +
    + +
    + +

    Impact

    +

    UID of the container processes could clash with host's UIDs and lead to unintentional authorization bypass

    + +

    Remediation

    +

    Set `securityContext.runAsUser` value to greater or equal than 10'000. SecurityContext can be set on both `pod` and `container` level. If both are set, then the container level takes precedence

    + + +
    +
    + + + +
    +
    +

    Container's or Pod's UID could clash with host's UID

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-11 +
    • + +
    • Introduced through: + [DocId: 43] + + input + + spec + + template + + spec + + containers[argocd-notifications-controller] + + securityContext + + runAsUser + +
    • + +
    • + Line number: 21295 +
    • +
    + +
    + +

    Impact

    +

    UID of the container processes could clash with host's UIDs and lead to unintentional authorization bypass

    + +

    Remediation

    +

    Set `securityContext.runAsUser` value to greater or equal than 10'000. SecurityContext can be set on both `pod` and `container` level. If both are set, then the container level takes precedence

    + + +
    +
    + + + +
    +
    +

    Container's or Pod's UID could clash with host's UID

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-11 +
    • + +
    • Introduced through: + [DocId: 44] + + input + + spec + + template + + spec + + containers[redis] + + securityContext + + runAsUser + +
    • + +
    • + Line number: 21371 +
    • +
    + +
    + +

    Impact

    +

    UID of the container processes could clash with host's UIDs and lead to unintentional authorization bypass

    + +

    Remediation

    +

    Set `securityContext.runAsUser` value to greater or equal than 10'000. SecurityContext can be set on both `pod` and `container` level. If both are set, then the container level takes precedence

    + + +
    +
    + + + +
    +
    +

    Container's or Pod's UID could clash with host's UID

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-11 +
    • + +
    • Introduced through: + [DocId: 45] + + input + + spec + + template + + spec + + initContainers[copyutil] + + securityContext + + runAsUser + +
    • + +
    • + Line number: 21625 +
    • +
    + +
    + +

    Impact

    +

    UID of the container processes could clash with host's UIDs and lead to unintentional authorization bypass

    + +

    Remediation

    +

    Set `securityContext.runAsUser` value to greater or equal than 10'000. SecurityContext can be set on both `pod` and `container` level. If both are set, then the container level takes precedence

    + + +
    +
    + + + +
    +
    +

    Container's or Pod's UID could clash with host's UID

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-11 +
    • + +
    • Introduced through: + [DocId: 45] + + input + + spec + + template + + spec + + containers[argocd-repo-server] + + securityContext + + runAsUser + +
    • + +
    • + Line number: 21591 +
    • +
    + +
    + +

    Impact

    +

    UID of the container processes could clash with host's UIDs and lead to unintentional authorization bypass

    + +

    Remediation

    +

    Set `securityContext.runAsUser` value to greater or equal than 10'000. SecurityContext can be set on both `pod` and `container` level. If both are set, then the container level takes precedence

    + + +
    +
    + + + +
    +
    +

    Container's or Pod's UID could clash with host's UID

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-11 +
    • + +
    • Introduced through: + [DocId: 46] + + input + + spec + + template + + spec + + containers[argocd-server] + + securityContext + + runAsUser + +
    • + +
    • + Line number: 21929 +
    • +
    + +
    + +

    Impact

    +

    UID of the container processes could clash with host's UIDs and lead to unintentional authorization bypass

    + +

    Remediation

    +

    Set `securityContext.runAsUser` value to greater or equal than 10'000. SecurityContext can be set on both `pod` and `container` level. If both are set, then the container level takes precedence

    + + +
    +
    + + + +
    +
    +

    Container's or Pod's UID could clash with host's UID

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-11 +
    • + +
    • Introduced through: + [DocId: 47] + + input + + spec + + template + + spec + + containers[argocd-application-controller] + + securityContext + + runAsUser + +
    • + +
    • + Line number: 22167 +
    • +
    + +
    + +

    Impact

    +

    UID of the container processes could clash with host's UIDs and lead to unintentional authorization bypass

    + +

    Remediation

    +

    Set `securityContext.runAsUser` value to greater or equal than 10'000. SecurityContext can be set on both `pod` and `container` level. If both are set, then the container level takes precedence

    + + +
    +
    + + + +
    +
    +
    + +
    + + + diff --git a/docs/snyk/v2.9.0-rc3/argocd-iac-namespace-install.html b/docs/snyk/v2.9.0-rc3/argocd-iac-namespace-install.html new file mode 100644 index 0000000000000..9e4ae7e5224e8 --- /dev/null +++ b/docs/snyk/v2.9.0-rc3/argocd-iac-namespace-install.html @@ -0,0 +1,2679 @@ + + + + + + + + + Snyk test report + + + + + + + + + +
    +
    +
    +
    + + + Snyk - Open Source Security + + + + + + + +
    +

    Snyk test report

    + +

    October 29th 2023, 12:21:10 am (UTC+00:00)

    +
    +
    + Scanned the following path: +
      +
    • /argo-cd/manifests/namespace-install.yaml (Kubernetes)
    • +
    +
    + +
    +
    40 total issues
    +
    +
    +
    +
    + +
    + + + + + + +
    Project manifests/namespace-install.yaml
    Path /argo-cd/manifests/namespace-install.yaml
    Project Type Kubernetes
    +
    +
    +
    +

    Role with dangerous permissions

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-47 +
    • + +
    • Introduced through: + [DocId: 7] + + rules[0] + + resources + +
    • + +
    • + Line number: 77 +
    • +
    + +
    + +

    Impact

    +

    Using this role grants dangerous permissions

    + +

    Remediation

    +

    Consider removing this permissions

    + + +
    +
    + + + +
    +
    +

    Role with dangerous permissions

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-47 +
    • + +
    • Introduced through: + [DocId: 8] + + rules[4] + + resources + +
    • + +
    • + Line number: 154 +
    • +
    + +
    + +

    Impact

    +

    Using this role grants dangerous permissions

    + +

    Remediation

    +

    Consider removing this permissions

    + + +
    +
    + + + +
    +
    +

    Role with dangerous permissions

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-47 +
    • + +
    • Introduced through: + [DocId: 9] + + rules[0] + + resources + +
    • + +
    • + Line number: 182 +
    • +
    + +
    + +

    Impact

    +

    Using this role grants dangerous permissions

    + +

    Remediation

    +

    Consider removing this permissions

    + + +
    +
    + + + +
    +
    +

    Role with dangerous permissions

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-47 +
    • + +
    • Introduced through: + [DocId: 10] + + rules[3] + + resources + +
    • + +
    • + Line number: 230 +
    • +
    + +
    + +

    Impact

    +

    Using this role grants dangerous permissions

    + +

    Remediation

    +

    Consider removing this permissions

    + + +
    +
    + + + +
    +
    +

    Role with dangerous permissions

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-47 +
    • + +
    • Introduced through: + [DocId: 10] + + rules[1] + + resources + +
    • + +
    • + Line number: 212 +
    • +
    + +
    + +

    Impact

    +

    Using this role grants dangerous permissions

    + +

    Remediation

    +

    Consider removing this permissions

    + + +
    +
    + + + +
    +
    +

    Role with dangerous permissions

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-47 +
    • + +
    • Introduced through: + [DocId: 11] + + rules[0] + + resources + +
    • + +
    • + Line number: 246 +
    • +
    + +
    + +

    Impact

    +

    Using this role grants dangerous permissions

    + +

    Remediation

    +

    Consider removing this permissions

    + + +
    +
    + + + +
    +
    +

    Container could be running with outdated image

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-42 +
    • + +
    • Introduced through: + [DocId: 38] + + spec + + template + + spec + + initContainers[copyutil] + + imagePullPolicy + +
    • + +
    • + Line number: 1274 +
    • +
    + +
    + +

    Impact

    +

    The container may run with outdated or unauthorized image

    + +

    Remediation

    +

    Set `imagePullPolicy` attribute to `Always`

    + + +
    +
    + + + +
    +
    +

    Container has no CPU limit

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-5 +
    • + +
    • Introduced through: + [DocId: 34] + + input + + spec + + template + + spec + + containers[argocd-applicationset-controller] + + resources + + limits + + cpu + +
    • + +
    • + Line number: 625 +
    • +
    + +
    + +

    Impact

    +

    CPU limits can prevent containers from consuming valuable compute time for no benefit (e.g. inefficient code) that might lead to unnecessary costs. It is advisable to also configure CPU requests to ensure application stability.

    + +

    Remediation

    +

    Add `resources.limits.cpu` field with required CPU limit value

    + + +
    +
    + + + +
    +
    +

    Container has no CPU limit

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-5 +
    • + +
    • Introduced through: + [DocId: 35] + + input + + spec + + template + + spec + + initContainers[copyutil] + + resources + + limits + + cpu + +
    • + +
    • + Line number: 870 +
    • +
    + +
    + +

    Impact

    +

    CPU limits can prevent containers from consuming valuable compute time for no benefit (e.g. inefficient code) that might lead to unnecessary costs. It is advisable to also configure CPU requests to ensure application stability.

    + +

    Remediation

    +

    Add `resources.limits.cpu` field with required CPU limit value

    + + +
    +
    + + + +
    +
    +

    Container has no CPU limit

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-5 +
    • + +
    • Introduced through: + [DocId: 35] + + input + + spec + + template + + spec + + containers[dex] + + resources + + limits + + cpu + +
    • + +
    • + Line number: 836 +
    • +
    + +
    + +

    Impact

    +

    CPU limits can prevent containers from consuming valuable compute time for no benefit (e.g. inefficient code) that might lead to unnecessary costs. It is advisable to also configure CPU requests to ensure application stability.

    + +

    Remediation

    +

    Add `resources.limits.cpu` field with required CPU limit value

    + + +
    +
    + + + +
    +
    +

    Container has no CPU limit

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-5 +
    • + +
    • Introduced through: + [DocId: 36] + + input + + spec + + template + + spec + + containers[argocd-notifications-controller] + + resources + + limits + + cpu + +
    • + +
    • + Line number: 930 +
    • +
    + +
    + +

    Impact

    +

    CPU limits can prevent containers from consuming valuable compute time for no benefit (e.g. inefficient code) that might lead to unnecessary costs. It is advisable to also configure CPU requests to ensure application stability.

    + +

    Remediation

    +

    Add `resources.limits.cpu` field with required CPU limit value

    + + +
    +
    + + + +
    +
    +

    Container has no CPU limit

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-5 +
    • + +
    • Introduced through: + [DocId: 37] + + input + + spec + + template + + spec + + containers[redis] + + resources + + limits + + cpu + +
    • + +
    • + Line number: 1017 +
    • +
    + +
    + +

    Impact

    +

    CPU limits can prevent containers from consuming valuable compute time for no benefit (e.g. inefficient code) that might lead to unnecessary costs. It is advisable to also configure CPU requests to ensure application stability.

    + +

    Remediation

    +

    Add `resources.limits.cpu` field with required CPU limit value

    + + +
    +
    + + + +
    +
    +

    Container has no CPU limit

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-5 +
    • + +
    • Introduced through: + [DocId: 38] + + input + + spec + + template + + spec + + initContainers[copyutil] + + resources + + limits + + cpu + +
    • + +
    • + Line number: 1274 +
    • +
    + +
    + +

    Impact

    +

    CPU limits can prevent containers from consuming valuable compute time for no benefit (e.g. inefficient code) that might lead to unnecessary costs. It is advisable to also configure CPU requests to ensure application stability.

    + +

    Remediation

    +

    Add `resources.limits.cpu` field with required CPU limit value

    + + +
    +
    + + + +
    +
    +

    Container has no CPU limit

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-5 +
    • + +
    • Introduced through: + [DocId: 38] + + input + + spec + + template + + spec + + containers[argocd-repo-server] + + resources + + limits + + cpu + +
    • + +
    • + Line number: 1074 +
    • +
    + +
    + +

    Impact

    +

    CPU limits can prevent containers from consuming valuable compute time for no benefit (e.g. inefficient code) that might lead to unnecessary costs. It is advisable to also configure CPU requests to ensure application stability.

    + +

    Remediation

    +

    Add `resources.limits.cpu` field with required CPU limit value

    + + +
    +
    + + + +
    +
    +

    Container has no CPU limit

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-5 +
    • + +
    • Introduced through: + [DocId: 39] + + input + + spec + + template + + spec + + containers[argocd-server] + + resources + + limits + + cpu + +
    • + +
    • + Line number: 1359 +
    • +
    + +
    + +

    Impact

    +

    CPU limits can prevent containers from consuming valuable compute time for no benefit (e.g. inefficient code) that might lead to unnecessary costs. It is advisable to also configure CPU requests to ensure application stability.

    + +

    Remediation

    +

    Add `resources.limits.cpu` field with required CPU limit value

    + + +
    +
    + + + +
    +
    +

    Container has no CPU limit

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-5 +
    • + +
    • Introduced through: + [DocId: 40] + + input + + spec + + template + + spec + + containers[argocd-application-controller] + + resources + + limits + + cpu + +
    • + +
    • + Line number: 1675 +
    • +
    + +
    + +

    Impact

    +

    CPU limits can prevent containers from consuming valuable compute time for no benefit (e.g. inefficient code) that might lead to unnecessary costs. It is advisable to also configure CPU requests to ensure application stability.

    + +

    Remediation

    +

    Add `resources.limits.cpu` field with required CPU limit value

    + + +
    +
    + + + +
    +
    +

    Container is running with multiple open ports

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-36 +
    • + +
    • Introduced through: + [DocId: 35] + + spec + + template + + spec + + containers[dex] + + ports + +
    • + +
    • + Line number: 850 +
    • +
    + +
    + +

    Impact

    +

    Increases the attack surface of the application and the container.

    + +

    Remediation

    +

    Reduce `ports` count to 2

    + + +
    +
    + + + +
    +
    +

    Container is running without liveness probe

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-41 +
    • + +
    • Introduced through: + [DocId: 34] + + spec + + template + + spec + + containers[argocd-applicationset-controller] + + livenessProbe + +
    • + +
    • + Line number: 625 +
    • +
    + +
    + +

    Impact

    +

    Kubernetes will not be able to detect if application is able to service requests, and will not restart unhealthy pods

    + +

    Remediation

    +

    Add `livenessProbe` attribute

    + + +
    +
    + + + +
    +
    +

    Container is running without liveness probe

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-41 +
    • + +
    • Introduced through: + [DocId: 35] + + spec + + template + + spec + + initContainers[copyutil] + + livenessProbe + +
    • + +
    • + Line number: 870 +
    • +
    + +
    + +

    Impact

    +

    Kubernetes will not be able to detect if application is able to service requests, and will not restart unhealthy pods

    + +

    Remediation

    +

    Add `livenessProbe` attribute

    + + +
    +
    + + + +
    +
    +

    Container is running without liveness probe

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-41 +
    • + +
    • Introduced through: + [DocId: 35] + + spec + + template + + spec + + containers[dex] + + livenessProbe + +
    • + +
    • + Line number: 836 +
    • +
    + +
    + +

    Impact

    +

    Kubernetes will not be able to detect if application is able to service requests, and will not restart unhealthy pods

    + +

    Remediation

    +

    Add `livenessProbe` attribute

    + + +
    +
    + + + +
    +
    +

    Container is running without liveness probe

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-41 +
    • + +
    • Introduced through: + [DocId: 37] + + spec + + template + + spec + + containers[redis] + + livenessProbe + +
    • + +
    • + Line number: 1017 +
    • +
    + +
    + +

    Impact

    +

    Kubernetes will not be able to detect if application is able to service requests, and will not restart unhealthy pods

    + +

    Remediation

    +

    Add `livenessProbe` attribute

    + + +
    +
    + + + +
    +
    +

    Container is running without liveness probe

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-41 +
    • + +
    • Introduced through: + [DocId: 38] + + spec + + template + + spec + + initContainers[copyutil] + + livenessProbe + +
    • + +
    • + Line number: 1274 +
    • +
    + +
    + +

    Impact

    +

    Kubernetes will not be able to detect if application is able to service requests, and will not restart unhealthy pods

    + +

    Remediation

    +

    Add `livenessProbe` attribute

    + + +
    +
    + + + +
    +
    +

    Container is running without memory limit

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-4 +
    • + +
    • Introduced through: + [DocId: 34] + + input + + spec + + template + + spec + + containers[argocd-applicationset-controller] + + resources + + limits + + memory + +
    • + +
    • + Line number: 625 +
    • +
    + +
    + +

    Impact

    +

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    + +

    Remediation

    +

    Set `resources.limits.memory` value

    + + +
    +
    + + + +
    +
    +

    Container is running without memory limit

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-4 +
    • + +
    • Introduced through: + [DocId: 35] + + input + + spec + + template + + spec + + containers[dex] + + resources + + limits + + memory + +
    • + +
    • + Line number: 836 +
    • +
    + +
    + +

    Impact

    +

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    + +

    Remediation

    +

    Set `resources.limits.memory` value

    + + +
    +
    + + + +
    +
    +

    Container is running without memory limit

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-4 +
    • + +
    • Introduced through: + [DocId: 35] + + input + + spec + + template + + spec + + initContainers[copyutil] + + resources + + limits + + memory + +
    • + +
    • + Line number: 870 +
    • +
    + +
    + +

    Impact

    +

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    + +

    Remediation

    +

    Set `resources.limits.memory` value

    + + +
    +
    + + + +
    +
    +

    Container is running without memory limit

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-4 +
    • + +
    • Introduced through: + [DocId: 36] + + input + + spec + + template + + spec + + containers[argocd-notifications-controller] + + resources + + limits + + memory + +
    • + +
    • + Line number: 930 +
    • +
    + +
    + +

    Impact

    +

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    + +

    Remediation

    +

    Set `resources.limits.memory` value

    + + +
    +
    + + + +
    +
    +

    Container is running without memory limit

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-4 +
    • + +
    • Introduced through: + [DocId: 37] + + input + + spec + + template + + spec + + containers[redis] + + resources + + limits + + memory + +
    • + +
    • + Line number: 1017 +
    • +
    + +
    + +

    Impact

    +

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    + +

    Remediation

    +

    Set `resources.limits.memory` value

    + + +
    +
    + + + +
    +
    +

    Container is running without memory limit

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-4 +
    • + +
    • Introduced through: + [DocId: 38] + + input + + spec + + template + + spec + + initContainers[copyutil] + + resources + + limits + + memory + +
    • + +
    • + Line number: 1274 +
    • +
    + +
    + +

    Impact

    +

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    + +

    Remediation

    +

    Set `resources.limits.memory` value

    + + +
    +
    + + + +
    +
    +

    Container is running without memory limit

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-4 +
    • + +
    • Introduced through: + [DocId: 38] + + input + + spec + + template + + spec + + containers[argocd-repo-server] + + resources + + limits + + memory + +
    • + +
    • + Line number: 1074 +
    • +
    + +
    + +

    Impact

    +

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    + +

    Remediation

    +

    Set `resources.limits.memory` value

    + + +
    +
    + + + +
    +
    +

    Container is running without memory limit

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-4 +
    • + +
    • Introduced through: + [DocId: 39] + + input + + spec + + template + + spec + + containers[argocd-server] + + resources + + limits + + memory + +
    • + +
    • + Line number: 1359 +
    • +
    + +
    + +

    Impact

    +

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    + +

    Remediation

    +

    Set `resources.limits.memory` value

    + + +
    +
    + + + +
    +
    +

    Container is running without memory limit

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-4 +
    • + +
    • Introduced through: + [DocId: 40] + + input + + spec + + template + + spec + + containers[argocd-application-controller] + + resources + + limits + + memory + +
    • + +
    • + Line number: 1675 +
    • +
    + +
    + +

    Impact

    +

    Containers without memory limits are more likely to be terminated when the node runs out of memory

    + +

    Remediation

    +

    Set `resources.limits.memory` value

    + + +
    +
    + + + +
    +
    +

    Container's or Pod's UID could clash with host's UID

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-11 +
    • + +
    • Introduced through: + [DocId: 34] + + input + + spec + + template + + spec + + containers[argocd-applicationset-controller] + + securityContext + + runAsUser + +
    • + +
    • + Line number: 760 +
    • +
    + +
    + +

    Impact

    +

    UID of the container processes could clash with host's UIDs and lead to unintentional authorization bypass

    + +

    Remediation

    +

    Set `securityContext.runAsUser` value to greater or equal than 10'000. SecurityContext can be set on both `pod` and `container` level. If both are set, then the container level takes precedence

    + + +
    +
    + + + +
    +
    +

    Container's or Pod's UID could clash with host's UID

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-11 +
    • + +
    • Introduced through: + [DocId: 35] + + input + + spec + + template + + spec + + initContainers[copyutil] + + securityContext + + runAsUser + +
    • + +
    • + Line number: 878 +
    • +
    + +
    + +

    Impact

    +

    UID of the container processes could clash with host's UIDs and lead to unintentional authorization bypass

    + +

    Remediation

    +

    Set `securityContext.runAsUser` value to greater or equal than 10'000. SecurityContext can be set on both `pod` and `container` level. If both are set, then the container level takes precedence

    + + +
    +
    + + + +
    +
    +

    Container's or Pod's UID could clash with host's UID

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-11 +
    • + +
    • Introduced through: + [DocId: 35] + + input + + spec + + template + + spec + + containers[dex] + + securityContext + + runAsUser + +
    • + +
    • + Line number: 853 +
    • +
    + +
    + +

    Impact

    +

    UID of the container processes could clash with host's UIDs and lead to unintentional authorization bypass

    + +

    Remediation

    +

    Set `securityContext.runAsUser` value to greater or equal than 10'000. SecurityContext can be set on both `pod` and `container` level. If both are set, then the container level takes precedence

    + + +
    +
    + + + +
    +
    +

    Container's or Pod's UID could clash with host's UID

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-11 +
    • + +
    • Introduced through: + [DocId: 36] + + input + + spec + + template + + spec + + containers[argocd-notifications-controller] + + securityContext + + runAsUser + +
    • + +
    • + Line number: 951 +
    • +
    + +
    + +

    Impact

    +

    UID of the container processes could clash with host's UIDs and lead to unintentional authorization bypass

    + +

    Remediation

    +

    Set `securityContext.runAsUser` value to greater or equal than 10'000. SecurityContext can be set on both `pod` and `container` level. If both are set, then the container level takes precedence

    + + +
    +
    + + + +
    +
    +

    Container's or Pod's UID could clash with host's UID

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-11 +
    • + +
    • Introduced through: + [DocId: 37] + + input + + spec + + template + + spec + + containers[redis] + + securityContext + + runAsUser + +
    • + +
    • + Line number: 1027 +
    • +
    + +
    + +

    Impact

    +

    UID of the container processes could clash with host's UIDs and lead to unintentional authorization bypass

    + +

    Remediation

    +

    Set `securityContext.runAsUser` value to greater or equal than 10'000. SecurityContext can be set on both `pod` and `container` level. If both are set, then the container level takes precedence

    + + +
    +
    + + + +
    +
    +

    Container's or Pod's UID could clash with host's UID

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-11 +
    • + +
    • Introduced through: + [DocId: 38] + + input + + spec + + template + + spec + + initContainers[copyutil] + + securityContext + + runAsUser + +
    • + +
    • + Line number: 1281 +
    • +
    + +
    + +

    Impact

    +

    UID of the container processes could clash with host's UIDs and lead to unintentional authorization bypass

    + +

    Remediation

    +

    Set `securityContext.runAsUser` value to greater or equal than 10'000. SecurityContext can be set on both `pod` and `container` level. If both are set, then the container level takes precedence

    + + +
    +
    + + + +
    +
    +

    Container's or Pod's UID could clash with host's UID

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-11 +
    • + +
    • Introduced through: + [DocId: 38] + + input + + spec + + template + + spec + + containers[argocd-repo-server] + + securityContext + + runAsUser + +
    • + +
    • + Line number: 1247 +
    • +
    + +
    + +

    Impact

    +

    UID of the container processes could clash with host's UIDs and lead to unintentional authorization bypass

    + +

    Remediation

    +

    Set `securityContext.runAsUser` value to greater or equal than 10'000. SecurityContext can be set on both `pod` and `container` level. If both are set, then the container level takes precedence

    + + +
    +
    + + + +
    +
    +

    Container's or Pod's UID could clash with host's UID

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-11 +
    • + +
    • Introduced through: + [DocId: 39] + + input + + spec + + template + + spec + + containers[argocd-server] + + securityContext + + runAsUser + +
    • + +
    • + Line number: 1585 +
    • +
    + +
    + +

    Impact

    +

    UID of the container processes could clash with host's UIDs and lead to unintentional authorization bypass

    + +

    Remediation

    +

    Set `securityContext.runAsUser` value to greater or equal than 10'000. SecurityContext can be set on both `pod` and `container` level. If both are set, then the container level takes precedence

    + + +
    +
    + + + +
    +
    +

    Container's or Pod's UID could clash with host's UID

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Public ID: SNYK-CC-K8S-11 +
    • + +
    • Introduced through: + [DocId: 40] + + input + + spec + + template + + spec + + containers[argocd-application-controller] + + securityContext + + runAsUser + +
    • + +
    • + Line number: 1823 +
    • +
    + +
    + +

    Impact

    +

    UID of the container processes could clash with host's UIDs and lead to unintentional authorization bypass

    + +

    Remediation

    +

    Set `securityContext.runAsUser` value to greater or equal than 10'000. SecurityContext can be set on both `pod` and `container` level. If both are set, then the container level takes precedence

    + + +
    +
    + + + +
    +
    +
    + +
    + + + diff --git a/docs/snyk/v2.9.0-rc3/argocd-test.html b/docs/snyk/v2.9.0-rc3/argocd-test.html new file mode 100644 index 0000000000000..8a9efc79fd7df --- /dev/null +++ b/docs/snyk/v2.9.0-rc3/argocd-test.html @@ -0,0 +1,3779 @@ + + + + + + + + + Snyk test report + + + + + + + + + +
    +
    +
    +
    + + + Snyk - Open Source Security + + + + + + + +
    +

    Snyk test report

    + +

    October 29th 2023, 12:18:17 am (UTC+00:00)

    +
    +
    + Scanned the following paths: +
      +
    • /argo-cd/argoproj/argo-cd/v2 (gomodules)
    • /argo-cd (yarn)
    • +
    +
    + +
    +
    8 known vulnerabilities
    +
    167 vulnerable dependency paths
    +
    1920 dependencies
    +
    +
    +
    +
    + +
    +
    +
    +

    Denial of Service (DoS)

    +
    + +
    + high severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + google.golang.org/grpc +
    • + +
    • Introduced through: + + github.com/argoproj/argo-cd/v2@0.0.0 and google.golang.org/grpc@1.56.2 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc@1.56.2 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/go-grpc-middleware@1.4.0 + + google.golang.org/grpc@1.56.2 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc/health/grpc_health_v1@1.56.2 + + google.golang.org/grpc@1.56.2 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/improbable-eng/grpc-web/go/grpcweb@0.15.0 + + google.golang.org/grpc@1.56.2 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc/health@1.56.2 + + google.golang.org/grpc@1.56.2 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc/reflection@1.56.2 + + google.golang.org/grpc@1.56.2 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/go-grpc-middleware/auth@1.4.0 + + google.golang.org/grpc@1.56.2 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/go-grpc-middleware/retry@1.4.0 + + google.golang.org/grpc@1.56.2 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/go-grpc-prometheus@1.2.0 + + google.golang.org/grpc@1.56.2 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.16.0 + + google.golang.org/grpc@1.56.2 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus@1.4.0 + + google.golang.org/grpc@1.56.2 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc@0.42.0 + + google.golang.org/grpc@1.56.2 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/go-grpc-middleware/auth@1.4.0 + + github.com/grpc-ecosystem/go-grpc-middleware@1.4.0 + + google.golang.org/grpc@1.56.2 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.16.0 + + go.opentelemetry.io/otel/exporters/otlp/otlptrace/internal/otlpconfig@1.16.0 + + google.golang.org/grpc@1.56.2 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.16.0 + + go.opentelemetry.io/proto/otlp/collector/trace/v1@0.19.0 + + google.golang.org/grpc@1.56.2 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/improbable-eng/grpc-web/go/grpcweb@0.15.0 + + google.golang.org/grpc/health/grpc_health_v1@1.56.2 + + google.golang.org/grpc@1.56.2 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc/reflection@1.56.2 + + google.golang.org/grpc/reflection/grpc_reflection_v1alpha@1.56.2 + + google.golang.org/grpc@1.56.2 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc/health@1.56.2 + + google.golang.org/grpc/health/grpc_health_v1@1.56.2 + + google.golang.org/grpc@1.56.2 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus@1.4.0 + + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus@1.4.0 + + github.com/grpc-ecosystem/go-grpc-middleware/tags@1.4.0 + + google.golang.org/grpc@1.56.2 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/go-grpc-middleware/tags/logrus@1.4.0 + + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus@1.4.0 + + github.com/grpc-ecosystem/go-grpc-middleware/tags@1.4.0 + + google.golang.org/grpc@1.56.2 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus@1.4.0 + + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus@1.4.0 + + github.com/grpc-ecosystem/go-grpc-middleware/tags@1.4.0 + + github.com/grpc-ecosystem/go-grpc-middleware@1.4.0 + + google.golang.org/grpc@1.56.2 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.16.0 + + go.opentelemetry.io/proto/otlp/collector/trace/v1@0.19.0 + + github.com/grpc-ecosystem/grpc-gateway/v2/runtime@2.11.3 + + google.golang.org/grpc/health/grpc_health_v1@1.56.2 + + google.golang.org/grpc@1.56.2 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/go-grpc-middleware/tags/logrus@1.4.0 + + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus@1.4.0 + + github.com/grpc-ecosystem/go-grpc-middleware/tags@1.4.0 + + github.com/grpc-ecosystem/go-grpc-middleware@1.4.0 + + google.golang.org/grpc@1.56.2 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    google.golang.org/grpc is a Go implementation of gRPC

    +

    Affected versions of this package are vulnerable to Denial of Service (DoS) in the implementation of the HTTP/2 protocol. An attacker can cause a denial of service (including via DDoS) by rapidly resetting many streams through request cancellation.

    +

    Remediation

    +

    Upgrade google.golang.org/grpc to version 1.56.3, 1.57.1, 1.58.3 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Denial of Service (DoS)

    +
    + +
    + high severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + golang.org/x/net/http2 +
    • + +
    • Introduced through: + + + github.com/argoproj/argo-cd/v2@0.0.0, k8s.io/apimachinery/pkg/util/net@0.24.2 and others +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/soheilhy/cmux@0.1.5 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/improbable-eng/grpc-web/go/grpcweb@0.15.0 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc@1.56.2 + + google.golang.org/grpc/internal/transport@1.56.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/transport/spdy@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/pkg/kubeclientmetrics@#d56162821bd1 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/testing@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/dynamic@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/tools/cache@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/plugin/pkg/client/auth/azure@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/plugin/pkg/client/auth/gcp@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/plugin/pkg/client/auth/oidc@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/tools/record@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/rest@0.24.2 + + k8s.io/client-go/transport@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/go-grpc-middleware@1.4.0 + + google.golang.org/grpc@1.56.2 + + google.golang.org/grpc/internal/transport@1.56.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc/health/grpc_health_v1@1.56.2 + + google.golang.org/grpc@1.56.2 + + google.golang.org/grpc/internal/transport@1.56.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/go-grpc-middleware/auth@1.4.0 + + google.golang.org/grpc@1.56.2 + + google.golang.org/grpc/internal/transport@1.56.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/go-grpc-middleware/retry@1.4.0 + + google.golang.org/grpc@1.56.2 + + google.golang.org/grpc/internal/transport@1.56.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/go-grpc-prometheus@1.2.0 + + google.golang.org/grpc@1.56.2 + + google.golang.org/grpc/internal/transport@1.56.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc@1.16.0 + + google.golang.org/grpc@1.56.2 + + google.golang.org/grpc/internal/transport@1.56.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus@1.4.0 + + google.golang.org/grpc@1.56.2 + + google.golang.org/grpc/internal/transport@1.56.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc@0.42.0 + + google.golang.org/grpc@1.56.2 + + google.golang.org/grpc/internal/transport@1.56.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/kubectl/pkg/util/openapi@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/tools/clientcmd@0.24.2 + + k8s.io/client-go/tools/auth@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/controller@#9dcecdc3eebf + + k8s.io/client-go/tools/cache@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/discovery/fake@0.24.2 + + k8s.io/client-go/testing@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/kubernetes/fake@0.24.2 + + k8s.io/client-go/testing@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/client@0.11.0 + + k8s.io/client-go/dynamic@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/informers/apps/v1@0.24.2 + + k8s.io/client-go/tools/cache@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/informers@0.24.2 + + k8s.io/client-go/tools/cache@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/listers/core/v1@0.24.2 + + k8s.io/client-go/tools/cache@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/tools/remotecommand@0.24.2 + + k8s.io/client-go/transport/spdy@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/pkg/apis/clientauthentication/v1beta1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/api/rbac/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/apimachinery/pkg/api/errors@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/sync/common@#b0fffe419a0f + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/apimachinery/pkg/api/equality@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/transport/spdy@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + k8s.io/client-go/transport@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/pkg/kubeclientmetrics@#d56162821bd1 + + k8s.io/client-go/rest@0.24.2 + + k8s.io/client-go/transport@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/testing@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + k8s.io/client-go/transport@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/plugin/pkg/client/auth/azure@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + k8s.io/client-go/transport@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/plugin/pkg/client/auth/gcp@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + k8s.io/client-go/transport@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/plugin/pkg/client/auth/oidc@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + k8s.io/client-go/transport@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/improbable-eng/grpc-web/go/grpcweb@0.15.0 + + google.golang.org/grpc/health/grpc_health_v1@1.56.2 + + google.golang.org/grpc@1.56.2 + + google.golang.org/grpc/internal/transport@1.56.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc/reflection@1.56.2 + + google.golang.org/grpc/reflection/grpc_reflection_v1alpha@1.56.2 + + google.golang.org/grpc@1.56.2 + + google.golang.org/grpc/internal/transport@1.56.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + google.golang.org/grpc/health@1.56.2 + + google.golang.org/grpc/health/grpc_health_v1@1.56.2 + + google.golang.org/grpc@1.56.2 + + google.golang.org/grpc/internal/transport@1.56.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/cache@#b0fffe419a0f + + k8s.io/kubectl/pkg/util/openapi@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/sync@#b0fffe419a0f + + k8s.io/kubectl/pkg/util/openapi@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/utils/kube@#b0fffe419a0f + + k8s.io/kubectl/pkg/util/openapi@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/api@#9dcecdc3eebf + + k8s.io/client-go/listers/core/v1@0.24.2 + + k8s.io/client-go/tools/cache@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/cmd@#9dcecdc3eebf + + k8s.io/client-go/tools/clientcmd@0.24.2 + + k8s.io/client-go/tools/auth@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/event@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/client@0.11.0 + + k8s.io/client-go/dynamic@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/informers/core/v1@0.24.2 + + k8s.io/client-go/listers/core/v1@0.24.2 + + k8s.io/client-go/tools/cache@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/cache@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/cache/internal@0.11.0 + + k8s.io/client-go/tools/cache@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/kubectl/pkg/util/term@0.24.2 + + k8s.io/client-go/tools/remotecommand@0.24.2 + + k8s.io/client-go/transport/spdy@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/Azure/kubelogin/pkg/token@0.0.20 + + k8s.io/client-go/pkg/apis/clientauthentication/v1beta1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/apimachinery/pkg/util/managedfields@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/sync/resource@#b0fffe419a0f + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/dynamic@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/sync/ignore@#b0fffe419a0f + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/sync/syncwaves@#b0fffe419a0f + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/utils/testing@#b0fffe419a0f + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/scheme@0.11.0 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/listers/core/v1@0.24.2 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/kubectl/pkg/util/resource@0.24.2 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/health@#b0fffe419a0f + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/util/retry@0.24.2 + + k8s.io/apimachinery/pkg/api/errors@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/tools/cache@0.24.2 + + k8s.io/client-go/tools/pager@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/tools/portforward@0.24.2 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1@0.24.2 + + k8s.io/apimachinery/pkg/api/equality@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/apimachinery/pkg/api/validation@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1/validation@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/discovery/fake@0.24.2 + + k8s.io/client-go/testing@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + k8s.io/client-go/transport@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/kubernetes/fake@0.24.2 + + k8s.io/client-go/testing@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + k8s.io/client-go/transport@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/tools/remotecommand@0.24.2 + + k8s.io/client-go/transport/spdy@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + k8s.io/client-go/transport@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/health@#b0fffe419a0f + + github.com/argoproj/gitops-engine/pkg/utils/kube@#b0fffe419a0f + + k8s.io/kubectl/pkg/util/openapi@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/sync/common@#b0fffe419a0f + + github.com/argoproj/gitops-engine/pkg/utils/kube@#b0fffe419a0f + + k8s.io/kubectl/pkg/util/openapi@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/controller/controllerutil@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/client/apiutil@0.11.0 + + k8s.io/client-go/restmapper@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/predicate@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/event@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/client@0.11.0 + + k8s.io/client-go/dynamic@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/envtest@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane@0.11.0 + + k8s.io/client-go/tools/clientcmd@0.24.2 + + k8s.io/client-go/tools/auth@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/diff@#b0fffe419a0f + + k8s.io/apimachinery/pkg/util/managedfields@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/sync/hook@#b0fffe419a0f + + github.com/argoproj/gitops-engine/pkg/sync/resource@#b0fffe419a0f + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/apimachinery/pkg/runtime/serializer@0.24.2 + + k8s.io/apimachinery/pkg/runtime/serializer/versioning@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/kubernetes/scheme@0.24.2 + + k8s.io/api/storage/v1beta1@0.24.2 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/informers/core/v1@0.24.2 + + k8s.io/client-go/listers/core/v1@0.24.2 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/tools/record@0.24.2 + + k8s.io/client-go/tools/reference@0.24.2 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/controller@#9dcecdc3eebf + + k8s.io/client-go/tools/cache@0.24.2 + + k8s.io/client-go/tools/pager@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/informers/apps/v1@0.24.2 + + k8s.io/client-go/tools/cache@0.24.2 + + k8s.io/client-go/tools/pager@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/informers@0.24.2 + + k8s.io/client-go/tools/cache@0.24.2 + + k8s.io/client-go/tools/pager@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/api@#9dcecdc3eebf + + k8s.io/client-go/listers/core/v1@0.24.2 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/client@0.11.0 + + k8s.io/client-go/dynamic@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/kubectl/pkg/util/term@0.24.2 + + k8s.io/client-go/tools/remotecommand@0.24.2 + + k8s.io/client-go/transport/spdy@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + k8s.io/client-go/transport@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/grpc-ecosystem/go-grpc-middleware/tags/logrus@1.4.0 + + github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus@1.4.0 + + github.com/grpc-ecosystem/go-grpc-middleware/tags@1.4.0 + + github.com/grpc-ecosystem/go-grpc-middleware@1.4.0 + + google.golang.org/grpc@1.56.2 + + google.golang.org/grpc/internal/transport@1.56.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/handler@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/runtime/inject@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/cache@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/cache/internal@0.11.0 + + k8s.io/client-go/tools/cache@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/kubernetes@0.24.2 + + k8s.io/client-go/kubernetes/typed/storage/v1beta1@0.24.2 + + k8s.io/client-go/applyconfigurations/storage/v1beta1@0.24.2 + + k8s.io/client-go/applyconfigurations/meta/v1@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/builder@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/webhook/admission@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/webhook/internal/metrics@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/metrics@0.11.0 + + k8s.io/client-go/tools/cache@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/tools/clientcmd@0.24.2 + + k8s.io/client-go/tools/clientcmd/api/latest@0.24.2 + + k8s.io/apimachinery/pkg/runtime/serializer/versioning@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/kubernetes/scheme@0.24.2 + + k8s.io/api/storage/v1beta1@0.24.2 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/event@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/client@0.11.0 + + k8s.io/client-go/dynamic@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/cache@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/cache/internal@0.11.0 + + k8s.io/client-go/tools/cache@0.24.2 + + k8s.io/client-go/tools/pager@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/sync/hook@#b0fffe419a0f + + github.com/argoproj/gitops-engine/pkg/sync/hook/helm@#b0fffe419a0f + + github.com/argoproj/gitops-engine/pkg/sync/common@#b0fffe419a0f + + github.com/argoproj/gitops-engine/pkg/utils/kube@#b0fffe419a0f + + k8s.io/kubectl/pkg/util/openapi@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/sync/syncwaves@#b0fffe419a0f + + github.com/argoproj/gitops-engine/pkg/sync/hook/helm@#b0fffe419a0f + + github.com/argoproj/gitops-engine/pkg/sync/common@#b0fffe419a0f + + github.com/argoproj/gitops-engine/pkg/utils/kube@#b0fffe419a0f + + k8s.io/kubectl/pkg/util/openapi@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/manager@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/webhook@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/webhook/internal/metrics@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/metrics@0.11.0 + + k8s.io/client-go/tools/cache@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/source@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/source/internal@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/predicate@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/event@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/client@0.11.0 + + k8s.io/client-go/dynamic@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/builder@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/webhook/conversion@0.11.0 + + k8s.io/apimachinery/pkg/runtime/serializer@0.24.2 + + k8s.io/apimachinery/pkg/runtime/serializer/versioning@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/envtest@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/webhook/conversion@0.11.0 + + k8s.io/apimachinery/pkg/runtime/serializer@0.24.2 + + k8s.io/apimachinery/pkg/runtime/serializer/versioning@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/cmd@#9dcecdc3eebf + + k8s.io/client-go/tools/clientcmd@0.24.2 + + k8s.io/client-go/tools/clientcmd/api/latest@0.24.2 + + k8s.io/apimachinery/pkg/runtime/serializer/versioning@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/kubectl/pkg/util/openapi@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/kubernetes/scheme@0.24.2 + + k8s.io/api/storage/v1beta1@0.24.2 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + k8s.io/client-go/kubernetes@0.24.2 + + k8s.io/client-go/kubernetes/typed/storage/v1beta1@0.24.2 + + k8s.io/client-go/kubernetes/scheme@0.24.2 + + k8s.io/api/storage/v1beta1@0.24.2 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/utils/kube/scheme@#b0fffe419a0f + + k8s.io/kubernetes/pkg/apis/storage/install@1.24.2 + + k8s.io/kubernetes/pkg/apis/storage/v1alpha1@1.24.2 + + k8s.io/api/storage/v1alpha1@0.24.2 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/predicate@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/event@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/client@0.11.0 + + k8s.io/client-go/dynamic@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/sync/ignore@#b0fffe419a0f + + github.com/argoproj/gitops-engine/pkg/sync/hook@#b0fffe419a0f + + github.com/argoproj/gitops-engine/pkg/sync/hook/helm@#b0fffe419a0f + + github.com/argoproj/gitops-engine/pkg/sync/common@#b0fffe419a0f + + github.com/argoproj/gitops-engine/pkg/utils/kube@#b0fffe419a0f + + k8s.io/kubectl/pkg/util/openapi@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/controller@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/source@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/source/internal@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/predicate@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/event@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/client@0.11.0 + + k8s.io/client-go/dynamic@0.24.2 + + k8s.io/client-go/rest@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/cache@#b0fffe419a0f + + k8s.io/kubectl/pkg/util/openapi@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/kubernetes/scheme@0.24.2 + + k8s.io/api/storage/v1beta1@0.24.2 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/sync@#b0fffe419a0f + + k8s.io/kubectl/pkg/util/openapi@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/kubernetes/scheme@0.24.2 + + k8s.io/api/storage/v1beta1@0.24.2 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/gitops-engine/pkg/utils/kube@#b0fffe419a0f + + k8s.io/kubectl/pkg/util/openapi@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/kubernetes/scheme@0.24.2 + + k8s.io/api/storage/v1beta1@0.24.2 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/handler@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/runtime/inject@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/cache@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/cache/internal@0.11.0 + + k8s.io/client-go/tools/cache@0.24.2 + + k8s.io/client-go/tools/pager@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/controller/controllerutil@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/client/apiutil@0.11.0 + + k8s.io/client-go/restmapper@0.24.2 + + k8s.io/client-go/discovery@0.24.2 + + k8s.io/client-go/kubernetes/scheme@0.24.2 + + k8s.io/api/storage/v1beta1@0.24.2 + + k8s.io/api/core/v1@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/source@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/source/internal@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/predicate@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/event@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/client@0.11.0 + + k8s.io/client-go/dynamic@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + sigs.k8s.io/controller-runtime/pkg/controller@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/source@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/source/internal@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/predicate@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/event@0.11.0 + + sigs.k8s.io/controller-runtime/pkg/client@0.11.0 + + k8s.io/client-go/dynamic@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1/unstructured@0.24.2 + + k8s.io/apimachinery/pkg/apis/meta/v1@0.24.2 + + k8s.io/apimachinery/pkg/watch@0.24.2 + + k8s.io/apimachinery/pkg/util/net@0.24.2 + + golang.org/x/net/http2@0.15.0 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    golang.org/x/net/http2 is a work-in-progress HTTP/2 implementation for Go.

    +

    Affected versions of this package are vulnerable to Denial of Service (DoS) in the implementation of the HTTP/2 protocol. An attacker can cause a denial of service (including via DDoS) by rapidly resetting many streams through request cancellation.

    +

    Remediation

    +

    Upgrade golang.org/x/net/http2 to version 0.17.0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    LGPL-3.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Module: + + gopkg.in/retry.v1 +
    • + +
    • Introduced through: + + + github.com/argoproj/argo-cd/v2@0.0.0, github.com/Azure/kubelogin/pkg/token@0.0.20 and others +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/Azure/kubelogin/pkg/token@0.0.20 + + gopkg.in/retry.v1@1.0.3 + + + +
    • +
    + +
    + +
    + +

    LGPL-3.0 license

    + +
    + + + +
    +
    +

    MPL-2.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Module: + + github.com/r3labs/diff +
    • + +
    • Introduced through: + + github.com/argoproj/argo-cd/v2@0.0.0 and github.com/r3labs/diff@1.1.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/r3labs/diff@1.1.0 + + + +
    • +
    + +
    + +
    + +

    MPL-2.0 license

    + +
    + + + +
    +
    +

    MPL-2.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Module: + + github.com/hashicorp/go-version +
    • + +
    • Introduced through: + + + github.com/argoproj/argo-cd/v2@0.0.0, code.gitea.io/sdk/gitea@0.15.1 and others +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + code.gitea.io/sdk/gitea@0.15.1 + + github.com/hashicorp/go-version@1.2.1 + + + +
    • +
    + +
    + +
    + +

    MPL-2.0 license

    + +
    + + + +
    +
    +

    MPL-2.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Module: + + github.com/hashicorp/go-retryablehttp +
    • + +
    • Introduced through: + + github.com/argoproj/argo-cd/v2@0.0.0 and github.com/hashicorp/go-retryablehttp@0.7.4 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/hashicorp/go-retryablehttp@0.7.4 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/xanzy/go-gitlab@0.91.1 + + github.com/hashicorp/go-retryablehttp@0.7.4 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/services@#9dcecdc3eebf + + github.com/opsgenie/opsgenie-go-sdk-v2/client@1.0.5 + + github.com/hashicorp/go-retryablehttp@0.7.4 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/subscriptions@#9dcecdc3eebf + + github.com/argoproj/notifications-engine/pkg/services@#9dcecdc3eebf + + github.com/opsgenie/opsgenie-go-sdk-v2/client@1.0.5 + + github.com/hashicorp/go-retryablehttp@0.7.4 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/cmd@#9dcecdc3eebf + + github.com/argoproj/notifications-engine/pkg/services@#9dcecdc3eebf + + github.com/opsgenie/opsgenie-go-sdk-v2/client@1.0.5 + + github.com/hashicorp/go-retryablehttp@0.7.4 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/api@#9dcecdc3eebf + + github.com/argoproj/notifications-engine/pkg/subscriptions@#9dcecdc3eebf + + github.com/argoproj/notifications-engine/pkg/services@#9dcecdc3eebf + + github.com/opsgenie/opsgenie-go-sdk-v2/client@1.0.5 + + github.com/hashicorp/go-retryablehttp@0.7.4 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/controller@#9dcecdc3eebf + + github.com/argoproj/notifications-engine/pkg/subscriptions@#9dcecdc3eebf + + github.com/argoproj/notifications-engine/pkg/services@#9dcecdc3eebf + + github.com/opsgenie/opsgenie-go-sdk-v2/client@1.0.5 + + github.com/hashicorp/go-retryablehttp@0.7.4 + + + +
    • +
    + +
    + +
    + +

    MPL-2.0 license

    + +
    + + + +
    +
    +

    MPL-2.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Module: + + github.com/hashicorp/go-cleanhttp +
    • + +
    • Introduced through: + + + github.com/argoproj/argo-cd/v2@0.0.0, github.com/hashicorp/go-retryablehttp@0.7.4 and others +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/hashicorp/go-retryablehttp@0.7.4 + + github.com/hashicorp/go-cleanhttp@0.5.2 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/xanzy/go-gitlab@0.91.1 + + github.com/hashicorp/go-cleanhttp@0.5.2 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/xanzy/go-gitlab@0.91.1 + + github.com/hashicorp/go-retryablehttp@0.7.4 + + github.com/hashicorp/go-cleanhttp@0.5.2 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/services@#9dcecdc3eebf + + github.com/opsgenie/opsgenie-go-sdk-v2/client@1.0.5 + + github.com/hashicorp/go-retryablehttp@0.7.4 + + github.com/hashicorp/go-cleanhttp@0.5.2 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/subscriptions@#9dcecdc3eebf + + github.com/argoproj/notifications-engine/pkg/services@#9dcecdc3eebf + + github.com/opsgenie/opsgenie-go-sdk-v2/client@1.0.5 + + github.com/hashicorp/go-retryablehttp@0.7.4 + + github.com/hashicorp/go-cleanhttp@0.5.2 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/cmd@#9dcecdc3eebf + + github.com/argoproj/notifications-engine/pkg/services@#9dcecdc3eebf + + github.com/opsgenie/opsgenie-go-sdk-v2/client@1.0.5 + + github.com/hashicorp/go-retryablehttp@0.7.4 + + github.com/hashicorp/go-cleanhttp@0.5.2 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/api@#9dcecdc3eebf + + github.com/argoproj/notifications-engine/pkg/subscriptions@#9dcecdc3eebf + + github.com/argoproj/notifications-engine/pkg/services@#9dcecdc3eebf + + github.com/opsgenie/opsgenie-go-sdk-v2/client@1.0.5 + + github.com/hashicorp/go-retryablehttp@0.7.4 + + github.com/hashicorp/go-cleanhttp@0.5.2 + + + +
    • +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/argoproj/notifications-engine/pkg/controller@#9dcecdc3eebf + + github.com/argoproj/notifications-engine/pkg/subscriptions@#9dcecdc3eebf + + github.com/argoproj/notifications-engine/pkg/services@#9dcecdc3eebf + + github.com/opsgenie/opsgenie-go-sdk-v2/client@1.0.5 + + github.com/hashicorp/go-retryablehttp@0.7.4 + + github.com/hashicorp/go-cleanhttp@0.5.2 + + + +
    • +
    + +
    + +
    + +

    MPL-2.0 license

    + +
    + + + +
    +
    +

    MPL-2.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Module: + + github.com/gosimple/slug +
    • + +
    • Introduced through: + + github.com/argoproj/argo-cd/v2@0.0.0 and github.com/gosimple/slug@1.13.1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@0.0.0 + + github.com/gosimple/slug@1.13.1 + + + +
    • +
    + +
    + +
    + +

    MPL-2.0 license

    + +
    + + + +
    +
    +
    +
    + + + diff --git a/docs/snyk/v2.9.0-rc3/ghcr.io_dexidp_dex_v2.37.0.html b/docs/snyk/v2.9.0-rc3/ghcr.io_dexidp_dex_v2.37.0.html new file mode 100644 index 0000000000000..99e019bd198fc --- /dev/null +++ b/docs/snyk/v2.9.0-rc3/ghcr.io_dexidp_dex_v2.37.0.html @@ -0,0 +1,2862 @@ + + + + + + + + + Snyk test report + + + + + + + + + +
    +
    +
    +
    + + + Snyk - Open Source Security + + + + + + + +
    +

    Snyk test report

    + +

    October 29th 2023, 12:18:27 am (UTC+00:00)

    +
    +
    + Scanned the following paths: +
      +
    • ghcr.io/dexidp/dex:v2.37.0/dexidp/dex (apk)
    • ghcr.io/dexidp/dex:v2.37.0/hairyhenderson/gomplate/v3 (gomodules)
    • ghcr.io/dexidp/dex:v2.37.0/dexidp/dex (gomodules)
    • ghcr.io/dexidp/dex:v2.37.0/dexidp/dex (gomodules)
    • +
    +
    + +
    +
    28 known vulnerabilities
    +
    79 vulnerable dependency paths
    +
    786 dependencies
    +
    +
    +
    +
    + +
    +
    +
    +

    Out-of-bounds Write

    +
    + +
    + critical severity +
    + +
    + +
      +
    • + Package Manager: alpine:3.18 +
    • +
    • + Vulnerable module: + + busybox/busybox +
    • + +
    • Introduced through: + + docker-image|ghcr.io/dexidp/dex@v2.37.0 and busybox/busybox@1.36.1-r0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + busybox/busybox@1.36.1-r0 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + alpine-baselayout/alpine-baselayout@3.4.3-r1 + + busybox/busybox-binsh@1.36.1-r0 + + busybox/busybox@1.36.1-r0 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + busybox/busybox-binsh@1.36.1-r0 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + alpine-baselayout/alpine-baselayout@3.4.3-r1 + + busybox/busybox-binsh@1.36.1-r0 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + busybox/ssl_client@1.36.1-r0 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream busybox package and not the busybox package as distributed by Alpine. + See How to fix? for Alpine:3.18 relevant fixed versions and status.

    +

    There is a stack overflow vulnerability in ash.c:6030 in busybox before 1.35. In the environment of Internet of Vehicles, this vulnerability can be executed from command to arbitrary code execution.

    +

    Remediation

    +

    Upgrade Alpine:3.18 busybox to version 1.36.1-r1 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Denial of Service (DoS)

    +
    + +
    + high severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + google.golang.org/grpc +
    • + +
    • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and google.golang.org/grpc@v1.46.2 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + google.golang.org/grpc@v1.46.2 + + + +
    • +
    • + Introduced through: + github.com/dexidp/dex@* + + google.golang.org/grpc@v1.56.1 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    google.golang.org/grpc is a Go implementation of gRPC

    +

    Affected versions of this package are vulnerable to Denial of Service (DoS) in the implementation of the HTTP/2 protocol. An attacker can cause a denial of service (including via DDoS) by rapidly resetting many streams through request cancellation.

    +

    Remediation

    +

    Upgrade google.golang.org/grpc to version 1.56.3, 1.57.1, 1.58.3 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Denial of Service (DoS)

    +
    + +
    + high severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + golang.org/x/net/http2 +
    • + +
    • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and golang.org/x/net/http2@v0.7.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + golang.org/x/net/http2@v0.7.0 + + + +
    • +
    • + Introduced through: + github.com/dexidp/dex@* + + golang.org/x/net/http2@v0.11.0 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    golang.org/x/net/http2 is a work-in-progress HTTP/2 implementation for Go.

    +

    Affected versions of this package are vulnerable to Denial of Service (DoS) in the implementation of the HTTP/2 protocol. An attacker can cause a denial of service (including via DDoS) by rapidly resetting many streams through request cancellation.

    +

    Remediation

    +

    Upgrade golang.org/x/net/http2 to version 0.17.0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Improper Authentication

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: alpine:3.18 +
    • +
    • + Vulnerable module: + + openssl/libcrypto3 +
    • + +
    • Introduced through: + + docker-image|ghcr.io/dexidp/dex@v2.37.0 and openssl/libcrypto3@3.1.1-r1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + busybox/ssl_client@1.36.1-r0 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libssl3@3.1.1-r1 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + busybox/ssl_client@1.36.1-r0 + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine:3.18. + See How to fix? for Alpine:3.18 relevant fixed versions and status.

    +

    Issue summary: The AES-SIV cipher implementation contains a bug that causes + it to ignore empty associated data entries which are unauthenticated as + a consequence.

    +

    Impact summary: Applications that use the AES-SIV algorithm and want to + authenticate empty data entries as associated data can be mislead by removing + adding or reordering such empty entries as these are ignored by the OpenSSL + implementation. We are currently unaware of any such applications.

    +

    The AES-SIV algorithm allows for authentication of multiple associated + data entries along with the encryption. To authenticate empty data the + application has to call EVP_EncryptUpdate() (or EVP_CipherUpdate()) with + NULL pointer as the output buffer and 0 as the input buffer length. + The AES-SIV implementation in OpenSSL just returns success for such a call + instead of performing the associated data authentication operation. + The empty data thus will not be authenticated.

    +

    As this issue does not affect non-empty associated data authentication and + we expect it to be rare for an application to use empty associated data + entries this is qualified as Low severity issue.

    +

    Remediation

    +

    Upgrade Alpine:3.18 openssl to version 3.1.1-r2 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Inefficient Regular Expression Complexity

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: alpine:3.18 +
    • +
    • + Vulnerable module: + + openssl/libcrypto3 +
    • + +
    • Introduced through: + + docker-image|ghcr.io/dexidp/dex@v2.37.0 and openssl/libcrypto3@3.1.1-r1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + busybox/ssl_client@1.36.1-r0 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libssl3@3.1.1-r1 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + busybox/ssl_client@1.36.1-r0 + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine. + See How to fix? for Alpine:3.18 relevant fixed versions and status.

    +

    Issue summary: Checking excessively long DH keys or parameters may be very slow.

    +

    Impact summary: Applications that use the functions DH_check(), DH_check_ex() + or EVP_PKEY_param_check() to check a DH key or DH parameters may experience long + delays. Where the key or parameters that are being checked have been obtained + from an untrusted source this may lead to a Denial of Service.

    +

    The function DH_check() performs various checks on DH parameters. One of those + checks confirms that the modulus ('p' parameter) is not too large. Trying to use + a very large modulus is slow and OpenSSL will not normally use a modulus which + is over 10,000 bits in length.

    +

    However the DH_check() function checks numerous aspects of the key or parameters + that have been supplied. Some of those checks use the supplied modulus value + even if it has already been found to be too large.

    +

    An application that calls DH_check() and supplies a key or parameters obtained + from an untrusted source could be vulernable to a Denial of Service attack.

    +

    The function DH_check() is itself called by a number of other OpenSSL functions. + An application calling any of those other functions may similarly be affected. + The other functions affected by this are DH_check_ex() and + EVP_PKEY_param_check().

    +

    Also vulnerable are the OpenSSL dhparam and pkeyparam command line applications + when using the '-check' option.

    +

    The OpenSSL SSL/TLS implementation is not affected by this issue. + The OpenSSL 3.0 and 3.1 FIPS providers are not affected by this issue.

    +

    Remediation

    +

    Upgrade Alpine:3.18 openssl to version 3.1.1-r3 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Excessive Iteration

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: alpine:3.18 +
    • +
    • + Vulnerable module: + + openssl/libcrypto3 +
    • + +
    • Introduced through: + + docker-image|ghcr.io/dexidp/dex@v2.37.0 and openssl/libcrypto3@3.1.1-r1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + busybox/ssl_client@1.36.1-r0 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libssl3@3.1.1-r1 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + busybox/ssl_client@1.36.1-r0 + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine. + See How to fix? for Alpine:3.18 relevant fixed versions and status.

    +

    Issue summary: Checking excessively long DH keys or parameters may be very slow.

    +

    Impact summary: Applications that use the functions DH_check(), DH_check_ex() + or EVP_PKEY_param_check() to check a DH key or DH parameters may experience long + delays. Where the key or parameters that are being checked have been obtained + from an untrusted source this may lead to a Denial of Service.

    +

    The function DH_check() performs various checks on DH parameters. After fixing + CVE-2023-3446 it was discovered that a large q parameter value can also trigger + an overly long computation during some of these checks. A correct q value, + if present, cannot be larger than the modulus p parameter, thus it is + unnecessary to perform these checks if q is larger than p.

    +

    An application that calls DH_check() and supplies a key or parameters obtained + from an untrusted source could be vulnerable to a Denial of Service attack.

    +

    The function DH_check() is itself called by a number of other OpenSSL functions. + An application calling any of those other functions may similarly be affected. + The other functions affected by this are DH_check_ex() and + EVP_PKEY_param_check().

    +

    Also vulnerable are the OpenSSL dhparam and pkeyparam command line applications + when using the "-check" option.

    +

    The OpenSSL SSL/TLS implementation is not affected by this issue.

    +

    The OpenSSL 3.0 and 3.1 FIPS providers are not affected by this issue.

    +

    Remediation

    +

    Upgrade Alpine:3.18 openssl to version 3.1.2-r0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Cross-site Scripting (XSS)

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + golang.org/x/net/html +
    • + +
    • Introduced through: + + github.com/dexidp/dex@* and golang.org/x/net/html@v0.11.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/dexidp/dex@* + + golang.org/x/net/html@v0.11.0 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    golang.org/x/net/html is a package that implements an HTML5-compliant tokenizer and parser.

    +

    Affected versions of this package are vulnerable to Cross-site Scripting (XSS) in the render1() function in render.go. Text nodes not in the HTML namespace are incorrectly literally rendered, causing text which should be escaped to not be.

    +

    Details

    +

    A cross-site scripting attack occurs when the attacker tricks a legitimate web-based application or site to accept a request as originating from a trusted source.

    +

    This is done by escaping the context of the web application; the web application then delivers that data to its users along with other trusted dynamic content, without validating it. The browser unknowingly executes malicious script on the client side (through client-side languages; usually JavaScript or HTML) in order to perform actions that are otherwise typically blocked by the browser’s Same Origin Policy.

    +

    Injecting malicious code is the most prevalent manner by which XSS is exploited; for this reason, escaping characters in order to prevent this manipulation is the top method for securing code against this vulnerability.

    +

    Escaping means that the application is coded to mark key characters, and particularly key characters included in user input, to prevent those characters from being interpreted in a dangerous context. For example, in HTML, < can be coded as &lt; and > can be coded as &gt; in order to be interpreted and displayed as themselves in text, while within the code itself, they are used for HTML tags. If malicious content is injected into an application that escapes special characters and that malicious content uses < and > as HTML tags, those characters are nonetheless not interpreted as HTML tags by the browser if they’ve been correctly escaped in the application code and in this way the attempted attack is diverted.

    +

    The most prominent use of XSS is to steal cookies (source: OWASP HttpOnly) and hijack user sessions, but XSS exploits have been used to expose sensitive information, enable access to privileged services and functionality and deliver malware.

    +

    Types of attacks

    +

    There are a few methods by which XSS can be manipulated:

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    TypeOriginDescription
    StoredServerThe malicious code is inserted in the application (usually as a link) by the attacker. The code is activated every time a user clicks the link.
    ReflectedServerThe attacker delivers a malicious link externally from the vulnerable web site application to a user. When clicked, malicious code is sent to the vulnerable web site, which reflects the attack back to the user’s browser.
    DOM-basedClientThe attacker forces the user’s browser to render a malicious page. The data in the page itself delivers the cross-site scripting data.
    MutatedThe attacker injects code that appears safe, but is then rewritten and modified by the browser, while parsing the markup. An example is rebalancing unclosed quotation marks or even adding quotation marks to unquoted parameters.
    +

    Affected environments

    +

    The following environments are susceptible to an XSS attack:

    +
      +
    • Web servers
    • +
    • Application servers
    • +
    • Web application environments
    • +
    +

    How to prevent

    +

    This section describes the top best practices designed to specifically protect your code:

    +
      +
    • Sanitize data input in an HTTP request before reflecting it back, ensuring all data is validated, filtered or escaped before echoing anything back to the user, such as the values of query parameters during searches.
    • +
    • Convert special characters such as ?, &, /, <, > and spaces to their respective HTML or URL encoded equivalents.
    • +
    • Give users the option to disable client-side scripts.
    • +
    • Redirect invalid requests.
    • +
    • Detect simultaneous logins, including those from two separate IP addresses, and invalidate those sessions.
    • +
    • Use and enforce a Content Security Policy (source: Wikipedia) to disable any features that might be manipulated for an XSS attack.
    • +
    • Read the documentation for any of the libraries referenced in your code to understand which elements allow for embedded HTML.
    • +
    +

    Remediation

    +

    Upgrade golang.org/x/net/html to version 0.13.0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    MPL-2.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Module: + + github.com/hashicorp/vault/sdk/helper/certutil +
    • + +
    • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and github.com/hashicorp/vault/sdk/helper/certutil@v0.5.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + github.com/hashicorp/vault/sdk/helper/certutil@v0.5.0 + + + +
    • +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + github.com/hashicorp/vault/sdk/helper/compressutil@v0.5.0 + + + +
    • +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + github.com/hashicorp/vault/sdk/helper/consts@v0.5.0 + + + +
    • +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + github.com/hashicorp/vault/sdk/helper/jsonutil@v0.5.0 + + + +
    • +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + github.com/hashicorp/vault/sdk/helper/pluginutil@v0.5.0 + + + +
    • +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + github.com/hashicorp/vault/sdk/helper/strutil@v0.5.0 + + + +
    • +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + github.com/hashicorp/vault/sdk/logical@v0.5.0 + + + +
    • +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + github.com/hashicorp/vault/sdk/physical@v0.5.0 + + + +
    • +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + github.com/hashicorp/vault/sdk/physical/inmem@v0.5.0 + + + +
    • +
    + +
    + +
    + +

    MPL-2.0 license

    + +
    + + + +
    +
    +

    MPL-2.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Module: + + github.com/hashicorp/vault/api +
    • + +
    • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and github.com/hashicorp/vault/api@v1.6.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + github.com/hashicorp/vault/api@v1.6.0 + + + +
    • +
    + +
    + +
    + +

    MPL-2.0 license

    + +
    + + + +
    +
    +

    MPL-2.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Module: + + github.com/hashicorp/serf/coordinate +
    • + +
    • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and github.com/hashicorp/serf/coordinate@v0.9.7 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + github.com/hashicorp/serf/coordinate@v0.9.7 + + + +
    • +
    + +
    + +
    + +

    MPL-2.0 license

    + +
    + + + +
    +
    +

    MPL-2.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Module: + + github.com/hashicorp/hcl/v2 +
    • + +
    • Introduced through: + + github.com/dexidp/dex@* and github.com/hashicorp/hcl/v2@v2.13.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/dexidp/dex@* + + github.com/hashicorp/hcl/v2@v2.13.0 + + + +
    • +
    • + Introduced through: + github.com/dexidp/dex@* + + github.com/hashicorp/hcl/v2/ext/customdecode@v2.13.0 + + + +
    • +
    • + Introduced through: + github.com/dexidp/dex@* + + github.com/hashicorp/hcl/v2/ext/tryfunc@v2.13.0 + + + +
    • +
    • + Introduced through: + github.com/dexidp/dex@* + + github.com/hashicorp/hcl/v2/gohcl@v2.13.0 + + + +
    • +
    • + Introduced through: + github.com/dexidp/dex@* + + github.com/hashicorp/hcl/v2/hclparse@v2.13.0 + + + +
    • +
    • + Introduced through: + github.com/dexidp/dex@* + + github.com/hashicorp/hcl/v2/hclsyntax@v2.13.0 + + + +
    • +
    • + Introduced through: + github.com/dexidp/dex@* + + github.com/hashicorp/hcl/v2/hclwrite@v2.13.0 + + + +
    • +
    • + Introduced through: + github.com/dexidp/dex@* + + github.com/hashicorp/hcl/v2/json@v2.13.0 + + + +
    • +
    + +
    + +
    + +

    MPL-2.0 license

    + +
    + + + +
    +
    +

    MPL-2.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Module: + + github.com/hashicorp/hcl +
    • + +
    • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and github.com/hashicorp/hcl@v1.0.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + github.com/hashicorp/hcl@v1.0.0 + + + +
    • +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + github.com/hashicorp/hcl/hcl/parser@v1.0.0 + + + +
    • +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + github.com/hashicorp/hcl/hcl/strconv@v1.0.0 + + + +
    • +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + github.com/hashicorp/hcl/hcl/token@v1.0.0 + + + +
    • +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + github.com/hashicorp/hcl/json/parser@v1.0.0 + + + +
    • +
    + +
    + +
    + +

    MPL-2.0 license

    + +
    + + + +
    +
    +

    MPL-2.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Module: + + github.com/hashicorp/golang-lru/simplelru +
    • + +
    • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and github.com/hashicorp/golang-lru/simplelru@v0.5.4 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + github.com/hashicorp/golang-lru/simplelru@v0.5.4 + + + +
    • +
    + +
    + +
    + +

    MPL-2.0 license

    + +
    + + + +
    +
    +

    MPL-2.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Module: + + github.com/hashicorp/go-version +
    • + +
    • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and github.com/hashicorp/go-version@v1.5.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + github.com/hashicorp/go-version@v1.5.0 + + + +
    • +
    + +
    + +
    + +

    MPL-2.0 license

    + +
    + + + +
    +
    +

    MPL-2.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Module: + + github.com/hashicorp/go-sockaddr +
    • + +
    • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and github.com/hashicorp/go-sockaddr@v1.0.2 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + github.com/hashicorp/go-sockaddr@v1.0.2 + + + +
    • +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + github.com/hashicorp/go-sockaddr/template@v1.0.2 + + + +
    • +
    + +
    + +
    + +

    MPL-2.0 license

    + +
    + + + +
    +
    +

    MPL-2.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Module: + + github.com/hashicorp/go-secure-stdlib/strutil +
    • + +
    • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and github.com/hashicorp/go-secure-stdlib/strutil@v0.1.2 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + github.com/hashicorp/go-secure-stdlib/strutil@v0.1.2 + + + +
    • +
    + +
    + +
    + +

    MPL-2.0 license

    + +
    + + + +
    +
    +

    MPL-2.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Module: + + github.com/hashicorp/go-secure-stdlib/parseutil +
    • + +
    • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and github.com/hashicorp/go-secure-stdlib/parseutil@v0.1.5 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + github.com/hashicorp/go-secure-stdlib/parseutil@v0.1.5 + + + +
    • +
    + +
    + +
    + +

    MPL-2.0 license

    + +
    + + + +
    +
    +

    MPL-2.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Module: + + github.com/hashicorp/go-secure-stdlib/mlock +
    • + +
    • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and github.com/hashicorp/go-secure-stdlib/mlock@v0.1.2 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + github.com/hashicorp/go-secure-stdlib/mlock@v0.1.2 + + + +
    • +
    + +
    + +
    + +

    MPL-2.0 license

    + +
    + + + +
    +
    +

    MPL-2.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Module: + + github.com/hashicorp/go-rootcerts +
    • + +
    • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and github.com/hashicorp/go-rootcerts@v1.0.2 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + github.com/hashicorp/go-rootcerts@v1.0.2 + + + +
    • +
    + +
    + +
    + +

    MPL-2.0 license

    + +
    + + + +
    +
    +

    MPL-2.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Module: + + github.com/hashicorp/go-retryablehttp +
    • + +
    • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and github.com/hashicorp/go-retryablehttp@v0.7.1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + github.com/hashicorp/go-retryablehttp@v0.7.1 + + + +
    • +
    + +
    + +
    + +

    MPL-2.0 license

    + +
    + + + +
    +
    +

    MPL-2.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Module: + + github.com/hashicorp/go-plugin +
    • + +
    • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and github.com/hashicorp/go-plugin@v1.4.4 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + github.com/hashicorp/go-plugin@v1.4.4 + + + +
    • +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + github.com/hashicorp/go-plugin/internal/plugin@v1.4.4 + + + +
    • +
    + +
    + +
    + +

    MPL-2.0 license

    + +
    + + + +
    +
    +

    MPL-2.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Module: + + github.com/hashicorp/go-immutable-radix +
    • + +
    • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and github.com/hashicorp/go-immutable-radix@v1.3.1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + github.com/hashicorp/go-immutable-radix@v1.3.1 + + + +
    • +
    + +
    + +
    + +

    MPL-2.0 license

    + +
    + + + +
    +
    +

    MPL-2.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Module: + + github.com/hashicorp/go-cleanhttp +
    • + +
    • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and github.com/hashicorp/go-cleanhttp@v0.5.2 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + github.com/hashicorp/go-cleanhttp@v0.5.2 + + + +
    • +
    + +
    + +
    + +

    MPL-2.0 license

    + +
    + + + +
    +
    +

    MPL-2.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Module: + + github.com/hashicorp/errwrap +
    • + +
    • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and github.com/hashicorp/errwrap@v1.1.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + github.com/hashicorp/errwrap@v1.1.0 + + + +
    • +
    + +
    + +
    + +

    MPL-2.0 license

    + +
    + + + +
    +
    +

    MPL-2.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Module: + + github.com/hashicorp/consul/api +
    • + +
    • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and github.com/hashicorp/consul/api@v1.13.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + github.com/hashicorp/consul/api@v1.13.0 + + + +
    • +
    + +
    + +
    + +

    MPL-2.0 license

    + +
    + + + +
    +
    +

    MPL-2.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Module: + + github.com/gosimple/slug +
    • + +
    • Introduced through: + + github.com/hairyhenderson/gomplate/v3@* and github.com/gosimple/slug@v1.12.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/hairyhenderson/gomplate/v3@* + + github.com/gosimple/slug@v1.12.0 + + + +
    • +
    + +
    + +
    + +

    MPL-2.0 license

    + +
    + + + +
    +
    +

    MPL-2.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Module: + + github.com/go-sql-driver/mysql +
    • + +
    • Introduced through: + + github.com/dexidp/dex@* and github.com/go-sql-driver/mysql@v1.7.1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/dexidp/dex@* + + github.com/go-sql-driver/mysql@v1.7.1 + + + +
    • +
    + +
    + +
    + +

    MPL-2.0 license

    + +
    + + + +
    +
    +

    CVE-2023-5363

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Package Manager: alpine:3.18 +
    • +
    • + Vulnerable module: + + openssl/libcrypto3 +
    • + +
    • Introduced through: + + docker-image|ghcr.io/dexidp/dex@v2.37.0 and openssl/libcrypto3@3.1.1-r1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + busybox/ssl_client@1.36.1-r0 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libssl3@3.1.1-r1 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|ghcr.io/dexidp/dex@v2.37.0 + + busybox/ssl_client@1.36.1-r0 + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine. + See How to fix? for Alpine:3.18 relevant fixed versions and status.

    +

    Issue summary: A bug has been identified in the processing of key and + initialisation vector (IV) lengths. This can lead to potential truncation + or overruns during the initialisation of some symmetric ciphers.

    +

    Impact summary: A truncation in the IV can result in non-uniqueness, + which could result in loss of confidentiality for some cipher modes.

    +

    When calling EVP_EncryptInit_ex2(), EVP_DecryptInit_ex2() or + EVP_CipherInit_ex2() the provided OSSL_PARAM array is processed after + the key and IV have been established. Any alterations to the key length, + via the "keylen" parameter or the IV length, via the "ivlen" parameter, + within the OSSL_PARAM array will not take effect as intended, potentially + causing truncation or overreading of these values. The following ciphers + and cipher modes are impacted: RC2, RC4, RC5, CCM, GCM and OCB.

    +

    For the CCM, GCM and OCB cipher modes, truncation of the IV can result in + loss of confidentiality. For example, when following NIST's SP 800-38D + section 8.2.1 guidance for constructing a deterministic IV for AES in + GCM mode, truncation of the counter portion could lead to IV reuse.

    +

    Both truncations and overruns of the key and overruns of the IV will + produce incorrect results and could, in some cases, trigger a memory + exception. However, these issues are not currently assessed as security + critical.

    +

    Changing the key and/or IV lengths is not considered to be a common operation + and the vulnerable API was recently introduced. Furthermore it is likely that + application developers will have spotted this problem during testing since + decryption would fail unless both peers in the communication were similarly + vulnerable. For these reasons we expect the probability of an application being + vulnerable to this to be quite low. However if an application is vulnerable then + this issue is considered very serious. For these reasons we have assessed this + issue as Moderate severity overall.

    +

    The OpenSSL SSL/TLS implementation is not affected by this issue.

    +

    The OpenSSL 3.0 and 3.1 FIPS providers are not affected by this because + the issue lies outside of the FIPS provider boundary.

    +

    OpenSSL 3.1 and 3.0 are vulnerable to this issue.

    +

    Remediation

    +

    Upgrade Alpine:3.18 openssl to version 3.1.4-r0 or higher.

    +

    References

    + + +
    + + + +
    +
    +
    +
    + + + diff --git a/docs/snyk/v2.9.0-rc3/haproxy_2.6.14-alpine.html b/docs/snyk/v2.9.0-rc3/haproxy_2.6.14-alpine.html new file mode 100644 index 0000000000000..d4837cba79b4d --- /dev/null +++ b/docs/snyk/v2.9.0-rc3/haproxy_2.6.14-alpine.html @@ -0,0 +1,683 @@ + + + + + + + + + Snyk test report + + + + + + + + + +
    +
    +
    +
    + + + Snyk - Open Source Security + + + + + + + +
    +

    Snyk test report

    + +

    October 29th 2023, 12:18:32 am (UTC+00:00)

    +
    +
    + Scanned the following path: +
      +
    • haproxy:2.6.14-alpine (apk)
    • +
    +
    + +
    +
    1 known vulnerabilities
    +
    9 vulnerable dependency paths
    +
    18 dependencies
    +
    +
    +
    +
    +
    + + + + + + + +
    Project docker-image|haproxy
    Path haproxy:2.6.14-alpine
    Package Manager apk
    +
    +
    +
    +
    +

    CVE-2023-5363

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Package Manager: alpine:3.18 +
    • +
    • + Vulnerable module: + + openssl/libcrypto3 +
    • + +
    • Introduced through: + + docker-image|haproxy@2.6.14-alpine and openssl/libcrypto3@3.1.2-r0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|haproxy@2.6.14-alpine + + openssl/libcrypto3@3.1.2-r0 + + + +
    • +
    • + Introduced through: + docker-image|haproxy@2.6.14-alpine + + .haproxy-rundeps@20230809.001942 + + openssl/libcrypto3@3.1.2-r0 + + + +
    • +
    • + Introduced through: + docker-image|haproxy@2.6.14-alpine + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libcrypto3@3.1.2-r0 + + + +
    • +
    • + Introduced through: + docker-image|haproxy@2.6.14-alpine + + busybox/ssl_client@1.36.1-r2 + + openssl/libcrypto3@3.1.2-r0 + + + +
    • +
    • + Introduced through: + docker-image|haproxy@2.6.14-alpine + + .haproxy-rundeps@20230809.001942 + + openssl/libssl3@3.1.2-r0 + + openssl/libcrypto3@3.1.2-r0 + + + +
    • +
    • + Introduced through: + docker-image|haproxy@2.6.14-alpine + + openssl/libssl3@3.1.2-r0 + + + +
    • +
    • + Introduced through: + docker-image|haproxy@2.6.14-alpine + + .haproxy-rundeps@20230809.001942 + + openssl/libssl3@3.1.2-r0 + + + +
    • +
    • + Introduced through: + docker-image|haproxy@2.6.14-alpine + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libssl3@3.1.2-r0 + + + +
    • +
    • + Introduced through: + docker-image|haproxy@2.6.14-alpine + + busybox/ssl_client@1.36.1-r2 + + openssl/libssl3@3.1.2-r0 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine. + See How to fix? for Alpine:3.18 relevant fixed versions and status.

    +

    Issue summary: A bug has been identified in the processing of key and + initialisation vector (IV) lengths. This can lead to potential truncation + or overruns during the initialisation of some symmetric ciphers.

    +

    Impact summary: A truncation in the IV can result in non-uniqueness, + which could result in loss of confidentiality for some cipher modes.

    +

    When calling EVP_EncryptInit_ex2(), EVP_DecryptInit_ex2() or + EVP_CipherInit_ex2() the provided OSSL_PARAM array is processed after + the key and IV have been established. Any alterations to the key length, + via the "keylen" parameter or the IV length, via the "ivlen" parameter, + within the OSSL_PARAM array will not take effect as intended, potentially + causing truncation or overreading of these values. The following ciphers + and cipher modes are impacted: RC2, RC4, RC5, CCM, GCM and OCB.

    +

    For the CCM, GCM and OCB cipher modes, truncation of the IV can result in + loss of confidentiality. For example, when following NIST's SP 800-38D + section 8.2.1 guidance for constructing a deterministic IV for AES in + GCM mode, truncation of the counter portion could lead to IV reuse.

    +

    Both truncations and overruns of the key and overruns of the IV will + produce incorrect results and could, in some cases, trigger a memory + exception. However, these issues are not currently assessed as security + critical.

    +

    Changing the key and/or IV lengths is not considered to be a common operation + and the vulnerable API was recently introduced. Furthermore it is likely that + application developers will have spotted this problem during testing since + decryption would fail unless both peers in the communication were similarly + vulnerable. For these reasons we expect the probability of an application being + vulnerable to this to be quite low. However if an application is vulnerable then + this issue is considered very serious. For these reasons we have assessed this + issue as Moderate severity overall.

    +

    The OpenSSL SSL/TLS implementation is not affected by this issue.

    +

    The OpenSSL 3.0 and 3.1 FIPS providers are not affected by this because + the issue lies outside of the FIPS provider boundary.

    +

    OpenSSL 3.1 and 3.0 are vulnerable to this issue.

    +

    Remediation

    +

    Upgrade Alpine:3.18 openssl to version 3.1.4-r0 or higher.

    +

    References

    + + +
    + + + +
    +
    +
    +
    + + + diff --git a/docs/snyk/v2.9.0-rc3/quay.io_argoproj_argocd_v2.9.0-rc3.html b/docs/snyk/v2.9.0-rc3/quay.io_argoproj_argocd_v2.9.0-rc3.html new file mode 100644 index 0000000000000..c815a4833afb8 --- /dev/null +++ b/docs/snyk/v2.9.0-rc3/quay.io_argoproj_argocd_v2.9.0-rc3.html @@ -0,0 +1,3366 @@ + + + + + + + + + Snyk test report + + + + + + + + + +
    +
    +
    +
    + + + Snyk - Open Source Security + + + + + + + +
    +

    Snyk test report

    + +

    October 29th 2023, 12:18:58 am (UTC+00:00)

    +
    +
    + Scanned the following paths: +
      +
    • quay.io/argoproj/argocd:v2.9.0-rc3/argoproj/argocd (deb)
    • quay.io/argoproj/argocd:v2.9.0-rc3/argoproj/argo-cd/v2 (gomodules)
    • quay.io/argoproj/argocd:v2.9.0-rc3 (gomodules)
    • quay.io/argoproj/argocd:v2.9.0-rc3/helm/v3 (gomodules)
    • quay.io/argoproj/argocd:v2.9.0-rc3/git-lfs/git-lfs (gomodules)
    • +
    +
    + +
    +
    30 known vulnerabilities
    +
    99 vulnerable dependency paths
    +
    2185 dependencies
    +
    +
    +
    +
    + +
    +
    +
    +

    Denial of Service (DoS)

    +
    + +
    + high severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + google.golang.org/grpc +
    • + +
    • Introduced through: + + github.com/argoproj/argo-cd/v2@* and google.golang.org/grpc@v1.56.2 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@* + + google.golang.org/grpc@v1.56.2 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    google.golang.org/grpc is a Go implementation of gRPC

    +

    Affected versions of this package are vulnerable to Denial of Service (DoS) in the implementation of the HTTP/2 protocol. An attacker can cause a denial of service (including via DDoS) by rapidly resetting many streams through request cancellation.

    +

    Remediation

    +

    Upgrade google.golang.org/grpc to version 1.56.3, 1.57.1, 1.58.3 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Denial of Service (DoS)

    +
    + +
    + high severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + golang.org/x/net/http2 +
    • + +
    • Introduced through: + + github.com/argoproj/argo-cd/v2@* and golang.org/x/net/http2@v0.15.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@* + + golang.org/x/net/http2@v0.15.0 + + + +
    • +
    • + Introduced through: + helm.sh/helm/v3@* + + golang.org/x/net/http2@v0.8.0 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    golang.org/x/net/http2 is a work-in-progress HTTP/2 implementation for Go.

    +

    Affected versions of this package are vulnerable to Denial of Service (DoS) in the implementation of the HTTP/2 protocol. An attacker can cause a denial of service (including via DDoS) by rapidly resetting many streams through request cancellation.

    +

    Remediation

    +

    Upgrade golang.org/x/net/http2 to version 0.17.0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Directory Traversal

    +
    + +
    + high severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Vulnerable module: + + github.com/cyphar/filepath-securejoin +
    • + +
    • Introduced through: + + helm.sh/helm/v3@* and github.com/cyphar/filepath-securejoin@v0.2.3 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + helm.sh/helm/v3@* + + github.com/cyphar/filepath-securejoin@v0.2.3 + + + +
    • +
    + +
    + +
    + +

    Overview

    +

    Affected versions of this package are vulnerable to Directory Traversal via the filepath.FromSlash() function, allwoing attackers to generate paths that were outside of the provided rootfs.

    +

    Note: + This vulnerability is only exploitable on Windows OS.

    +

    Details

    +

    A Directory Traversal attack (also known as path traversal) aims to access files and directories that are stored outside the intended folder. By manipulating files with "dot-dot-slash (../)" sequences and its variations, or by using absolute file paths, it may be possible to access arbitrary files and directories stored on file system, including application source code, configuration, and other critical system files.

    +

    Directory Traversal vulnerabilities can be generally divided into two types:

    +
      +
    • Information Disclosure: Allows the attacker to gain information about the folder structure or read the contents of sensitive files on the system.
    • +
    +

    st is a module for serving static files on web pages, and contains a vulnerability of this type. In our example, we will serve files from the public route.

    +

    If an attacker requests the following URL from our server, it will in turn leak the sensitive private key of the root user.

    +
    curl http://localhost:8080/public/%2e%2e/%2e%2e/%2e%2e/%2e%2e/%2e%2e/root/.ssh/id_rsa
    +        
    +

    Note %2e is the URL encoded version of . (dot).

    +
      +
    • Writing arbitrary files: Allows the attacker to create or replace existing files. This type of vulnerability is also known as Zip-Slip.
    • +
    +

    One way to achieve this is by using a malicious zip archive that holds path traversal filenames. When each filename in the zip archive gets concatenated to the target extraction folder, without validation, the final path ends up outside of the target folder. If an executable or a configuration file is overwritten with a file containing malicious code, the problem can turn into an arbitrary code execution issue quite easily.

    +

    The following is an example of a zip archive with one benign file and one malicious file. Extracting the malicious file will result in traversing out of the target folder, ending up in /root/.ssh/ overwriting the authorized_keys file:

    +
    2018-04-15 22:04:29 .....           19           19  good.txt
    +        2018-04-15 22:04:42 .....           20           20  ../../../../../../root/.ssh/authorized_keys
    +        
    +

    Remediation

    +

    Upgrade github.com/cyphar/filepath-securejoin to version 0.2.4 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    CVE-2020-22916

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + xz-utils/liblzma5 +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 and xz-utils/liblzma5@5.2.5-2ubuntu1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + xz-utils/liblzma5@5.2.5-2ubuntu1 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream xz-utils package and not the xz-utils package as distributed by Ubuntu. + See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    +

    ** DISPUTED ** An issue discovered in XZ 5.2.5 allows attackers to cause a denial of service via decompression of a crafted file. NOTE: the vendor disputes the claims of "endless output" and "denial of service" because decompression of the 17,486 bytes always results in 114,881,179 bytes, which is often a reasonable size increase.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 xz-utils.

    +

    References

    + + +
    + + + +
    +
    +

    Out-of-bounds Write

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + perl/perl-modules-5.34 +
    • + +
    • Introduced through: + + + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3, git@1:2.34.1-1ubuntu1.10 and others +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + git@1:2.34.1-1ubuntu1.10 + + perl@5.34.0-3ubuntu1.2 + + perl/perl-modules-5.34@5.34.0-3ubuntu1.2 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + git@1:2.34.1-1ubuntu1.10 + + perl@5.34.0-3ubuntu1.2 + + perl/libperl5.34@5.34.0-3ubuntu1.2 + + perl/perl-modules-5.34@5.34.0-3ubuntu1.2 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + git@1:2.34.1-1ubuntu1.10 + + perl@5.34.0-3ubuntu1.2 + + perl/libperl5.34@5.34.0-3ubuntu1.2 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + git@1:2.34.1-1ubuntu1.10 + + perl@5.34.0-3ubuntu1.2 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + perl/perl-base@5.34.0-3ubuntu1.2 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream perl package and not the perl package as distributed by Ubuntu. + See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    +

    In Perl 5.34.0, function S_find_uninit_var in sv.c has a stack-based crash that can lead to remote code execution or local privilege escalation.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 perl.

    +

    References

    + + +
    + + + +
    +
    +

    Access of Uninitialized Pointer

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + krb5/libk5crypto3 +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 and krb5/libk5crypto3@1.19.2-2ubuntu0.2 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + krb5/libk5crypto3@1.19.2-2ubuntu0.2 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.1 + + pam/libpam-modules@1.4.0-11ubuntu2.3 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.2 + + krb5/libk5crypto3@1.19.2-2ubuntu0.2 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.1 + + pam/libpam-modules@1.4.0-11ubuntu2.3 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.2 + + krb5/libkrb5-3@1.19.2-2ubuntu0.2 + + krb5/libk5crypto3@1.19.2-2ubuntu0.2 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + krb5/libkrb5-3@1.19.2-2ubuntu0.2 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.1 + + pam/libpam-modules@1.4.0-11ubuntu2.3 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.2 + + krb5/libkrb5-3@1.19.2-2ubuntu0.2 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.2 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + openssh/openssh-client@1:8.9p1-3ubuntu0.4 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.2 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.14 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.2 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.14 + + libssh/libssh-4@0.9.6-2ubuntu0.22.04.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.2 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.1 + + pam/libpam-modules@1.4.0-11ubuntu2.3 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.2 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + krb5/libkrb5support0@1.19.2-2ubuntu0.2 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream krb5 package and not the krb5 package as distributed by Ubuntu. + See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    +

    lib/kadm5/kadm_rpc_xdr.c in MIT Kerberos 5 (aka krb5) before 1.20.2 and 1.21.x before 1.21.1 frees an uninitialized pointer. A remote authenticated user can trigger a kadmind crash. This occurs because _xdr_kadm5_principal_ent_rec does not validate the relationship between n_key_data and the key_data array count.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 krb5.

    +

    References

    + + +
    + + + +
    +
    +

    LGPL-3.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Module: + + gopkg.in/retry.v1 +
    • + +
    • Introduced through: + + github.com/argoproj/argo-cd/v2@* and gopkg.in/retry.v1@v1.0.3 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@* + + gopkg.in/retry.v1@v1.0.3 + + + +
    • +
    + +
    + +
    + +

    LGPL-3.0 license

    + +
    + + + +
    +
    +

    Memory Leak

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + glibc/libc-bin +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 and glibc/libc-bin@2.35-0ubuntu3.4 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + glibc/libc-bin@2.35-0ubuntu3.4 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + glibc/libc6@2.35-0ubuntu3.4 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream glibc package and not the glibc package as distributed by Ubuntu. + See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    +

    A flaw was found in the GNU C Library. A recent fix for CVE-2023-4806 introduced the potential for a memory leak, which may result in an application crash.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 glibc.

    +

    References

    + + +
    + + + +
    +
    +

    MPL-2.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Module: + + github.com/r3labs/diff +
    • + +
    • Introduced through: + + github.com/argoproj/argo-cd/v2@* and github.com/r3labs/diff@v1.1.0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@* + + github.com/r3labs/diff@v1.1.0 + + + +
    • +
    + +
    + +
    + +

    MPL-2.0 license

    + +
    + + + +
    +
    +

    MPL-2.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Module: + + github.com/hashicorp/go-version +
    • + +
    • Introduced through: + + github.com/argoproj/argo-cd/v2@* and github.com/hashicorp/go-version@v1.2.1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@* + + github.com/hashicorp/go-version@v1.2.1 + + + +
    • +
    + +
    + +
    + +

    MPL-2.0 license

    + +
    + + + +
    +
    +

    MPL-2.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Module: + + github.com/hashicorp/go-retryablehttp +
    • + +
    • Introduced through: + + github.com/argoproj/argo-cd/v2@* and github.com/hashicorp/go-retryablehttp@v0.7.4 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@* + + github.com/hashicorp/go-retryablehttp@v0.7.4 + + + +
    • +
    + +
    + +
    + +

    MPL-2.0 license

    + +
    + + + +
    +
    +

    MPL-2.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Module: + + github.com/hashicorp/go-multierror +
    • + +
    • Introduced through: + + helm.sh/helm/v3@* and github.com/hashicorp/go-multierror@v1.1.1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + helm.sh/helm/v3@* + + github.com/hashicorp/go-multierror@v1.1.1 + + + +
    • +
    + +
    + +
    + +

    MPL-2.0 license

    + +
    + + + +
    +
    +

    MPL-2.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Module: + + github.com/hashicorp/go-cleanhttp +
    • + +
    • Introduced through: + + github.com/argoproj/argo-cd/v2@* and github.com/hashicorp/go-cleanhttp@v0.5.2 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@* + + github.com/hashicorp/go-cleanhttp@v0.5.2 + + + +
    • +
    + +
    + +
    + +

    MPL-2.0 license

    + +
    + + + +
    +
    +

    MPL-2.0 license

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: golang +
    • +
    • + Module: + + github.com/gosimple/slug +
    • + +
    • Introduced through: + + github.com/argoproj/argo-cd/v2@* and github.com/gosimple/slug@v1.13.1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + github.com/argoproj/argo-cd/v2@* + + github.com/gosimple/slug@v1.13.1 + + + +
    • +
    + +
    + +
    + +

    MPL-2.0 license

    + +
    + + + +
    +
    +

    CVE-2022-46908

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + sqlite3/libsqlite3-0 +
    • + +
    • Introduced through: + + + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3, gnupg2/gpg@2.2.27-3ubuntu2.1 and others +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + gnupg2/gpg@2.2.27-3ubuntu2.1 + + sqlite3/libsqlite3-0@3.37.2-2ubuntu0.1 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream sqlite3 package and not the sqlite3 package as distributed by Ubuntu:22.04. + See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    +

    SQLite through 3.40.0, when relying on --safe for execution of an untrusted CLI script, does not properly implement the azProhibitedFunctions protection mechanism, and instead allows UDF functions such as WRITEFILE.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 sqlite3.

    +

    References

    + + +
    + + + +
    +
    +

    Arbitrary Code Injection

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + shadow/passwd +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 and shadow/passwd@1:4.8.1-2ubuntu2.1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + shadow/passwd@1:4.8.1-2ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + openssh/openssh-client@1:8.9p1-3ubuntu0.4 + + shadow/passwd@1:4.8.1-2ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + shadow/login@1:4.8.1-2ubuntu2.1 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream shadow package and not the shadow package as distributed by Ubuntu:22.04. + See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    +

    In Shadow 4.13, it is possible to inject control characters into fields provided to the SUID program chfn (change finger). Although it is not possible to exploit this directly (e.g., adding a new user fails because \n is in the block list), it is possible to misrepresent the /etc/passwd file when viewed. Use of \r manipulations and Unicode characters to work around blocking of the : character make it possible to give the impression that a new user has been added. In other words, an adversary may be able to convince a system administrator to take the system offline (an indirect, social-engineered denial of service) by demonstrating that "cat /etc/passwd" shows a rogue user account.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 shadow.

    +

    References

    + + +
    + + + +
    +
    +

    Out-of-bounds Write

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + procps/libprocps8 +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 and procps/libprocps8@2:3.3.17-6ubuntu2 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + procps/libprocps8@2:3.3.17-6ubuntu2 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + procps@2:3.3.17-6ubuntu2 + + procps/libprocps8@2:3.3.17-6ubuntu2 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + procps@2:3.3.17-6ubuntu2 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream procps package and not the procps package as distributed by Ubuntu. + See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    +

    Under some circumstances, this weakness allows a user who has access to run the “ps” utility on a machine, the ability to write almost unlimited amounts of unfiltered data into the process heap.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 procps.

    +

    References

    + + +
    + + + +
    +
    +

    Uncontrolled Recursion

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + pcre3/libpcre3 +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 and pcre3/libpcre3@2:8.39-13ubuntu0.22.04.1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + pcre3/libpcre3@2:8.39-13ubuntu0.22.04.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + grep@3.7-1build1 + + pcre3/libpcre3@2:8.39-13ubuntu0.22.04.1 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream pcre3 package and not the pcre3 package as distributed by Ubuntu:22.04. + See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    +

    In PCRE 8.41, the OP_KETRMAX feature in the match function in pcre_exec.c allows stack exhaustion (uncontrolled recursion) when processing a crafted regular expression.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 pcre3.

    +

    References

    + + +
    + + + +
    +
    +

    Release of Invalid Pointer or Reference

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + patch +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 and patch@2.7.6-7build2 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + patch@2.7.6-7build2 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream patch package and not the patch package as distributed by Ubuntu:22.04. + See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    +

    An Invalid Pointer vulnerability exists in GNU patch 2.7 via the another_hunk function, which causes a Denial of Service.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 patch.

    +

    References

    + + +
    + + + +
    +
    +

    Double Free

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + patch +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 and patch@2.7.6-7build2 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + patch@2.7.6-7build2 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream patch package and not the patch package as distributed by Ubuntu:22.04. + See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    +

    A double free exists in the another_hunk function in pch.c in GNU patch through 2.7.6.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 patch.

    +

    References

    + + +
    + + + +
    +
    +

    CVE-2023-28531

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + openssh/openssh-client +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 and openssh/openssh-client@1:8.9p1-3ubuntu0.4 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + openssh/openssh-client@1:8.9p1-3ubuntu0.4 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream openssh package and not the openssh package as distributed by Ubuntu:22.04. + See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    +

    ssh-add in OpenSSH before 9.3 adds smartcard keys to ssh-agent without the intended per-hop destination constraints. The earliest affected version is 8.9.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 openssh.

    +

    References

    + + +
    + + + +
    +
    +

    NULL Pointer Dereference

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + openldap/libldap-2.5-0 +
    • + +
    • Introduced through: + + + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3, gnupg2/dirmngr@2.2.27-3ubuntu2.1 and others +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + gnupg2/dirmngr@2.2.27-3ubuntu2.1 + + openldap/libldap-2.5-0@2.5.16+dfsg-0ubuntu0.22.04.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.14 + + openldap/libldap-2.5-0@2.5.16+dfsg-0ubuntu0.22.04.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + openldap/libldap-common@2.5.16+dfsg-0ubuntu0.22.04.1 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream openldap package and not the openldap package as distributed by Ubuntu:22.04. + See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    +

    A vulnerability was found in openldap. This security flaw causes a null pointer dereference in ber_memalloc_x() function.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 openldap.

    +

    References

    + + +
    + + + +
    +
    +

    Resource Exhaustion

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + libzstd/libzstd1 +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 and libzstd/libzstd1@1.4.8+dfsg-3build1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + libzstd/libzstd1@1.4.8+dfsg-3build1 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream libzstd package and not the libzstd package as distributed by Ubuntu. + See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    +

    A vulnerability was found in zstd v1.4.10, where an attacker can supply empty string as an argument to the command line tool to cause buffer overrun.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 libzstd.

    +

    References

    + + +
    + + + +
    +
    +

    Integer Overflow or Wraparound

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + krb5/libk5crypto3 +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 and krb5/libk5crypto3@1.19.2-2ubuntu0.2 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + krb5/libk5crypto3@1.19.2-2ubuntu0.2 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.1 + + pam/libpam-modules@1.4.0-11ubuntu2.3 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.2 + + krb5/libk5crypto3@1.19.2-2ubuntu0.2 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.1 + + pam/libpam-modules@1.4.0-11ubuntu2.3 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.2 + + krb5/libkrb5-3@1.19.2-2ubuntu0.2 + + krb5/libk5crypto3@1.19.2-2ubuntu0.2 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + krb5/libkrb5-3@1.19.2-2ubuntu0.2 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.1 + + pam/libpam-modules@1.4.0-11ubuntu2.3 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.2 + + krb5/libkrb5-3@1.19.2-2ubuntu0.2 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.2 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + openssh/openssh-client@1:8.9p1-3ubuntu0.4 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.2 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.14 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.2 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + git@1:2.34.1-1ubuntu1.10 + + curl/libcurl3-gnutls@7.81.0-1ubuntu1.14 + + libssh/libssh-4@0.9.6-2ubuntu0.22.04.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.2 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + adduser@3.118ubuntu5 + + shadow/passwd@1:4.8.1-2ubuntu2.1 + + pam/libpam-modules@1.4.0-11ubuntu2.3 + + libnsl/libnsl2@1.3.0-2build2 + + libtirpc/libtirpc3@1.3.2-2ubuntu0.1 + + krb5/libgssapi-krb5-2@1.19.2-2ubuntu0.2 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + krb5/libkrb5support0@1.19.2-2ubuntu0.2 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream krb5 package and not the krb5 package as distributed by Ubuntu:22.04. + See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    +

    An issue was discovered in MIT Kerberos 5 (aka krb5) through 1.16. There is a variable "dbentry->n_key_data" in kadmin/dbutil/dump.c that can store 16-bit data but unknowingly the developer has assigned a "u4" variable to it, which is for 32-bit data. An attacker can use this vulnerability to affect other artifacts of the database as we know that a Kerberos database dump file contains trusted data.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 krb5.

    +

    References

    + + +
    + + + +
    +
    +

    Out-of-bounds Write

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + gnupg2/gpgv +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 and gnupg2/gpgv@2.2.27-3ubuntu2.1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + gnupg2/gpgv@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + apt@2.4.10 + + gnupg2/gpgv@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gpgv@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + gnupg2/dirmngr@2.2.27-3ubuntu2.1 + + gnupg2/gpgconf@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + gnupg2/gpg@2.2.27-3ubuntu2.1 + + gnupg2/gpgconf@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gpg-agent@2.2.27-3ubuntu2.1 + + gnupg2/gpgconf@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gpgsm@2.2.27-3ubuntu2.1 + + gnupg2/gpgconf@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + gnupg2/dirmngr@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/dirmngr@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gpg-wks-client@2.2.27-3ubuntu2.1 + + gnupg2/dirmngr@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + gnupg2/gnupg-l10n@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gnupg-l10n@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + gnupg2/gnupg-utils@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gnupg-utils@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + gnupg2/gpg@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gpg@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gpg-wks-client@2.2.27-3ubuntu2.1 + + gnupg2/gpg@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gpg-wks-server@2.2.27-3ubuntu2.1 + + gnupg2/gpg@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + gnupg2/gpg-agent@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gpg-agent@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gpg-wks-client@2.2.27-3ubuntu2.1 + + gnupg2/gpg-agent@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gpg-wks-server@2.2.27-3ubuntu2.1 + + gnupg2/gpg-agent@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + gnupg2/gpg-wks-client@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gpg-wks-client@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + gnupg2/gpg-wks-server@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gpg-wks-server@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + gnupg2/gpgsm@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + gnupg2/gpgsm@2.2.27-3ubuntu2.1 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + gnupg2/gnupg@2.2.27-3ubuntu2.1 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream gnupg2 package and not the gnupg2 package as distributed by Ubuntu:22.04. + See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    +

    GnuPG can be made to spin on a relatively small input by (for example) crafting a public key with thousands of signatures attached, compressed down to just a few KB.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 gnupg2.

    +

    References

    + + +
    + + + +
    +
    +

    Allocation of Resources Without Limits or Throttling

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + glibc/libc-bin +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 and glibc/libc-bin@2.35-0ubuntu3.4 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + glibc/libc-bin@2.35-0ubuntu3.4 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + glibc/libc6@2.35-0ubuntu3.4 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream glibc package and not the glibc package as distributed by Ubuntu:22.04. + See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    +

    sha256crypt and sha512crypt through 0.6 allow attackers to cause a denial of service (CPU consumption) because the algorithm's runtime is proportional to the square of the length of the password.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 glibc.

    +

    References

    + + +
    + + + +
    +
    +

    Improper Input Validation

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + git/git-man +
    • + +
    • Introduced through: + + + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3, git@1:2.34.1-1ubuntu1.10 and others +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + git@1:2.34.1-1ubuntu1.10 + + git/git-man@1:2.34.1-1ubuntu1.10 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + git@1:2.34.1-1ubuntu1.10 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + git-lfs@3.0.2-1ubuntu0.2 + + git@1:2.34.1-1ubuntu1.10 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream git package and not the git package as distributed by Ubuntu:22.04. + See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    +

    GIT version 2.15.1 and earlier contains a Input Validation Error vulnerability in Client that can result in problems including messing up terminal configuration to RCE. This attack appear to be exploitable via The user must interact with a malicious git server, (or have their traffic modified in a MITM attack).

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 git.

    +

    References

    + + +
    + + + +
    +
    +

    Uncontrolled Recursion

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + gcc-12/libstdc++6 +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 and gcc-12/libstdc++6@12.3.0-1ubuntu1~22.04 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + gcc-12/libstdc++6@12.3.0-1ubuntu1~22.04 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + apt@2.4.10 + + gcc-12/libstdc++6@12.3.0-1ubuntu1~22.04 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + apt@2.4.10 + + apt/libapt-pkg6.0@2.4.10 + + gcc-12/libstdc++6@12.3.0-1ubuntu1~22.04 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + gcc-12/gcc-12-base@12.3.0-1ubuntu1~22.04 + + + +
    • +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + gcc-12/libgcc-s1@12.3.0-1ubuntu1~22.04 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream gcc-12 package and not the gcc-12 package as distributed by Ubuntu:22.04. + See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    +

    libiberty/rust-demangle.c in GNU GCC 11.2 allows stack consumption in demangle_const, as demonstrated by nm-new.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 gcc-12.

    +

    References

    + + +
    + + + +
    +
    +

    Improper Input Validation

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + coreutils +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 and coreutils@8.32-4.1ubuntu1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + coreutils@8.32-4.1ubuntu1 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream coreutils package and not the coreutils package as distributed by Ubuntu:22.04. + See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    +

    chroot in GNU coreutils, when used with --userspec, allows local users to escape to the parent session via a crafted TIOCSTI ioctl call, which pushes characters to the terminal's input buffer.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 coreutils.

    +

    References

    + + +
    + + + +
    +
    +

    Out-of-bounds Write

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Package Manager: ubuntu:22.04 +
    • +
    • + Vulnerable module: + + bash +
    • + +
    • Introduced through: + + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 and bash@5.1-6ubuntu1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|quay.io/argoproj/argocd@v2.9.0-rc3 + + bash@5.1-6ubuntu1 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream bash package and not the bash package as distributed by Ubuntu:22.04. + See How to fix? for Ubuntu:22.04 relevant fixed versions and status.

    +

    A flaw was found in the bash package, where a heap-buffer overflow can occur in valid parameter_transform. This issue may lead to memory problems.

    +

    Remediation

    +

    There is no fixed version for Ubuntu:22.04 bash.

    +

    References

    + + +
    + + + +
    +
    +
    +
    + + + diff --git a/docs/snyk/v2.9.0-rc3/redis_7.0.11-alpine.html b/docs/snyk/v2.9.0-rc3/redis_7.0.11-alpine.html new file mode 100644 index 0000000000000..8efb859567ad3 --- /dev/null +++ b/docs/snyk/v2.9.0-rc3/redis_7.0.11-alpine.html @@ -0,0 +1,1335 @@ + + + + + + + + + Snyk test report + + + + + + + + + +
    +
    +
    +
    + + + Snyk - Open Source Security + + + + + + + +
    +

    Snyk test report

    + +

    October 29th 2023, 12:19:03 am (UTC+00:00)

    +
    +
    + Scanned the following path: +
      +
    • redis:7.0.11-alpine (apk)
    • +
    +
    + +
    +
    5 known vulnerabilities
    +
    41 vulnerable dependency paths
    +
    18 dependencies
    +
    +
    +
    +
    +
    + + + + + + + +
    Project docker-image|redis
    Path redis:7.0.11-alpine
    Package Manager apk
    +
    +
    +
    +
    +

    Out-of-bounds Write

    +
    + +
    + critical severity +
    + +
    + +
      +
    • + Package Manager: alpine:3.18 +
    • +
    • + Vulnerable module: + + busybox/busybox +
    • + +
    • Introduced through: + + docker-image|redis@7.0.11-alpine and busybox/busybox@1.36.1-r0 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + busybox/busybox@1.36.1-r0 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + alpine-baselayout/alpine-baselayout@3.4.3-r1 + + busybox/busybox-binsh@1.36.1-r0 + + busybox/busybox@1.36.1-r0 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + busybox/busybox-binsh@1.36.1-r0 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + alpine-baselayout/alpine-baselayout@3.4.3-r1 + + busybox/busybox-binsh@1.36.1-r0 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + busybox/ssl_client@1.36.1-r0 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream busybox package and not the busybox package as distributed by Alpine. + See How to fix? for Alpine:3.18 relevant fixed versions and status.

    +

    There is a stack overflow vulnerability in ash.c:6030 in busybox before 1.35. In the environment of Internet of Vehicles, this vulnerability can be executed from command to arbitrary code execution.

    +

    Remediation

    +

    Upgrade Alpine:3.18 busybox to version 1.36.1-r1 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Improper Authentication

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: alpine:3.18 +
    • +
    • + Vulnerable module: + + openssl/libcrypto3 +
    • + +
    • Introduced through: + + docker-image|redis@7.0.11-alpine and openssl/libcrypto3@3.1.1-r1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + .redis-rundeps@20230614.215749 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + busybox/ssl_client@1.36.1-r0 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + .redis-rundeps@20230614.215749 + + openssl/libssl3@3.1.1-r1 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + .redis-rundeps@20230614.215749 + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + busybox/ssl_client@1.36.1-r0 + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine:3.18. + See How to fix? for Alpine:3.18 relevant fixed versions and status.

    +

    Issue summary: The AES-SIV cipher implementation contains a bug that causes + it to ignore empty associated data entries which are unauthenticated as + a consequence.

    +

    Impact summary: Applications that use the AES-SIV algorithm and want to + authenticate empty data entries as associated data can be mislead by removing + adding or reordering such empty entries as these are ignored by the OpenSSL + implementation. We are currently unaware of any such applications.

    +

    The AES-SIV algorithm allows for authentication of multiple associated + data entries along with the encryption. To authenticate empty data the + application has to call EVP_EncryptUpdate() (or EVP_CipherUpdate()) with + NULL pointer as the output buffer and 0 as the input buffer length. + The AES-SIV implementation in OpenSSL just returns success for such a call + instead of performing the associated data authentication operation. + The empty data thus will not be authenticated.

    +

    As this issue does not affect non-empty associated data authentication and + we expect it to be rare for an application to use empty associated data + entries this is qualified as Low severity issue.

    +

    Remediation

    +

    Upgrade Alpine:3.18 openssl to version 3.1.1-r2 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Inefficient Regular Expression Complexity

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: alpine:3.18 +
    • +
    • + Vulnerable module: + + openssl/libcrypto3 +
    • + +
    • Introduced through: + + docker-image|redis@7.0.11-alpine and openssl/libcrypto3@3.1.1-r1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + .redis-rundeps@20230614.215749 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + busybox/ssl_client@1.36.1-r0 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + .redis-rundeps@20230614.215749 + + openssl/libssl3@3.1.1-r1 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + .redis-rundeps@20230614.215749 + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + busybox/ssl_client@1.36.1-r0 + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine. + See How to fix? for Alpine:3.18 relevant fixed versions and status.

    +

    Issue summary: Checking excessively long DH keys or parameters may be very slow.

    +

    Impact summary: Applications that use the functions DH_check(), DH_check_ex() + or EVP_PKEY_param_check() to check a DH key or DH parameters may experience long + delays. Where the key or parameters that are being checked have been obtained + from an untrusted source this may lead to a Denial of Service.

    +

    The function DH_check() performs various checks on DH parameters. One of those + checks confirms that the modulus ('p' parameter) is not too large. Trying to use + a very large modulus is slow and OpenSSL will not normally use a modulus which + is over 10,000 bits in length.

    +

    However the DH_check() function checks numerous aspects of the key or parameters + that have been supplied. Some of those checks use the supplied modulus value + even if it has already been found to be too large.

    +

    An application that calls DH_check() and supplies a key or parameters obtained + from an untrusted source could be vulernable to a Denial of Service attack.

    +

    The function DH_check() is itself called by a number of other OpenSSL functions. + An application calling any of those other functions may similarly be affected. + The other functions affected by this are DH_check_ex() and + EVP_PKEY_param_check().

    +

    Also vulnerable are the OpenSSL dhparam and pkeyparam command line applications + when using the '-check' option.

    +

    The OpenSSL SSL/TLS implementation is not affected by this issue. + The OpenSSL 3.0 and 3.1 FIPS providers are not affected by this issue.

    +

    Remediation

    +

    Upgrade Alpine:3.18 openssl to version 3.1.1-r3 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    Excessive Iteration

    +
    + +
    + medium severity +
    + +
    + +
      +
    • + Package Manager: alpine:3.18 +
    • +
    • + Vulnerable module: + + openssl/libcrypto3 +
    • + +
    • Introduced through: + + docker-image|redis@7.0.11-alpine and openssl/libcrypto3@3.1.1-r1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + .redis-rundeps@20230614.215749 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + busybox/ssl_client@1.36.1-r0 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + .redis-rundeps@20230614.215749 + + openssl/libssl3@3.1.1-r1 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + .redis-rundeps@20230614.215749 + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + busybox/ssl_client@1.36.1-r0 + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine. + See How to fix? for Alpine:3.18 relevant fixed versions and status.

    +

    Issue summary: Checking excessively long DH keys or parameters may be very slow.

    +

    Impact summary: Applications that use the functions DH_check(), DH_check_ex() + or EVP_PKEY_param_check() to check a DH key or DH parameters may experience long + delays. Where the key or parameters that are being checked have been obtained + from an untrusted source this may lead to a Denial of Service.

    +

    The function DH_check() performs various checks on DH parameters. After fixing + CVE-2023-3446 it was discovered that a large q parameter value can also trigger + an overly long computation during some of these checks. A correct q value, + if present, cannot be larger than the modulus p parameter, thus it is + unnecessary to perform these checks if q is larger than p.

    +

    An application that calls DH_check() and supplies a key or parameters obtained + from an untrusted source could be vulnerable to a Denial of Service attack.

    +

    The function DH_check() is itself called by a number of other OpenSSL functions. + An application calling any of those other functions may similarly be affected. + The other functions affected by this are DH_check_ex() and + EVP_PKEY_param_check().

    +

    Also vulnerable are the OpenSSL dhparam and pkeyparam command line applications + when using the "-check" option.

    +

    The OpenSSL SSL/TLS implementation is not affected by this issue.

    +

    The OpenSSL 3.0 and 3.1 FIPS providers are not affected by this issue.

    +

    Remediation

    +

    Upgrade Alpine:3.18 openssl to version 3.1.2-r0 or higher.

    +

    References

    + + +
    + + + +
    +
    +

    CVE-2023-5363

    +
    + +
    + low severity +
    + +
    + +
      +
    • + Package Manager: alpine:3.18 +
    • +
    • + Vulnerable module: + + openssl/libcrypto3 +
    • + +
    • Introduced through: + + docker-image|redis@7.0.11-alpine and openssl/libcrypto3@3.1.1-r1 + +
    • +
    + +
    + + +

    Detailed paths

    + +
      +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + .redis-rundeps@20230614.215749 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + busybox/ssl_client@1.36.1-r0 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + .redis-rundeps@20230614.215749 + + openssl/libssl3@3.1.1-r1 + + openssl/libcrypto3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + .redis-rundeps@20230614.215749 + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + apk-tools/apk-tools@2.14.0-r2 + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    • + Introduced through: + docker-image|redis@7.0.11-alpine + + busybox/ssl_client@1.36.1-r0 + + openssl/libssl3@3.1.1-r1 + + + +
    • +
    + +
    + +
    + +

    NVD Description

    +

    Note: Versions mentioned in the description apply only to the upstream openssl package and not the openssl package as distributed by Alpine. + See How to fix? for Alpine:3.18 relevant fixed versions and status.

    +

    Issue summary: A bug has been identified in the processing of key and + initialisation vector (IV) lengths. This can lead to potential truncation + or overruns during the initialisation of some symmetric ciphers.

    +

    Impact summary: A truncation in the IV can result in non-uniqueness, + which could result in loss of confidentiality for some cipher modes.

    +

    When calling EVP_EncryptInit_ex2(), EVP_DecryptInit_ex2() or + EVP_CipherInit_ex2() the provided OSSL_PARAM array is processed after + the key and IV have been established. Any alterations to the key length, + via the "keylen" parameter or the IV length, via the "ivlen" parameter, + within the OSSL_PARAM array will not take effect as intended, potentially + causing truncation or overreading of these values. The following ciphers + and cipher modes are impacted: RC2, RC4, RC5, CCM, GCM and OCB.

    +

    For the CCM, GCM and OCB cipher modes, truncation of the IV can result in + loss of confidentiality. For example, when following NIST's SP 800-38D + section 8.2.1 guidance for constructing a deterministic IV for AES in + GCM mode, truncation of the counter portion could lead to IV reuse.

    +

    Both truncations and overruns of the key and overruns of the IV will + produce incorrect results and could, in some cases, trigger a memory + exception. However, these issues are not currently assessed as security + critical.

    +

    Changing the key and/or IV lengths is not considered to be a common operation + and the vulnerable API was recently introduced. Furthermore it is likely that + application developers will have spotted this problem during testing since + decryption would fail unless both peers in the communication were similarly + vulnerable. For these reasons we expect the probability of an application being + vulnerable to this to be quite low. However if an application is vulnerable then + this issue is considered very serious. For these reasons we have assessed this + issue as Moderate severity overall.

    +

    The OpenSSL SSL/TLS implementation is not affected by this issue.

    +

    The OpenSSL 3.0 and 3.1 FIPS providers are not affected by this because + the issue lies outside of the FIPS provider boundary.

    +

    OpenSSL 3.1 and 3.0 are vulnerable to this issue.

    +

    Remediation

    +

    Upgrade Alpine:3.18 openssl to version 3.1.4-r0 or higher.

    +

    References

    + + +
    + + + +
    +
    +
    +
    + + + diff --git a/docs/user-guide/annotations-and-labels.md b/docs/user-guide/annotations-and-labels.md index 4e3a997b393d4..032824c8708f3 100644 --- a/docs/user-guide/annotations-and-labels.md +++ b/docs/user-guide/annotations-and-labels.md @@ -20,7 +20,7 @@ ## Labels -| Label key | Target resource(es) | Possible values | Description | -|--------------------------------|---------------------|---------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------| -| argocd.argoproj.io/instance | Application | any | Recommended tracking label to [avoid conflicts with other tools which use `app.kubernetes.io/instance`](../faq.md#why-is-my-app-out-of-sync-even-after-syncing. | -| argocd.argoproj.io/secret-type | Secret | `cluster`, `repository`, `repo-creds` | Identifies certain types of Secrets used by Argo CD. See the [Declarative Setup docs](../operator-manual/declarative-setup.md) for details. | +| Label key | Target resource(es) | Possible values | Description | +|--------------------------------|---------------------|---------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| argocd.argoproj.io/instance | Application | any | Recommended tracking label to [avoid conflicts with other tools which use `app.kubernetes.io/instance`](../faq.md#why-is-my-app-out-of-sync-even-after-syncing). | +| argocd.argoproj.io/secret-type | Secret | `cluster`, `repository`, `repo-creds` | Identifies certain types of Secrets used by Argo CD. See the [Declarative Setup docs](../operator-manual/declarative-setup.md) for details. | diff --git a/docs/user-guide/best_practices.md b/docs/user-guide/best_practices.md index 2326cce9a430e..718ab022f3e50 100644 --- a/docs/user-guide/best_practices.md +++ b/docs/user-guide/best_practices.md @@ -2,7 +2,7 @@ ## Separating Config Vs. Source Code Repositories -Using a separate Git repository to hold your kubernetes manifests, keeping the config separate +Using a separate Git repository to hold your Kubernetes manifests, keeping the config separate from your application source code, is highly recommended for the following reasons: 1. It provides a clean separation of application code vs. application config. There will be times diff --git a/docs/user-guide/ci_automation.md b/docs/user-guide/ci_automation.md index 9aafa385f0461..433483eba7a3f 100644 --- a/docs/user-guide/ci_automation.md +++ b/docs/user-guide/ci_automation.md @@ -18,7 +18,7 @@ docker push mycompany/guestbook:v2.0 ## Update The Local Manifests Using Your Preferred Templating Tool, And Push The Changes To Git !!! tip - The use of a different Git repository to hold your kubernetes manifests (separate from + The use of a different Git repository to hold your Kubernetes manifests (separate from your application source code), is highly recommended. See [best practices](best_practices.md) for further rationale. @@ -43,7 +43,7 @@ useful so that the CLI used in the CI pipeline is always kept in-sync and uses a that is always compatible with the Argo CD API server. ```bash -export ARGOCD_SERVER=argocd.mycompany.com +export ARGOCD_SERVER=argocd.example.com export ARGOCD_AUTH_TOKEN= curl -sSL -o /usr/local/bin/argocd https://${ARGOCD_SERVER}/download/argocd-linux-amd64 argocd app sync guestbook diff --git a/docs/user-guide/commands/argocd_account.md b/docs/user-guide/commands/argocd_account.md index 2d25f8df3225b..88d483ffac68e 100644 --- a/docs/user-guide/commands/argocd_account.md +++ b/docs/user-guide/commands/argocd_account.md @@ -35,6 +35,7 @@ argocd account [flags] --client-key string Path to a client key file for TLS --cluster string The name of the kubeconfig cluster to use --context string The name of the kubeconfig context to use + --disable-compression If true, opt-out of response compression for all requests to the server -h, --help help for account --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure --kubeconfig string Path to a kube config. Only required if out-of-cluster diff --git a/docs/user-guide/commands/argocd_admin.md b/docs/user-guide/commands/argocd_admin.md index 7a3ff2fde6e89..7966e5a3cb9b1 100644 --- a/docs/user-guide/commands/argocd_admin.md +++ b/docs/user-guide/commands/argocd_admin.md @@ -8,6 +8,92 @@ Contains a set of commands useful for Argo CD administrators and requires direct argocd admin [flags] ``` +### Examples + +``` +# List all clusters +$ argocd admin cluster list + +# Add a new cluster +$ argocd admin cluster add my-cluster --name my-cluster --in-cluster-context + +# Remove a cluster +argocd admin cluster remove my-cluster + +# List all projects +$ argocd admin project list + +# Create a new project +$argocd admin project create my-project --src-namespace my-source-namespace --dest-namespace my-dest-namespace + +# Update a project +$ argocd admin project update my-project --src-namespace my-updated-source-namespace --dest-namespace my-updated-dest-namespace + +# Delete a project +$ argocd admin project delete my-project + +# List all settings +$ argocd admin settings list + +# Get the current settings +$ argocd admin settings get + +# Update settings +$ argocd admin settings update --repository.resync --value 15 + +# List all applications +$ argocd admin app list + +# Get application details +$ argocd admin app get my-app + +# Sync an application +$ argocd admin app sync my-app + +# Pause an application +$ argocd admin app pause my-app + +# Resume an application +$ argocd admin app resume my-app + +# List all repositories +$ argocd admin repo list + +# Add a repository +$ argocd admin repo add https://github.com/argoproj/my-repo.git + +# Remove a repository +$ argocd admin repo remove https://github.com/argoproj/my-repo.git + +# Import an application from a YAML file +$ argocd admin app import -f my-app.yaml + +# Export an application to a YAML file +$ argocd admin app export my-app -o my-exported-app.yaml + +# Access the Argo CD web UI +$ argocd admin dashboard + +# List notifications +$ argocd admin notification list + +# Get notification details +$ argocd admin notification get my-notification + +# Create a new notification +$ argocd admin notification create my-notification -f notification-config.yaml + +# Update a notification +$ argocd admin notification update my-notification -f updated-notification-config.yaml + +# Delete a notification +$ argocd admin notification delete my-notification + +# Reset the initial admin password +$ argocd admin initial-password reset + +``` + ### Options ``` diff --git a/docs/user-guide/commands/argocd_admin_app.md b/docs/user-guide/commands/argocd_admin_app.md index 5b2200bf1116f..58e0f50f25846 100644 --- a/docs/user-guide/commands/argocd_admin_app.md +++ b/docs/user-guide/commands/argocd_admin_app.md @@ -8,6 +8,21 @@ Manage applications configuration argocd admin app [flags] ``` +### Examples + +``` + +# Compare results of two reconciliations and print diff +argocd admin app diff-reconcile-results APPNAME [flags] + +# Generate declarative config for an application +argocd admin app generate-spec APPNAME + +# Reconcile all applications and store reconciliation summary in the specified file +argocd admin app get-reconcile-results APPNAME + +``` + ### Options ``` diff --git a/docs/user-guide/commands/argocd_admin_app_get-reconcile-results.md b/docs/user-guide/commands/argocd_admin_app_get-reconcile-results.md index de477064a2ad3..29fa5d54d9388 100644 --- a/docs/user-guide/commands/argocd_admin_app_get-reconcile-results.md +++ b/docs/user-guide/commands/argocd_admin_app_get-reconcile-results.md @@ -19,6 +19,7 @@ argocd admin app get-reconcile-results PATH [flags] --client-key string Path to a client key file for TLS --cluster string The name of the kubeconfig cluster to use --context string The name of the kubeconfig context to use + --disable-compression If true, opt-out of response compression for all requests to the server -h, --help help for get-reconcile-results --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure --kubeconfig string Path to a kube config. Only required if out-of-cluster @@ -31,6 +32,7 @@ argocd admin app get-reconcile-results PATH [flags] --repo-server string Repo server address. --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") --server string The address and port of the Kubernetes API server + --server-side-diff If set to "true" will use server-side diff while comparing resources. Default ("false") --tls-server-name string If provided, this name will be used to validate server certificate. If this is not provided, hostname used to contact the server is used. --token string Bearer token for authentication to the API server --user string The name of the kubeconfig user to use diff --git a/docs/user-guide/commands/argocd_admin_cluster.md b/docs/user-guide/commands/argocd_admin_cluster.md index 1a469c3f818ca..544c0de08959c 100644 --- a/docs/user-guide/commands/argocd_admin_cluster.md +++ b/docs/user-guide/commands/argocd_admin_cluster.md @@ -8,6 +8,20 @@ Manage clusters configuration argocd admin cluster [flags] ``` +### Examples + +``` + +#Generate declarative config for a cluster +argocd admin cluster generate-spec my-cluster -o yaml + +#Generate a kubeconfig for a cluster named "my-cluster" and display it in the console +argocd admin cluster kubeconfig my-cluster + +#Print information namespaces which Argo CD manages in each cluster +argocd admin cluster namespaces my-cluster +``` + ### Options ``` @@ -48,6 +62,6 @@ argocd admin cluster [flags] * [argocd admin cluster generate-spec](argocd_admin_cluster_generate-spec.md) - Generate declarative config for a cluster * [argocd admin cluster kubeconfig](argocd_admin_cluster_kubeconfig.md) - Generates kubeconfig for the specified cluster * [argocd admin cluster namespaces](argocd_admin_cluster_namespaces.md) - Print information namespaces which Argo CD manages in each cluster. -* [argocd admin cluster shards](argocd_admin_cluster_shards.md) - Print information about each controller shard and portion of Kubernetes resources it is responsible for. +* [argocd admin cluster shards](argocd_admin_cluster_shards.md) - Print information about each controller shard and the estimated portion of Kubernetes resources it is responsible for. * [argocd admin cluster stats](argocd_admin_cluster_stats.md) - Prints information cluster statistics and inferred shard number diff --git a/docs/user-guide/commands/argocd_admin_cluster_generate-spec.md b/docs/user-guide/commands/argocd_admin_cluster_generate-spec.md index cc24418b023f8..79f88233fab32 100644 --- a/docs/user-guide/commands/argocd_admin_cluster_generate-spec.md +++ b/docs/user-guide/commands/argocd_admin_cluster_generate-spec.md @@ -13,6 +13,7 @@ argocd admin cluster generate-spec CONTEXT [flags] ``` --annotation stringArray Set metadata annotations (e.g. --annotation key=value) --aws-cluster-name string AWS Cluster name if set then aws cli eks token command will be used to access cluster + --aws-profile string Optional AWS profile. If set then AWS IAM Authenticator uses this profile to perform cluster operations instead of the default AWS credential provider chain. --aws-role-arn string Optional AWS role arn. If set then AWS IAM Authenticator assumes a role to perform cluster operations instead of the default AWS credential provider chain. --bearer-token string Authentication token that should be used to access K8S API server --cluster-endpoint string Cluster endpoint to use. Can be one of the following: 'kubeconfig', 'kube-public', or 'internal'. diff --git a/docs/user-guide/commands/argocd_admin_cluster_kubeconfig.md b/docs/user-guide/commands/argocd_admin_cluster_kubeconfig.md index 3266b7ad1beb1..38f61ce5cd8a2 100644 --- a/docs/user-guide/commands/argocd_admin_cluster_kubeconfig.md +++ b/docs/user-guide/commands/argocd_admin_cluster_kubeconfig.md @@ -8,6 +8,23 @@ Generates kubeconfig for the specified cluster argocd admin cluster kubeconfig CLUSTER_URL OUTPUT_PATH [flags] ``` +### Examples + +``` + +#Generate a kubeconfig for a cluster named "my-cluster" on console +argocd admin cluster kubeconfig my-cluster + +#Listing available kubeconfigs for clusters managed by argocd +argocd admin cluster kubeconfig + +#Removing a specific kubeconfig file +argocd admin cluster kubeconfig my-cluster --delete + +#Generate a Kubeconfig for a Cluster with TLS Verification Disabled +argocd admin cluster kubeconfig https://cluster-api-url:6443 /path/to/output/kubeconfig.yaml --insecure-skip-tls-verify +``` + ### Options ``` @@ -19,6 +36,7 @@ argocd admin cluster kubeconfig CLUSTER_URL OUTPUT_PATH [flags] --client-key string Path to a client key file for TLS --cluster string The name of the kubeconfig cluster to use --context string The name of the kubeconfig context to use + --disable-compression If true, opt-out of response compression for all requests to the server -h, --help help for kubeconfig --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure --kubeconfig string Path to a kube config. Only required if out-of-cluster diff --git a/docs/user-guide/commands/argocd_admin_cluster_namespaces.md b/docs/user-guide/commands/argocd_admin_cluster_namespaces.md index e784f9e66bf72..fee5c7679e159 100644 --- a/docs/user-guide/commands/argocd_admin_cluster_namespaces.md +++ b/docs/user-guide/commands/argocd_admin_cluster_namespaces.md @@ -19,6 +19,7 @@ argocd admin cluster namespaces [flags] --client-key string Path to a client key file for TLS --cluster string The name of the kubeconfig cluster to use --context string The name of the kubeconfig context to use + --disable-compression If true, opt-out of response compression for all requests to the server -h, --help help for namespaces --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure --kubeconfig string Path to a kube config. Only required if out-of-cluster diff --git a/docs/user-guide/commands/argocd_admin_cluster_namespaces_disable-namespaced-mode.md b/docs/user-guide/commands/argocd_admin_cluster_namespaces_disable-namespaced-mode.md index 33eb9c5fc1f90..fcbebd7612337 100644 --- a/docs/user-guide/commands/argocd_admin_cluster_namespaces_disable-namespaced-mode.md +++ b/docs/user-guide/commands/argocd_admin_cluster_namespaces_disable-namespaced-mode.md @@ -19,6 +19,7 @@ argocd admin cluster namespaces disable-namespaced-mode PATTERN [flags] --client-key string Path to a client key file for TLS --cluster string The name of the kubeconfig cluster to use --context string The name of the kubeconfig context to use + --disable-compression If true, opt-out of response compression for all requests to the server --dry-run Print what will be performed (default true) -h, --help help for disable-namespaced-mode --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure diff --git a/docs/user-guide/commands/argocd_admin_cluster_namespaces_enable-namespaced-mode.md b/docs/user-guide/commands/argocd_admin_cluster_namespaces_enable-namespaced-mode.md index 20f94415c5000..762a652d7ab12 100644 --- a/docs/user-guide/commands/argocd_admin_cluster_namespaces_enable-namespaced-mode.md +++ b/docs/user-guide/commands/argocd_admin_cluster_namespaces_enable-namespaced-mode.md @@ -20,6 +20,7 @@ argocd admin cluster namespaces enable-namespaced-mode PATTERN [flags] --cluster string The name of the kubeconfig cluster to use --cluster-resources Indicates if cluster level resources should be managed. --context string The name of the kubeconfig context to use + --disable-compression If true, opt-out of response compression for all requests to the server --dry-run Print what will be performed (default true) -h, --help help for enable-namespaced-mode --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure diff --git a/docs/user-guide/commands/argocd_admin_cluster_shards.md b/docs/user-guide/commands/argocd_admin_cluster_shards.md index 31f3524b3f0e0..48f6138d47b4a 100644 --- a/docs/user-guide/commands/argocd_admin_cluster_shards.md +++ b/docs/user-guide/commands/argocd_admin_cluster_shards.md @@ -2,7 +2,7 @@ ## argocd admin cluster shards -Print information about each controller shard and portion of Kubernetes resources it is responsible for. +Print information about each controller shard and the estimated portion of Kubernetes resources it is responsible for. ``` argocd admin cluster shards [flags] @@ -21,6 +21,7 @@ argocd admin cluster shards [flags] --cluster string The name of the kubeconfig cluster to use --context string The name of the kubeconfig context to use --default-cache-expiration duration Cache expiration default (default 24h0m0s) + --disable-compression If true, opt-out of response compression for all requests to the server -h, --help help for shards --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure --kubeconfig string Path to a kube config. Only required if out-of-cluster @@ -42,6 +43,7 @@ argocd admin cluster shards [flags] --sentinelmaster string Redis sentinel master group name. (default "master") --server string The address and port of the Kubernetes API server --shard int Cluster shard filter (default -1) + --sharding-method string Sharding method. Defaults: legacy. Supported sharding methods are : [legacy, round-robin] (default "legacy") --tls-server-name string If provided, this name will be used to validate server certificate. If this is not provided, hostname used to contact the server is used. --token string Bearer token for authentication to the API server --user string The name of the kubeconfig user to use diff --git a/docs/user-guide/commands/argocd_admin_cluster_stats.md b/docs/user-guide/commands/argocd_admin_cluster_stats.md index 65ae696744c56..c5297ce7e35ed 100644 --- a/docs/user-guide/commands/argocd_admin_cluster_stats.md +++ b/docs/user-guide/commands/argocd_admin_cluster_stats.md @@ -8,6 +8,20 @@ Prints information cluster statistics and inferred shard number argocd admin cluster stats [flags] ``` +### Examples + +``` + +#Display stats and shards for clusters +argocd admin cluster stats + +#Display Cluster Statistics for a Specific Shard +argocd admin cluster stats --shard=1 + +#In a multi-cluster environment to print stats for a specific cluster say(target-cluster) +argocd admin cluster stats target-cluster +``` + ### Options ``` @@ -21,6 +35,7 @@ argocd admin cluster stats [flags] --cluster string The name of the kubeconfig cluster to use --context string The name of the kubeconfig context to use --default-cache-expiration duration Cache expiration default (default 24h0m0s) + --disable-compression If true, opt-out of response compression for all requests to the server -h, --help help for stats --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure --kubeconfig string Path to a kube config. Only required if out-of-cluster @@ -42,6 +57,7 @@ argocd admin cluster stats [flags] --sentinelmaster string Redis sentinel master group name. (default "master") --server string The address and port of the Kubernetes API server --shard int Cluster shard filter (default -1) + --sharding-method string Sharding method. Defaults: legacy. Supported sharding methods are : [legacy, round-robin] (default "legacy") --tls-server-name string If provided, this name will be used to validate server certificate. If this is not provided, hostname used to contact the server is used. --token string Bearer token for authentication to the API server --user string The name of the kubeconfig user to use diff --git a/docs/user-guide/commands/argocd_admin_dashboard.md b/docs/user-guide/commands/argocd_admin_dashboard.md index f3336df30e0d4..71e11a173906a 100644 --- a/docs/user-guide/commands/argocd_admin_dashboard.md +++ b/docs/user-guide/commands/argocd_admin_dashboard.md @@ -8,6 +8,20 @@ Starts Argo CD Web UI locally argocd admin dashboard [flags] ``` +### Examples + +``` +# Start the Argo CD Web UI locally on the default port and address +$ argocd admin dashboard + +# Start the Argo CD Web UI locally on a custom port and address +$ argocd admin dashboard --port 8080 --address 127.0.0.1 + +# Start the Argo CD Web UI with GZip compression +$ argocd admin dashboard --redis-compress gzip + +``` + ### Options ``` @@ -20,6 +34,7 @@ argocd admin dashboard [flags] --client-key string Path to a client key file for TLS --cluster string The name of the kubeconfig cluster to use --context string The name of the kubeconfig context to use + --disable-compression If true, opt-out of response compression for all requests to the server -h, --help help for dashboard --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure --kubeconfig string Path to a kube config. Only required if out-of-cluster @@ -29,6 +44,7 @@ argocd admin dashboard [flags] --proxy-url string If provided, this URL will be used to connect via proxy --redis-compress string Enable this if the application controller is configured with redis compression enabled. (possible values: gzip, none) (default "gzip") --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") + --server string The address and port of the Kubernetes API server --tls-server-name string If provided, this name will be used to validate server certificate. If this is not provided, hostname used to contact the server is used. --token string Bearer token for authentication to the API server --user string The name of the kubeconfig user to use @@ -58,7 +74,6 @@ argocd admin dashboard [flags] --redis-haproxy-name string Name of the Redis HA Proxy; set this or the ARGOCD_REDIS_HAPROXY_NAME environment variable when the HA Proxy's name label differs from the default, for example when installing via the Helm chart (default "argocd-redis-ha-haproxy") --redis-name string Name of the Redis deployment; set this or the ARGOCD_REDIS_NAME environment variable when the Redis's name label differs from the default, for example when installing via the Helm chart (default "argocd-redis") --repo-server-name string Name of the Argo CD Repo server; set this or the ARGOCD_REPO_SERVER_NAME environment variable when the server's name label differs from the default, for example when installing via the Helm chart (default "argocd-repo-server") - --server string Argo CD server address --server-crt string Server certificate file --server-name string Name of the Argo CD API server; set this or the ARGOCD_SERVER_NAME environment variable when the server's name label differs from the default, for example when installing via the Helm chart (default "argocd-server") ``` diff --git a/docs/user-guide/commands/argocd_admin_export.md b/docs/user-guide/commands/argocd_admin_export.md index f609439979ad3..d168fe5450a74 100644 --- a/docs/user-guide/commands/argocd_admin_export.md +++ b/docs/user-guide/commands/argocd_admin_export.md @@ -19,6 +19,7 @@ argocd admin export [flags] --client-key string Path to a client key file for TLS --cluster string The name of the kubeconfig cluster to use --context string The name of the kubeconfig context to use + --disable-compression If true, opt-out of response compression for all requests to the server -h, --help help for export --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure --kubeconfig string Path to a kube config. Only required if out-of-cluster diff --git a/docs/user-guide/commands/argocd_admin_import.md b/docs/user-guide/commands/argocd_admin_import.md index 834f72396effa..dc8a4b2dbf947 100644 --- a/docs/user-guide/commands/argocd_admin_import.md +++ b/docs/user-guide/commands/argocd_admin_import.md @@ -19,6 +19,7 @@ argocd admin import SOURCE [flags] --client-key string Path to a client key file for TLS --cluster string The name of the kubeconfig cluster to use --context string The name of the kubeconfig context to use + --disable-compression If true, opt-out of response compression for all requests to the server --dry-run Print what will be performed -h, --help help for import --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure diff --git a/docs/user-guide/commands/argocd_admin_initial-password.md b/docs/user-guide/commands/argocd_admin_initial-password.md index fc61e7f722213..dbc44561debdc 100644 --- a/docs/user-guide/commands/argocd_admin_initial-password.md +++ b/docs/user-guide/commands/argocd_admin_initial-password.md @@ -19,6 +19,7 @@ argocd admin initial-password [flags] --client-key string Path to a client key file for TLS --cluster string The name of the kubeconfig cluster to use --context string The name of the kubeconfig context to use + --disable-compression If true, opt-out of response compression for all requests to the server -h, --help help for initial-password --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure --kubeconfig string Path to a kube config. Only required if out-of-cluster diff --git a/docs/user-guide/commands/argocd_admin_notifications.md b/docs/user-guide/commands/argocd_admin_notifications.md index 779832d0a1b47..87429217f99e9 100644 --- a/docs/user-guide/commands/argocd_admin_notifications.md +++ b/docs/user-guide/commands/argocd_admin_notifications.md @@ -23,6 +23,7 @@ argocd admin notifications [flags] --cluster string The name of the kubeconfig cluster to use --config-map string argocd-notifications-cm.yaml file path --context string The name of the kubeconfig context to use + --disable-compression If true, opt-out of response compression for all requests to the server -h, --help help for notifications --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure --kubeconfig string Path to a kube config. Only required if out-of-cluster diff --git a/docs/user-guide/commands/argocd_admin_notifications_template.md b/docs/user-guide/commands/argocd_admin_notifications_template.md index f3519e631af25..75d5700aaac04 100644 --- a/docs/user-guide/commands/argocd_admin_notifications_template.md +++ b/docs/user-guide/commands/argocd_admin_notifications_template.md @@ -35,6 +35,7 @@ argocd admin notifications template [flags] --context string The name of the kubeconfig context to use --controller-name string Name of the Argo CD Application controller; set this or the ARGOCD_APPLICATION_CONTROLLER_NAME environment variable when the controller's name label differs from the default, for example when installing via the Helm chart (default "argocd-application-controller") --core If set to true then CLI talks directly to Kubernetes instead of talking to Argo CD API server + --disable-compression If true, opt-out of response compression for all requests to the server --grpc-web Enables gRPC-web protocol. Useful if Argo CD server is behind proxy which does not support HTTP2. --grpc-web-root-path string Enables gRPC-web protocol. Useful if Argo CD server is behind proxy which does not support HTTP2. Set web root. -H, --header strings Sets additional header to all requests made by Argo CD CLI. (Can be repeated multiple times to add multiple headers, also supports comma separated headers) diff --git a/docs/user-guide/commands/argocd_admin_notifications_template_get.md b/docs/user-guide/commands/argocd_admin_notifications_template_get.md index 432e0b6b1c5d7..214a8e5cd442b 100644 --- a/docs/user-guide/commands/argocd_admin_notifications_template_get.md +++ b/docs/user-guide/commands/argocd_admin_notifications_template_get.md @@ -47,6 +47,7 @@ argocd admin notifications template get app-sync-succeeded -o=yaml --context string The name of the kubeconfig context to use --controller-name string Name of the Argo CD Application controller; set this or the ARGOCD_APPLICATION_CONTROLLER_NAME environment variable when the controller's name label differs from the default, for example when installing via the Helm chart (default "argocd-application-controller") --core If set to true then CLI talks directly to Kubernetes instead of talking to Argo CD API server + --disable-compression If true, opt-out of response compression for all requests to the server --grpc-web Enables gRPC-web protocol. Useful if Argo CD server is behind proxy which does not support HTTP2. --grpc-web-root-path string Enables gRPC-web protocol. Useful if Argo CD server is behind proxy which does not support HTTP2. Set web root. -H, --header strings Sets additional header to all requests made by Argo CD CLI. (Can be repeated multiple times to add multiple headers, also supports comma separated headers) diff --git a/docs/user-guide/commands/argocd_admin_notifications_template_notify.md b/docs/user-guide/commands/argocd_admin_notifications_template_notify.md index a26b70dd80d70..4f94a9d960476 100644 --- a/docs/user-guide/commands/argocd_admin_notifications_template_notify.md +++ b/docs/user-guide/commands/argocd_admin_notifications_template_notify.md @@ -48,6 +48,7 @@ argocd admin notifications template notify app-sync-succeeded guestbook --context string The name of the kubeconfig context to use --controller-name string Name of the Argo CD Application controller; set this or the ARGOCD_APPLICATION_CONTROLLER_NAME environment variable when the controller's name label differs from the default, for example when installing via the Helm chart (default "argocd-application-controller") --core If set to true then CLI talks directly to Kubernetes instead of talking to Argo CD API server + --disable-compression If true, opt-out of response compression for all requests to the server --grpc-web Enables gRPC-web protocol. Useful if Argo CD server is behind proxy which does not support HTTP2. --grpc-web-root-path string Enables gRPC-web protocol. Useful if Argo CD server is behind proxy which does not support HTTP2. Set web root. -H, --header strings Sets additional header to all requests made by Argo CD CLI. (Can be repeated multiple times to add multiple headers, also supports comma separated headers) diff --git a/docs/user-guide/commands/argocd_admin_notifications_trigger.md b/docs/user-guide/commands/argocd_admin_notifications_trigger.md index 6e15faa0dcd92..d6ff9e53ab235 100644 --- a/docs/user-guide/commands/argocd_admin_notifications_trigger.md +++ b/docs/user-guide/commands/argocd_admin_notifications_trigger.md @@ -35,6 +35,7 @@ argocd admin notifications trigger [flags] --context string The name of the kubeconfig context to use --controller-name string Name of the Argo CD Application controller; set this or the ARGOCD_APPLICATION_CONTROLLER_NAME environment variable when the controller's name label differs from the default, for example when installing via the Helm chart (default "argocd-application-controller") --core If set to true then CLI talks directly to Kubernetes instead of talking to Argo CD API server + --disable-compression If true, opt-out of response compression for all requests to the server --grpc-web Enables gRPC-web protocol. Useful if Argo CD server is behind proxy which does not support HTTP2. --grpc-web-root-path string Enables gRPC-web protocol. Useful if Argo CD server is behind proxy which does not support HTTP2. Set web root. -H, --header strings Sets additional header to all requests made by Argo CD CLI. (Can be repeated multiple times to add multiple headers, also supports comma separated headers) diff --git a/docs/user-guide/commands/argocd_admin_notifications_trigger_get.md b/docs/user-guide/commands/argocd_admin_notifications_trigger_get.md index 2a23ea1c1ec01..acd2ab5af9553 100644 --- a/docs/user-guide/commands/argocd_admin_notifications_trigger_get.md +++ b/docs/user-guide/commands/argocd_admin_notifications_trigger_get.md @@ -47,6 +47,7 @@ argocd admin notifications trigger get on-sync-failed -o=yaml --context string The name of the kubeconfig context to use --controller-name string Name of the Argo CD Application controller; set this or the ARGOCD_APPLICATION_CONTROLLER_NAME environment variable when the controller's name label differs from the default, for example when installing via the Helm chart (default "argocd-application-controller") --core If set to true then CLI talks directly to Kubernetes instead of talking to Argo CD API server + --disable-compression If true, opt-out of response compression for all requests to the server --grpc-web Enables gRPC-web protocol. Useful if Argo CD server is behind proxy which does not support HTTP2. --grpc-web-root-path string Enables gRPC-web protocol. Useful if Argo CD server is behind proxy which does not support HTTP2. Set web root. -H, --header strings Sets additional header to all requests made by Argo CD CLI. (Can be repeated multiple times to add multiple headers, also supports comma separated headers) diff --git a/docs/user-guide/commands/argocd_admin_notifications_trigger_run.md b/docs/user-guide/commands/argocd_admin_notifications_trigger_run.md index 4caf2d389b009..f8bebb2937937 100644 --- a/docs/user-guide/commands/argocd_admin_notifications_trigger_run.md +++ b/docs/user-guide/commands/argocd_admin_notifications_trigger_run.md @@ -47,6 +47,7 @@ argocd admin notifications trigger run on-sync-status-unknown ./sample-app.yaml --context string The name of the kubeconfig context to use --controller-name string Name of the Argo CD Application controller; set this or the ARGOCD_APPLICATION_CONTROLLER_NAME environment variable when the controller's name label differs from the default, for example when installing via the Helm chart (default "argocd-application-controller") --core If set to true then CLI talks directly to Kubernetes instead of talking to Argo CD API server + --disable-compression If true, opt-out of response compression for all requests to the server --grpc-web Enables gRPC-web protocol. Useful if Argo CD server is behind proxy which does not support HTTP2. --grpc-web-root-path string Enables gRPC-web protocol. Useful if Argo CD server is behind proxy which does not support HTTP2. Set web root. -H, --header strings Sets additional header to all requests made by Argo CD CLI. (Can be repeated multiple times to add multiple headers, also supports comma separated headers) diff --git a/docs/user-guide/commands/argocd_admin_proj_generate-allow-list.md b/docs/user-guide/commands/argocd_admin_proj_generate-allow-list.md index 81cb5c7cbf1f4..83dc00a6096b4 100644 --- a/docs/user-guide/commands/argocd_admin_proj_generate-allow-list.md +++ b/docs/user-guide/commands/argocd_admin_proj_generate-allow-list.md @@ -8,6 +8,13 @@ Generates project allow list from the specified clusterRole file argocd admin proj generate-allow-list CLUSTERROLE_PATH PROJ_NAME [flags] ``` +### Examples + +``` +# Generates project allow list from the specified clusterRole file +argocd admin proj generate-allow-list /path/to/clusterrole.yaml my-project +``` + ### Options ``` @@ -19,6 +26,7 @@ argocd admin proj generate-allow-list CLUSTERROLE_PATH PROJ_NAME [flags] --client-key string Path to a client key file for TLS --cluster string The name of the kubeconfig cluster to use --context string The name of the kubeconfig context to use + --disable-compression If true, opt-out of response compression for all requests to the server -h, --help help for generate-allow-list --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure --kubeconfig string Path to a kube config. Only required if out-of-cluster diff --git a/docs/user-guide/commands/argocd_admin_proj_update-role-policy.md b/docs/user-guide/commands/argocd_admin_proj_update-role-policy.md index cc3a3e6320ef5..c1c4823077e01 100644 --- a/docs/user-guide/commands/argocd_admin_proj_update-role-policy.md +++ b/docs/user-guide/commands/argocd_admin_proj_update-role-policy.md @@ -30,6 +30,7 @@ argocd admin proj update-role-policy PROJECT_GLOB MODIFICATION ACTION [flags] --client-key string Path to a client key file for TLS --cluster string The name of the kubeconfig cluster to use --context string The name of the kubeconfig context to use + --disable-compression If true, opt-out of response compression for all requests to the server --dry-run Dry run (default true) -h, --help help for update-role-policy --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure diff --git a/docs/user-guide/commands/argocd_admin_settings.md b/docs/user-guide/commands/argocd_admin_settings.md index 5687a473f9fa7..3c631cf8f123b 100644 --- a/docs/user-guide/commands/argocd_admin_settings.md +++ b/docs/user-guide/commands/argocd_admin_settings.md @@ -21,6 +21,7 @@ argocd admin settings [flags] --client-key string Path to a client key file for TLS --cluster string The name of the kubeconfig cluster to use --context string The name of the kubeconfig context to use + --disable-compression If true, opt-out of response compression for all requests to the server -h, --help help for settings --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure --kubeconfig string Path to a kube config. Only required if out-of-cluster diff --git a/docs/user-guide/commands/argocd_admin_settings_rbac.md b/docs/user-guide/commands/argocd_admin_settings_rbac.md index fabdee7171051..043c39979a98a 100644 --- a/docs/user-guide/commands/argocd_admin_settings_rbac.md +++ b/docs/user-guide/commands/argocd_admin_settings_rbac.md @@ -33,6 +33,7 @@ argocd admin settings rbac [flags] --context string The name of the kubeconfig context to use --controller-name string Name of the Argo CD Application controller; set this or the ARGOCD_APPLICATION_CONTROLLER_NAME environment variable when the controller's name label differs from the default, for example when installing via the Helm chart (default "argocd-application-controller") --core If set to true then CLI talks directly to Kubernetes instead of talking to Argo CD API server + --disable-compression If true, opt-out of response compression for all requests to the server --grpc-web Enables gRPC-web protocol. Useful if Argo CD server is behind proxy which does not support HTTP2. --grpc-web-root-path string Enables gRPC-web protocol. Useful if Argo CD server is behind proxy which does not support HTTP2. Set web root. -H, --header strings Sets additional header to all requests made by Argo CD CLI. (Can be repeated multiple times to add multiple headers, also supports comma separated headers) diff --git a/docs/user-guide/commands/argocd_admin_settings_rbac_can.md b/docs/user-guide/commands/argocd_admin_settings_rbac_can.md index 2aafc6bd07cf7..f14092785facf 100644 --- a/docs/user-guide/commands/argocd_admin_settings_rbac_can.md +++ b/docs/user-guide/commands/argocd_admin_settings_rbac_can.md @@ -50,6 +50,7 @@ argocd admin settings rbac can someuser create application 'default/app' --defau --cluster string The name of the kubeconfig cluster to use --context string The name of the kubeconfig context to use --default-role string name of the default role to use + --disable-compression If true, opt-out of response compression for all requests to the server -h, --help help for can --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure --kubeconfig string Path to a kube config. Only required if out-of-cluster diff --git a/docs/user-guide/commands/argocd_admin_settings_rbac_validate.md b/docs/user-guide/commands/argocd_admin_settings_rbac_validate.md index 9ad6ec2bc4c37..b051c7c63694b 100644 --- a/docs/user-guide/commands/argocd_admin_settings_rbac_validate.md +++ b/docs/user-guide/commands/argocd_admin_settings_rbac_validate.md @@ -8,18 +8,57 @@ Validate RBAC policy Validates an RBAC policy for being syntactically correct. The policy must be -a local file, and in either CSV or K8s ConfigMap format. +a local file or a K8s ConfigMap in the provided namespace, and in either CSV or K8s ConfigMap format. ``` -argocd admin settings rbac validate --policy-file=POLICYFILE [flags] +argocd admin settings rbac validate [--policy-file POLICYFILE] [--namespace NAMESPACE] [flags] +``` + +### Examples + +``` + +# Check whether a given policy file is valid using a local policy.csv file. +argocd admin settings rbac validate --policy-file policy.csv + +# Policy file can also be K8s config map with data keys like argocd-rbac-cm, +# i.e. 'policy.csv' and (optionally) 'policy.default' +argocd admin settings rbac validate --policy-file argocd-rbac-cm.yaml + +# If --policy-file is not given, and instead --namespace is giventhe ConfigMap 'argocd-rbac-cm' +# from K8s is used. +argocd admin settings rbac validate --namespace argocd + +# Either --policy-file or --namespace must be given. + ``` ### Options ``` - -h, --help help for validate - --policy-file string path to the policy file to use + --as string Username to impersonate for the operation + --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. + --as-uid string UID to impersonate for the operation + --certificate-authority string Path to a cert file for the certificate authority + --client-certificate string Path to a client certificate file for TLS + --client-key string Path to a client key file for TLS + --cluster string The name of the kubeconfig cluster to use + --context string The name of the kubeconfig context to use + --disable-compression If true, opt-out of response compression for all requests to the server + -h, --help help for validate + --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure + --kubeconfig string Path to a kube config. Only required if out-of-cluster + --namespace string namespace to get argo rbac configmap from + --password string Password for basic authentication to the API server + --policy-file string path to the policy file to use + --proxy-url string If provided, this URL will be used to connect via proxy + --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") + --server string The address and port of the Kubernetes API server + --tls-server-name string If provided, this name will be used to validate server certificate. If this is not provided, hostname used to contact the server is used. + --token string Bearer token for authentication to the API server + --user string The name of the kubeconfig user to use + --username string Username for basic authentication to the API server ``` ### Options inherited from parent commands @@ -27,18 +66,10 @@ argocd admin settings rbac validate --policy-file=POLICYFILE [flags] ``` --argocd-cm-path string Path to local argocd-cm.yaml file --argocd-secret-path string Path to local argocd-secret.yaml file - --as string Username to impersonate for the operation - --as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups. - --as-uid string UID to impersonate for the operation --auth-token string Authentication token - --certificate-authority string Path to a cert file for the certificate authority - --client-certificate string Path to a client certificate file for TLS --client-crt string Client certificate file --client-crt-key string Client certificate key file - --client-key string Path to a client key file for TLS - --cluster string The name of the kubeconfig cluster to use --config string Path to Argo CD config (default "/home/user/.config/argocd/config") - --context string The name of the kubeconfig context to use --controller-name string Name of the Argo CD Application controller; set this or the ARGOCD_APPLICATION_CONTROLLER_NAME environment variable when the controller's name label differs from the default, for example when installing via the Helm chart (default "argocd-application-controller") --core If set to true then CLI talks directly to Kubernetes instead of talking to Argo CD API server --grpc-web Enables gRPC-web protocol. Useful if Argo CD server is behind proxy which does not support HTTP2. @@ -46,29 +77,18 @@ argocd admin settings rbac validate --policy-file=POLICYFILE [flags] -H, --header strings Sets additional header to all requests made by Argo CD CLI. (Can be repeated multiple times to add multiple headers, also supports comma separated headers) --http-retry-max int Maximum number of retries to establish http connection to Argo CD server --insecure Skip server certificate and domain verification - --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure --kube-context string Directs the command to the given kube-context - --kubeconfig string Path to a kube config. Only required if out-of-cluster --load-cluster-settings Indicates that config map and secret should be loaded from cluster unless local file path is provided --logformat string Set the logging format. One of: text|json (default "text") --loglevel string Set the logging level. One of: debug|info|warn|error (default "info") - -n, --namespace string If present, the namespace scope for this CLI request - --password string Password for basic authentication to the API server --plaintext Disable TLS --port-forward Connect to a random argocd-server port using port forwarding --port-forward-namespace string Namespace name which should be used for port forwarding - --proxy-url string If provided, this URL will be used to connect via proxy --redis-haproxy-name string Name of the Redis HA Proxy; set this or the ARGOCD_REDIS_HAPROXY_NAME environment variable when the HA Proxy's name label differs from the default, for example when installing via the Helm chart (default "argocd-redis-ha-haproxy") --redis-name string Name of the Redis deployment; set this or the ARGOCD_REDIS_NAME environment variable when the Redis's name label differs from the default, for example when installing via the Helm chart (default "argocd-redis") --repo-server-name string Name of the Argo CD Repo server; set this or the ARGOCD_REPO_SERVER_NAME environment variable when the server's name label differs from the default, for example when installing via the Helm chart (default "argocd-repo-server") - --request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0") - --server string The address and port of the Kubernetes API server --server-crt string Server certificate file --server-name string Name of the Argo CD API server; set this or the ARGOCD_SERVER_NAME environment variable when the server's name label differs from the default, for example when installing via the Helm chart (default "argocd-server") - --tls-server-name string If provided, this name will be used to validate server certificate. If this is not provided, hostname used to contact the server is used. - --token string Bearer token for authentication to the API server - --user string The name of the kubeconfig user to use - --username string Username for basic authentication to the API server ``` ### SEE ALSO diff --git a/docs/user-guide/commands/argocd_admin_settings_resource-overrides.md b/docs/user-guide/commands/argocd_admin_settings_resource-overrides.md index 1191f8cd0be9e..eeec6bcf5f63a 100644 --- a/docs/user-guide/commands/argocd_admin_settings_resource-overrides.md +++ b/docs/user-guide/commands/argocd_admin_settings_resource-overrides.md @@ -33,6 +33,7 @@ argocd admin settings resource-overrides [flags] --context string The name of the kubeconfig context to use --controller-name string Name of the Argo CD Application controller; set this or the ARGOCD_APPLICATION_CONTROLLER_NAME environment variable when the controller's name label differs from the default, for example when installing via the Helm chart (default "argocd-application-controller") --core If set to true then CLI talks directly to Kubernetes instead of talking to Argo CD API server + --disable-compression If true, opt-out of response compression for all requests to the server --grpc-web Enables gRPC-web protocol. Useful if Argo CD server is behind proxy which does not support HTTP2. --grpc-web-root-path string Enables gRPC-web protocol. Useful if Argo CD server is behind proxy which does not support HTTP2. Set web root. -H, --header strings Sets additional header to all requests made by Argo CD CLI. (Can be repeated multiple times to add multiple headers, also supports comma separated headers) diff --git a/docs/user-guide/commands/argocd_admin_settings_resource-overrides_health.md b/docs/user-guide/commands/argocd_admin_settings_resource-overrides_health.md index d240f57a81294..1e5cc49335cc5 100644 --- a/docs/user-guide/commands/argocd_admin_settings_resource-overrides_health.md +++ b/docs/user-guide/commands/argocd_admin_settings_resource-overrides_health.md @@ -44,6 +44,7 @@ argocd admin settings resource-overrides health ./deploy.yaml --argocd-cm-path . --context string The name of the kubeconfig context to use --controller-name string Name of the Argo CD Application controller; set this or the ARGOCD_APPLICATION_CONTROLLER_NAME environment variable when the controller's name label differs from the default, for example when installing via the Helm chart (default "argocd-application-controller") --core If set to true then CLI talks directly to Kubernetes instead of talking to Argo CD API server + --disable-compression If true, opt-out of response compression for all requests to the server --grpc-web Enables gRPC-web protocol. Useful if Argo CD server is behind proxy which does not support HTTP2. --grpc-web-root-path string Enables gRPC-web protocol. Useful if Argo CD server is behind proxy which does not support HTTP2. Set web root. -H, --header strings Sets additional header to all requests made by Argo CD CLI. (Can be repeated multiple times to add multiple headers, also supports comma separated headers) diff --git a/docs/user-guide/commands/argocd_admin_settings_resource-overrides_ignore-differences.md b/docs/user-guide/commands/argocd_admin_settings_resource-overrides_ignore-differences.md index adc9451de05da..752b3a64c59c7 100644 --- a/docs/user-guide/commands/argocd_admin_settings_resource-overrides_ignore-differences.md +++ b/docs/user-guide/commands/argocd_admin_settings_resource-overrides_ignore-differences.md @@ -44,6 +44,7 @@ argocd admin settings resource-overrides ignore-differences ./deploy.yaml --argo --context string The name of the kubeconfig context to use --controller-name string Name of the Argo CD Application controller; set this or the ARGOCD_APPLICATION_CONTROLLER_NAME environment variable when the controller's name label differs from the default, for example when installing via the Helm chart (default "argocd-application-controller") --core If set to true then CLI talks directly to Kubernetes instead of talking to Argo CD API server + --disable-compression If true, opt-out of response compression for all requests to the server --grpc-web Enables gRPC-web protocol. Useful if Argo CD server is behind proxy which does not support HTTP2. --grpc-web-root-path string Enables gRPC-web protocol. Useful if Argo CD server is behind proxy which does not support HTTP2. Set web root. -H, --header strings Sets additional header to all requests made by Argo CD CLI. (Can be repeated multiple times to add multiple headers, also supports comma separated headers) diff --git a/docs/user-guide/commands/argocd_admin_settings_resource-overrides_ignore-resource-updates.md b/docs/user-guide/commands/argocd_admin_settings_resource-overrides_ignore-resource-updates.md index f520c56fba20d..69f09208cf42f 100644 --- a/docs/user-guide/commands/argocd_admin_settings_resource-overrides_ignore-resource-updates.md +++ b/docs/user-guide/commands/argocd_admin_settings_resource-overrides_ignore-resource-updates.md @@ -44,6 +44,7 @@ argocd admin settings resource-overrides ignore-resource-updates ./deploy.yaml - --context string The name of the kubeconfig context to use --controller-name string Name of the Argo CD Application controller; set this or the ARGOCD_APPLICATION_CONTROLLER_NAME environment variable when the controller's name label differs from the default, for example when installing via the Helm chart (default "argocd-application-controller") --core If set to true then CLI talks directly to Kubernetes instead of talking to Argo CD API server + --disable-compression If true, opt-out of response compression for all requests to the server --grpc-web Enables gRPC-web protocol. Useful if Argo CD server is behind proxy which does not support HTTP2. --grpc-web-root-path string Enables gRPC-web protocol. Useful if Argo CD server is behind proxy which does not support HTTP2. Set web root. -H, --header strings Sets additional header to all requests made by Argo CD CLI. (Can be repeated multiple times to add multiple headers, also supports comma separated headers) diff --git a/docs/user-guide/commands/argocd_admin_settings_resource-overrides_list-actions.md b/docs/user-guide/commands/argocd_admin_settings_resource-overrides_list-actions.md index 342339af2fc9d..57f60f3d726f5 100644 --- a/docs/user-guide/commands/argocd_admin_settings_resource-overrides_list-actions.md +++ b/docs/user-guide/commands/argocd_admin_settings_resource-overrides_list-actions.md @@ -44,6 +44,7 @@ argocd admin settings resource-overrides action list /tmp/deploy.yaml --argocd-c --context string The name of the kubeconfig context to use --controller-name string Name of the Argo CD Application controller; set this or the ARGOCD_APPLICATION_CONTROLLER_NAME environment variable when the controller's name label differs from the default, for example when installing via the Helm chart (default "argocd-application-controller") --core If set to true then CLI talks directly to Kubernetes instead of talking to Argo CD API server + --disable-compression If true, opt-out of response compression for all requests to the server --grpc-web Enables gRPC-web protocol. Useful if Argo CD server is behind proxy which does not support HTTP2. --grpc-web-root-path string Enables gRPC-web protocol. Useful if Argo CD server is behind proxy which does not support HTTP2. Set web root. -H, --header strings Sets additional header to all requests made by Argo CD CLI. (Can be repeated multiple times to add multiple headers, also supports comma separated headers) diff --git a/docs/user-guide/commands/argocd_admin_settings_resource-overrides_run-action.md b/docs/user-guide/commands/argocd_admin_settings_resource-overrides_run-action.md index 7ebc5d0873a78..f7ce62d4559fe 100644 --- a/docs/user-guide/commands/argocd_admin_settings_resource-overrides_run-action.md +++ b/docs/user-guide/commands/argocd_admin_settings_resource-overrides_run-action.md @@ -44,6 +44,7 @@ argocd admin settings resource-overrides action run /tmp/deploy.yaml restart --a --context string The name of the kubeconfig context to use --controller-name string Name of the Argo CD Application controller; set this or the ARGOCD_APPLICATION_CONTROLLER_NAME environment variable when the controller's name label differs from the default, for example when installing via the Helm chart (default "argocd-application-controller") --core If set to true then CLI talks directly to Kubernetes instead of talking to Argo CD API server + --disable-compression If true, opt-out of response compression for all requests to the server --grpc-web Enables gRPC-web protocol. Useful if Argo CD server is behind proxy which does not support HTTP2. --grpc-web-root-path string Enables gRPC-web protocol. Useful if Argo CD server is behind proxy which does not support HTTP2. Set web root. -H, --header strings Sets additional header to all requests made by Argo CD CLI. (Can be repeated multiple times to add multiple headers, also supports comma separated headers) diff --git a/docs/user-guide/commands/argocd_admin_settings_validate.md b/docs/user-guide/commands/argocd_admin_settings_validate.md index dd66ef2fec386..8e40a403441b5 100644 --- a/docs/user-guide/commands/argocd_admin_settings_validate.md +++ b/docs/user-guide/commands/argocd_admin_settings_validate.md @@ -49,6 +49,7 @@ argocd admin settings validate --group accounts --group plugins --load-cluster-s --context string The name of the kubeconfig context to use --controller-name string Name of the Argo CD Application controller; set this or the ARGOCD_APPLICATION_CONTROLLER_NAME environment variable when the controller's name label differs from the default, for example when installing via the Helm chart (default "argocd-application-controller") --core If set to true then CLI talks directly to Kubernetes instead of talking to Argo CD API server + --disable-compression If true, opt-out of response compression for all requests to the server --grpc-web Enables gRPC-web protocol. Useful if Argo CD server is behind proxy which does not support HTTP2. --grpc-web-root-path string Enables gRPC-web protocol. Useful if Argo CD server is behind proxy which does not support HTTP2. Set web root. -H, --header strings Sets additional header to all requests made by Argo CD CLI. (Can be repeated multiple times to add multiple headers, also supports comma separated headers) diff --git a/docs/user-guide/commands/argocd_app.md b/docs/user-guide/commands/argocd_app.md index f4a057ea70c1a..543fcd96035ec 100644 --- a/docs/user-guide/commands/argocd_app.md +++ b/docs/user-guide/commands/argocd_app.md @@ -32,6 +32,7 @@ argocd app [flags] --client-key string Path to a client key file for TLS --cluster string The name of the kubeconfig cluster to use --context string The name of the kubeconfig context to use + --disable-compression If true, opt-out of response compression for all requests to the server -h, --help help for app --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure --kubeconfig string Path to a kube config. Only required if out-of-cluster diff --git a/docs/user-guide/commands/argocd_app_delete-resource.md b/docs/user-guide/commands/argocd_app_delete-resource.md index f65873227473a..4a305eb4b4489 100644 --- a/docs/user-guide/commands/argocd_app_delete-resource.md +++ b/docs/user-guide/commands/argocd_app_delete-resource.md @@ -18,6 +18,7 @@ argocd app delete-resource APPNAME [flags] --kind string Kind --namespace string Namespace --orphan Indicates whether to force delete the resource + --project string The name of the application's project - specifying this allows the command to report "not found" instead of "permission denied" if the app does not exist --resource-name string Name of resource ``` diff --git a/docs/user-guide/commands/argocd_app_get.md b/docs/user-guide/commands/argocd_app_get.md index 33787d8083f22..cf766ed9eb0d7 100644 --- a/docs/user-guide/commands/argocd_app_get.md +++ b/docs/user-guide/commands/argocd_app_get.md @@ -8,6 +8,37 @@ Get application details argocd app get APPNAME [flags] ``` +### Examples + +``` + # Get basic details about the application "my-app" in wide format + argocd app get my-app -o wide + + # Get detailed information about the application "my-app" in YAML format + argocd app get my-app -o yaml + + # Get details of the application "my-app" in JSON format + argocd get my-app -o json + + # Get application details and include information about the current operation + argocd app get my-app --show-operation + + # Show application parameters and overrides + argocd app get my-app --show-params + + # Refresh application data when retrieving + argocd app get my-app --refresh + + # Perform a hard refresh, including refreshing application data and target manifests cache + argocd app get my-app --hard-refresh + + # Get application details and display them in a tree format + argocd app get my-app --output tree + + # Get application details and display them in a detailed tree format + argocd app get my-app --output tree=detailed +``` + ### Options ``` diff --git a/docs/user-guide/commands/argocd_app_patch-resource.md b/docs/user-guide/commands/argocd_app_patch-resource.md index 9211f410ea5b1..c849395cb3ea8 100644 --- a/docs/user-guide/commands/argocd_app_patch-resource.md +++ b/docs/user-guide/commands/argocd_app_patch-resource.md @@ -18,6 +18,7 @@ argocd app patch-resource APPNAME [flags] --namespace string Namespace --patch string Patch --patch-type string Which Patching strategy to use: 'application/json-patch+json', 'application/merge-patch+json', or 'application/strategic-merge-patch+json'. Defaults to 'application/merge-patch+json' (default "application/merge-patch+json") + --project string The name of the application's project - specifying this allows the command to report "not found" instead of "permission denied" if the app does not exist --resource-name string Name of resource ``` diff --git a/docs/user-guide/commands/argocd_app_resources.md b/docs/user-guide/commands/argocd_app_resources.md index b704ad1c41770..22027f74ba3d7 100644 --- a/docs/user-guide/commands/argocd_app_resources.md +++ b/docs/user-guide/commands/argocd_app_resources.md @@ -11,9 +11,10 @@ argocd app resources APPNAME [flags] ### Options ``` - -h, --help help for resources - --orphaned Lists only orphaned resources - --output string Provides the tree view of the resources + -h, --help help for resources + --orphaned Lists only orphaned resources + --output string Provides the tree view of the resources + --project string The name of the application's project - specifying this allows the command to report "not found" instead of "permission denied" if the app does not exist ``` ### Options inherited from parent commands diff --git a/docs/user-guide/commands/argocd_appset.md b/docs/user-guide/commands/argocd_appset.md index 1965ec0ca6be7..7b543ae318831 100644 --- a/docs/user-guide/commands/argocd_appset.md +++ b/docs/user-guide/commands/argocd_appset.md @@ -35,6 +35,7 @@ argocd appset [flags] --client-key string Path to a client key file for TLS --cluster string The name of the kubeconfig cluster to use --context string The name of the kubeconfig context to use + --disable-compression If true, opt-out of response compression for all requests to the server -h, --help help for appset --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure --kubeconfig string Path to a kube config. Only required if out-of-cluster diff --git a/docs/user-guide/commands/argocd_cert.md b/docs/user-guide/commands/argocd_cert.md index 54d913937131b..b126328a4372f 100644 --- a/docs/user-guide/commands/argocd_cert.md +++ b/docs/user-guide/commands/argocd_cert.md @@ -42,6 +42,7 @@ argocd cert [flags] --client-key string Path to a client key file for TLS --cluster string The name of the kubeconfig cluster to use --context string The name of the kubeconfig context to use + --disable-compression If true, opt-out of response compression for all requests to the server -h, --help help for cert --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure --kubeconfig string Path to a kube config. Only required if out-of-cluster diff --git a/docs/user-guide/commands/argocd_cluster.md b/docs/user-guide/commands/argocd_cluster.md index 7cd7e142b4c27..a30c357d54d71 100644 --- a/docs/user-guide/commands/argocd_cluster.md +++ b/docs/user-guide/commands/argocd_cluster.md @@ -39,6 +39,7 @@ argocd cluster [flags] --client-key string Path to a client key file for TLS --cluster string The name of the kubeconfig cluster to use --context string The name of the kubeconfig context to use + --disable-compression If true, opt-out of response compression for all requests to the server -h, --help help for cluster --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure --kubeconfig string Path to a kube config. Only required if out-of-cluster diff --git a/docs/user-guide/commands/argocd_cluster_add.md b/docs/user-guide/commands/argocd_cluster_add.md index 6d3a094b4bf83..8a80a12f5a4d5 100644 --- a/docs/user-guide/commands/argocd_cluster_add.md +++ b/docs/user-guide/commands/argocd_cluster_add.md @@ -13,6 +13,7 @@ argocd cluster add CONTEXT [flags] ``` --annotation stringArray Set metadata annotations (e.g. --annotation key=value) --aws-cluster-name string AWS Cluster name if set then aws cli eks token command will be used to access cluster + --aws-profile string Optional AWS profile. If set then AWS IAM Authenticator uses this profile to perform cluster operations instead of the default AWS credential provider chain. --aws-role-arn string Optional AWS role arn. If set then AWS IAM Authenticator assumes a role to perform cluster operations instead of the default AWS credential provider chain. --cluster-endpoint string Cluster endpoint to use. Can be one of the following: 'kubeconfig', 'kube-public', or 'internal'. --cluster-resources Indicates if cluster level resources should be managed. The setting is used only if list of managed namespaces is not empty. diff --git a/docs/user-guide/commands/argocd_cluster_list.md b/docs/user-guide/commands/argocd_cluster_list.md index aa5e090f4f4bd..9779a4fb8af0b 100644 --- a/docs/user-guide/commands/argocd_cluster_list.md +++ b/docs/user-guide/commands/argocd_cluster_list.md @@ -8,6 +8,28 @@ List configured clusters argocd cluster list [flags] ``` +### Examples + +``` + +# List Clusters in Default "Wide" Format +argocd cluster list + +# List Cluster via specifing the server +argocd cluster list --server + +# List Clusters in JSON Format +argocd cluster list -o json --server + +# List Clusters in YAML Format +argocd cluster list -o yaml --server + +# List Clusters that have been added to your Argo CD +argocd cluster list -o server + + +``` + ### Options ``` diff --git a/docs/user-guide/commands/argocd_gpg.md b/docs/user-guide/commands/argocd_gpg.md index 45f4f4134176a..bca15e98b7c87 100644 --- a/docs/user-guide/commands/argocd_gpg.md +++ b/docs/user-guide/commands/argocd_gpg.md @@ -19,6 +19,7 @@ argocd gpg [flags] --client-key string Path to a client key file for TLS --cluster string The name of the kubeconfig cluster to use --context string The name of the kubeconfig context to use + --disable-compression If true, opt-out of response compression for all requests to the server -h, --help help for gpg --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure --kubeconfig string Path to a kube config. Only required if out-of-cluster diff --git a/docs/user-guide/commands/argocd_gpg_add.md b/docs/user-guide/commands/argocd_gpg_add.md index c3fb32369d86d..3ef5d4e6c72d5 100644 --- a/docs/user-guide/commands/argocd_gpg_add.md +++ b/docs/user-guide/commands/argocd_gpg_add.md @@ -8,6 +8,13 @@ Adds a GPG public key to the server's keyring argocd gpg add [flags] ``` +### Examples + +``` + # Add a GPG public key to the server's keyring from a file. + argocd gpg add --from /path/to/keyfile +``` + ### Options ``` diff --git a/docs/user-guide/commands/argocd_gpg_get.md b/docs/user-guide/commands/argocd_gpg_get.md index 0810b880cd8d2..e0ad3d9ee25d6 100644 --- a/docs/user-guide/commands/argocd_gpg_get.md +++ b/docs/user-guide/commands/argocd_gpg_get.md @@ -8,6 +8,19 @@ Get the GPG public key with ID from the server argocd gpg get KEYID [flags] ``` +### Examples + +``` + # Get a GPG public key with the specified KEYID in wide format (default). + argocd gpg get KEYID + + # Get a GPG public key with the specified KEYID in JSON format. + argocd gpg get KEYID -o json + + # Get a GPG public key with the specified KEYID in YAML format. + argocd gpg get KEYID -o yaml +``` + ### Options ``` diff --git a/docs/user-guide/commands/argocd_gpg_list.md b/docs/user-guide/commands/argocd_gpg_list.md index 9e280cca30631..50f0e72e83c0d 100644 --- a/docs/user-guide/commands/argocd_gpg_list.md +++ b/docs/user-guide/commands/argocd_gpg_list.md @@ -8,6 +8,19 @@ List configured GPG public keys argocd gpg list [flags] ``` +### Examples + +``` + # List all configured GPG public keys in wide format (default). + argocd gpg list + + # List all configured GPG public keys in JSON format. + argocd gpg list -o json + + # List all configured GPG public keys in YAML format. + argocd gpg list -o yaml +``` + ### Options ``` diff --git a/docs/user-guide/commands/argocd_proj.md b/docs/user-guide/commands/argocd_proj.md index ed119f226756d..17aeef0cdfc27 100644 --- a/docs/user-guide/commands/argocd_proj.md +++ b/docs/user-guide/commands/argocd_proj.md @@ -35,6 +35,7 @@ argocd proj [flags] --client-key string Path to a client key file for TLS --cluster string The name of the kubeconfig cluster to use --context string The name of the kubeconfig context to use + --disable-compression If true, opt-out of response compression for all requests to the server -h, --help help for proj --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure --kubeconfig string Path to a kube config. Only required if out-of-cluster diff --git a/docs/user-guide/commands/argocd_proj_create.md b/docs/user-guide/commands/argocd_proj_create.md index d99c66a19555d..fd8687c1b2982 100644 --- a/docs/user-guide/commands/argocd_proj_create.md +++ b/docs/user-guide/commands/argocd_proj_create.md @@ -14,7 +14,7 @@ argocd proj create PROJECT [flags] # Create a new project with name PROJECT argocd proj create PROJECT - # Create a new project with name PROJECT from a file or URL to a kubernetes manifest + # Create a new project with name PROJECT from a file or URL to a Kubernetes manifest argocd proj create PROJECT -f FILE|URL ``` diff --git a/docs/user-guide/commands/argocd_proj_role_add-policy.md b/docs/user-guide/commands/argocd_proj_role_add-policy.md index a19b51e405e95..d4804d31d66a1 100644 --- a/docs/user-guide/commands/argocd_proj_role_add-policy.md +++ b/docs/user-guide/commands/argocd_proj_role_add-policy.md @@ -8,6 +8,35 @@ Add a policy to a project role argocd proj role add-policy PROJECT ROLE-NAME [flags] ``` +### Examples + +``` +# Before adding new policy +$ argocd proj role get test-project test-role +Role Name: test-role +Description: +Policies: +p, proj:test-project:test-role, projects, get, test-project, allow +JWT Tokens: +ID ISSUED-AT EXPIRES-AT +1696759698 2023-10-08T11:08:18+01:00 (3 hours ago) + +# Add a new policy to allow update to the project +$ argocd proj role add-policy test-project test-role -a update -p allow -o project + +# Policy should be updated +$ argocd proj role get test-project test-role +Role Name: test-role +Description: +Policies: +p, proj:test-project:test-role, projects, get, test-project, allow +p, proj:test-project:test-role, applications, update, test-project/project, allow +JWT Tokens: +ID ISSUED-AT EXPIRES-AT +1696759698 2023-10-08T11:08:18+01:00 (3 hours ago) + +``` + ### Options ``` diff --git a/docs/user-guide/commands/argocd_proj_role_create-token.md b/docs/user-guide/commands/argocd_proj_role_create-token.md index 3d88481a9bc5e..fc7eaf93c2307 100644 --- a/docs/user-guide/commands/argocd_proj_role_create-token.md +++ b/docs/user-guide/commands/argocd_proj_role_create-token.md @@ -8,6 +8,18 @@ Create a project token argocd proj role create-token PROJECT ROLE-NAME [flags] ``` +### Examples + +``` +$ argocd proj role create-token test-project test-role +Create token succeeded for proj:test-project:test-role. + ID: f316c466-40bd-4cfd-8a8c-1392e92255d4 + Issued At: 2023-10-08T15:21:40+01:00 + Expires At: Never + Token: xxx + +``` + ### Options ``` diff --git a/docs/user-guide/commands/argocd_proj_role_create.md b/docs/user-guide/commands/argocd_proj_role_create.md index 6bfbd0c077232..60974c9e1b4e6 100644 --- a/docs/user-guide/commands/argocd_proj_role_create.md +++ b/docs/user-guide/commands/argocd_proj_role_create.md @@ -8,6 +8,13 @@ Create a project role argocd proj role create PROJECT ROLE-NAME [flags] ``` +### Examples + +``` + # Create a project role in the "my-project" project with the name "my-role". + argocd proj role create my-project my-role --description "My project role description" +``` + ### Options ``` diff --git a/docs/user-guide/commands/argocd_proj_role_delete-token.md b/docs/user-guide/commands/argocd_proj_role_delete-token.md index c4aa602628144..006746f8faeeb 100644 --- a/docs/user-guide/commands/argocd_proj_role_delete-token.md +++ b/docs/user-guide/commands/argocd_proj_role_delete-token.md @@ -8,6 +8,38 @@ Delete a project token argocd proj role delete-token PROJECT ROLE-NAME ISSUED-AT [flags] ``` +### Examples + +``` +#Create project test-project +$ argocd proj create test-project + +# Create a role associated with test-project +$ argocd proj role create test-project test-role +Role 'test-role' created + +# Create test-role associated with test-project +$ argocd proj role create-token test-project test-role +Create token succeeded for proj:test-project:test-role. + ID: c312450e-12e1-4e0d-9f65-fac9cb027b32 + Issued At: 2023-10-08T13:58:57+01:00 + Expires At: Never + Token: xxx + +# Get test-role id to input into the delete-token command below +$ argocd proj role get test-project test-role +Role Name: test-role +Description: +Policies: +p, proj:test-project:test-role, projects, get, test-project, allow +JWT Tokens: +ID ISSUED-AT EXPIRES-AT +1696769937 2023-10-08T13:58:57+01:00 (6 minutes ago) + +$ argocd proj role delete-token test-project test-role 1696769937 + +``` + ### Options ``` diff --git a/docs/user-guide/commands/argocd_proj_role_delete.md b/docs/user-guide/commands/argocd_proj_role_delete.md index 42fc14fd031b8..fe94a2231db60 100644 --- a/docs/user-guide/commands/argocd_proj_role_delete.md +++ b/docs/user-guide/commands/argocd_proj_role_delete.md @@ -8,6 +8,12 @@ Delete a project role argocd proj role delete PROJECT ROLE-NAME [flags] ``` +### Examples + +``` +$ argocd proj role delete test-project test-role +``` + ### Options ``` diff --git a/docs/user-guide/commands/argocd_proj_role_get.md b/docs/user-guide/commands/argocd_proj_role_get.md index a469c4d695203..e21276ce85116 100644 --- a/docs/user-guide/commands/argocd_proj_role_get.md +++ b/docs/user-guide/commands/argocd_proj_role_get.md @@ -8,6 +8,21 @@ Get the details of a specific role argocd proj role get PROJECT ROLE-NAME [flags] ``` +### Examples + +``` +$ argocd proj role get test-project test-role +Role Name: test-role +Description: +Policies: +p, proj:test-project:test-role, projects, get, test-project, allow +JWT Tokens: +ID ISSUED-AT EXPIRES-AT +1696774900 2023-10-08T15:21:40+01:00 (4 minutes ago) +1696759698 2023-10-08T11:08:18+01:00 (4 hours ago) + +``` + ### Options ``` diff --git a/docs/user-guide/commands/argocd_proj_role_list-tokens.md b/docs/user-guide/commands/argocd_proj_role_list-tokens.md index 46e9e131f52bf..8d1fe93163dfc 100644 --- a/docs/user-guide/commands/argocd_proj_role_list-tokens.md +++ b/docs/user-guide/commands/argocd_proj_role_list-tokens.md @@ -8,6 +8,16 @@ List tokens for a given role. argocd proj role list-tokens PROJECT ROLE-NAME [flags] ``` +### Examples + +``` +$ argocd proj role list-tokens test-project test-role +ID ISSUED AT EXPIRES AT +f316c466-40bd-4cfd-8a8c-1392e92255d4 2023-10-08T15:21:40+01:00 Never +fa9d3517-c52d-434c-9bff-215b38508842 2023-10-08T11:08:18+01:00 Never + +``` + ### Options ``` diff --git a/docs/user-guide/commands/argocd_proj_role_list.md b/docs/user-guide/commands/argocd_proj_role_list.md index b535cf724add9..3cfd630ddc988 100644 --- a/docs/user-guide/commands/argocd_proj_role_list.md +++ b/docs/user-guide/commands/argocd_proj_role_list.md @@ -8,6 +8,16 @@ List all the roles in a project argocd proj role list PROJECT [flags] ``` +### Examples + +``` + # This command will list all the roles in argocd-project in a default table format. + argocd proj role list PROJECT + + # List the roles in the project in formats like json, yaml, wide, or name. + argocd proj role list PROJECT --output json +``` + ### Options ``` diff --git a/docs/user-guide/commands/argocd_proj_role_remove-policy.md b/docs/user-guide/commands/argocd_proj_role_remove-policy.md index 3f77922eacb09..96aee05da86eb 100644 --- a/docs/user-guide/commands/argocd_proj_role_remove-policy.md +++ b/docs/user-guide/commands/argocd_proj_role_remove-policy.md @@ -8,6 +8,35 @@ Remove a policy from a role within a project argocd proj role remove-policy PROJECT ROLE-NAME [flags] ``` +### Examples + +``` +List the policy of the test-role before removing a policy +$ argocd proj role get test-project test-role +Role Name: test-role +Description: +Policies: +p, proj:test-project:test-role, projects, get, test-project, allow +p, proj:test-project:test-role, applications, update, test-project/project, allow +JWT Tokens: +ID ISSUED-AT EXPIRES-AT +1696759698 2023-10-08T11:08:18+01:00 (3 hours ago) + +# Remove the policy to allow update to objects +$ argocd proj role remove-policy test-project test-role -a update -p allow -o project + +# The role should be removed now. +$ argocd proj role get test-project test-role +Role Name: test-role +Description: +Policies: +p, proj:test-project:test-role, projects, get, test-project, allow +JWT Tokens: +ID ISSUED-AT EXPIRES-AT +1696759698 2023-10-08T11:08:18+01:00 (4 hours ago) + +``` + ### Options ``` diff --git a/docs/user-guide/commands/argocd_proj_windows.md b/docs/user-guide/commands/argocd_proj_windows.md index dc1b68bf0191b..0b22c2098dc82 100644 --- a/docs/user-guide/commands/argocd_proj_windows.md +++ b/docs/user-guide/commands/argocd_proj_windows.md @@ -8,6 +8,23 @@ Manage a project's sync windows argocd proj windows [flags] ``` +### Examples + +``` + +#Add a sync window to a project +argocd proj windows add my-project \ +--schedule "0 0 * * 1-5" \ +--duration 3600 \ +--prune + +#Delete a sync window from a project +argocd proj windows delete + +#List project sync windows +argocd proj windows list +``` + ### Options ``` diff --git a/docs/user-guide/commands/argocd_proj_windows_add.md b/docs/user-guide/commands/argocd_proj_windows_add.md index 72d916b114910..52fd3a8354ee3 100644 --- a/docs/user-guide/commands/argocd_proj_windows_add.md +++ b/docs/user-guide/commands/argocd_proj_windows_add.md @@ -8,6 +8,29 @@ Add a sync window to a project argocd proj windows add PROJECT [flags] ``` +### Examples + +``` + +#Add a 1 hour allow sync window +argocd proj windows add PROJECT \ + --kind allow \ + --schedule "0 22 * * *" \ + --duration 1h \ + --applications "*" + +#Add a deny sync window with the ability to manually sync. +argocd proj windows add PROJECT \ + --kind deny \ + --schedule "30 10 * * *" \ + --duration 30m \ + --applications "prod-\\*,website" \ + --namespaces "default,\\*-prod" \ + --clusters "prod,staging" \ + --manual-sync + +``` + ### Options ``` diff --git a/docs/user-guide/commands/argocd_proj_windows_delete.md b/docs/user-guide/commands/argocd_proj_windows_delete.md index 316b25041fde2..6faf7dbeedc19 100644 --- a/docs/user-guide/commands/argocd_proj_windows_delete.md +++ b/docs/user-guide/commands/argocd_proj_windows_delete.md @@ -8,6 +8,17 @@ Delete a sync window from a project. Requires ID which can be found by running " argocd proj windows delete PROJECT ID [flags] ``` +### Examples + +``` + +#Delete a sync window from a project (default) with ID 0 +argocd proj windows delete default 0 + +#Delete a sync window from a project (new-project) with ID 1 +argocd proj windows delete new-project 1 +``` + ### Options ``` diff --git a/docs/user-guide/commands/argocd_proj_windows_disable-manual-sync.md b/docs/user-guide/commands/argocd_proj_windows_disable-manual-sync.md index 8951ad9371c90..e3b84ac38cc0e 100644 --- a/docs/user-guide/commands/argocd_proj_windows_disable-manual-sync.md +++ b/docs/user-guide/commands/argocd_proj_windows_disable-manual-sync.md @@ -12,6 +12,17 @@ Disable manual sync for a sync window. Requires ID which can be found by running argocd proj windows disable-manual-sync PROJECT ID [flags] ``` +### Examples + +``` + +#Disable manual sync for a sync window for the Project +argocd proj windows disable-manual-sync PROJECT ID + +#Disbaling manual sync for a windows set on the default project with Id 0 +argocd proj windows disable-manual-sync default 0 +``` + ### Options ``` diff --git a/docs/user-guide/commands/argocd_proj_windows_enable-manual-sync.md b/docs/user-guide/commands/argocd_proj_windows_enable-manual-sync.md index a1ca162840f7a..7ecbb50e6ac1b 100644 --- a/docs/user-guide/commands/argocd_proj_windows_enable-manual-sync.md +++ b/docs/user-guide/commands/argocd_proj_windows_enable-manual-sync.md @@ -12,6 +12,20 @@ Enable manual sync for a sync window. Requires ID which can be found by running argocd proj windows enable-manual-sync PROJECT ID [flags] ``` +### Examples + +``` + +#Enabling manual sync for a general case +argocd proj windows enable-manual-sync PROJECT ID + +#Enabling manual sync for a windows set on the default project with Id 2 +argocd proj windows enable-manual-sync default 2 + +#Enabling manual sync with a custom message +argocd proj windows enable-manual-sync my-app-project --message "Manual sync initiated by admin +``` + ### Options ``` diff --git a/docs/user-guide/commands/argocd_proj_windows_list.md b/docs/user-guide/commands/argocd_proj_windows_list.md index e0267a2517252..3c361f90d2a68 100644 --- a/docs/user-guide/commands/argocd_proj_windows_list.md +++ b/docs/user-guide/commands/argocd_proj_windows_list.md @@ -8,6 +8,20 @@ List project sync windows argocd proj windows list PROJECT [flags] ``` +### Examples + +``` + +#List project windows +argocd proj windows list PROJECT + +#List project windows in yaml format +argocd proj windows list PROJECT -o yaml + +#List project windows info for a project name (test-project) +argocd proj windows list test-project +``` + ### Options ``` diff --git a/docs/user-guide/commands/argocd_proj_windows_update.md b/docs/user-guide/commands/argocd_proj_windows_update.md index 2d9f4f2dbb8a7..e01e3787d51a2 100644 --- a/docs/user-guide/commands/argocd_proj_windows_update.md +++ b/docs/user-guide/commands/argocd_proj_windows_update.md @@ -12,6 +12,15 @@ Update a project sync window. Requires ID which can be found by running "argocd argocd proj windows update PROJECT ID [flags] ``` +### Examples + +``` +# Change a sync window's schedule +argocd proj windows update PROJECT ID \ + --schedule "0 20 * * *" + +``` + ### Options ``` diff --git a/docs/user-guide/commands/argocd_repo.md b/docs/user-guide/commands/argocd_repo.md index cfc1bd4aba35a..4df85f7b00d3d 100644 --- a/docs/user-guide/commands/argocd_repo.md +++ b/docs/user-guide/commands/argocd_repo.md @@ -37,6 +37,7 @@ argocd repo rm https://github.com/yourusername/your-repo.git --client-key string Path to a client key file for TLS --cluster string The name of the kubeconfig cluster to use --context string The name of the kubeconfig context to use + --disable-compression If true, opt-out of response compression for all requests to the server -h, --help help for repo --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure --kubeconfig string Path to a kube config. Only required if out-of-cluster diff --git a/docs/user-guide/commands/argocd_repo_add.md b/docs/user-guide/commands/argocd_repo_add.md index 263dda07af7dc..8399d48302509 100644 --- a/docs/user-guide/commands/argocd_repo_add.md +++ b/docs/user-guide/commands/argocd_repo_add.md @@ -17,6 +17,12 @@ argocd repo add REPOURL [flags] # Add a Git repository via SSH on a non-default port - need to use ssh:// style URLs here argocd repo add ssh://git@git.example.com:2222/repos/repo --ssh-private-key-path ~/id_rsa + # Add a Git repository via SSH using socks5 proxy with no proxy credentials + argocd repo add ssh://git@github.com/argoproj/argocd-example-apps --ssh-private-key-path ~/id_rsa --proxy socks5://your.proxy.server.ip:1080 + + # Add a Git repository via SSH using socks5 proxy with proxy credentials + argocd repo add ssh://git@github.com/argoproj/argocd-example-apps --ssh-private-key-path ~/id_rsa --proxy socks5://username:password@your.proxy.server.ip:1080 + # Add a private Git repository via HTTPS using username/password and TLS client certificates: argocd repo add https://git.example.com/repos/repo --username git --password secret --tls-client-cert-path ~/mycert.crt --tls-client-cert-key-path ~/mycert.key diff --git a/docs/user-guide/commands/argocd_repocreds.md b/docs/user-guide/commands/argocd_repocreds.md index 5774654d4e3b5..f073b2bbb6161 100644 --- a/docs/user-guide/commands/argocd_repocreds.md +++ b/docs/user-guide/commands/argocd_repocreds.md @@ -32,6 +32,7 @@ argocd repocreds [flags] --client-key string Path to a client key file for TLS --cluster string The name of the kubeconfig cluster to use --context string The name of the kubeconfig context to use + --disable-compression If true, opt-out of response compression for all requests to the server -h, --help help for repocreds --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure --kubeconfig string Path to a kube config. Only required if out-of-cluster diff --git a/docs/user-guide/commands/argocd_repocreds_list.md b/docs/user-guide/commands/argocd_repocreds_list.md index 4db3506d3f580..ae358afab2056 100644 --- a/docs/user-guide/commands/argocd_repocreds_list.md +++ b/docs/user-guide/commands/argocd_repocreds_list.md @@ -11,11 +11,17 @@ argocd repocreds list [flags] ### Examples ``` - # List all the configured repository credentials + # List all repo urls argocd repocreds list - # List all the configured repository credentials in json format + # List all repo urls in json format argocd repocreds list -o json + + # List all repo urls in yaml format + argocd repocreds list -o yaml + + # List all repo urls in url format + argocd repocreds list -o url ``` ### Options diff --git a/docs/user-guide/commands/argocd_version.md b/docs/user-guide/commands/argocd_version.md index a1a1bb223d3fc..6a7fa7baf5ecb 100644 --- a/docs/user-guide/commands/argocd_version.md +++ b/docs/user-guide/commands/argocd_version.md @@ -37,6 +37,7 @@ argocd version [flags] --client-key string Path to a client key file for TLS --cluster string The name of the kubeconfig cluster to use --context string The name of the kubeconfig context to use + --disable-compression If true, opt-out of response compression for all requests to the server -h, --help help for version --insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure --kubeconfig string Path to a kube config. Only required if out-of-cluster diff --git a/docs/user-guide/diff-strategies.md b/docs/user-guide/diff-strategies.md new file mode 100644 index 0000000000000..2890fe64cbb0e --- /dev/null +++ b/docs/user-guide/diff-strategies.md @@ -0,0 +1,131 @@ +# Diff Strategies + +Argo CD calculates the diff between the desired state and the live +state in order to define if an Application is out-of-sync. This same +logic is also used in Argo CD UI to display the differences between +live and desired states for all resources belonging to an application. + +Argo CD currently has 3 different strategies to calculate diffs: + +- **Legacy**: This is the main diff strategy used by default. It + applies a 3-way diff based on live state, desired state and + last-applied-configuration (annotation). +- **Structured-Merge Diff**: Strategy automatically applied when + enabling Server-Side Apply sync option. +- **Server-Side Diff**: New strategy that invokes a Server-Side Apply + in dryrun mode in order to generate the predicted live state. + +## Structured-Merge Diff +*Current Status: [Beta][1] (Since v2.5.0)* + +This is diff strategy is automatically used when Server-Side Apply +sync option is enabled. It uses the [structured-merge-diff][2] library +used by Kubernetes to calculate diffs based on fields ownership. There +are some challenges using this strategy to calculate diffs for CRDs +that define default values. After different issues were identified by +the community, this strategy is being discontinued in favour of +Server-Side Diff. + +## Server-Side Diff +*Current Status: [Beta][1] (Since v2.10.0)* + +This diff strategy will execute a Server-Side Apply in dryrun mode for +each resource of the application. The response of this operation is then +compared with the live state in order to provide the diff results. The +diff results are cached and new Server-Side Apply requests to Kube API +are only triggered when: + +- An Application refresh or hard-refresh is requested. +- There is a new revision in the repo which the Argo CD Application is + targeting. +- The Argo CD Application spec changed. + +One advantage of Server-Side Diff is that Kubernetes Admission +Controllers will participate in the diff calculation. If for example +a validation webhook identifies a resource to be invalid, that will be +informed to Argo CD during the diff stage rather than during the sync +stage. + +### Enabling it + +Server-Side Diff can be enabled at the Argo CD Controller level or per +Application. + +**Enabling Server-Side Diff for all Applications** + +Add the following entry in the argocd-cmd-params-cm configmap: + +``` +apiVersion: v1 +kind: ConfigMap +metadata: + name: argocd-cmd-params-cm +data: + controller.diff.server.side: "true" +... +``` + +Note: It is necessary to restart the `argocd-application-controller` +after applying this configuration. + +**Enabling Server-Side Diff for one application** + +Add the following annotation in the Argo CD Application resource: + +``` +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + annotations: + argocd.argoproj.io/compare-options: ServerSideDiff=true +... +``` + +**Disabling Server-Side Diff for one application** + +If Server-Side Diff is enabled globally in your Argo CD instance, it +is possible to disable it at the application level. In order to do so, +add the following annotation in the Application resource: + +``` +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + annotations: + argocd.argoproj.io/compare-options: ServerSideDiff=false +... +``` + +*Note: Please report any issues that forced you to disable the +Server-Side Diff feature* + +### Mutation Webhooks + +Server-Side Diff does not include changes made by mutation webhooks by +default. If you want to include mutation webhooks in Argo CD diffs add +the following annotation in the Argo CD Application resource: + +``` +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + annotations: + argocd.argoproj.io/compare-options: IncludeMutationWebhook=true +... +``` + +Note: This annoation is only effective when Server-Side Diff is +enabled. To enable both options for a given application add the +following annotation in the Argo CD Application resource: + +``` +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + annotations: + argocd.argoproj.io/compare-options: ServerSideDiff=true,IncludeMutationWebhook=true +... +``` + +[1]: https://github.com/argoproj/argoproj/blob/main/community/feature-status.md#beta +[2]: https://github.com/kubernetes-sigs/structured-merge-diff diff --git a/docs/user-guide/diffing.md b/docs/user-guide/diffing.md index 5a056b9c3769b..61f799e514d6a 100644 --- a/docs/user-guide/diffing.md +++ b/docs/user-guide/diffing.md @@ -181,4 +181,7 @@ data: type: core/v1/PodSpec ``` -The list of supported Kubernetes types is available in [diffing_known_types.txt](https://raw.githubusercontent.com/argoproj/argo-cd/master/util/argo/normalizers/diffing_known_types.txt) +The list of supported Kubernetes types is available in [diffing_known_types.txt](https://raw.githubusercontent.com/argoproj/argo-cd/master/util/argo/normalizers/diffing_known_types.txt) and additionally: + +* `core/Quantity` +* `meta/v1/duration` diff --git a/docs/user-guide/environment-variables.md b/docs/user-guide/environment-variables.md index 238db85b5c718..cff6446617fa3 100644 --- a/docs/user-guide/environment-variables.md +++ b/docs/user-guide/environment-variables.md @@ -4,7 +4,7 @@ The following environment variables can be used with `argocd` CLI: | Environment Variable | Description | |--------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `ARGOCD_SERVER` | the address of the Argo CD server without `https://` prefix
    (instead of specifying `--server` for every command)
    eg. `ARGOCD_SERVER=argocd.mycompany.com` if served through an ingress with DNS | +| `ARGOCD_SERVER` | the address of the Argo CD server without `https://` prefix
    (instead of specifying `--server` for every command)
    eg. `ARGOCD_SERVER=argocd.example.com` if served through an ingress with DNS | | `ARGOCD_AUTH_TOKEN` | the Argo CD `apiKey` for your Argo CD user to be able to authenticate | | `ARGOCD_OPTS` | command-line options to pass to `argocd` CLI
    eg. `ARGOCD_OPTS="--grpc-web"` | | `ARGOCD_SERVER_NAME` | the Argo CD API Server name (default "argocd-server") | @@ -12,3 +12,4 @@ The following environment variables can be used with `argocd` CLI: | `ARGOCD_APPLICATION_CONTROLLER_NAME` | the Argo CD Application Controller name (default "argocd-application-controller") | | `ARGOCD_REDIS_NAME` | the Argo CD Redis name (default "argocd-redis") | | `ARGOCD_REDIS_HAPROXY_NAME` | the Argo CD Redis HA Proxy name (default "argocd-redis-ha-haproxy") | +| `ARGOCD_GRPC_KEEP_ALIVE_MIN` | defines the GRPCKeepAliveEnforcementMinimum, used in the grpc.KeepaliveEnforcementPolicy. Expects a "Duration" format (default `10s`). | diff --git a/docs/user-guide/external-url.md b/docs/user-guide/external-url.md index 792b8465b233b..7f08ea6c80bf4 100644 --- a/docs/user-guide/external-url.md +++ b/docs/user-guide/external-url.md @@ -12,7 +12,7 @@ kind: Deployment metadata: name: my-svc annotations: - link.argocd.argoproj.io/external-link: http://my-grafana.com/pre-generated-link + link.argocd.argoproj.io/external-link: http://my-grafana.example.com/pre-generated-link ``` ![External link](../assets/external-link.png) diff --git a/docs/user-guide/helm.md b/docs/user-guide/helm.md index 76853480a6def..ae6422f46382a 100644 --- a/docs/user-guide/helm.md +++ b/docs/user-guide/helm.md @@ -25,6 +25,23 @@ spec: namespace: kubeseal ``` +Another example using a public OCI helm chart: +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: nginx +spec: + project: default + source: + chart: nginx + repoURL: registry-1.docker.io/bitnamicharts # note: the oci:// syntax is not included. + targetRevision: 15.9.0 + destination: + name: "in-cluster" + namespace: nginx +``` + !!! note "When using multiple ways to provide values" Order of precedence is `parameters > valuesObject > values > valueFiles > helm repository values.yaml` (see [Here](./helm.md#helm-value-precedence) for a more detailed example) @@ -210,7 +227,7 @@ is any normal Kubernetes resource annotated with the `helm.sh/hook` annotation. Argo CD supports many (most?) Helm hooks by mapping the Helm annotations onto Argo CD's own hook annotations: | Helm Annotation | Notes | -| ------------------------------- | --------------------------------------------------------------------------------------------- | +| ------------------------------- |-----------------------------------------------------------------------------------------------| | `helm.sh/hook: crd-install` | Supported as equivalent to `argocd.argoproj.io/hook: PreSync`. | | `helm.sh/hook: pre-delete` | Not supported. In Helm stable there are 3 cases used to clean up CRDs and 3 to clean-up jobs. | | `helm.sh/hook: pre-rollback` | Not supported. Never used in Helm stable. | @@ -218,7 +235,7 @@ Argo CD supports many (most?) Helm hooks by mapping the Helm annotations onto Ar | `helm.sh/hook: pre-upgrade` | Supported as equivalent to `argocd.argoproj.io/hook: PreSync`. | | `helm.sh/hook: post-upgrade` | Supported as equivalent to `argocd.argoproj.io/hook: PostSync`. | | `helm.sh/hook: post-install` | Supported as equivalent to `argocd.argoproj.io/hook: PostSync`. | -| `helm.sh/hook: post-delete` | Not supported. Never used in Helm stable. | +| `helm.sh/hook: post-delete` | Supported as equivalent to `argocd.argoproj.io/hook: PostDelete`. | | `helm.sh/hook: post-rollback` | Not supported. Never used in Helm stable. | | `helm.sh/hook: test-success` | Not supported. No equivalent in Argo CD. | | `helm.sh/hook: test-failure` | Not supported. No equivalent in Argo CD. | diff --git a/docs/user-guide/kustomize.md b/docs/user-guide/kustomize.md index ee137cab27149..3da35b7eede76 100644 --- a/docs/user-guide/kustomize.md +++ b/docs/user-guide/kustomize.md @@ -9,10 +9,11 @@ The following configuration options are available for Kustomize: * `commonLabels` is a string map of additional labels * `forceCommonLabels` is a boolean value which defines if it's allowed to override existing labels * `commonAnnotations` is a string map of additional annotations -* `namespace` is a kubernetes resources namespace +* `namespace` is a Kubernetes resources namespace * `forceCommonAnnotations` is a boolean value which defines if it's allowed to override existing annotations * `commonAnnotationsEnvsubst` is a boolean value which enables env variables substition in annotation values * `patches` is a list of Kustomize patches that supports inline updates +* `components` is a list of Kustomize components To use Kustomize with an overlay, point your path to the overlay. @@ -20,9 +21,9 @@ To use Kustomize with an overlay, point your path to the overlay. If you're generating resources, you should read up how to ignore those generated resources using the [`IgnoreExtraneous` compare option](compare-options.md). ## Patches -Patches are a way to kustomize resources using inline configurations in Argo CD applications. This allows for kustomizing without kustomization file. `patches` follow the same logic as the corresponding Kustomization. Any patches that target existing Kustomization file will be merged. +Patches are a way to kustomize resources using inline configurations in Argo CD applications. `patches` follow the same logic as the corresponding Kustomization. Any patches that target existing Kustomization file will be merged. -The following Kustomization can be done similarly in an Argo CD application. +This Kustomize example sources manifests from the `/kustomize-guestbook` folder of the `argoproj/argocd-example-apps` repository, and patches the `Deployment` to use port `443` on the container. ```yaml apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization @@ -30,8 +31,7 @@ metadata: name: kustomize-inline-example namespace: test1 resources: - - https://raw.githubusercontent.com/argoproj/argocd-example-apps/master/guestbook/guestbook-ui-deployment.yaml - - https://raw.githubusercontent.com/argoproj/argocd-example-apps/master/guestbook/guestbook-ui-svc.yaml + - https://raw.githubusercontent.com/argoproj/argocd-example-apps/master/kustomize-guestbook/ patches: - target: kind: Deployment @@ -41,7 +41,8 @@ patches: path: /spec/template/spec/containers/0/ports/0/containerPort value: 443 ``` -Application will clone the repository, use the specified path, then kustomize using inline patches configuration. + +This `Application` does the equivalent using the inline `kustomize.patches` configuration. ```yaml apiVersion: argoproj.io/v1alpha1 kind: Application @@ -56,7 +57,7 @@ spec: server: https://kubernetes.default.svc project: default source: - path: guestbook + path: kustomize-guestbook repoURL: https://github.com/argoproj/argocd-example-apps.git targetRevision: master kustomize: @@ -70,6 +71,72 @@ spec: value: 443 ``` +The inline kustomize patches work well with `ApplicationSets`, too. Instead of maintaining a patch or overlay for each cluster, patches can now be done in the `Application` template and utilize attributes from the generators. For example, with [`external-dns`](https://github.com/kubernetes-sigs/external-dns/) to set the [`txt-owner-id`](https://github.com/kubernetes-sigs/external-dns/blob/e1adc9079b12774cccac051966b2c6a3f18f7872/docs/registry/registry.md?plain=1#L6) to the cluster name. + +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: ApplicationSet +metadata: + name: external-dns +spec: + goTemplate: true + goTemplateOptions: ["missingkey=error"] + generators: + - clusters: {} + template: + metadata: + name: 'external-dns' + spec: + project: default + source: + repoURL: https://github.com/kubernetes-sigs/external-dns/ + targetRevision: v0.14.0 + path: kustomize + kustomize: + patches: + - target: + kind: Deployment + name: external-dns + patch: |- + - op: add + path: /spec/template/spec/containers/0/args/3 + value: --txt-owner-id={{.name}} # patch using attribute from generator + destination: + name: 'in-cluster' + namespace: default +``` + +## Components +Kustomize [components](https://github.com/kubernetes-sigs/kustomize/blob/master/examples/components.md) encapsulate both resources and patches together. They provide a powerful way to modularize and reuse configuration in Kubernetes applications. + +Outside of Argo CD, to utilize components, you must add the following to the `kustomization.yaml` that the Application references. For example: +```yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +... +components: +- ../component +``` + +With support added for components in `v2.10.0`, you can now reference a component directly in the Application: +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: application-kustomize-components +spec: + ... + source: + path: examples/application-kustomize-components/base + repoURL: https://github.com/my-user/my-repo + targetRevision: main + + # This! + kustomize: + components: + - ../component # relative to the kustomization.yaml (`source.path`). +``` + ## Private Remote Bases If you have remote bases that are either (a) HTTPS and need username/password (b) SSH and need SSH private key, then they'll inherit that from the app's repo. @@ -95,6 +162,9 @@ data: kustomize.buildOptions: --load-restrictor LoadRestrictionsNone kustomize.buildOptions.v4.4.0: --output /tmp ``` + +After modifying `kustomize.buildOptions`, you may need to restart ArgoCD for the changes to take effect. + ## Custom Kustomize versions Argo CD supports using multiple Kustomize versions simultaneously and specifies required version per application. @@ -143,6 +213,34 @@ argocd app set --kustomize-version v3.5.4 Kustomize apps have access to the [standard build environment](build-environment.md) which can be used in combination with a [config managment plugin](../operator-manual/config-management-plugins.md) to alter the rendered manifests. +You can use these build environment variables in your Argo CD Application manifests. You can enable this by setting `.spec.source.kustomize.commonAnnotationsEnvsubst` to `true` in your Application manifest. + +For example, the following Application manifest will set the `app-source` annotation to the name of the Application: + +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: guestbook-app + namespace: argocd +spec: + project: default + destination: + namespace: demo + server: https://kubernetes.default.svc + source: + path: kustomize-guestbook + repoURL: https://github.com/argoproj/argocd-example-apps + targetRevision: HEAD + kustomize: + commonAnnotationsEnvsubst: true + commonAnnotations: + app-source: ${ARGOCD_APP_NAME} + syncPolicy: + syncOptions: + - CreateNamespace=true +``` + ## Kustomizing Helm charts It's possible to [render Helm charts with Kustomize](https://github.com/kubernetes-sigs/kustomize/blob/master/examples/chart.md). diff --git a/docs/user-guide/projects.md b/docs/user-guide/projects.md index 6fb59b1ef3456..f5979cf3c47b3 100644 --- a/docs/user-guide/projects.md +++ b/docs/user-guide/projects.md @@ -292,7 +292,7 @@ p, proj:my-project:admin, repositories, update, my-project/*, allow This provides extra flexibility so that admins can have stricter rules. e.g.: ``` -p, proj:my-project:admin, repositories, update, my-project/https://github.my-company.com/*, allow +p, proj:my-project:admin, repositories, update, my-project/https://github.example.com/*, allow ``` Once the appropriate RBAC rules are in place, developers can create their own Git repositories and (assuming @@ -321,6 +321,28 @@ stringData: All the examples above talk about Git repositories, but the same principles apply to clusters as well. +```yaml +apiVersion: v1 +kind: Secret +metadata: + name: mycluster-secret + labels: + argocd.argoproj.io/secret-type: cluster +type: Opaque +stringData: + name: mycluster.example.com + project: my-project1 # Project scoped + server: https://mycluster.example.com + config: | + { + "bearerToken": "", + "tlsClientConfig": { + "insecure": false, + "caData": "" + } + } +``` + With project-scoped clusters we can also restrict projects to only allow applications whose destinations belong to the same project. The default behavior allows for applications to be installed onto clusters which are not a part of the same project, as the example below demonstrates: diff --git a/docs/user-guide/resource_hooks.md b/docs/user-guide/resource_hooks.md index d705f8d21423d..6e15a55bb20c2 100644 --- a/docs/user-guide/resource_hooks.md +++ b/docs/user-guide/resource_hooks.md @@ -8,7 +8,9 @@ and after a Sync operation. Hooks can also be run if a Sync operation fails at a * Using a `Sync` hook to orchestrate a complex deployment requiring more sophistication than the Kubernetes rolling update strategy. * Using a `PostSync` hook to run integration and health checks after a deployment. -* Using a `SyncFail` hook to run clean-up or finalizer logic if a Sync operation fails. _`SyncFail` hooks are only available starting in v1.2_ +* Using a `SyncFail` hook to run clean-up or finalizer logic if a Sync operation fails. +* Using a `PostDelete` hook to run clean-up or finalizer logic after all Application resources are deleted. Please note that + `PostDelete` hooks are only deleted if the delete policy matches the aggregated deletion hooks status and not garbage collected after the application is deleted. ## Usage @@ -37,7 +39,8 @@ The following hooks are defined: | `Sync` | Executes after all `PreSync` hooks completed and were successful, at the same time as the application of the manifests. | | `Skip` | Indicates to Argo CD to skip the application of the manifest. | | `PostSync` | Executes after all `Sync` hooks completed and were successful, a successful application, and all resources in a `Healthy` state. | -| `SyncFail` | Executes when the sync operation fails. _Available starting in v1.2_ | +| `SyncFail` | Executes when the sync operation fails. | +| `PostDelete` | Executes after all Application resources are deleted. _Available starting in v2.10._ | ### Generate Name @@ -60,6 +63,7 @@ metadata: argocd.argoproj.io/hook: PostSync argocd.argoproj.io/hook-delete-policy: HookSucceeded ``` +Multiple hook delete policies can be specified as a comma separated list. The following policies define when the hook will be deleted. diff --git a/docs/user-guide/sync-options.md b/docs/user-guide/sync-options.md index 9afe031ba7469..985f9fcf3c974 100644 --- a/docs/user-guide/sync-options.md +++ b/docs/user-guide/sync-options.md @@ -29,7 +29,7 @@ The app will be out of sync if Argo CD expects a resource to be pruned. You may ## Disable Kubectl Validation -For a certain class of objects, it is necessary to `kubectl apply` them using the `--validate=false` flag. Examples of this are kubernetes types which uses `RawExtension`, such as [ServiceCatalog](https://github.com/kubernetes-incubator/service-catalog/blob/master/pkg/apis/servicecatalog/v1beta1/types.go#L497). You can do using this annotations: +For a certain class of objects, it is necessary to `kubectl apply` them using the `--validate=false` flag. Examples of this are Kubernetes types which uses `RawExtension`, such as [ServiceCatalog](https://github.com/kubernetes-incubator/service-catalog/blob/master/pkg/apis/servicecatalog/v1beta1/types.go#L497). You can do using this annotations: ```yaml @@ -270,7 +270,7 @@ spec: - RespectIgnoreDifferences=true ``` -The example above shows how an Argo CD Application can be configured so it will ignore the `spec.replicas` field from the desired state (git) during the sync stage. This is achieve by calculating and pre-patching the desired state before applying it in the cluster. Note that the `RespectIgnoreDifferences` sync option is only effective when the resource is already created in the cluster. If the Application is being created and no live state exists, the desired state is applied as-is. +The example above shows how an Argo CD Application can be configured so it will ignore the `spec.replicas` field from the desired state (git) during the sync stage. This is achieved by calculating and pre-patching the desired state before applying it in the cluster. Note that the `RespectIgnoreDifferences` sync option is only effective when the resource is already created in the cluster. If the Application is being created and no live state exists, the desired state is applied as-is. ## Create Namespace @@ -339,51 +339,11 @@ spec: - CreateNamespace=true ``` -In the case where Argo CD is "adopting" an existing namespace which already has metadata set on it, we rely on using -Server Side Apply in order not to lose metadata which has already been set. The main implication here is that it takes -a few extra steps to get rid of an already preexisting field. - -Imagine we have a pre-existing namespace as below: - -```yaml -apiVersion: v1 -kind: Namespace -metadata: - name: foobar - annotations: - foo: bar - abc: "123" -``` - -If we want to manage the `foobar` namespace with Argo CD and to then also remove the `foo: bar` annotation, in -`managedNamespaceMetadata` we'd need to first rename the `foo` value: - -```yaml -apiVersion: argoproj.io/v1alpha1 -kind: Application -spec: - syncPolicy: - managedNamespaceMetadata: - annotations: - abc: 123 # adding this is informational with SSA; this would be sticking around in any case until we set a new value - foo: remove-me - syncOptions: - - CreateNamespace=true -``` - -Once that has been synced, we're ok to remove `foo` - -```yaml -apiVersion: argoproj.io/v1alpha1 -kind: Application -spec: - syncPolicy: - managedNamespaceMetadata: - annotations: - abc: 123 # adding this is informational with SSA; this would be sticking around in any case until we set a new value - syncOptions: - - CreateNamespace=true -``` +In the case where Argo CD is "adopting" an existing namespace which already has metadata set on it, you should first +[upgrade the resource to server-side apply](https://kubernetes.io/docs/reference/using-api/server-side-apply/#upgrading-from-client-side-apply-to-server-side-apply) +before enabling `managedNamespaceMetadata`. Argo CD relies on `kubectl`, which does not support managing +client-side-applied resources with server-side-applies. If you do not upgrade the resource to server-side apply, Argo CD +may remove existing labels/annotations, which may or may not be the desired behavior. Another thing to keep mind of is that if you have a k8s manifest for the same namespace in your Argo CD application, that will take precedence and *overwrite whatever values that have been set in `managedNamespaceMetadata`*. In other words, if diff --git a/docs/user-guide/sync-waves.md b/docs/user-guide/sync-waves.md index 932ba396d68d2..8b17237c87571 100644 --- a/docs/user-guide/sync-waves.md +++ b/docs/user-guide/sync-waves.md @@ -37,7 +37,7 @@ Hooks and resources are assigned to wave zero by default. The wave can be negati When Argo CD starts a sync, it orders the resources in the following precedence: * The phase -* The wave they are in (lower values first) +* The wave they are in (lower values first for creation & updation and higher values first for deletion) * By kind (e.g. [namespaces first and then other Kubernetes resources, followed by custom resources](https://github.com/argoproj/gitops-engine/blob/bc9ce5764fa306f58cf59199a94f6c968c775a2d/pkg/sync/sync_tasks.go#L27-L66)) * By name @@ -49,6 +49,8 @@ It repeats this process until all phases and waves are in-sync and healthy. Because an application can have resources that are unhealthy in the first wave, it may be that the app can never get to healthy. +During pruning of resources, resources from higher waves are processed first before moving to lower waves. If, for any reason, a resource isn't removed/pruned in a wave, the resources in next waves won't be processed. This is to ensure proper resource cleanup between waves. + Note that there's currently a delay between each sync wave in order give other controllers a chance to react to the spec change that we just applied. This also prevent Argo CD from assessing resource health too quickly (against the stale object), causing hooks to fire prematurely. The current delay between each sync wave is 2 seconds and can be configured via environment diff --git a/docs/user-guide/sync_windows.md b/docs/user-guide/sync_windows.md index 031d8e6d67b30..f6bc6b82f8b69 100644 --- a/docs/user-guide/sync_windows.md +++ b/docs/user-guide/sync_windows.md @@ -64,6 +64,7 @@ spec: manualSync: true - kind: deny schedule: '0 22 * * *' + timeZone: "Europe/Amsterdam" duration: 1h namespaces: - default diff --git a/examples/k8s-rbac/argocd-server-applications/argocd-notifications-controller-rbac-clusterrole.yaml b/examples/k8s-rbac/argocd-server-applications/argocd-notifications-controller-rbac-clusterrole.yaml index 05f92abb11717..ecbf6de3efb01 100644 --- a/examples/k8s-rbac/argocd-server-applications/argocd-notifications-controller-rbac-clusterrole.yaml +++ b/examples/k8s-rbac/argocd-server-applications/argocd-notifications-controller-rbac-clusterrole.yaml @@ -16,4 +16,13 @@ rules: - list - watch - update - - patch \ No newline at end of file + - patch +- apiGroups: + - "" + resources: + - secrets + - configmaps + verbs: + - get + - list + - watch \ No newline at end of file diff --git a/examples/plugins/helm/get-parameters.sh b/examples/plugins/helm/get-parameters.sh index d89c29c46656e..5e7823a7c8c72 100755 --- a/examples/plugins/helm/get-parameters.sh +++ b/examples/plugins/helm/get-parameters.sh @@ -1,8 +1,8 @@ #!/bin/sh -yq e -o=json values.yaml | jq '{ +yq e -o=json values.yaml | jq '[{ name: "helm-parameters", title: "Helm Parameters", collectionType: "map", map: [leaf_paths as $path | {"key": $path | join("."), "value": getpath($path)|tostring}] | from_entries -}' +}]' diff --git a/go.mod b/go.mod index 3bc74be5d54de..cb024e3183404 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,8 @@ module github.com/argoproj/argo-cd/v2 -go 1.19 +go 1.21 + +toolchain go1.21.0 require ( code.gitea.io/sdk/gitea v0.15.1 @@ -11,22 +13,25 @@ require ( github.com/TomOnTime/utfutil v0.0.0-20180511104225-09c41003ee1d github.com/alicebob/miniredis/v2 v2.30.4 github.com/antonmedv/expr v1.15.2 - github.com/argoproj/gitops-engine v0.7.1-0.20230929203505-a00ce82f1c17 - github.com/argoproj/notifications-engine v0.4.1-0.20230905144632-9dcecdc3eebf + github.com/argoproj/gitops-engine v0.7.1-0.20240124052710-5fd9f449e757 + github.com/argoproj/notifications-engine v0.4.1-0.20240206192038-2daee6022f41 github.com/argoproj/pkg v0.13.7-0.20230626144333-d56162821bd1 - github.com/aws/aws-sdk-go v1.44.317 + github.com/aws/aws-sdk-go v1.50.8 github.com/bmatcuk/doublestar/v4 v4.6.0 github.com/bombsimon/logrusr/v2 v2.0.1 github.com/bradleyfalzon/ghinstallation/v2 v2.6.0 github.com/casbin/casbin/v2 v2.77.2 + github.com/cespare/xxhash/v2 v2.2.0 github.com/coreos/go-oidc/v3 v3.6.0 github.com/cyphar/filepath-securejoin v0.2.4 github.com/dustin/go-humanize v1.0.1 - github.com/evanphx/json-patch v5.6.0+incompatible + github.com/evanphx/json-patch v5.9.0+incompatible + github.com/felixge/httpsnoop v1.0.3 github.com/fsnotify/fsnotify v1.6.0 github.com/gfleury/go-bitbucket-v1 v0.0.0-20220301131131-8e7ed04b843e - github.com/go-git/go-git/v5 v5.8.1 - github.com/go-logr/logr v1.2.4 + github.com/go-git/go-git/v5 v5.11.0 + github.com/go-jose/go-jose/v3 v3.0.1 + github.com/go-logr/logr v1.3.0 github.com/go-openapi/loads v0.21.2 github.com/go-openapi/runtime v0.26.0 github.com/go-playground/webhooks/v6 v6.3.0 @@ -36,11 +41,11 @@ require ( github.com/gogo/protobuf v1.3.2 github.com/golang-jwt/jwt/v4 v4.5.0 github.com/golang/protobuf v1.5.3 - github.com/google/go-cmp v0.5.9 + github.com/google/go-cmp v0.6.0 github.com/google/go-github/v35 v35.3.0 github.com/google/go-jsonnet v0.20.0 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 - github.com/google/uuid v1.3.0 + github.com/google/uuid v1.3.1 github.com/gorilla/handlers v1.5.1 github.com/gorilla/websocket v1.5.0 github.com/gosimple/slug v1.13.1 @@ -74,34 +79,33 @@ require ( github.com/xanzy/go-gitlab v0.91.1 github.com/yuin/gopher-lua v1.1.0 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0 - go.opentelemetry.io/otel v1.16.0 - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0 - go.opentelemetry.io/otel/sdk v1.16.0 - golang.org/x/crypto v0.14.0 + go.opentelemetry.io/otel v1.21.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 + go.opentelemetry.io/otel/sdk v1.21.0 + golang.org/x/crypto v0.17.0 golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 golang.org/x/oauth2 v0.11.0 golang.org/x/sync v0.3.0 - golang.org/x/term v0.13.0 - google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 - google.golang.org/grpc v1.58.3 + golang.org/x/term v0.15.0 + google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d + google.golang.org/grpc v1.59.0 google.golang.org/protobuf v1.31.0 - gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 - k8s.io/api v0.24.2 - k8s.io/apiextensions-apiserver v0.24.2 - k8s.io/apimachinery v0.24.2 - k8s.io/apiserver v0.24.2 - k8s.io/client-go v0.24.2 - k8s.io/code-generator v0.24.2 - k8s.io/klog/v2 v2.70.1 - k8s.io/kube-openapi v0.0.0-20220627174259-011e075b9cb8 - k8s.io/kubectl v0.24.2 - k8s.io/utils v0.0.0-20220706174534-f6158b442e7c + k8s.io/api v0.26.11 + k8s.io/apiextensions-apiserver v0.26.4 + k8s.io/apimachinery v0.26.11 + k8s.io/apiserver v0.26.11 + k8s.io/client-go v0.26.11 + k8s.io/code-generator v0.26.11 + k8s.io/klog/v2 v2.100.1 + k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f + k8s.io/kubectl v0.26.4 + k8s.io/utils v0.0.0-20230220204549-a5ecb0141aa5 layeh.com/gopher-json v0.0.0-20190114024228-97fed8db8427 oras.land/oras-go/v2 v2.3.0 - sigs.k8s.io/controller-runtime v0.11.0 - sigs.k8s.io/structured-merge-diff/v4 v4.3.0 + sigs.k8s.io/controller-runtime v0.14.6 + sigs.k8s.io/structured-merge-diff/v4 v4.4.1 sigs.k8s.io/yaml v1.3.0 ) @@ -111,34 +115,40 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 // indirect github.com/AzureAD/microsoft-authentication-library-for-go v0.5.2 // indirect - github.com/aws/aws-sdk-go-v2 v1.17.3 // indirect - github.com/aws/aws-sdk-go-v2/config v1.18.8 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.13.8 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.21 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.27 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.21 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.3.28 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.21 // indirect - github.com/aws/aws-sdk-go-v2/service/sqs v1.20.0 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.12.0 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.0 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.18.0 // indirect - github.com/aws/smithy-go v1.13.5 // indirect + github.com/aws/aws-sdk-go-v2 v1.24.1 // indirect + github.com/aws/aws-sdk-go-v2/config v1.25.12 // 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.1 // 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/sqs v1.29.7 // 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/golang-jwt/jwt v3.2.2+incompatible // indirect + github.com/google/s2a-go v0.1.4 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.2.5 // indirect + github.com/googleapis/gax-go/v2 v2.12.0 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect github.com/tidwall/gjson v1.14.4 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect - google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect + go.opencensus.io v0.24.0 // indirect + google.golang.org/api v0.132.0 // indirect + google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect gopkg.in/retry.v1 v1.0.3 // indirect k8s.io/klog v1.0.0 // indirect nhooyr.io/websocket v1.8.7 // indirect ) require ( - cloud.google.com/go/compute v1.21.0 // indirect + cloud.google.com/go/compute v1.23.0 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect @@ -147,47 +157,45 @@ require ( github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect github.com/Azure/go-autorest/logger v0.2.1 // indirect github.com/Azure/go-autorest/tracing v0.6.0 // indirect - github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd // indirect + github.com/MakeNowJust/heredoc v1.0.0 // indirect github.com/Masterminds/goutils v1.1.1 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect github.com/PagerDuty/go-pagerduty v1.7.0 // indirect - github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95 // indirect + github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect github.com/RocketChat/Rocket.Chat.Go.SDK v0.0.0-20210112200207-10ab4d695d60 // indirect - github.com/acomagu/bufpipe v1.0.4 // indirect github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/beorn7/perks v1.0.1 // indirect + github.com/blang/semver/v4 v4.0.0 // indirect github.com/cenkalti/backoff/v4 v4.2.1 // indirect - github.com/cespare/xxhash/v2 v2.2.0 - github.com/chai2010/gettext-go v0.0.0-20170215093142-bf70f2a70fb1 // indirect + github.com/chai2010/gettext-go v1.0.2 // indirect github.com/cloudflare/circl v1.3.3 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/docker/distribution v2.8.2+incompatible // indirect - github.com/emicklei/go-restful/v3 v3.8.0 // indirect + github.com/emicklei/go-restful/v3 v3.9.0 // indirect github.com/emirpasic/gods v1.18.1 // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect github.com/fatih/camelcase v1.0.0 // indirect - github.com/felixge/httpsnoop v1.0.3 // indirect github.com/fvbommel/sortorder v1.0.1 // indirect github.com/ghodss/yaml v1.0.0 // 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.4.1 // indirect - github.com/go-jose/go-jose/v3 v3.0.0 // indirect + github.com/go-git/go-billy/v5 v5.5.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/analysis v0.21.4 // indirect github.com/go-openapi/errors v0.20.3 // indirect - github.com/go-openapi/jsonpointer v0.19.5 // indirect - github.com/go-openapi/jsonreference v0.20.0 // indirect + github.com/go-openapi/jsonpointer v0.19.6 // indirect + github.com/go-openapi/jsonreference v0.20.1 // indirect github.com/go-openapi/spec v0.20.8 // indirect github.com/go-openapi/strfmt v0.21.7 // indirect github.com/go-openapi/swag v0.22.3 // indirect github.com/go-openapi/validate v0.22.1 // indirect github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1 // indirect - github.com/golang/glog v1.1.0 // indirect + github.com/golang/glog v1.1.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/google/btree v1.1.2 // indirect github.com/google/gnostic v0.6.9 // indirect @@ -198,7 +206,7 @@ require ( github.com/gosimple/unidecode v1.0.1 // indirect github.com/gregdel/pushover v1.2.1 // indirect github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-version v1.2.1 // indirect github.com/huandu/xstrings v1.3.3 // indirect @@ -221,7 +229,7 @@ require ( github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/reflectwalk v1.0.0 // indirect github.com/moby/spdystream v0.2.0 // indirect - github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect + github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae // indirect 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 @@ -234,16 +242,15 @@ require ( github.com/pjbgf/sha1cd v0.3.0 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_model v0.3.0 // indirect + github.com/prometheus/client_model v0.3.0 github.com/prometheus/common v0.42.0 // indirect github.com/prometheus/procfs v0.10.1 // indirect github.com/rivo/uniseg v0.4.4 // indirect - github.com/rs/cors v1.8.0 // indirect - github.com/russross/blackfriday v1.6.0 // indirect + github.com/rs/cors v1.9.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sergi/go-diff v1.1.0 // indirect github.com/shopspring/decimal v1.2.0 // indirect - github.com/skeema/knownhosts v1.2.0 // indirect + github.com/skeema/knownhosts v1.2.1 // indirect github.com/slack-go/slack v0.12.2 // indirect github.com/spf13/cast v1.5.1 // indirect github.com/stretchr/objx v0.5.0 // indirect @@ -254,18 +261,17 @@ require ( github.com/xanzy/ssh-agent v0.3.3 // indirect github.com/xlab/treeprint v1.1.0 // indirect go.mongodb.org/mongo-driver v1.11.3 // indirect - go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0 // indirect - go.opentelemetry.io/otel/metric v1.16.0 // indirect - go.opentelemetry.io/otel/trace v1.16.0 // indirect - go.opentelemetry.io/proto/otlp v0.19.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 // indirect + go.opentelemetry.io/otel/metric v1.21.0 // indirect + go.opentelemetry.io/otel/trace v1.21.0 // indirect + go.opentelemetry.io/proto/otlp v1.0.0 // indirect go.starlark.net v0.0.0-20220328144851-d1966c6b9fcd // indirect - golang.org/x/mod v0.9.0 // indirect - golang.org/x/net v0.17.0 // indirect - golang.org/x/sys v0.13.0 // indirect - golang.org/x/text v0.13.0 // indirect - golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.7.0 // indirect + golang.org/x/mod v0.12.0 // indirect + golang.org/x/net v0.19.0 + golang.org/x/sys v0.15.0 // indirect + golang.org/x/text v0.14.0 // indirect + golang.org/x/time v0.3.0 + golang.org/x/tools v0.13.0 // indirect gomodules.xyz/envconfig v1.3.1-0.20190308184047-426f31af0d45 // indirect gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect gomodules.xyz/notify v0.1.1 // indirect @@ -274,19 +280,18 @@ require ( gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect - k8s.io/cli-runtime v0.24.2 // indirect - k8s.io/component-base v0.24.2 // indirect - k8s.io/component-helpers v0.24.2 // indirect - k8s.io/gengo v0.0.0-20211129171323-c02415ce4185 // indirect - k8s.io/kube-aggregator v0.24.2 // indirect - k8s.io/kubernetes v1.24.2 // indirect - sigs.k8s.io/json v0.0.0-20220525155127-227cbc7cc124 // indirect - sigs.k8s.io/kustomize/api v0.11.5 // indirect - sigs.k8s.io/kustomize/kyaml v0.13.7 // indirect + k8s.io/cli-runtime v0.26.11 // indirect + k8s.io/component-base v0.26.11 // indirect + k8s.io/component-helpers v0.26.11 // indirect + k8s.io/gengo v0.0.0-20220902162205-c0856e24416d // indirect + k8s.io/kube-aggregator v0.26.4 // indirect + k8s.io/kubernetes v1.26.11 // indirect + sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect + sigs.k8s.io/kustomize/api v0.12.1 // indirect + sigs.k8s.io/kustomize/kyaml v0.13.9 // indirect ) replace ( - github.com/antonmedv/expr => github.com/expr-lang/expr v0.0.0-20230912141041-709c5dd55aa7 // https://github.com/golang/go/issues/33546#issuecomment-519656923 github.com/go-check/check => github.com/go-check/check v0.0.0-20180628173108-788fd7840127 @@ -299,30 +304,34 @@ replace ( // Avoid CVE-2022-28948 gopkg.in/yaml.v3 => gopkg.in/yaml.v3 v3.0.1 - // https://github.com/kubernetes/kubernetes/issues/79384#issuecomment-505627280 - k8s.io/api => k8s.io/api v0.24.2 - k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.24.2 - k8s.io/apimachinery => k8s.io/apimachinery v0.24.2 - k8s.io/apiserver => k8s.io/apiserver v0.24.2 - k8s.io/cli-runtime => k8s.io/cli-runtime v0.24.2 - k8s.io/client-go => k8s.io/client-go v0.24.2 - k8s.io/cloud-provider => k8s.io/cloud-provider v0.24.2 - k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.24.2 - k8s.io/code-generator => k8s.io/code-generator v0.24.2 - k8s.io/component-base => k8s.io/component-base v0.24.2 - k8s.io/component-helpers => k8s.io/component-helpers v0.24.2 - k8s.io/controller-manager => k8s.io/controller-manager v0.24.2 - k8s.io/cri-api => k8s.io/cri-api v0.24.2 - k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.24.2 - k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.24.2 - k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.24.2 - k8s.io/kube-proxy => k8s.io/kube-proxy v0.24.2 - k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.24.2 - k8s.io/kubectl => k8s.io/kubectl v0.24.2 - k8s.io/kubelet => k8s.io/kubelet v0.24.2 - k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.24.2 - k8s.io/metrics => k8s.io/metrics v0.24.2 - k8s.io/mount-utils => k8s.io/mount-utils v0.24.2 - k8s.io/pod-security-admission => k8s.io/pod-security-admission v0.24.2 - k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.24.2 + k8s.io/api => k8s.io/api v0.26.11 + k8s.io/apiextensions-apiserver => k8s.io/apiextensions-apiserver v0.26.11 + k8s.io/apimachinery => k8s.io/apimachinery v0.26.11 + k8s.io/apiserver => k8s.io/apiserver v0.26.11 + k8s.io/cli-runtime => k8s.io/cli-runtime v0.26.11 + k8s.io/client-go => k8s.io/client-go v0.26.11 + k8s.io/cloud-provider => k8s.io/cloud-provider v0.26.11 + k8s.io/cluster-bootstrap => k8s.io/cluster-bootstrap v0.26.11 + k8s.io/code-generator => k8s.io/code-generator v0.26.11 + k8s.io/component-base => k8s.io/component-base v0.26.11 + k8s.io/component-helpers => k8s.io/component-helpers v0.26.11 + k8s.io/controller-manager => k8s.io/controller-manager v0.26.11 + k8s.io/cri-api => k8s.io/cri-api v0.26.11 + k8s.io/csi-translation-lib => k8s.io/csi-translation-lib v0.26.11 + k8s.io/dynamic-resource-allocation => k8s.io/dynamic-resource-allocation v0.26.11 + k8s.io/kms => k8s.io/kms v0.26.11 + k8s.io/kube-aggregator => k8s.io/kube-aggregator v0.26.11 + k8s.io/kube-controller-manager => k8s.io/kube-controller-manager v0.26.11 + k8s.io/kube-proxy => k8s.io/kube-proxy v0.26.11 + k8s.io/kube-scheduler => k8s.io/kube-scheduler v0.26.11 + k8s.io/kubectl => k8s.io/kubectl v0.26.11 + k8s.io/kubelet => k8s.io/kubelet v0.26.11 + k8s.io/legacy-cloud-providers => k8s.io/legacy-cloud-providers v0.26.11 + k8s.io/metrics => k8s.io/metrics v0.26.11 + k8s.io/mount-utils => k8s.io/mount-utils v0.26.11 + k8s.io/pod-security-admission => k8s.io/pod-security-admission v0.26.11 + k8s.io/sample-apiserver => k8s.io/sample-apiserver v0.26.11 + k8s.io/sample-cli-plugin => k8s.io/sample-cli-plugin v0.26.11 + k8s.io/sample-controller => k8s.io/sample-controller v0.26.11 + ) diff --git a/go.sum b/go.sum index 6945483f1f5a2..2d33e5a248cce 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,3 @@ -bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= -bitbucket.org/bertimus9/systemstat v0.0.0-20180207000608-0eeff89b0690/go.mod h1:Ulb78X89vxKYgdL24HMTiXYHlyHEvruOj1ZPlqeNEZM= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= @@ -176,8 +174,8 @@ cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOV cloud.google.com/go/compute v1.19.0/go.mod h1:rikpw2y+UMidAe9tISo04EHNOIf42RLYF/q8Bs93scU= cloud.google.com/go/compute v1.19.3/go.mod h1:qxvISKp/gYnXkSAD1ppcSOveRAmzxicEv/JlizULFrI= cloud.google.com/go/compute v1.20.1/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= -cloud.google.com/go/compute v1.21.0 h1:JNBsyXVoOoNJtTQcnEY5uYpZIbeCTYIeDe0Xh1bySMk= -cloud.google.com/go/compute v1.21.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= +cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY= +cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM= cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU= cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= @@ -277,7 +275,6 @@ cloud.google.com/go/filestore v1.3.0/go.mod h1:+qbvHGvXU1HaKX2nD0WEPo92TP/8AQuCV cloud.google.com/go/filestore v1.4.0/go.mod h1:PaG5oDfo9r224f8OYXURtAsY+Fbyq/bLYoINEK8XQAI= cloud.google.com/go/filestore v1.5.0/go.mod h1:FqBXDWBp4YLHqRnVGveOkHDf8svj9r5+mUDLupOWEDs= cloud.google.com/go/filestore v1.6.0/go.mod h1:di5unNuss/qfZTw2U9nhFqo8/ZDSc466dre85Kydllg= -cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= cloud.google.com/go/firestore v1.9.0/go.mod h1:HMkjKHNTtRyZNiMzu7YAsLr9K3X2udY2AMwDaMEQiiE= cloud.google.com/go/functions v1.6.0/go.mod h1:3H1UA3qiIPRWD7PeZKLvHZ9SaQhR26XIJcC0A5GbvAk= cloud.google.com/go/functions v1.7.0/go.mod h1:+d+QBcWM+RsrgZfV9xo6KfA1GlzJfxcfZcRPEhDDfzg= @@ -606,10 +603,8 @@ code.gitea.io/sdk/gitea v0.15.1/go.mod h1:klY2LVI3s3NChzIk/MzMn7G1FHrfU7qd63iSMV dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20201218220906-28db891af037/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8= git.sr.ht/~sbinet/gg v0.3.1/go.mod h1:KGYtlADtqsqANL9ueOFkWymvzUvLMQllU5Ixo+8v3pc= -github.com/Azure/azure-sdk-for-go v55.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.1 h1:tz19qLF65vuu2ibfTqGVJxG/zZAI27NEIIbvAOQwYbw= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.1/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.1.0 h1:QkAcEIAKbNL4KoFr4SathZPhDhF4mVwpBMFlYjyAqy8= @@ -620,10 +615,8 @@ github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOEl github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= github.com/Azure/go-autorest/autorest v0.11.27 h1:F3R3q42aWytozkV8ihzcgMO4OA4cuqr3bNlsEuF6//A= github.com/Azure/go-autorest/autorest v0.11.27/go.mod h1:7l8ybrIdUmGqZMTD0sRtAr8NvbHjfofbf8RSP2q7w7U= -github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= github.com/Azure/go-autorest/autorest/adal v0.9.18/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ= github.com/Azure/go-autorest/autorest/adal v0.9.20 h1:gJ3E98kMpFB1MFqQCvA1yFab8vthOeD4VlFRQULxahg= github.com/Azure/go-autorest/autorest/adal v0.9.20/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ= @@ -632,8 +625,6 @@ github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSY github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= github.com/Azure/go-autorest/autorest/mocks v0.4.2 h1:PGN4EDXnuQbojHbU0UWoNvmu9AGVwYHG9/fkDYhtAfw= github.com/Azure/go-autorest/autorest/mocks v0.4.2/go.mod h1:Vy7OitM9Kei0i1Oj+LvyAWMXJHeKH1MVlzFugfVrmyU= -github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE= -github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8= github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg= github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= @@ -644,15 +635,13 @@ github.com/AzureAD/microsoft-authentication-library-for-go v0.5.2 h1:BGX4OiGP9ht github.com/AzureAD/microsoft-authentication-library-for-go v0.5.2/go.mod h1:Vt9sXTKwMyGcOxSmLDMnGPgqsUg7m8pe215qMLrDXw4= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/GoogleCloudPlatform/k8s-cloud-provider v1.16.1-0.20210702024009-ea6160c1d0e3/go.mod h1:8XasY4ymP2V/tn2OOV9ZadmiTE1FIB/h3W+yNlPttKw= -github.com/JeffAshton/win_pdh v0.0.0-20161109143554-76bb4ee9f0ab/go.mod h1:3VYc5hodBMJ5+l/7J4xAyMeuM2PNuepvHlGs8yilUCA= github.com/Jeffail/gabs v1.4.0 h1://5fYRRTq1edjfIrQGvdkcd22pkYUrHZ5YC/H2GJVAo= github.com/Jeffail/gabs v1.4.0/go.mod h1:6xMvQMK4k33lb7GUUpaAPh6nKMmemQeg5d4gn7/bOXc= github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible h1:1G1pk05UrOh0NlF1oeaaix1x8XzrfjIDK47TY0Zehcw= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= -github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd h1:sjQovDkwrZp8u+gxLtPgKGjk5hCxuy2hrRejBTA9xFU= -github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E= +github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= +github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= @@ -660,20 +649,16 @@ github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0 github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= -github.com/Microsoft/go-winio v0.4.15/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= -github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= -github.com/Microsoft/hcsshim v0.8.22/go.mod h1:91uVCVzvX2QD16sMCenoxxXo6L1wJnLMX2PSufFMtF0= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= -github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/PagerDuty/go-pagerduty v1.7.0 h1:S1NcMKECxT5hJwV4VT+QzeSsSiv4oWl1s2821dUqG/8= github.com/PagerDuty/go-pagerduty v1.7.0/go.mod h1:PuFyJKRz1liIAH4h5KVXVD18Obpp1ZXRdxHvmGXooro= github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8/go.mod h1:I0gYDMZ6Z5GRU7l58bNFSkPTFN6Yl12dsUlAZ8xy98g= -github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95 h1:KLq8BE0KwCL+mmXnjLWEAOYO+2l2AE4YMmqG1ZpZHBs= -github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= +github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 h1:kkhsdkhsCvIsutKu5zLMgWtgh9YxGCNAw8Ad8hjwfYg= +github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/RocketChat/Rocket.Chat.Go.SDK v0.0.0-20210112200207-10ab4d695d60 h1:prBTRx78AQnXzivNT9Crhu564W/zPPr3ibSlpT9xKcE= @@ -683,8 +668,6 @@ github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMx github.com/TomOnTime/utfutil v0.0.0-20180511104225-09c41003ee1d h1:WtAMR0fPCOfK7TPGZ8ZpLLY18HRvL7XJ3xcs0wnREgo= github.com/TomOnTime/utfutil v0.0.0-20180511104225-09c41003ee1d/go.mod h1:WML6KOYjeU8N6YyusMjj2qRvaPNUEvrQvaxuFcMRFJY= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= -github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ= -github.com/acomagu/bufpipe v1.0.4/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= @@ -701,22 +684,23 @@ github.com/alicebob/miniredis/v2 v2.30.4 h1:8S4/o1/KoUArAGbGwPxcwf0krlzceva2XVOS github.com/alicebob/miniredis/v2 v2.30.4/go.mod h1:b25qWj4fCEsBeAAR2mlb0ufImGC6uH3VlUfb/HS5zKg= github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= +github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210826220005-b48c857c3a0e/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY= +github.com/antonmedv/expr v1.15.2 h1:afFXpDWIC2n3bF+kTZE1JvFo+c34uaM3sTqh8z0xfdU= +github.com/antonmedv/expr v1.15.2/go.mod h1:0E/6TxnOlRNp81GMzX9QfDPAmHo2Phg00y4JUv1ihsE= github.com/apache/arrow/go/v10 v10.0.1/go.mod h1:YvhnlEePVnBS4+0z3fhPfUy7W1Ikj0Ih0vcRo/gZ1M0= github.com/apache/arrow/go/v11 v11.0.0/go.mod h1:Eg5OsL5H+e299f7u5ssuXsuHQVEGC4xei5aX110hRiI= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/apache/thrift v0.16.0/go.mod h1:PHK3hniurgQaNMZYaCLEqXKsYK8upmhPbmdP2FXSqgU= github.com/appscode/go v0.0.0-20191119085241-0887d8ec2ecc/go.mod h1:OawnOmAL4ZX3YaPdN+8HTNwBveT1jMsqP74moa9XUbE= -github.com/argoproj/gitops-engine v0.7.1-0.20230929203505-a00ce82f1c17 h1:PD2CJKPakR4u5hDsi6MG8gJUB4oj4Peltm7bGkn0Rfc= -github.com/argoproj/gitops-engine v0.7.1-0.20230929203505-a00ce82f1c17/go.mod h1:/GMN0JuoJUUpnKlNLp2Wn/mfK8sglFsdPn+eoxSddmg= -github.com/argoproj/notifications-engine v0.4.1-0.20230905144632-9dcecdc3eebf h1:4wliaBwd6iKvT/5huDTJntaYtTSdwPLs00SOQwDSK6A= -github.com/argoproj/notifications-engine v0.4.1-0.20230905144632-9dcecdc3eebf/go.mod h1:TuK0BNKo34DIUOyCCGOB9ij+smGCxeCgt9ZB+0fMWno= +github.com/argoproj/gitops-engine v0.7.1-0.20240124052710-5fd9f449e757 h1:5fKAhTQcTBom0vin56cz/UTPx2GMuvdb+lJRAUOPbHA= +github.com/argoproj/gitops-engine v0.7.1-0.20240124052710-5fd9f449e757/go.mod h1:gWE8uROi7hIkWGNAVM+8FWkMfo0vZ03SLx/aFw/DBzg= +github.com/argoproj/notifications-engine v0.4.1-0.20240206192038-2daee6022f41 h1:PQE8LbcbRHdtnQzeEWwVU2QHXACKOA30yS3No5HSoTQ= +github.com/argoproj/notifications-engine v0.4.1-0.20240206192038-2daee6022f41/go.mod h1:TsyusmXQWIL0ST7YMRG/ered7WlWDmbmnPpXnS2LJmM= github.com/argoproj/pkg v0.13.7-0.20230626144333-d56162821bd1 h1:qsHwwOJ21K2Ao0xPju1sNuqphyMnMYkyB3ZLoLtxWpo= github.com/argoproj/pkg v0.13.7-0.20230626144333-d56162821bd1/go.mod h1:CZHlkyAD1/+FbEn6cB2DQTj48IoLGvEYsWEvtzP3238= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= @@ -726,56 +710,51 @@ github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:l github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= -github.com/auth0/go-jwt-middleware v1.0.1/go.mod h1:YSeUX3z6+TF2H+7padiEqNJ73Zy9vXW72U//IgN0BIM= github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.35.24/go.mod h1:tlPOdRjfxPBpNIwqDj61rmsnA85v9jc0Ps9+muhnW+k= -github.com/aws/aws-sdk-go v1.38.49/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/aws/aws-sdk-go v1.44.289/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= -github.com/aws/aws-sdk-go v1.44.317 h1:+8XWrLmGMwPPXSRSLPzhgcGnzJ2mYkgkrcB9C/GnSOU= -github.com/aws/aws-sdk-go v1.44.317/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go v1.50.8 h1:gY0WoOW+/Wz6XmYSgDH9ge3wnAevYDSQWPxxJvqAkP4= +github.com/aws/aws-sdk-go v1.50.8/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= -github.com/aws/aws-sdk-go-v2 v1.17.3 h1:shN7NlnVzvDUgPQ+1rLMSxY8OWRNDRYtiqe0p/PgrhY= -github.com/aws/aws-sdk-go-v2 v1.17.3/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw= -github.com/aws/aws-sdk-go-v2/config v1.18.8 h1:lDpy0WM8AHsywOnVrOHaSMfpaiV2igOw8D7svkFkXVA= -github.com/aws/aws-sdk-go-v2/config v1.18.8/go.mod h1:5XCmmyutmzzgkpk/6NYTjeWb6lgo9N170m1j6pQkIBs= -github.com/aws/aws-sdk-go-v2/credentials v1.13.8 h1:vTrwTvv5qAwjWIGhZDSBH/oQHuIQjGmD232k01FUh6A= -github.com/aws/aws-sdk-go-v2/credentials v1.13.8/go.mod h1:lVa4OHbvgjVot4gmh1uouF1ubgexSCN92P6CJQpT0t8= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.21 h1:j9wi1kQ8b+e0FBVHxCqCGo4kxDU175hoDHcWAi0sauU= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.21/go.mod h1:ugwW57Z5Z48bpvUyZuaPy4Kv+vEfJWnIrky7RmkBvJg= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.27 h1:I3cakv2Uy1vNmmhRQmFptYDxOvBnwCdNwyw63N0RaRU= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.27/go.mod h1:a1/UpzeyBBerajpnP5nGZa9mGzsBn5cOKxm6NWQsvoI= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.21 h1:5NbbMrIzmUn/TXFqAle6mgrH5m9cOvMLRGL7pnG8tRE= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.21/go.mod h1:+Gxn8jYn5k9ebfHEqlhrMirFjSW0v0C9fI+KN5vk2kE= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.28 h1:KeTxcGdNnQudb46oOl4d90f2I33DF/c6q3RnZAmvQdQ= -github.com/aws/aws-sdk-go-v2/internal/ini v1.3.28/go.mod h1:yRZVr/iT0AqyHeep00SZ4YfBAKojXz08w3XMBscdi0c= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.21 h1:5C6XgTViSb0bunmU57b3CT+MhxULqHH2721FVA+/kDM= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.21/go.mod h1:lRToEJsn+DRA9lW4O9L9+/3hjTkUzlzyzHqn8MTds5k= -github.com/aws/aws-sdk-go-v2/service/sqs v1.20.0 h1:tQoMg8i4nFAB70cJ4wiAYEiZRYo2P6uDmU2D6ys/igo= -github.com/aws/aws-sdk-go-v2/service/sqs v1.20.0/go.mod h1:jQhN5f4p3PALMNlUtfb/0wGIFlV7vGtJlPDVfxfNfPY= -github.com/aws/aws-sdk-go-v2/service/sso v1.12.0 h1:/2gzjhQowRLarkkBOGPXSRnb8sQ2RVsjdG1C/UliK/c= -github.com/aws/aws-sdk-go-v2/service/sso v1.12.0/go.mod h1:wo/B7uUm/7zw/dWhBJ4FXuw1sySU5lyIhVg1Bu2yL9A= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.0 h1:Jfly6mRxk2ZOSlbCvZfKNS7TukSx1mIzhSsqZ/IGSZI= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.0/go.mod h1:TZSH7xLO7+phDtViY/KUp9WGCJMQkLJ/VpgkTFd5gh8= -github.com/aws/aws-sdk-go-v2/service/sts v1.18.0 h1:kOO++CYo50RcTFISESluhWEi5Prhg+gaSs4whWabiZU= -github.com/aws/aws-sdk-go-v2/service/sts v1.18.0/go.mod h1:+lGbb3+1ugwKrNTWcf2RT05Xmp543B06zDFTwiTLp7I= -github.com/aws/smithy-go v1.13.5 h1:hgz0X/DX0dGqTYpGALqXJoRKRj5oQ7150i5FdTePzO8= -github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= +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.25.12 h1:mF4cMuNh/2G+d19nWnm1vJ/ak0qK6SbqF0KtSX9pxu0= +github.com/aws/aws-sdk-go-v2/config v1.25.12/go.mod h1:lOvvqtZP9p29GIjOTuA/76HiVk0c/s8qRcFRq2+E2uc= +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/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/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.1 h1:uR9lXYjdPX0xY+NhvaJ4dD8rpSRz5VY81ccIIoNG+lw= +github.com/aws/aws-sdk-go-v2/internal/ini v1.7.1/go.mod h1:6fQQgfuGmw8Al/3M2IgIllycxV7ZW7WCdVSqfBeUiCY= +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/sqs v1.29.7 h1:tRNrFDGRm81e6nTX5Q4CFblea99eAfm0dxXazGpLceU= +github.com/aws/aws-sdk-go-v2/service/sqs v1.29.7/go.mod h1:8GWUDux5Z2h6z2efAtr54RdHXtLm8sq7Rg85ZNY/CZM= +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/smithy-go v1.19.0 h1:KWFKQV80DpP3vJrrA9sVAHQ5gc2z8i4EzrLhLlWXcBM= +github.com/aws/smithy-go v1.19.0/go.mod h1:NukqUGpCZIILqqiV0NIjeFh24kd/FAa4beRb6nbIUPE= github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg= -github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= -github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= -github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/bmatcuk/doublestar/v4 v4.6.0 h1:HTuxyug8GyFbRkrffIpzNCSK4luc0TY3wzXvzIZhEXc= github.com/bmatcuk/doublestar/v4 v4.6.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= -github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= github.com/bombsimon/logrusr/v2 v2.0.1 h1:1VgxVNQMCvjirZIYaT9JYn6sAVGVEcNtRE0y4mvaOAM= github.com/bombsimon/logrusr/v2 v2.0.1/go.mod h1:ByVAX+vHdLGAfdroiMg6q0zgq2FODY2lc5YJvzmOJio= github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= @@ -783,7 +762,9 @@ github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl github.com/bradleyfalzon/ghinstallation/v2 v2.6.0 h1:IRY7Xy588KylkoycsUhFpW7cdGpy5Y5BPsz4IfuJtGk= github.com/bradleyfalzon/ghinstallation/v2 v2.6.0/go.mod h1:oQ3etOwN3TRH4EwgW5/7MxSVMGlMlzG/O8TU7eYdoSk= github.com/bsm/ginkgo/v2 v2.7.0 h1:ItPMPH90RbmZJt5GtkcNvIRuGEdwlBItdNVoyzaNQao= +github.com/bsm/ginkgo/v2 v2.7.0/go.mod h1:AiKlXPm7ItEHNc/2+OkrNG4E0ITzojb9/xWzvQ9XZ9w= github.com/bsm/gomega v1.26.0 h1:LhQm+AFcgV2M0WyKroMASzAzCAJVpAxQXv4SaI9a69Y= +github.com/bsm/gomega v1.26.0/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= @@ -799,28 +780,20 @@ github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyY 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/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= -github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= -github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw= -github.com/chai2010/gettext-go v0.0.0-20170215093142-bf70f2a70fb1 h1:HD4PLRzjuCVW79mQ0/pdsalOLHJ+FaEoqJLxfltpb2U= -github.com/chai2010/gettext-go v0.0.0-20170215093142-bf70f2a70fb1/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw= -github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= +github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk= +github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= -github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I= github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs= github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= -github.com/clusterhq/flocker-go v0.0.0-20160920122132-2b8b7259d313/go.mod h1:P1wt9Z3DP8O6W3rvwCt0REIlshg1InHImaLW0t3ObY0= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= @@ -835,73 +808,38 @@ github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20230310173818-32f1caf87195/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k= +github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= -github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo= -github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA= -github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27/go.mod h1:VQx0hjo2oUeQkQUET7wRwradO6f+fN5jzXgB/zROxxE= -github.com/container-storage-interface/spec v1.5.0/go.mod h1:8K96oQNkJ7pFcC2R9Z1ynGGBB1I93kcS6PGg3SsOk8s= -github.com/containerd/cgroups v1.0.1/go.mod h1:0SJrPIenamHDcZhEcJMNBB85rHcUsw4f25ZfBiPYRkU= -github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw= -github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ= -github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= -github.com/containerd/containerd v1.4.9/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/containerd v1.4.12/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/continuity v0.1.0/go.mod h1:ICJu0PwR54nI0yPEnJ6jcS+J7CZAUXrLh8lPo2knzsM= -github.com/containerd/fifo v1.0.0/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4= -github.com/containerd/go-runc v1.0.0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok= -github.com/containerd/ttrpc v1.0.2/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y= -github.com/containerd/typeurl v1.0.2/go.mod h1:9trJWW2sRlGub4wZJRTW83VtbOLS6hwcDZXTn6oPz9s= -github.com/coredns/caddy v1.1.0/go.mod h1:A6ntJQlAWuQfFlsd9hvigKbo2WS0VUs2l1e2F+BawD4= -github.com/coredns/corefile-migration v1.0.14/go.mod h1:XnhgULOEouimnzgn0t4WPuFDN2/PJQcTxdWKC5eXNGE= -github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= github.com/coreos/go-oidc/v3 v3.6.0 h1:AKVxfYw1Gmkn/w96z0DbT/B/xFnzTd3MkZvWLjF4n/o= github.com/coreos/go-oidc/v3 v3.6.0/go.mod h1:ZpHUsHBucTUj6WOkrP4E20UPynbLZzhTQ1XKCXkxyPc= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= -github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= 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.0/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.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw= github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE= github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f h1:U5y3Y5UE0w7amNe7Z5G/twsBW0KEalRQXZzf8ufSh9I= github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFMt8koVQZ6WFms69WAsDWr2XsYL3Hkl7jkoLE= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= -github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= github.com/dnaeon/go-vcr v1.1.0 h1:ReYa/UBrRyQdant9B4fNHGoCNKw6qh6P0fsdGmZpR7c= -github.com/docker/distribution v2.8.0+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v20.10.12+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= -github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= @@ -912,11 +850,11 @@ github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1 github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= -github.com/elazarl/goproxy v0.0.0-20221015165544-a0805db90819 h1:RIB4cRk+lBqKK3Oy0r2gRX4ui7tuhiZq2SuTtTCi0/0= -github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/emicklei/go-restful/v3 v3.8.0 h1:eCZ8ulSerjdAiaNpF7GxXIE7ZCMo1moN1qX+S609eVw= +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/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE= +github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= @@ -936,16 +874,15 @@ github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w= github.com/envoyproxy/protoc-gen-validate v0.10.0/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss= github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA= -github.com/euank/go-kmsg-parser v2.0.0+incompatible/go.mod h1:MhmAMZ8V4CYH4ybgdRwPr2TU5ThnS43puaKEMpja1uw= +github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE= github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= -github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= -github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v5.9.0+incompatible h1:fBXyNpNMuTTDdquAq/uisOr2lShz4oaXpDTX2bLe7ls= +github.com/evanphx/json-patch v5.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= -github.com/expr-lang/expr v0.0.0-20230912141041-709c5dd55aa7 h1:Sg2XxaymeyqqaLG34aB2mvlX+nii916/Gv1ovWc4jMc= -github.com/expr-lang/expr v0.0.0-20230912141041-709c5dd55aa7/go.mod h1:0E/6TxnOlRNp81GMzX9QfDPAmHo2Phg00y4JUv1ihsE= github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51/go.mod h1:Yg+htXGokKKdzcwhuNDwVvN+uBxDGXJ7G/VN1d8fa64= github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg= github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= @@ -956,35 +893,29 @@ github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSw github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM0rVwpMwimd3F3N0= -github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= -github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= -github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/frankban/quicktest v1.2.2/go.mod h1:Qh/WofXFeiAFII1aEBu529AtJo6Zg2VHscnEsbBnJ20= -github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= +github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/fvbommel/sortorder v1.0.1 h1:dSnXLt4mJYH25uDDGa3biZNQsozaUWDSWeKJ0qqFfzE= github.com/fvbommel/sortorder v1.0.1/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0= -github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= -github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= github.com/gfleury/go-bitbucket-v1 v0.0.0-20220301131131-8e7ed04b843e h1:C3DkNr9pxqXqCrmRHO7s3XgZS3zpi9GEA01GuWZODfo= github.com/gfleury/go-bitbucket-v1 v0.0.0-20220301131131-8e7ed04b843e/go.mod h1:LB3osS9X2JMYmTzcCArHHLrndBAfcVLQAvUddfs+ONs= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do= github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY= -github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g= @@ -994,16 +925,17 @@ github.com/go-fonts/liberation v0.2.0/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2H github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= -github.com/go-git/go-billy/v5 v5.4.1 h1:Uwp5tDRkPr+l/TnbHOQzp+tmJfLceOlbVucgpTz8ix4= -github.com/go-git/go-billy/v5 v5.4.1/go.mod h1:vjbugF6Fz7JIflbVpl1hJsGjSHNltrSw45YK/ukIvQg= -github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20230305113008-0c11038e723f h1:Pz0DHeFij3XFhoBRGUDPzSJ+w2UcK5/0JvF8DRI58r8= -github.com/go-git/go-git/v5 v5.8.1 h1:Zo79E4p7TRk0xoRgMq0RShiTHGKcKI4+DI6BfJc/Q+A= -github.com/go-git/go-git/v5 v5.8.1/go.mod h1:FHFuoD6yGz5OSKEBK+aWN9Oah0q54Jxl0abmj6GnqAo= +github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= +github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= +github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= +github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= +github.com/go-git/go-git/v5 v5.11.0 h1:XIZc1p+8YzypNr34itUfSvYJcv+eYdTnTvOZ2vD3cA4= +github.com/go-git/go-git/v5 v5.11.0/go.mod h1:6GFcX2P3NM7FPBfpePbpLd21XxsgdAt+lKqXmCUiUCY= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-jose/go-jose/v3 v3.0.0 h1:s6rrhirfEP/CGIoc6p+PZAeogN2SxKav6Wp7+dyMWVo= -github.com/go-jose/go-jose/v3 v3.0.0/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8= +github.com/go-jose/go-jose/v3 v3.0.1 h1:pWmKFVtt+Jl0vBZTIpz/eAKwsm6LkIxDVVbFHKkchhA= +github.com/go-jose/go-jose/v3 v3.0.1/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8= 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-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= @@ -1020,12 +952,12 @@ github.com/go-logr/logr v1.0.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbV github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= -github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= +github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-logr/zapr v1.2.0 h1:n4JnPI1T3Qq1SFEi/F8rwLrZERp2bso19PJZDB9dayk= -github.com/go-logr/zapr v1.2.0/go.mod h1:Qa4Bsj2Vb+FAVeAKsLD8RLQ+YRJB8YDmOAKxaBQf7Ro= +github.com/go-logr/zapr v1.2.3 h1:a9vnzlIBPQBBkeaR9IuMUfmVOrQlkoC4YfPoFkX3T7A= +github.com/go-logr/zapr v1.2.3/go.mod h1:eIauM6P8qSvTw5o2ez6UEAfGjQKrxQTl5EoK+Qa2oG4= github.com/go-openapi/analysis v0.21.2/go.mod h1:HZwRk4RRisyG8vx2Oe6aqeSQcoxRp47Xkp3+K6q+LdY= github.com/go-openapi/analysis v0.21.4 h1:ZDFLvSNxpDaomuCueM0BlSXxpANBlFYiBvr+GXrvIHc= github.com/go-openapi/analysis v0.21.4/go.mod h1:4zQ35W4neeZTqh3ol0rv/O8JBbka9QyAgQRPp9y3pfo= @@ -1035,13 +967,14 @@ github.com/go-openapi/errors v0.20.2/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpX github.com/go-openapi/errors v0.20.3 h1:rz6kiC84sqNQoqrtulzaL/VERgkoCyB6WdEkc2ujzUc= github.com/go-openapi/errors v0.20.3/go.mod h1:Z3FlZ4I8jEGxjUK+bugx3on2mIAk4txuAOhlsB1FSgk= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= -github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= -github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA= github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= +github.com/go-openapi/jsonreference v0.20.1 h1:FBLnyygC4/IZZr893oiomc9XaghoveYTrLC1F86HID8= +github.com/go-openapi/jsonreference v0.20.1/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= github.com/go-openapi/loads v0.21.1/go.mod h1:/DtAMXXneXFjbQMGEtbamCZb+4x7eGwkvZCvBmwUG+g= github.com/go-openapi/loads v0.21.2 h1:r2a/xFIYeZ4Qd2TnGpWDIQNcP80dIaZgf704za8enro= github.com/go-openapi/loads v0.21.2/go.mod h1:Jq58Os6SSGz0rzh62ptiu8Z31I+OTHqmULx5e/gJbNw= @@ -1064,14 +997,11 @@ github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/ github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-openapi/validate v0.22.1 h1:G+c2ub6q47kfX1sOBLwIQwzBVt8qmOAARyo/9Fqs9NU= github.com/go-openapi/validate v0.22.1/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg= -github.com/go-ozzo/ozzo-validation v3.5.0+incompatible/go.mod h1:gsEKFIVnabGBt6mXmxK0MoFy+cZoTJY6mu5Ll3LVLBU= github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM= github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= -github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= @@ -1120,17 +1050,12 @@ github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6Wezm github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogits/go-gogs-client v0.0.0-20200905025246-8bb8a50cb355 h1:HTVNOdTWO/gHYeFnr/HwpYwY6tgMcYd+Rgf1XrHnORY= github.com/gogits/go-gogs-client v0.0.0-20200905025246-8bb8a50cb355/go.mod h1:cY2AIrMgHm6oOHmR7jY+9TtjzSjQ3iG7tURJG3Y6XH0= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= @@ -1143,8 +1068,9 @@ github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= -github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE= github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= +github.com/golang/glog v1.1.2 h1:DVjP2PbBOzHyzA+dn3WhHIq4NdVu3Q+pvivFICf/7fo= +github.com/golang/glog v1.1.2/go.mod h1:zR+okUeTbrL6EL3xHUDxZuEtGv04p5shwip1+mL/rLQ= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -1168,15 +1094,11 @@ github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8l github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= -github.com/google/cadvisor v0.44.1/go.mod h1:GQ9KQfz0iNHQk3D6ftzJWK4TXabfIgM10Oy3FkR+Gzg= -github.com/google/cel-go v0.10.1/go.mod h1:U7ayypeSkw23szu4GaQTPJGx66c20mx8JklMSxrmI1w= -github.com/google/cel-spec v0.6.0/go.mod h1:Nwjgxy5CbjlPrtCWjeDjUyKMl8w41YBYGjsyDdqk0xA= github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= github.com/google/gnostic v0.6.9 h1:ZK/5VhkoX835RikCHpSUJV9a+S3e1zLh59YnyWeBW+0= @@ -1196,8 +1118,9 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= 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-github/v35 v35.3.0 h1:fU+WBzuukn0VssbayTT+Zo3/ESKX9JYWjbZTLOTEyho= github.com/google/go-github/v35 v35.3.0/go.mod h1:yWB7uCcVWaUbUP74Aq3whuMySRMatyRmq5U9FTNlbio= github.com/google/go-github/v41 v41.0.0 h1:HseJrM2JFf2vfiZJ8anY2hqBjdfY1Vlj/K27ueww4gg= @@ -1237,19 +1160,23 @@ github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLe github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/s2a-go v0.1.0/go.mod h1:OJpEgntRZo8ugHpF9hkoLJbS5dSI20XZeXJ9JVywLlM= github.com/google/s2a-go v0.1.3/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= +github.com/google/s2a-go v0.1.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc= github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= +github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg= github.com/googleapis/enterprise-certificate-proxy v0.2.1/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5Nm3pW+v7rGDHp09LsPtGY9MduiEsR9k= +github.com/googleapis/enterprise-certificate-proxy v0.2.5 h1:UR4rDjcgpgEnqpIEvkiqTYKBCKLNmlge2eVjoZfySzM= +github.com/googleapis/enterprise-certificate-proxy v0.2.5/go.mod h1:RxW0N9901Cko1VOCW3SXCpWP+mlIEkk2tP7jnHy9a3w= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= @@ -1264,21 +1191,18 @@ github.com/googleapis/gax-go/v2 v2.7.1/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38 github.com/googleapis/gax-go/v2 v2.8.0/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= github.com/googleapis/gax-go/v2 v2.10.0/go.mod h1:4UOEnMCrxsSqQ940WnTiD6qJ63le2ev3xfyagutxiPw= github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5iydzRfb3peWZJI= -github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= +github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= +github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gopackage/ddp v0.0.0-20170117053602-652027933df4 h1:4EZlYQIiyecYJlUbVkFXCXHz1QPhVXcHnQKAzBTPfQo= github.com/gopackage/ddp v0.0.0-20170117053602-652027933df4/go.mod h1:lEO7XoHJ/xNRBCxrn4h/CEB67h0kW1B0t4ooP2yrjUA= -github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= @@ -1294,10 +1218,8 @@ github.com/gregdel/pushover v1.2.1/go.mod h1:EcaO66Nn1StkpEm1iKtBTV3d2A16SoMsVER github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI= -github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= @@ -1305,11 +1227,10 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgf 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.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3 h1:lLT7ZLSzGLI08vc9cpd+tYmNWjdKDqyr/2L+f6U12Fk= github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w= -github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= -github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= @@ -1335,13 +1256,10 @@ github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09 github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= -github.com/heketi/heketi v10.3.0+incompatible/go.mod h1:bB9ly3RchcQqsQ9CpyaQwvva7RS5ytVoSoholZQON6o= -github.com/heketi/tests v0.0.0-20151005000721-f3775cbcefd6/go.mod h1:xGMAM8JLi7UkZt1i4FQeQy0R2T8GLUwQhOP5M1gBhy4= github.com/howeyc/gopass v0.0.0-20170109162249-bf9dde6d0d2c/go.mod h1:lADxMC39cJJqL93Duh1xhAs4I2Zs8mKS89XWXFGp9cs= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4= @@ -1350,7 +1268,7 @@ github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmK github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= @@ -1360,7 +1278,6 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= -github.com/ishidawataru/sctp v0.0.0-20190723014705-7c296d48a2b5/go.mod h1:DM4VvS+hD/kDi1U1QsX2fnZowwBhqD0Dk3bRPKF/Oc8= github.com/itchyny/gojq v0.12.13 h1:IxyYlHYIlspQHHTE0f3cJF0NKDMfajxViuhBLnHd/QU= github.com/itchyny/gojq v0.12.13/go.mod h1:JzwzAqenfhrPUuwbmEz3nu3JQmFLlQTQMUcOdnu/Sf4= github.com/itchyny/timefmt-go v0.1.5 h1:G0INE2la8S6ru/ZI5JecgyzbbJNs5lG1RcBqa7Jm6GE= @@ -1388,7 +1305,6 @@ github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= @@ -1402,13 +1318,11 @@ github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q github.com/k0kubun/pp v3.0.1+incompatible/go.mod h1:GWse8YhT0p8pT4ir3ZgBbfZild3tgzSScAn6HmfYukg= github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= -github.com/karrick/godirwalk v1.16.1/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= -github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE= @@ -1432,6 +1346,7 @@ github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= @@ -1440,29 +1355,21 @@ github.com/ktrysmt/go-bitbucket v0.9.67 h1:pFQs95TTgrwd3I9gKnas8zTYMVUOId0ZI4N0y github.com/ktrysmt/go-bitbucket v0.9.67/go.mod h1:g4i0XvhrK5dQ+RIZAJmF0XfBvhBEn3Ibt/6YbEyXkXw= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= -github.com/libopenstorage/openstorage v1.0.0/go.mod h1:Sp1sIObHjat1BeXhfMqLZ14wnOzEhNx2YQedreMcUyc= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= -github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc= -github.com/lpabon/godbc v0.1.1/go.mod h1:Jo9QV0cf3U6jZABgiJ2skINAXb9j8m51r07g4KI92ZA= github.com/lusis/go-slackbot v0.0.0-20180109053408-401027ccfef5/go.mod h1:c2mYKRyMb1BPkO5St0c/ps62L4S0W2NAkaTXj9qEI+0= github.com/lusis/slack-test v0.0.0-20190426140909-c40012f20018/go.mod h1:sFlOUpQL1YcjhFVXhg1CG8ZASEs/Mf1oVb6H75JL/zg= github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= github.com/lyft/protoc-gen-star/v2 v2.0.1/go.mod h1:RcCdONR2ScXaYnQC5tUzxzlpA3WVYF7/opLeUgcQs/o= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mailgun/mailgun-go v2.0.0+incompatible/go.mod h1:NWTyU+O4aczg/nsGhQnvHL6v2n5Gy6Sv5tNDVvC6FbU= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= @@ -1470,21 +1377,17 @@ github.com/malexdev/utfutil v0.0.0-20180510171754-00c8d4a8e7a8 h1:A6SLdFpRzUUF5v github.com/malexdev/utfutil v0.0.0-20180510171754-00c8d4a8e7a8/go.mod h1:UtpLyb/EupVKXF/N0b4NRe1DNg+QYJsnsHQ038romhM= github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= -github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A= -github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= @@ -1492,24 +1395,20 @@ github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4 github.com/mattn/go-zglob v0.0.4 h1:LQi2iOm0/fGgu80AioIJ/1j9w9Oh+9DZ39J4VAGzHQM= github.com/mattn/go-zglob v0.0.4/go.mod h1:MxxjyoXXnMxfIpxTK2GAkw1w8glPsQILx3N5wrKakiY= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/microsoft/azure-devops-go-api/azuredevops v1.0.0-b5 h1:YH424zrwLTlyHSH/GzLMJeu5zhYVZSx5RQxGKm1h96s= github.com/microsoft/azure-devops-go-api/azuredevops v1.0.0-b5/go.mod h1:PoGiBqKSQK1vIfQ+yVaFcGjDySHvym6FM1cNYnwzbrY= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/mindprince/gonvml v0.0.0-20190828220739-9ebdce4bb989/go.mod h1:2eu9pRWp8mo84xCg6KswZ+USQHjwgRhNp06sozOdsTY= github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcsrzbxHt8iiaC+zU4b1ylILSosueou12R++wfY= github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE= github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= github.com/minio/minio-go/v7 v7.0.58/go.mod h1:NUDy4A4oXPq1l2yK6LTSvCEzAMeIcoz9lcj5dbzSrRE= github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= -github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= @@ -1523,13 +1422,10 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/moby/ipvs v1.0.1/go.mod h1:2pngiyseZbIKXNv7hsKj3O9UEz30c53MT9005gt2hxQ= github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= -github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= -github.com/moby/sys/mountinfo v0.6.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= -github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 h1:dcztxKSvZ4Id8iPpHERQBbIJfabdt4wUm5qy3wOL2Zc= -github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= +github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae h1:O4SWKdcHVCvYqyDV+9CJA1fcDN2L11Bule0iFy3YlAI= +github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -1537,18 +1433,14 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/mohae/deepcopy v0.0.0-20170603005431-491d3605edfb/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/montanaflynn/stats v0.6.6/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= -github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= -github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/mvdan/xurls v1.1.0/go.mod h1:tQlNn3BED8bE/15hnSL2HLkDeLWpNPAwtw7wkEq44oU= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= @@ -1572,16 +1464,13 @@ github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/oliveagle/jsonpath v0.0.0-20180606110733-2e52cf6e6852/go.mod h1:eqOVx5Vwu4gd2mmMZvVZsgIqNSaW3xxRThUJ0k/TPk4= -github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.14.1/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= @@ -1594,7 +1483,6 @@ github.com/onsi/ginkgo/v2 v2.4.0/go.mod h1:iHkDK1fKGcBoEHT5W7YBq4RFWaQulw+caOMkA github.com/onsi/ginkgo/v2 v2.5.0/go.mod h1:Luc4sArBICYCS8THh8v3i3i5CuSZO+RaQRaJoeNwomw= github.com/onsi/ginkgo/v2 v2.7.0 h1:/XxtEV3I3Eif/HobnVx9YmJgk8ENdRsuUmM+fLCFNow= github.com/onsi/ginkgo/v2 v2.7.0/go.mod h1:yjiuMwPokqY1XauOgju45q3sJt6VzQ/Fict1LFVcsAo= -github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= @@ -1605,22 +1493,17 @@ github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9 github.com/onsi/gomega v1.20.1/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo= github.com/onsi/gomega v1.21.1/go.mod h1:iYAIXgPSaDHak0LCMA+AWBpIKBr8WZicMxnE8luStNc= github.com/onsi/gomega v1.22.1/go.mod h1:x6n7VNe4hw0vkyYUM4mjIXx3JbLiPaBPNgB7PRQ1tuM= +github.com/onsi/gomega v1.23.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg= github.com/onsi/gomega v1.24.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg= github.com/onsi/gomega v1.24.1/go.mod h1:3AOiACssS3/MajrniINInwbfOOtfZvplPzuRSmvt1jM= -github.com/onsi/gomega v1.25.0 h1:Vw7br2PCDYijJHSfBOWhov+8cAnUf8MfMaIOV323l6Y= github.com/onsi/gomega v1.25.0/go.mod h1:r+zV744Re+DiYCIPRlYOTxn0YkOLcAnW8k1xXdMPGhM= +github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= +github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/image-spec v1.1.0-rc4 h1:oOxKUJWnFC4YGHCCMNql1x4YaDfYBTS5Y4x/Cgeo1E0= github.com/opencontainers/image-spec v1.1.0-rc4/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= -github.com/opencontainers/runc v1.1.0/go.mod h1:Tj1hFw6eFWp/o33uxGf5yF2BX5yz2Z6iptFpuvbbKqc= -github.com/opencontainers/runc v1.1.1/go.mod h1:Tj1hFw6eFWp/o33uxGf5yF2BX5yz2Z6iptFpuvbbKqc= -github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= @@ -1636,9 +1519,7 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= -github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= 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= @@ -1664,15 +1545,11 @@ github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qR github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= -github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= @@ -1683,38 +1560,27 @@ github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6T github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= -github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= -github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.0-20190522114515-bc1a522cf7b1/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.3.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg= github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM= -github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/quobyte/api v0.1.8/go.mod h1:jL7lIHrmqQ7yh05OJ+eEEdHr0u/kmT1Ff9iHd+4H6VI= github.com/r3labs/diff v1.1.0 h1:V53xhrbTHrWFWq3gI4b94AjgEJOerO1+1l0xyHOBi8M= github.com/r3labs/diff v1.1.0/go.mod h1:7WjXasNzi0vJetRcB/RqNl5dlIsmXcTTLmF5IoH6Xig= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/redis/go-redis/v9 v9.0.0-rc.4/go.mod h1:Vo3EsyWnicKnSKCA7HhgnvnyA74wOA69Cd2Meli5mmA= github.com/redis/go-redis/v9 v9.0.5 h1:CuQcn5HIEeK7BgElubPP8CGtE0KakrnbBSTLjathl5o= github.com/redis/go-redis/v9 v9.0.5/go.mod h1:WqMKv5vnQbRuZstUwxQI195wHy+t4PuXDOjzMvcuQHk= -github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= @@ -1728,16 +1594,13 @@ github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= -github.com/rs/cors v1.8.0 h1:P2KMzcFwrPoSjkF1WLRPsp3UMLyql8L4v9hQpVeK5so= -github.com/rs/cors v1.8.0/go.mod h1:EBwu+T5AvHOcXwvZIkQFjUN6s8Czyqw12GL/Y0tUyRM= +github.com/rs/cors v1.9.0 h1:l9HGsTsHJcvW14Nk7J9KFz8bzeAWXn3CG6bgt7LsrAE= +github.com/rs/cors v1.9.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= -github.com/rubiojr/go-vhd v0.0.0-20200706105327-02e210299021/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= -github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww= -github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -1746,7 +1609,6 @@ github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZ github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= @@ -1762,14 +1624,13 @@ github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic github.com/sirupsen/logrus v1.9.2/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/skeema/knownhosts v1.2.0 h1:h9r9cf0+u7wSE+M183ZtMGgOJKiL96brpaz5ekfJCpM= -github.com/skeema/knownhosts v1.2.0/go.mod h1:g4fPeYpque7P0xefxtGzV81ihjC8sX2IqpAoNkjxbMo= +github.com/skeema/knownhosts v1.2.1 h1:SHWdIUa82uGZz+F+47k8SY4QhhI291cXCpopT1lK2AQ= +github.com/skeema/knownhosts v1.2.1/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= github.com/skratchdot/open-golang v0.0.0-20160302144031-75fb7ed4208c h1:fyKiXKO1/I/B6Y2U8T7WdQGWzwehOuGIrljPtt7YTTI= github.com/skratchdot/open-golang v0.0.0-20160302144031-75fb7ed4208c/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= github.com/slack-go/slack v0.12.2 h1:x3OppyMyGIbbiyFhsBmpf9pwkUzMhthJMRNmNlA4LaQ= github.com/slack-go/slack v0.12.2/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= @@ -1779,41 +1640,27 @@ github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJ github.com/sony/sonyflake v1.0.0 h1:MpU6Ro7tfXwgn2l5eluf9xQvQJDROTBImNCfRXn/YeM= github.com/sony/sonyflake v1.0.0/go.mod h1:Jv3cfhf/UFtolOTTRd3q4Nl6ENqM+KfyZ5PseKfZGF4= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= -github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= -github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= -github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= -github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= -github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= -github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf/go.mod h1:RJID2RhlZKId02nZ62WenDCkgHFerpIOmW0iT7GKmXM= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= -github.com/storageos/go-api v2.2.0+incompatible/go.mod h1:ZrLn+e0ZuF3Y65PNF6dIwbJPZqfmtCXxFm9ckv0agOY= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -1828,8 +1675,6 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM= github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= @@ -1838,31 +1683,22 @@ github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhV github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= -github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= -github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= -github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vmihailenco/go-tinylfu v0.2.2 h1:H1eiG6HM36iniK6+21n9LLpzx1G9R3DJa2UjUjbynsI= github.com/vmihailenco/go-tinylfu v0.2.2/go.mod h1:CutYi2Q9puTxfcolkliPq4npPuofg9N9t8JVrjzwa3Q= github.com/vmihailenco/msgpack/v5 v5.3.4 h1:qMKAwOV+meBw2Y8k9cVwAy7qErtYCwBzZ2ellBfvnqc= github.com/vmihailenco/msgpack/v5 v5.3.4/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= -github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= github.com/whilp/git-urls v1.0.0 h1:95f6UMWN5FKW71ECsXRUd3FVYiXdrE7aX4NZKcPmIjU= github.com/whilp/git-urls v1.0.0/go.mod h1:J16SAmobsqc3Qcy98brfl5f5+e0clUvg1krgwk/qCfE= github.com/xanzy/go-gitlab v0.91.1 h1:gnV57IPGYywWer32oXKBcdmc8dVxeKl3AauV8Bu17rw= @@ -1878,10 +1714,8 @@ github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2 github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/xlab/treeprint v1.1.0 h1:G/1DjNkPpfZCFt9CSh6b5/nY4VimlbHF3Rh4obvtzDk= github.com/xlab/treeprint v1.1.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -1894,20 +1728,8 @@ github.com/yuin/gopher-lua v1.1.0 h1:BojcDhfyDWgU2f2TOzYK/g5p2gxMrku8oupLDqlnSqE github.com/yuin/gopher-lua v1.1.0/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= -go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= -go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= -go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= -go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= -go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= -go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= -go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= -go.etcd.io/etcd/client/v3 v3.5.1/go.mod h1:OnjH4M8OnAotwaB2l9bVgZzRFKru7/ZMoS46OtKyd3Q= -go.etcd.io/etcd/pkg/v3 v3.5.0/go.mod h1:UzJGatBQ1lXChBkQF0AuAtkRQMYnHubxAEYIrC3MSsE= -go.etcd.io/etcd/raft/v3 v3.5.0/go.mod h1:UFOHSIvO/nKwd4lhkwabrTD3cqW5yVyYYf/KlD00Szc= -go.etcd.io/etcd/server/v3 v3.5.0/go.mod h1:3Ah5ruV+M+7RZr0+Y/5mNLwC+eQlni+mQmOVdCRJoS4= go.mongodb.org/mongo-driver v1.7.3/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R79oO62zWg= go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng= go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8= @@ -1922,39 +1744,27 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0 h1:ZOLJc06r4CB42laIXg/7udr0pbZyuAihN10A/XuiQRY= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0/go.mod h1:5z+/ZWJQKXa9YT34fQNx5K8Hd1EoIhvtUygUQPqEOgQ= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0/go.mod h1:2AboqHi0CiIZU0qwhtUfCYD1GeUzvvIXWNkhDt7ZMG4= -go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo= -go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= -go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= -go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM= -go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0 h1:t4ZwRPU+emrcvM2e9DHd0Fsf0JTPVcbfa/BhTDF03d0= -go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0/go.mod h1:vLarbg68dH2Wa77g71zmKQqlQ8+8Rq3GRG31uc0WcWI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0 h1:cbsD4cUcviQGXdw8+bo5x2wazq10SKz8hEbtCRPcU78= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0/go.mod h1:JgXSGah17croqhJfhByOLVY719k1emAXC8MVhCIJlRs= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0 h1:TVQp/bboR4mhZSav+MdgXB8FaRho1RC8UwVn3T0vjVc= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0/go.mod h1:I33vtIe0sR96wfrUcilIzLoA3mLHhRmz9S9Te0S3gDo= -go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU= -go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= -go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= -go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw= -go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc= -go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= -go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= -go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE= -go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE= -go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw= -go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= -go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= +go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= +go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0 h1:cl5P5/GIfFh4t6xyruOgJP5QiA1pw4fYYdv6nc6CBWw= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.21.0/go.mod h1:zgBdWWAu7oEEMC06MMKc5NLbA/1YDXV1sMpSqEeLQLg= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 h1:tIqheXEFWAZ7O8A7m+J0aPTmpJN3YQ7qetUAdkkkKpk= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0/go.mod h1:nUeKExfxAQVbiVFn32YXpXZZHZ61Cc3s3Rn1pDBGAb0= +go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4= +go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= +go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8= +go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E= +go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc= +go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= -go.opentelemetry.io/proto/otlp v0.19.0 h1:IVN6GR+mhC4s5yfcTbmzHYODqvWAp3ZedA2SJPI1Nnw= go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= -go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o= +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.starlark.net v0.0.0-20220328144851-d1966c6b9fcd h1:Uo/x0Ir5vQJ+683GXB9Ug+4fcjsbp7z7Ul8UaZbhsRM= go.starlark.net v0.0.0-20220328144851-d1966c6b9fcd/go.mod h1:t3mmBBPzAVvK0L0n1drDmrQsJ8FoIx4INCqVMTr/Zo0= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -1963,7 +1773,8 @@ go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= -go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= @@ -1971,14 +1782,12 @@ go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9i go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= -go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= -go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= -go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI= +go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= +go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190422183909-d864b10871cd/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -1990,13 +1799,11 @@ golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= @@ -2007,16 +1814,15 @@ golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0 golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= -golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/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-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE= golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= @@ -2026,7 +1832,6 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0 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-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= -golang.org/x/exp v0.0.0-20210220032938-85be41e4509f/go.mod h1:I6l2HNBLBZEcrOoCpyKLdY2lHoRZ8lI4x60KMCQDft4= golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc= golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= @@ -2057,15 +1862,12 @@ golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPI golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mobile v0.0.0-20201217150744-e6ae53a27f4f/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -2076,8 +1878,9 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91 golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -2091,7 +1894,6 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190607181551-461777fb6f67/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -2130,10 +1932,8 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= @@ -2161,8 +1961,9 @@ 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.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= 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= @@ -2174,8 +1975,6 @@ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210427180440-81ed05c6b58c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= @@ -2222,12 +2021,10 @@ golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190124100055-b90733256f2e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -2239,19 +2036,13 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -2259,11 +2050,9 @@ golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -2278,8 +2067,6 @@ golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -2293,16 +2080,12 @@ golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210503080704-8803ae5d1324/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210608053332-aa57babbf139/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -2313,17 +2096,13 @@ golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -2355,8 +2134,9 @@ 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.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -2370,8 +2150,9 @@ 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.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= -golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= +golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= 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= @@ -2390,14 +2171,13 @@ golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20220922220347-f3bd1da661af/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= @@ -2406,7 +2186,6 @@ golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -2432,7 +2211,6 @@ golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -2441,7 +2219,6 @@ golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= @@ -2479,15 +2256,15 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= -golang.org/x/tools v0.1.10-0.20220218145154-897bd77cd717/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= +golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -2504,13 +2281,10 @@ gomodules.xyz/notify v0.1.1 h1:1tTuoyswmPvzqPCTEDQK8SZ3ukCxLsonAAwst2+y1a0= gomodules.xyz/notify v0.1.1/go.mod h1:QgQyU4xEA/plJcDeT66J2Go2V7U4c0pD9wjo7HfFil4= gomodules.xyz/version v0.1.0/go.mod h1:Y8xuV02mL/45psyPKG3NCVOwvAOy6T5Kx0l3rCjKSjU= gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= -gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= -gonum.org/v1/gonum v0.6.2/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU= gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= gonum.org/v1/gonum v0.9.3/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0= gonum.org/v1/gonum v0.11.0/go.mod h1:fSG4YDCxxUZQJ7rKsQrj0gMOg00Il0Z96/qMA4bVQhA= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= -gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= gonum.org/v1/plot v0.9.0/go.mod h1:3Pcqqmp6RHvJI72kgb8fThyUnav364FOsdDo2aGW5lY= gonum.org/v1/plot v0.10.1/go.mod h1:VZW5OlhkL1mysU9vaqNHnsy86inf6Ot+jB3r+BczCEo= @@ -2536,8 +2310,6 @@ google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34q google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= -google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= -google.golang.org/api v0.46.0/go.mod h1:ceL4oozhkAiTID8XMmJBsIxID/9wMXJVVFXPg4ylg3I= google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= @@ -2578,6 +2350,8 @@ google.golang.org/api v0.118.0/go.mod h1:76TtD3vkgmZ66zZzp72bUUklpmQmKlhh6sYtIjY google.golang.org/api v0.122.0/go.mod h1:gcitW0lvnyWjSp9nKxAbdHKIZ6vF4aajGueeslZOyms= google.golang.org/api v0.124.0/go.mod h1:xu2HQurE5gi/3t1aFCvhPD781p0a3p11sdunTJ2BlP4= google.golang.org/api v0.126.0/go.mod h1:mBwVAtz+87bEN6CbA1GtZPDOqY2R5ONPqJeIlvyo4Aw= +google.golang.org/api v0.132.0 h1:8t2/+qZ26kAOGSmOiHwVycqVaDg7q3JDILrNi/Z6rvc= +google.golang.org/api v0.132.0/go.mod h1:AeTBC6GpJnJSRJjktDcPX0QwtS8pGYZOV6MSuSCusw0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -2601,7 +2375,6 @@ google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvx google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200117163144-32f20d992d24/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= @@ -2622,7 +2395,6 @@ google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201102152239-715cce707fb0/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= @@ -2636,7 +2408,6 @@ google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210429181445-86c259c2b4ab/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= @@ -2730,21 +2501,21 @@ google.golang.org/genproto v0.0.0-20230403163135-c38d8f061ccd/go.mod h1:UUQDJDOl google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= google.golang.org/genproto v0.0.0-20230525234025-438c736192d0/go.mod h1:9ExIQyXL5hZrHzQceCwuSYwZZ5QZBazOcprJ5rgs3lY= google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64= -google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 h1:Z0hjGZePRE0ZBWotvtrwxFNrNE9CUAGtplaDK5NNI/g= -google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98/go.mod h1:S7mY02OqCJTD0E1OiQy1F72PWFB4bZJ87cAtLPYgDR0= +google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d h1:VBu5YqKPv6XiJ199exd8Br+Aetz+o08F+PLMnwJQHAY= +google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= google.golang.org/genproto/googleapis/api v0.0.0-20230525234020-1aefcd67740a/go.mod h1:ts19tUU+Z0ZShN1y3aPyq2+O3d5FUNNgT6FtOzmrNn8= google.golang.org/genproto/googleapis/api v0.0.0-20230525234035-dd9d682886f9/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= google.golang.org/genproto/googleapis/api v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig= -google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98 h1:FmF5cCW94Ij59cfpoLiwTgodWmm60eEV0CjlsVg2fuw= -google.golang.org/genproto/googleapis/api v0.0.0-20230711160842-782d3b101e98/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ= +google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d h1:DoPTO70H+bcDXcd39vOqb2viZxgqeBeSGtZ55yZU4/Q= +google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= google.golang.org/genproto/googleapis/bytestream v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:ylj+BE99M198VPbBh6A8d9n3w8fChvyLK3wwBOjXBFA= google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234015-3fc162c6f38a/go.mod h1:xURIpW9ES5+/GZhnV6beoEtxQrnkRGIfP5VQG2tCBLc= google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= google.golang.org/genproto/googleapis/rpc v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 h1:bVf09lpb+OJbByTj913DRJioFFAjf/ZGxEz7MajTp2U= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d h1:uvYuEyMHKNt+lT4K3bN6fGswmK8qSvcreM3BwjDh+y4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= @@ -2792,15 +2563,14 @@ google.golang.org/grpc v1.52.0/go.mod h1:pu6fVzoFb+NBYNAvQL08ic+lvB2IojljRYuun5v google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g= google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8= -google.golang.org/grpc v1.58.3 h1:BjnpXut1btbtgN/6sp+brB2Kbm2LjNXnidYujAVbSoQ= -google.golang.org/grpc v1.58.3/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0= +google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= +google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= @@ -2821,26 +2591,16 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EV gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= -gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= -gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE= gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= 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.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/retry.v1 v1.0.3 h1:a9CArYczAVv6Qs6VGoLMio99GEs7kY9UzSF9+LD+iGs= gopkg.in/retry.v1 v1.0.3/go.mod h1:FJkXmWiMaAo7xB+xhvDF59zhfjDWyzmyAxiT4dB688g= -gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= -gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= -gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/warnings.v0 v0.1.1/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= @@ -2859,73 +2619,52 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt 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= honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= -k8s.io/api v0.24.2 h1:g518dPU/L7VRLxWfcadQn2OnsiGWVOadTLpdnqgY2OI= -k8s.io/api v0.24.2/go.mod h1:AHqbSkTm6YrQ0ObxjO3Pmp/ubFF/KuM7jU+3khoBsOg= -k8s.io/apiextensions-apiserver v0.24.2 h1:/4NEQHKlEz1MlaK/wHT5KMKC9UKYz6NZz6JE6ov4G6k= -k8s.io/apiextensions-apiserver v0.24.2/go.mod h1:e5t2GMFVngUEHUd0wuCJzw8YDwZoqZfJiGOW6mm2hLQ= -k8s.io/apimachinery v0.24.2 h1:5QlH9SL2C8KMcrNJPor+LbXVTaZRReml7svPEh4OKDM= -k8s.io/apimachinery v0.24.2/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM= -k8s.io/apiserver v0.24.2 h1:orxipm5elPJSkkFNlwH9ClqaKEDJJA3yR2cAAlCnyj4= -k8s.io/apiserver v0.24.2/go.mod h1:pSuKzr3zV+L+MWqsEo0kHHYwCo77AT5qXbFXP2jbvFI= -k8s.io/cli-runtime v0.24.2 h1:KxY6tSgPGsahA6c1/dmR3uF5jOxXPx2QQY6C5ZrLmtE= -k8s.io/cli-runtime v0.24.2/go.mod h1:1LIhKL2RblkhfG4v5lZEt7FtgFG5mVb8wqv5lE9m5qY= -k8s.io/client-go v0.24.2 h1:CoXFSf8if+bLEbinDqN9ePIDGzcLtqhfd6jpfnwGOFA= -k8s.io/client-go v0.24.2/go.mod h1:zg4Xaoo+umDsfCWr4fCnmLEtQXyCNXCvJuSsglNcV30= -k8s.io/cloud-provider v0.24.2/go.mod h1:a7jyWjizk+IKbcIf8+mX2cj3NvpRv9ZyGdXDyb8UEkI= -k8s.io/cluster-bootstrap v0.24.2/go.mod h1:eIHV338K03vBm3u/ROZiNXxWJ4AJRoTR9PEUhcTvYkg= -k8s.io/code-generator v0.24.2 h1:EGeRWzJrpwi6T6CvoNl0spM6fnAnOdCr0rz7H4NU1rk= -k8s.io/code-generator v0.24.2/go.mod h1:dpVhs00hTuTdTY6jvVxvTFCk6gSMrtfRydbhZwHI15w= -k8s.io/component-base v0.24.2 h1:kwpQdoSfbcH+8MPN4tALtajLDfSfYxBDYlXobNWI6OU= -k8s.io/component-base v0.24.2/go.mod h1:ucHwW76dajvQ9B7+zecZAP3BVqvrHoOxm8olHEg0nmM= -k8s.io/component-helpers v0.24.2 h1:gtXmI/TjVINtkAdZn7m5p8+Vd0Mk4d1q8kwJMMLBdwY= -k8s.io/component-helpers v0.24.2/go.mod h1:TRQPBQKfmqkmV6c0HAmUs8cXVNYYYLsXy4zu8eODi9g= -k8s.io/controller-manager v0.24.2/go.mod h1:hpwCof4KxP4vrw/M5QiVxU6Zmmggmr1keGXtjGHF+vc= -k8s.io/cri-api v0.24.2/go.mod h1:t3tImFtGeStN+ES69bQUX9sFg67ek38BM9YIJhMmuig= -k8s.io/csi-translation-lib v0.24.2/go.mod h1:pdHc2CYLViQYYsOqOp79hjKYi8J4NZ7vpiVzn1SqBrg= -k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/api v0.26.11 h1:hLhTZRdYc3vBBOY4wbEyTLWgMyieOAk2Ws9NG57QqO4= +k8s.io/api v0.26.11/go.mod h1:bSr/A0TKRt5W2OMDdexkM/ER1NxOxiQqNNFXW2nMZrM= +k8s.io/apiextensions-apiserver v0.26.11 h1:6/T0Jm9c+Aw1AYUflPOz2sAsty304/DDSkciTr8+HuE= +k8s.io/apiextensions-apiserver v0.26.11/go.mod h1:xMqWxAB+AvSTdmFRVWlpavY9bJl/3g6yWiPn/fwZbT0= +k8s.io/apimachinery v0.26.11 h1:w//840HHdwSRKqD15j9YX9HLlU6RPlfrvW0xEhLk2+0= +k8s.io/apimachinery v0.26.11/go.mod h1:2/HZp0l6coXtS26du1Bk36fCuAEr/lVs9Q9NbpBtd1Y= +k8s.io/apiserver v0.26.11 h1:JcrlATLu5xQVLV7/rfRFFl9ivvNLmZH0dM3DFFdFp+w= +k8s.io/apiserver v0.26.11/go.mod h1:htEG/Q3sI3+6Is3Z26QzBjaCGICsz/kFj+IhIP4oJuE= +k8s.io/cli-runtime v0.26.11 h1:HO3Sgf06XkT8/8wWnhskfz4+LMKrChRz+A13vDJSQrE= +k8s.io/cli-runtime v0.26.11/go.mod h1:D98GjQtDmqn7WDuKBgWivd6R8qEs3yzT19EmCM5pqBs= +k8s.io/client-go v0.26.11 h1:RjfZr5+vQjjTRmk4oCqHyC0cgrZXPjw+X+ge35sk4GI= +k8s.io/client-go v0.26.11/go.mod h1:+emNszw9va/uRJIM5ALTBtFnlZMTjwBrNjRfEh0iuw8= +k8s.io/code-generator v0.26.11 h1:S0PJxapUhG6LWYezYB/FVE5Gf4BxGY0fCwnLrwfQ/70= +k8s.io/code-generator v0.26.11/go.mod h1:Hjxj7hpvSxcNnYIWzCSuEdwN0/9aHlezQRKJXr0Kv8U= +k8s.io/component-base v0.26.11 h1:1/JmB6fexefGByfFyIK6aHksZZVtaDskttzXOzmZ6zA= +k8s.io/component-base v0.26.11/go.mod h1:jYNisnoM6iWFRUg51pxaQabzL5fBYTr5CMpsLjUYGp0= +k8s.io/component-helpers v0.26.11 h1:XD2/2lik/5n1WFepDvgHzIGL0tix/EU3GaxGJHdsgkA= +k8s.io/component-helpers v0.26.11/go.mod h1:lw3bchkI0NHMPmb+CE73GznPW0Mvqd/Y9UVMEqBkysE= k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= -k8s.io/gengo v0.0.0-20211129171323-c02415ce4185 h1:TT1WdmqqXareKxZ/oNXEUSwKlLiHzPMyB0t8BaFeBYI= -k8s.io/gengo v0.0.0-20211129171323-c02415ce4185/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/gengo v0.0.0-20220902162205-c0856e24416d h1:U9tB195lKdzwqicbJvyJeOXV7Klv+wNAWENRnXEGi08= +k8s.io/gengo v0.0.0-20220902162205-c0856e24416d/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.5.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= -k8s.io/klog/v2 v2.60.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/klog/v2 v2.70.1 h1:7aaoSdahviPmR+XkS7FyxlkkXs6tHISSG03RxleQAVQ= -k8s.io/klog/v2 v2.70.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kube-aggregator v0.24.2 h1:vaKw45vFA5fIT0wdSehPIL7idjVxgLqz6iedOHedLG4= -k8s.io/kube-aggregator v0.24.2/go.mod h1:Ju2jNDixn+vqeeKEBfjfpc204bO1pbdXX0N9knCxeMQ= -k8s.io/kube-controller-manager v0.24.2/go.mod h1:KDE0yqiEvxYiO0WRpPA4rVx8AcK1vsWydUF37AJ9lTI= -k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= -k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42/go.mod h1:Z/45zLw8lUo4wdiUkI+v/ImEGAvu3WatcZl3lPMR4Rk= -k8s.io/kube-openapi v0.0.0-20220401212409-b28bf2818661/go.mod h1:daOouuuwd9JXpv1L7Y34iV3yf6nxzipkKMWWlqlvK9M= -k8s.io/kube-openapi v0.0.0-20220627174259-011e075b9cb8 h1:yEQKdMCjzAOvGeiTwG4hO/hNVNtDOuUFvMUZ0OlaIzs= -k8s.io/kube-openapi v0.0.0-20220627174259-011e075b9cb8/go.mod h1:mbJ+NSUoAhuR14N0S63bPkh8MGVSo3VYSGZtH/mfMe0= -k8s.io/kube-proxy v0.24.2/go.mod h1:bozS2ufl/Ns6s40Ue34eV7rqyLVygi5usSmCgW7rFU8= -k8s.io/kube-scheduler v0.24.2/go.mod h1:DRa+aeXKSYUUOHHIc/9EcaO9+FW5FydaOfPSvaSW5Ko= -k8s.io/kubectl v0.24.2 h1:+RfQVhth8akUmIc2Ge8krMl/pt66V7210ka3RE/p0J4= -k8s.io/kubectl v0.24.2/go.mod h1:+HIFJc0bA6Tzu5O/YcuUt45APAxnNL8LeMuXwoiGsPg= -k8s.io/kubelet v0.24.2/go.mod h1:Xm9DkWQjwOs+uGOUIIGIPMvvmenvj0lDVOErvIKOOt0= -k8s.io/kubernetes v1.24.2 h1:AyjtHzSysliKR04Km91njmk2yaKmOa3ZISQZCIGUnVI= -k8s.io/kubernetes v1.24.2/go.mod h1:8e8maMiZzBR2/8Po5Uulx+MXZUYJuN3vtKwD4Ct1Xi0= -k8s.io/legacy-cloud-providers v0.24.2/go.mod h1:sgkasgIP2ZOew8fzoOq0mQLVXJ4AmB57IUbFUjzPWEo= -k8s.io/metrics v0.24.2/go.mod h1:5NWURxZ6Lz5gj8TFU83+vdWIVASx7W8lwPpHYCqopMo= -k8s.io/mount-utils v0.24.2/go.mod h1:XrSqB3a2e8sq+aU+rlbcBtQ3EgcuDk5RP9ZsGxjoDrI= -k8s.io/pod-security-admission v0.24.2/go.mod h1:znnuDHWWWvh/tpbYYPwTsd4y//qHi3cOX+wGxET/mMI= -k8s.io/sample-apiserver v0.24.2/go.mod h1:mf8qgDdu450wqpCJOkSAmoTgU4PIMAcfa5uTBwmJekE= -k8s.io/system-validators v1.7.0/go.mod h1:gP1Ky+R9wtrSiFbrpEPwWMeYz9yqyy1S/KOh0Vci7WI= +k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg= +k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kube-aggregator v0.26.11 h1:P46aQPWOE+8bTbK2cqxUFP1XwH4ShZEHnlk1T5QFT8U= +k8s.io/kube-aggregator v0.26.11/go.mod h1:XNGLFzn4Ex7qFVqpCnvLUr354EM4QhMFuFSoB6JHmL4= +k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280/go.mod h1:+Axhij7bCpeqhklhUTe3xmOn6bWxolyZEeyaFpjGtl4= +k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f h1:2kWPakN3i/k81b0gvD5C5FJ2kxm1WrQFanWchyKuqGg= +k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f/go.mod h1:byini6yhqGC14c3ebc/QwanvYwhuMWF6yz2F8uwW8eg= +k8s.io/kubectl v0.26.11 h1:cVPzYA4HKefU3tPiVK7hZpJ+5Lm04XoyvCCY5ODznpQ= +k8s.io/kubectl v0.26.11/go.mod h1:xjEX/AHtEQrGj2AGqVopyHr/JU1hLy1k7Yn48JuK9LQ= +k8s.io/kubernetes v1.26.11 h1:g3r1IAUqsaHnOG2jdpoagJ5W9UCXkR2ljQ/7BmCzPNg= +k8s.io/kubernetes v1.26.11/go.mod h1:z1URAaBJ+XnOTr3Q/l4umxRUxn/OyD2fbkUgS0Bl7u4= k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20220706174534-f6158b442e7c h1:hFZO68mv/0xe8+V0gRT9BAq3/31cKjjeVv4nScriuBk= -k8s.io/utils v0.0.0-20220706174534-f6158b442e7c/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20221107191617-1a15be271d1d/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/utils v0.0.0-20230220204549-a5ecb0141aa5 h1:kmDqav+P+/5e1i9tFfHq1qcF3sOrDp+YEkVDAHu7Jwk= +k8s.io/utils v0.0.0-20230220204549-a5ecb0141aa5/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= layeh.com/gopher-json v0.0.0-20190114024228-97fed8db8427 h1:RZkKxMR3jbQxdCEcglq3j7wY3PRJIopAwBlx1RE71X0= layeh.com/gopher-json v0.0.0-20190114024228-97fed8db8427/go.mod h1:ivKkcY8Zxw5ba0jldhZCYYQfGdb2K6u9tbYK1AwMIBc= lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= -modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= modernc.org/cc/v3 v3.36.2/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= modernc.org/cc/v3 v3.36.3/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= @@ -2936,7 +2675,6 @@ modernc.org/ccgo/v3 v3.16.6/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWs modernc.org/ccgo/v3 v3.16.8/go.mod h1:zNjwkizS+fIFDrDjIAgBSCLkWbJuHF+ar3QRn+Z9aws= modernc.org/ccgo/v3 v3.16.9/go.mod h1:zNMzC9A9xeNUepy6KuZBbugn3c0Mc9TeiJO4lgvkJDo= modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= -modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= modernc.org/libc v0.0.0-20220428101251-2d5f3daf273b/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= modernc.org/libc v1.16.0/go.mod h1:N4LD6DBE9cf+Dzf9buBlzVJndKr/iJHG97vGLHYnb5A= @@ -2945,7 +2683,6 @@ modernc.org/libc v1.16.17/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU= modernc.org/libc v1.16.19/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= modernc.org/libc v1.17.0/go.mod h1:XsgLldpP4aWlPlsjqKRdHPqCxCjISdHfM/yeWC5GyW0= modernc.org/libc v1.17.1/go.mod h1:FZ23b+8LjxZs7XtFMbSzL/EhPxNbfZbErxEHc7cbD9s= -modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= @@ -2955,12 +2692,10 @@ modernc.org/memory v1.2.1/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= modernc.org/sqlite v1.18.1/go.mod h1:6ho+Gow7oX5V+OiOQ6Tr4xeqbx13UZ6t+Fw9IRUG4d4= -modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= modernc.org/tcl v1.13.1/go.mod h1:XOLfOwzhkljL4itZkK6T72ckMgvj0BDsnKNdZVUOecw= modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= -modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8= nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g= @@ -2971,24 +2706,18 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8 rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.30/go.mod h1:fEO7lRTdivWO2qYVCVG7dEADOMo/MLDCVr8So2g88Uw= -sigs.k8s.io/controller-runtime v0.11.0 h1:DqO+c8mywcZLFJWILq4iktoECTyn30Bkj0CwgqMpZWQ= -sigs.k8s.io/controller-runtime v0.11.0/go.mod h1:KKwLiTooNGu+JmLZGn9Sl3Gjmfj66eMbCQznLP5zcqA= -sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2/go.mod h1:B+TnT182UBxE84DiCz4CVE26eOSDAeYCpfDnC2kdKMY= -sigs.k8s.io/json v0.0.0-20220525155127-227cbc7cc124 h1:2sgAQQcY0dEW2SsQwTXhQV4vO6+rSslYx8K3XmM5hqQ= -sigs.k8s.io/json v0.0.0-20220525155127-227cbc7cc124/go.mod h1:B+TnT182UBxE84DiCz4CVE26eOSDAeYCpfDnC2kdKMY= -sigs.k8s.io/kustomize/api v0.11.4/go.mod h1:k+8RsqYbgpkIrJ4p9jcdPqe8DprLxFUUO0yNOq8C+xI= -sigs.k8s.io/kustomize/api v0.11.5 h1:vLDp++YAX7iy2y2CVPJNy9pk9CY8XaUKgHkjbVtnWag= -sigs.k8s.io/kustomize/api v0.11.5/go.mod h1:2UDpxS6AonWXow2ZbySd4AjUxmdXLeTlvGBC46uSiq8= -sigs.k8s.io/kustomize/cmd/config v0.10.6/go.mod h1:/S4A4nUANUa4bZJ/Edt7ZQTyKOY9WCER0uBS1SW2Rco= -sigs.k8s.io/kustomize/kustomize/v4 v4.5.4/go.mod h1:Zo/Xc5FKD6sHl0lilbrieeGeZHVYCA4BzxeAaLI05Bg= -sigs.k8s.io/kustomize/kyaml v0.13.6/go.mod h1:yHP031rn1QX1lr/Xd934Ri/xdVNG8BE2ECa78Ht/kEg= -sigs.k8s.io/kustomize/kyaml v0.13.7 h1:/EZ/nPaLUzeJKF/BuJ4QCuMVJWiEVoI8iftOHY3g3tk= -sigs.k8s.io/kustomize/kyaml v0.13.7/go.mod h1:6K+IUOuir3Y7nucPRAjw9yth04KSWBnP5pqUTGwj/qU= -sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= -sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= -sigs.k8s.io/structured-merge-diff/v4 v4.3.0 h1:UZbZAZfX0wV2zr7YZorDz6GXROfDFj6LvqCRm4VUVKk= -sigs.k8s.io/structured-merge-diff/v4 v4.3.0/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= +sigs.k8s.io/controller-runtime v0.14.6 h1:oxstGVvXGNnMvY7TAESYk+lzr6S3V5VFxQ6d92KcwQA= +sigs.k8s.io/controller-runtime v0.14.6/go.mod h1:WqIdsAY6JBsjfc/CqO0CORmNtoCtE4S6qbPc9s68h+0= +sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/kustomize/api v0.12.1 h1:7YM7gW3kYBwtKvoY216ZzY+8hM+lV53LUayghNRJ0vM= +sigs.k8s.io/kustomize/api v0.12.1/go.mod h1:y3JUhimkZkR6sbLNwfJHxvo1TCLwuwm14sCYnkH6S1s= +sigs.k8s.io/kustomize/kyaml v0.13.9 h1:Qz53EAaFFANyNgyOEJbT/yoIHygK40/ZcvU3rgry2Tk= +sigs.k8s.io/kustomize/kyaml v0.13.9/go.mod h1:QsRbD0/KcU+wdk0/L0fIp2KLnohkVzs6fQ85/nOXac4= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= diff --git a/hack/dev-mounter/main.go b/hack/dev-mounter/main.go index bd01ae939e5b9..61988b2daa275 100644 --- a/hack/dev-mounter/main.go +++ b/hack/dev-mounter/main.go @@ -97,12 +97,15 @@ func newCommand() *cobra.Command { kubeClient := kubernetes.NewForConfigOrDie(config) factory := informers.NewSharedInformerFactoryWithOptions(kubeClient, 1*time.Minute, informers.WithNamespace(ns)) informer := factory.Core().V1().ConfigMaps().Informer() - informer.AddEventHandler(cache.ResourceEventHandlerFuncs{ + _, err = informer.AddEventHandler(cache.ResourceEventHandlerFuncs{ AddFunc: handledConfigMap, UpdateFunc: func(oldObj, newObj interface{}) { handledConfigMap(newObj) }, }) + if err != nil { + log.Error(err) + } informer.Run(context.Background().Done()) }, } diff --git a/hack/gen-resources/generators/cluster_generator.go b/hack/gen-resources/generators/cluster_generator.go index eec1cdfe3cc2e..6f125723c35ef 100644 --- a/hack/gen-resources/generators/cluster_generator.go +++ b/hack/gen-resources/generators/cluster_generator.go @@ -99,7 +99,7 @@ func (cg *ClusterGenerator) getClusterCredentials(namespace string, releaseSuffi return nil, nil, nil, err } - err = exec.Stream(remotecommand.StreamOptions{ + err = exec.StreamWithContext(context.Background(), remotecommand.StreamOptions{ Stdin: &stdin, Stdout: &stdout, Stderr: &stderr, diff --git a/hack/generate-proto.sh b/hack/generate-proto.sh index 8466993ebc544..fa5d7322c7f81 100755 --- a/hack/generate-proto.sh +++ b/hack/generate-proto.sh @@ -10,9 +10,13 @@ set -o nounset set -o pipefail # shellcheck disable=SC2128 -PROJECT_ROOT=$(cd "$(dirname "${BASH_SOURCE}")"/..; pwd) +PROJECT_ROOT=$( + cd "$(dirname "${BASH_SOURCE}")"/.. + pwd +) PATH="${PROJECT_ROOT}/dist:${PATH}" GOPATH=$(go env GOPATH) +GOPATH_PROJECT_ROOT="${GOPATH}/src/github.com/argoproj/argo-cd" # output tool versions go version @@ -41,6 +45,7 @@ APIMACHINERY_PKGS=( export GO111MODULE=on [ -e ./v2 ] || ln -s . v2 +[ -e "${GOPATH_PROJECT_ROOT}" ] || (mkdir -p "$(dirname "${GOPATH_PROJECT_ROOT}")" && ln -s "${PROJECT_ROOT}" "${GOPATH_PROJECT_ROOT}") # protoc_include is the include directory containing the .proto files distributed with protoc binary if [ -d /dist/protoc-include ]; then @@ -53,10 +58,17 @@ fi go-to-protobuf \ --go-header-file="${PROJECT_ROOT}"/hack/custom-boilerplate.go.txt \ - --packages="$(IFS=, ; echo "${PACKAGES[*]}")" \ - --apimachinery-packages="$(IFS=, ; echo "${APIMACHINERY_PKGS[*]}")" \ - --proto-import=./vendor \ - --proto-import="${protoc_include}" + --packages="$( + IFS=, + echo "${PACKAGES[*]}" + )" \ + --apimachinery-packages="$( + IFS=, + echo "${APIMACHINERY_PKGS[*]}" + )" \ + --proto-import="${PROJECT_ROOT}"/vendor \ + --proto-import="${protoc_include}" \ + --output-base="${GOPATH}/src/" # Either protoc-gen-go, protoc-gen-gofast, or protoc-gen-gogofast can be used to build # server/*/.pb.go from .proto files. golang/protobuf and gogo/protobuf can be used @@ -86,9 +98,11 @@ for i in ${PROTO_FILES}; do --${GOPROTOBINARY}_out=plugins=grpc:"$GOPATH"/src \ --grpc-gateway_out=logtostderr=true:"$GOPATH"/src \ --swagger_out=logtostderr=true:. \ - $i + "$i" done -[ -e ./v2 ] && rm -rf v2 + +[ -L "${GOPATH_PROJECT_ROOT}" ] && rm -rf "${GOPATH_PROJECT_ROOT}" +[ -L ./v2 ] && rm -rf v2 # collect_swagger gathers swagger files into a subdirectory collect_swagger() { @@ -97,7 +111,7 @@ collect_swagger() { PRIMARY_SWAGGER=$(mktemp) COMBINED_SWAGGER=$(mktemp) - cat < "${PRIMARY_SWAGGER}" + cat <"${PRIMARY_SWAGGER}" { "swagger": "2.0", "info": { @@ -111,7 +125,7 @@ EOF rm -f "${SWAGGER_OUT}" - find "${SWAGGER_ROOT}" -name '*.swagger.json' -exec swagger mixin --ignore-conflicts "${PRIMARY_SWAGGER}" '{}' \+ > "${COMBINED_SWAGGER}" + find "${SWAGGER_ROOT}" -name '*.swagger.json' -exec swagger mixin --ignore-conflicts "${PRIMARY_SWAGGER}" '{}' \+ >"${COMBINED_SWAGGER}" jq -r 'del(.definitions[].properties[]? | select(."$ref"!=null and .description!=null).description) | del(.definitions[].properties[]? | select(."$ref"!=null and .title!=null).title) | # The "array" and "map" fields have custom unmarshaling. Modify the swagger to reflect this. .definitions.v1alpha1ApplicationSourcePluginParameter.properties.array = {"description":"Array is the value of an array type parameter.","type":"array","items":{"type":"string"}} | @@ -120,10 +134,10 @@ EOF del(.definitions.v1alpha1OptionalMap) | # Output for int64 is incorrect, because it is based on proto definitions, where int64 is a string. In our JSON API, we expect int64 to be an integer. https://github.com/grpc-ecosystem/grpc-gateway/issues/219 (.definitions[]?.properties[]? | select(.type == "string" and .format == "int64")) |= (.type = "integer") - ' "${COMBINED_SWAGGER}" | \ - jq '.definitions.v1Time.type = "string" | .definitions.v1Time.format = "date-time" | del(.definitions.v1Time.properties)' | \ - jq '.definitions.v1alpha1ResourceNode.allOf = [{"$ref": "#/definitions/v1alpha1ResourceRef"}] | del(.definitions.v1alpha1ResourceNode.properties.resourceRef) ' \ - > "${SWAGGER_OUT}" + ' "${COMBINED_SWAGGER}" | + jq '.definitions.v1Time.type = "string" | .definitions.v1Time.format = "date-time" | del(.definitions.v1Time.properties)' | + jq '.definitions.v1alpha1ResourceNode.allOf = [{"$ref": "#/definitions/v1alpha1ResourceRef"}] | del(.definitions.v1alpha1ResourceNode.properties.resourceRef) ' \ + >"${SWAGGER_OUT}" /bin/rm "${PRIMARY_SWAGGER}" "${COMBINED_SWAGGER}" } @@ -139,4 +153,3 @@ clean_swagger server clean_swagger reposerver clean_swagger controller clean_swagger cmpserver - diff --git a/hack/installers/checksums/helm-v3.13.1-linux-amd64.tar.gz.sha256 b/hack/installers/checksums/helm-v3.13.1-linux-amd64.tar.gz.sha256 new file mode 100644 index 0000000000000..752a8c186935c --- /dev/null +++ b/hack/installers/checksums/helm-v3.13.1-linux-amd64.tar.gz.sha256 @@ -0,0 +1 @@ +98c363564d00afd0cc3088e8f830f2a0eeb5f28755b3d8c48df89866374a1ed0 helm-v3.13.1-linux-amd64.tar.gz diff --git a/hack/installers/checksums/helm-v3.13.1-linux-arm64.tar.gz.sha256 b/hack/installers/checksums/helm-v3.13.1-linux-arm64.tar.gz.sha256 new file mode 100644 index 0000000000000..16904cec9ea94 --- /dev/null +++ b/hack/installers/checksums/helm-v3.13.1-linux-arm64.tar.gz.sha256 @@ -0,0 +1 @@ +8c4a0777218b266a7b977394aaf0e9cef30ed2df6e742d683e523d75508d6efe helm-v3.13.1-linux-arm64.tar.gz diff --git a/hack/installers/checksums/helm-v3.13.1-linux-ppc64le.tar.gz.sha256 b/hack/installers/checksums/helm-v3.13.1-linux-ppc64le.tar.gz.sha256 new file mode 100644 index 0000000000000..3f1e79193a05e --- /dev/null +++ b/hack/installers/checksums/helm-v3.13.1-linux-ppc64le.tar.gz.sha256 @@ -0,0 +1 @@ +f0d4ae95b4db25d03ced987e30d424564bd4727af6a4a0b7fca41f14203306fb helm-v3.13.1-linux-ppc64le.tar.gz diff --git a/hack/installers/checksums/helm-v3.13.1-linux-s390x.tar.gz.sha256 b/hack/installers/checksums/helm-v3.13.1-linux-s390x.tar.gz.sha256 new file mode 100644 index 0000000000000..493db677b1cf2 --- /dev/null +++ b/hack/installers/checksums/helm-v3.13.1-linux-s390x.tar.gz.sha256 @@ -0,0 +1 @@ +b657b72b34f568527093dede148ae72fcbc1f2e67d3fd6f2ffa1095637fbddb6 helm-v3.13.1-linux-s390x.tar.gz diff --git a/hack/installers/checksums/helm-v3.13.2-linux-amd64.tar.gz.sha256 b/hack/installers/checksums/helm-v3.13.2-linux-amd64.tar.gz.sha256 new file mode 100644 index 0000000000000..8908445e50510 --- /dev/null +++ b/hack/installers/checksums/helm-v3.13.2-linux-amd64.tar.gz.sha256 @@ -0,0 +1 @@ +55a8e6dce87a1e52c61e0ce7a89bf85b38725ba3e8deb51d4a08ade8a2c70b2d helm-v3.13.2-linux-amd64.tar.gz diff --git a/hack/installers/checksums/helm-v3.13.2-linux-arm64.tar.gz.sha256 b/hack/installers/checksums/helm-v3.13.2-linux-arm64.tar.gz.sha256 new file mode 100644 index 0000000000000..cf6b333b8d98b --- /dev/null +++ b/hack/installers/checksums/helm-v3.13.2-linux-arm64.tar.gz.sha256 @@ -0,0 +1 @@ +f5654aaed63a0da72852776e1d3f851b2ea9529cb5696337202703c2e1ed2321 helm-v3.13.2-linux-arm64.tar.gz diff --git a/hack/installers/checksums/helm-v3.13.2-linux-ppc64le.tar.gz.sha256 b/hack/installers/checksums/helm-v3.13.2-linux-ppc64le.tar.gz.sha256 new file mode 100644 index 0000000000000..696df1bb8df5e --- /dev/null +++ b/hack/installers/checksums/helm-v3.13.2-linux-ppc64le.tar.gz.sha256 @@ -0,0 +1 @@ +11d96134cc4ec106c23cd8c163072e9aed6cd73e36a3da120e5876d426203f37 helm-v3.13.2-linux-ppc64le.tar.gz diff --git a/hack/installers/checksums/helm-v3.13.2-linux-s390x.tar.gz.sha256 b/hack/installers/checksums/helm-v3.13.2-linux-s390x.tar.gz.sha256 new file mode 100644 index 0000000000000..f539faf320db7 --- /dev/null +++ b/hack/installers/checksums/helm-v3.13.2-linux-s390x.tar.gz.sha256 @@ -0,0 +1 @@ +3ffc5b4a041e5306dc00905ebe5dfea449e34ada268a713d34c69709afd6a9a2 helm-v3.13.2-linux-s390x.tar.gz diff --git a/hack/installers/checksums/helm-v3.14.0-linux-amd64.tar.gz.sha256 b/hack/installers/checksums/helm-v3.14.0-linux-amd64.tar.gz.sha256 new file mode 100644 index 0000000000000..6f9aaf5a270d5 --- /dev/null +++ b/hack/installers/checksums/helm-v3.14.0-linux-amd64.tar.gz.sha256 @@ -0,0 +1 @@ +f43e1c3387de24547506ab05d24e5309c0ce0b228c23bd8aa64e9ec4b8206651 helm-v3.14.0-linux-amd64.tar.gz diff --git a/hack/installers/checksums/helm-v3.14.0-linux-arm64.tar.gz.sha256 b/hack/installers/checksums/helm-v3.14.0-linux-arm64.tar.gz.sha256 new file mode 100644 index 0000000000000..d0e09bd4b41f7 --- /dev/null +++ b/hack/installers/checksums/helm-v3.14.0-linux-arm64.tar.gz.sha256 @@ -0,0 +1 @@ +b29e61674731b15f6ad3d1a3118a99d3cc2ab25a911aad1b8ac8c72d5a9d2952 helm-v3.14.0-linux-arm64.tar.gz diff --git a/hack/installers/checksums/helm-v3.14.0-linux-ppc64le.tar.gz.sha256 b/hack/installers/checksums/helm-v3.14.0-linux-ppc64le.tar.gz.sha256 new file mode 100644 index 0000000000000..d179322b99dd5 --- /dev/null +++ b/hack/installers/checksums/helm-v3.14.0-linux-ppc64le.tar.gz.sha256 @@ -0,0 +1 @@ +f1f9d3561724863edd4c06d89acb2e2fd8ae0f1b72058ceb891fa1c346ce5dbc helm-v3.14.0-linux-ppc64le.tar.gz diff --git a/hack/installers/checksums/helm-v3.14.0-linux-s390x.tar.gz.sha256 b/hack/installers/checksums/helm-v3.14.0-linux-s390x.tar.gz.sha256 new file mode 100644 index 0000000000000..31ff04397b29e --- /dev/null +++ b/hack/installers/checksums/helm-v3.14.0-linux-s390x.tar.gz.sha256 @@ -0,0 +1 @@ +82298ef39936f1bef848959a29f77bff92d1309d8646657e3a7733702e81288c helm-v3.14.0-linux-s390x.tar.gz diff --git a/hack/installers/checksums/kustomize_5.1.1_darwin_amd64.tar.gz.sha256 b/hack/installers/checksums/kustomize_5.1.1_darwin_amd64.tar.gz.sha256 new file mode 100644 index 0000000000000..09a5d2486e71c --- /dev/null +++ b/hack/installers/checksums/kustomize_5.1.1_darwin_amd64.tar.gz.sha256 @@ -0,0 +1 @@ +94047e967028b2849f9be1988f0cc084187ee3b77a1a0d88ede3979894da4af4 kustomize_5.1.1_darwin_amd64.tar.gz diff --git a/hack/installers/checksums/kustomize_5.1.1_linux_amd64.tar.gz.sha256 b/hack/installers/checksums/kustomize_5.1.1_linux_amd64.tar.gz.sha256 new file mode 100644 index 0000000000000..79e38f6c825b7 --- /dev/null +++ b/hack/installers/checksums/kustomize_5.1.1_linux_amd64.tar.gz.sha256 @@ -0,0 +1 @@ +3b30477a7ff4fb6547fa77d8117e66d995c2bdd526de0dafbf8b7bcb9556c85d kustomize_5.1.1_linux_amd64.tar.gz diff --git a/hack/installers/checksums/kustomize_5.1.1_linux_arm64.tar.gz.sha256 b/hack/installers/checksums/kustomize_5.1.1_linux_arm64.tar.gz.sha256 new file mode 100644 index 0000000000000..5a5da060b3d58 --- /dev/null +++ b/hack/installers/checksums/kustomize_5.1.1_linux_arm64.tar.gz.sha256 @@ -0,0 +1 @@ +a1bfb5d919c84817b8265d661fb99aae8176bcfe0b9df92651de93304cae953d kustomize_5.1.1_linux_arm64.tar.gz diff --git a/hack/installers/checksums/kustomize_5.1.1_linux_ppc64le.tar.gz.sha256 b/hack/installers/checksums/kustomize_5.1.1_linux_ppc64le.tar.gz.sha256 new file mode 100644 index 0000000000000..de21b4f3fd6d7 --- /dev/null +++ b/hack/installers/checksums/kustomize_5.1.1_linux_ppc64le.tar.gz.sha256 @@ -0,0 +1 @@ +d9437fcadb9f3ff321ed83c8b485a7066cb7274971ee2e599be238c08be88493 kustomize_5.1.1_linux_ppc64le.tar.gz diff --git a/hack/installers/checksums/kustomize_5.1.1_linux_s390x.tar.gz.sha256 b/hack/installers/checksums/kustomize_5.1.1_linux_s390x.tar.gz.sha256 new file mode 100644 index 0000000000000..86e92abf259ae --- /dev/null +++ b/hack/installers/checksums/kustomize_5.1.1_linux_s390x.tar.gz.sha256 @@ -0,0 +1 @@ +24712149a2ebf38b854918988314df7d3255f738c8f1875c9823dd2e6aa07a60 kustomize_5.1.1_linux_s390x.tar.gz diff --git a/hack/installers/checksums/kustomize_5.2.1_darwin_amd64.tar.gz.sha256 b/hack/installers/checksums/kustomize_5.2.1_darwin_amd64.tar.gz.sha256 new file mode 100644 index 0000000000000..655910d278d31 --- /dev/null +++ b/hack/installers/checksums/kustomize_5.2.1_darwin_amd64.tar.gz.sha256 @@ -0,0 +1 @@ +b7aba749da75d33e6fea49a5098747d379abc45583ff5cd16e2356127a396549 kustomize_5.2.1_darwin_amd64.tar.gz diff --git a/hack/installers/checksums/kustomize_5.2.1_darwin_arm64.tar.gz.sha256 b/hack/installers/checksums/kustomize_5.2.1_darwin_arm64.tar.gz.sha256 new file mode 100644 index 0000000000000..55f753b7cb4a5 --- /dev/null +++ b/hack/installers/checksums/kustomize_5.2.1_darwin_arm64.tar.gz.sha256 @@ -0,0 +1 @@ +f6a5f3cffd45bac585a0c80b5ed855c2b72d932a1d6e8e7c87aae3be4eba5750 kustomize_5.2.1_darwin_arm64.tar.gz diff --git a/hack/installers/checksums/kustomize_5.2.1_linux_amd64.tar.gz.sha256 b/hack/installers/checksums/kustomize_5.2.1_linux_amd64.tar.gz.sha256 new file mode 100644 index 0000000000000..a9cb3b79c77e8 --- /dev/null +++ b/hack/installers/checksums/kustomize_5.2.1_linux_amd64.tar.gz.sha256 @@ -0,0 +1 @@ +88346543206b889f9287c0b92c70708040ecd5aad54dd33019c4d6579cd24de8 kustomize_5.2.1_linux_amd64.tar.gz diff --git a/hack/installers/checksums/kustomize_5.2.1_linux_arm64.tar.gz.sha256 b/hack/installers/checksums/kustomize_5.2.1_linux_arm64.tar.gz.sha256 new file mode 100644 index 0000000000000..ff4078ddd85f3 --- /dev/null +++ b/hack/installers/checksums/kustomize_5.2.1_linux_arm64.tar.gz.sha256 @@ -0,0 +1 @@ +5566f7badece5a72d42075d8dffa6296a228966dd6ac2390de7afbb9675c3aaa kustomize_5.2.1_linux_arm64.tar.gz diff --git a/hack/installers/checksums/kustomize_5.2.1_linux_ppc64le.tar.gz.sha256 b/hack/installers/checksums/kustomize_5.2.1_linux_ppc64le.tar.gz.sha256 new file mode 100644 index 0000000000000..b5b6c7e9f077c --- /dev/null +++ b/hack/installers/checksums/kustomize_5.2.1_linux_ppc64le.tar.gz.sha256 @@ -0,0 +1 @@ +82d732cf624b6fa67dfabe751e9a1510e2d08605996b1b130b4c0f5b835b130e kustomize_5.2.1_linux_ppc64le.tar.gz diff --git a/hack/installers/checksums/kustomize_5.2.1_linux_s390x.tar.gz.sha256 b/hack/installers/checksums/kustomize_5.2.1_linux_s390x.tar.gz.sha256 new file mode 100644 index 0000000000000..565fb1df10d8e --- /dev/null +++ b/hack/installers/checksums/kustomize_5.2.1_linux_s390x.tar.gz.sha256 @@ -0,0 +1 @@ +d94cb97a2776b4685ab41233dfd5f0b426f399d2fce87d2b69e1ce4907f3aad2 kustomize_5.2.1_linux_s390x.tar.gz diff --git a/hack/tool-versions.sh b/hack/tool-versions.sh index 0a78a89c9f0f4..3cd1bc15aa4c4 100644 --- a/hack/tool-versions.sh +++ b/hack/tool-versions.sh @@ -11,8 +11,8 @@ # Use ./hack/installers/checksums/add-helm-checksums.sh and # add-kustomize-checksums.sh to help download checksums. ############################################################################### -helm3_version=3.12.1 +helm3_version=3.14.0 kubectl_version=1.17.8 kubectx_version=0.6.3 -kustomize5_version=5.1.0 +kustomize5_version=5.2.1 protoc_version=3.17.3 diff --git a/hack/update-codegen.sh b/hack/update-codegen.sh index abee0493ead86..9f6d15524d04d 100755 --- a/hack/update-codegen.sh +++ b/hack/update-codegen.sh @@ -19,21 +19,31 @@ set -o errexit set -o nounset set -o pipefail -PROJECT_ROOT=$(cd $(dirname ${BASH_SOURCE})/..; pwd) +PROJECT_ROOT=$( + cd $(dirname ${BASH_SOURCE})/.. + pwd +) PATH="${PROJECT_ROOT}/dist:${PATH}" +GOPATH=$(go env GOPATH) +GOPATH_PROJECT_ROOT="${GOPATH}/src/github.com/argoproj/argo-cd" TARGET_SCRIPT=/tmp/generate-groups.sh # codegen utilities are installed outside of generate-groups.sh so remove the `go install` step in the script. -sed -e '/go install/d' ${PROJECT_ROOT}/vendor/k8s.io/code-generator/generate-groups.sh > ${TARGET_SCRIPT} +sed -e '/go install/d' ${PROJECT_ROOT}/vendor/k8s.io/code-generator/generate-groups.sh >${TARGET_SCRIPT} # generate-groups.sh assumes codegen utilities are installed to GOBIN, but we just ensure the CLIs # are in the path and invoke them without assumption of their location sed -i.bak -e 's#${gobin}/##g' ${TARGET_SCRIPT} [ -e ./v2 ] || ln -s . v2 +[ -e "${GOPATH_PROJECT_ROOT}" ] || (mkdir -p "$(dirname "${GOPATH_PROJECT_ROOT}")" && ln -s "${PROJECT_ROOT}" "${GOPATH_PROJECT_ROOT}") + bash -x ${TARGET_SCRIPT} "deepcopy,client,informer,lister" \ github.com/argoproj/argo-cd/v2/pkg/client github.com/argoproj/argo-cd/v2/pkg/apis \ "application:v1alpha1" \ - --go-header-file ${PROJECT_ROOT}/hack/custom-boilerplate.go.txt -[ -e ./v2 ] && rm -rf v2 \ No newline at end of file + --go-header-file "${PROJECT_ROOT}/hack/custom-boilerplate.go.txt" \ + --output-base "${GOPATH}/src" + +[ -L "${GOPATH_PROJECT_ROOT}" ] && rm -rf "${GOPATH_PROJECT_ROOT}" +[ -L ./v2 ] && rm -rf v2 diff --git a/hack/update-kubernetes-version.sh b/hack/update-kubernetes-version.sh new file mode 100755 index 0000000000000..8d52033a601fc --- /dev/null +++ b/hack/update-kubernetes-version.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +set -euo pipefail + +if [ -z "${1:-}" ]; then + echo "Example usage: ./hack/update-kubernetes-version.sh v1.26.11" + exit 1 +fi +VERSION=${1#"v"} +MODS=($( + curl -sS https://raw.githubusercontent.com/kubernetes/kubernetes/v${VERSION}/go.mod | + sed -n 's|.*k8s.io/\(.*\) => ./staging/src/k8s.io/.*|k8s.io/\1|p' +)) +for MOD in "${MODS[@]}"; do + echo "Updating $MOD..." >&2 + V=$( + go mod download -json "${MOD}@kubernetes-${VERSION}" | + sed -n 's|.*"Version": "\(.*\)".*|\1|p' + ) + go mod edit "-replace=${MOD}=${MOD}@${V}" +done +go get "k8s.io/kubernetes@v${VERSION}" +go mod tidy diff --git a/hack/update-openapi.sh b/hack/update-openapi.sh index 2db84ed5f6242..0250ed45b93ac 100755 --- a/hack/update-openapi.sh +++ b/hack/update-openapi.sh @@ -5,20 +5,30 @@ set -o errexit set -o nounset set -o pipefail -PROJECT_ROOT=$(cd $(dirname "$0")/.. ; pwd) +PROJECT_ROOT=$( + cd $(dirname "$0")/.. + pwd +) PATH="${PROJECT_ROOT}/dist:${PATH}" +GOPATH=$(go env GOPATH) +GOPATH_PROJECT_ROOT="${GOPATH}/src/github.com/argoproj/argo-cd" + VERSION="v1alpha1" - + [ -e ./v2 ] || ln -s . v2 +[ -e "${GOPATH_PROJECT_ROOT}" ] || (mkdir -p "$(dirname "${GOPATH_PROJECT_ROOT}")" && ln -s "${PROJECT_ROOT}" "${GOPATH_PROJECT_ROOT}") + openapi-gen \ --go-header-file ${PROJECT_ROOT}/hack/custom-boilerplate.go.txt \ --input-dirs github.com/argoproj/argo-cd/v2/pkg/apis/application/${VERSION} \ --output-package github.com/argoproj/argo-cd/v2/pkg/apis/application/${VERSION} \ --report-filename pkg/apis/api-rules/violation_exceptions.list \ + --output-base "${GOPATH}/src" \ $@ -[ -e ./v2 ] && rm -rf v2 + +[ -L "${GOPATH_PROJECT_ROOT}" ] && rm -rf "${GOPATH_PROJECT_ROOT}" +[ -L ./v2 ] && rm -rf v2 export GO111MODULE=on -go build -o ./dist/gen-crd-spec ${PROJECT_ROOT}/hack/gen-crd-spec +go build -o ./dist/gen-crd-spec "${PROJECT_ROOT}/hack/gen-crd-spec" ./dist/gen-crd-spec - diff --git a/manifests/base/application-controller-deployment/argocd-application-controller-deployment.yaml b/manifests/base/application-controller-deployment/argocd-application-controller-deployment.yaml index 14cb1a317bab3..68dd75de2f47f 100644 --- a/manifests/base/application-controller-deployment/argocd-application-controller-deployment.yaml +++ b/manifests/base/application-controller-deployment/argocd-application-controller-deployment.yaml @@ -20,8 +20,6 @@ spec: - args: - /usr/local/bin/argocd-application-controller env: - - name: ARGOCD_CONTROLLER_REPLICAS - value: "1" - name: ARGOCD_RECONCILIATION_TIMEOUT valueFrom: configMapKeyRef: @@ -34,24 +32,36 @@ spec: name: argocd-cm key: timeout.hard.reconciliation optional: true + - name: ARGOCD_RECONCILIATION_JITTER + valueFrom: + configMapKeyRef: + key: timeout.reconciliation.jitter + name: argocd-cm + optional: true + - name: ARGOCD_REPO_ERROR_GRACE_PERIOD_SECONDS + valueFrom: + configMapKeyRef: + name: argocd-cmd-params-cm + key: controller.repo.error.grace.period.seconds + optional: true - name: ARGOCD_APPLICATION_CONTROLLER_REPO_SERVER valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: repo.server - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: repo.server + optional: true - name: ARGOCD_APPLICATION_CONTROLLER_REPO_SERVER_TIMEOUT_SECONDS valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: controller.repo.server.timeout.seconds - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: controller.repo.server.timeout.seconds + optional: true - name: ARGOCD_APPLICATION_CONTROLLER_STATUS_PROCESSORS valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: controller.status.processors - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: controller.status.processors + optional: true - name: ARGOCD_APPLICATION_CONTROLLER_OPERATION_PROCESSORS valueFrom: configMapKeyRef: @@ -78,22 +88,22 @@ spec: optional: true - name: ARGOCD_APPLICATION_CONTROLLER_SELF_HEAL_TIMEOUT_SECONDS valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: controller.self.heal.timeout.seconds - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: controller.self.heal.timeout.seconds + optional: true - name: ARGOCD_APPLICATION_CONTROLLER_REPO_SERVER_PLAINTEXT valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: controller.repo.server.plaintext - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: controller.repo.server.plaintext + optional: true - name: ARGOCD_APPLICATION_CONTROLLER_REPO_SERVER_STRICT_TLS valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: controller.repo.server.strict.tls - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: controller.repo.server.strict.tls + optional: true - name: ARGOCD_APPLICATION_CONTROLLER_PERSIST_RESOURCE_HEALTH valueFrom: configMapKeyRef: @@ -102,16 +112,16 @@ spec: optional: true - name: ARGOCD_APP_STATE_CACHE_EXPIRATION valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: controller.app.state.cache.expiration - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: controller.app.state.cache.expiration + optional: true - name: REDIS_SERVER valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: redis.server - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: redis.server + optional: true - name: REDIS_COMPRESSION valueFrom: configMapKeyRef: @@ -120,45 +130,69 @@ spec: optional: true - name: REDISDB valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: redis.db - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: redis.db + optional: true - name: ARGOCD_DEFAULT_CACHE_EXPIRATION valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: controller.default.cache.expiration - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: controller.default.cache.expiration + optional: true - name: ARGOCD_APPLICATION_CONTROLLER_OTLP_ADDRESS valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: otlp.address - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: otlp.address + optional: true + - name: ARGOCD_APPLICATION_CONTROLLER_OTLP_INSECURE + valueFrom: + configMapKeyRef: + name: argocd-cmd-params-cm + key: otlp.insecure + optional: true + - name: ARGOCD_APPLICATION_CONTROLLER_OTLP_HEADERS + valueFrom: + configMapKeyRef: + name: argocd-cmd-params-cm + key: otlp.headers + optional: true - name: ARGOCD_APPLICATION_NAMESPACES valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: application.namespaces - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: application.namespaces + optional: true - name: ARGOCD_CONTROLLER_SHARDING_ALGORITHM valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: controller.sharding.algorithm - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: controller.sharding.algorithm + optional: true - name: ARGOCD_APPLICATION_CONTROLLER_KUBECTL_PARALLELISM_LIMIT valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: controller.kubectl.parallelism.limit - optional: true - - name: ARGOCD_CONTROLLER_HEARTBEAT_TIME + configMapKeyRef: + name: argocd-cmd-params-cm + key: controller.kubectl.parallelism.limit + optional: true + - name: ARGOCD_K8SCLIENT_RETRY_MAX + valueFrom: + configMapKeyRef: + name: argocd-cmd-params-cm + key: controller.k8sclient.retry.max + optional: true + - name: ARGOCD_K8SCLIENT_RETRY_BASE_BACKOFF + valueFrom: + configMapKeyRef: + name: argocd-cmd-params-cm + key: controller.k8sclient.retry.base.backoff + optional: true + - name: ARGOCD_APPLICATION_CONTROLLER_SERVER_SIDE_DIFF valueFrom: configMapKeyRef: name: argocd-cmd-params-cm - key: controller.heatbeat.time + key: controller.diff.server.side optional: true image: quay.io/argoproj/argocd:latest imagePullPolicy: Always @@ -215,4 +249,4 @@ spec: - key: tls.key path: tls.key - key: ca.crt - path: ca.crt \ No newline at end of file + path: ca.crt diff --git a/manifests/base/application-controller-deployment/argocd-application-controller-statefulset.yaml b/manifests/base/application-controller-deployment/argocd-application-controller-statefulset.yaml new file mode 100644 index 0000000000000..10e4ea2ac7e3e --- /dev/null +++ b/manifests/base/application-controller-deployment/argocd-application-controller-statefulset.yaml @@ -0,0 +1,15 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: argocd-application-controller +spec: + replicas: 0 + template: + spec: + containers: + - name: argocd-application-controller + args: + - /usr/local/bin/argocd-application-controller + env: + - name: ARGOCD_CONTROLLER_REPLICAS + value: "0" \ No newline at end of file diff --git a/manifests/base/application-controller-deployment/kustomization.yaml b/manifests/base/application-controller-deployment/kustomization.yaml index 8f35ec8bd388f..733a378e013e0 100644 --- a/manifests/base/application-controller-deployment/kustomization.yaml +++ b/manifests/base/application-controller-deployment/kustomization.yaml @@ -2,5 +2,8 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: +- ../application-controller-roles - argocd-application-controller-service.yaml +- argocd-application-controller-statefulset.yaml - argocd-application-controller-deployment.yaml + diff --git a/manifests/base/application-controller/argocd-application-controller-role.yaml b/manifests/base/application-controller-roles/argocd-application-controller-role.yaml similarity index 87% rename from manifests/base/application-controller/argocd-application-controller-role.yaml rename to manifests/base/application-controller-roles/argocd-application-controller-role.yaml index 27e0bc7bfe9cb..a672268eb1dd9 100644 --- a/manifests/base/application-controller/argocd-application-controller-role.yaml +++ b/manifests/base/application-controller-roles/argocd-application-controller-role.yaml @@ -36,3 +36,11 @@ rules: verbs: - create - list +- apiGroups: + - apps + resources: + - deployments + verbs: + - get + - list + - watch diff --git a/manifests/base/application-controller/argocd-application-controller-rolebinding.yaml b/manifests/base/application-controller-roles/argocd-application-controller-rolebinding.yaml similarity index 100% rename from manifests/base/application-controller/argocd-application-controller-rolebinding.yaml rename to manifests/base/application-controller-roles/argocd-application-controller-rolebinding.yaml diff --git a/manifests/base/application-controller/argocd-application-controller-sa.yaml b/manifests/base/application-controller-roles/argocd-application-controller-sa.yaml similarity index 100% rename from manifests/base/application-controller/argocd-application-controller-sa.yaml rename to manifests/base/application-controller-roles/argocd-application-controller-sa.yaml diff --git a/manifests/base/application-controller-roles/kustomization.yaml b/manifests/base/application-controller-roles/kustomization.yaml new file mode 100644 index 0000000000000..f834d2ef3dbc4 --- /dev/null +++ b/manifests/base/application-controller-roles/kustomization.yaml @@ -0,0 +1,7 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: +- argocd-application-controller-sa.yaml +- argocd-application-controller-role.yaml +- argocd-application-controller-rolebinding.yaml diff --git a/manifests/base/application-controller/argocd-application-controller-statefulset.yaml b/manifests/base/application-controller/argocd-application-controller-statefulset.yaml index 33f02100a947a..d974edffdd618 100644 --- a/manifests/base/application-controller/argocd-application-controller-statefulset.yaml +++ b/manifests/base/application-controller/argocd-application-controller-statefulset.yaml @@ -35,24 +35,36 @@ spec: name: argocd-cm key: timeout.hard.reconciliation optional: true + - name: ARGOCD_RECONCILIATION_JITTER + valueFrom: + configMapKeyRef: + key: timeout.reconciliation.jitter + name: argocd-cm + optional: true + - name: ARGOCD_REPO_ERROR_GRACE_PERIOD_SECONDS + valueFrom: + configMapKeyRef: + name: argocd-cmd-params-cm + key: controller.repo.error.grace.period.seconds + optional: true - name: ARGOCD_APPLICATION_CONTROLLER_REPO_SERVER valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: repo.server - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: repo.server + optional: true - name: ARGOCD_APPLICATION_CONTROLLER_REPO_SERVER_TIMEOUT_SECONDS valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: controller.repo.server.timeout.seconds - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: controller.repo.server.timeout.seconds + optional: true - name: ARGOCD_APPLICATION_CONTROLLER_STATUS_PROCESSORS valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: controller.status.processors - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: controller.status.processors + optional: true - name: ARGOCD_APPLICATION_CONTROLLER_OPERATION_PROCESSORS valueFrom: configMapKeyRef: @@ -79,22 +91,22 @@ spec: optional: true - name: ARGOCD_APPLICATION_CONTROLLER_SELF_HEAL_TIMEOUT_SECONDS valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: controller.self.heal.timeout.seconds - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: controller.self.heal.timeout.seconds + optional: true - name: ARGOCD_APPLICATION_CONTROLLER_REPO_SERVER_PLAINTEXT valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: controller.repo.server.plaintext - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: controller.repo.server.plaintext + optional: true - name: ARGOCD_APPLICATION_CONTROLLER_REPO_SERVER_STRICT_TLS valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: controller.repo.server.strict.tls - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: controller.repo.server.strict.tls + optional: true - name: ARGOCD_APPLICATION_CONTROLLER_PERSIST_RESOURCE_HEALTH valueFrom: configMapKeyRef: @@ -103,16 +115,16 @@ spec: optional: true - name: ARGOCD_APP_STATE_CACHE_EXPIRATION valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: controller.app.state.cache.expiration - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: controller.app.state.cache.expiration + optional: true - name: REDIS_SERVER valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: redis.server - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: redis.server + optional: true - name: REDIS_COMPRESSION valueFrom: configMapKeyRef: @@ -121,40 +133,70 @@ spec: optional: true - name: REDISDB valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: redis.db - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: redis.db + optional: true - name: ARGOCD_DEFAULT_CACHE_EXPIRATION valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: controller.default.cache.expiration - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: controller.default.cache.expiration + optional: true - name: ARGOCD_APPLICATION_CONTROLLER_OTLP_ADDRESS valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: otlp.address - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: otlp.address + optional: true + - name: ARGOCD_APPLICATION_CONTROLLER_OTLP_INSECURE + valueFrom: + configMapKeyRef: + name: argocd-cmd-params-cm + key: otlp.insecure + optional: true + - name: ARGOCD_APPLICATION_CONTROLLER_OTLP_HEADERS + valueFrom: + configMapKeyRef: + name: argocd-cmd-params-cm + key: otlp.headers + optional: true - name: ARGOCD_APPLICATION_NAMESPACES valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: application.namespaces - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: application.namespaces + optional: true - name: ARGOCD_CONTROLLER_SHARDING_ALGORITHM valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: controller.sharding.algorithm - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: controller.sharding.algorithm + optional: true - name: ARGOCD_APPLICATION_CONTROLLER_KUBECTL_PARALLELISM_LIMIT valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: controller.kubectl.parallelism.limit - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: controller.kubectl.parallelism.limit + optional: true + - name: ARGOCD_K8SCLIENT_RETRY_MAX + valueFrom: + configMapKeyRef: + name: argocd-cmd-params-cm + key: controller.k8sclient.retry.max + optional: true + - name: ARGOCD_K8SCLIENT_RETRY_BASE_BACKOFF + valueFrom: + configMapKeyRef: + name: argocd-cmd-params-cm + key: controller.k8sclient.retry.base.backoff + optional: true + - name: ARGOCD_APPLICATION_CONTROLLER_SERVER_SIDE_DIFF + valueFrom: + configMapKeyRef: + name: argocd-cmd-params-cm + key: controller.diff.server.side + optional: true image: quay.io/argoproj/argocd:latest imagePullPolicy: Always name: argocd-application-controller @@ -210,4 +252,4 @@ spec: - key: tls.key path: tls.key - key: ca.crt - path: ca.crt \ No newline at end of file + path: ca.crt diff --git a/manifests/base/application-controller/kustomization.yaml b/manifests/base/application-controller/kustomization.yaml index 9a801ad877bd2..616977fb9b08b 100644 --- a/manifests/base/application-controller/kustomization.yaml +++ b/manifests/base/application-controller/kustomization.yaml @@ -2,9 +2,7 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: -- argocd-application-controller-sa.yaml -- argocd-application-controller-role.yaml -- argocd-application-controller-rolebinding.yaml +- ../application-controller-roles - argocd-application-controller-statefulset.yaml - argocd-metrics.yaml - argocd-application-controller-network-policy.yaml \ No newline at end of file diff --git a/manifests/base/dex/argocd-dex-server-deployment.yaml b/manifests/base/dex/argocd-dex-server-deployment.yaml index 8d3b37d177913..7ff5985f44a90 100644 --- a/manifests/base/dex/argocd-dex-server-deployment.yaml +++ b/manifests/base/dex/argocd-dex-server-deployment.yaml @@ -37,7 +37,7 @@ spec: type: RuntimeDefault containers: - name: dex - image: ghcr.io/dexidp/dex:v2.37.0 + image: ghcr.io/dexidp/dex:v2.38.0 imagePullPolicy: Always command: [/shared/argocd-dex, rundex] env: diff --git a/manifests/base/notification/argocd-notifications-controller-deployment.yaml b/manifests/base/notification/argocd-notifications-controller-deployment.yaml index 9cd1a068808b1..876a207c16e42 100644 --- a/manifests/base/notification/argocd-notifications-controller-deployment.yaml +++ b/manifests/base/notification/argocd-notifications-controller-deployment.yaml @@ -54,6 +54,12 @@ spec: key: application.namespaces name: argocd-cmd-params-cm optional: true + - name: ARGOCD_NOTIFICATION_CONTROLLER_SELF_SERVICE_NOTIFICATION_ENABLED + valueFrom: + configMapKeyRef: + key: notificationscontroller.selfservice.enabled + name: argocd-cmd-params-cm + optional: true workingDir: /app livenessProbe: tcpSocket: diff --git a/manifests/base/redis/argocd-redis-deployment.yaml b/manifests/base/redis/argocd-redis-deployment.yaml index 8d649e3995ebc..6fc776785185f 100644 --- a/manifests/base/redis/argocd-redis-deployment.yaml +++ b/manifests/base/redis/argocd-redis-deployment.yaml @@ -23,7 +23,7 @@ spec: serviceAccountName: argocd-redis containers: - name: redis - image: redis:7.0.11-alpine + image: redis:7.0.14-alpine imagePullPolicy: Always args: - "--save" diff --git a/manifests/base/repo-server/argocd-repo-server-deployment.yaml b/manifests/base/repo-server/argocd-repo-server-deployment.yaml index eb230e0f9b856..907bc80a34e56 100644 --- a/manifests/base/repo-server/argocd-repo-server-deployment.yaml +++ b/manifests/base/repo-server/argocd-repo-server-deployment.yaml @@ -120,6 +120,18 @@ spec: name: argocd-cmd-params-cm key: otlp.address optional: true + - name: ARGOCD_REPO_SERVER_OTLP_INSECURE + valueFrom: + configMapKeyRef: + name: argocd-cmd-params-cm + key: otlp.insecure + optional: true + - name: ARGOCD_REPO_SERVER_OTLP_HEADERS + valueFrom: + configMapKeyRef: + name: argocd-cmd-params-cm + key: otlp.headers + optional: true - name: ARGOCD_REPO_SERVER_MAX_COMBINED_DIRECTORY_MANIFESTS_SIZE valueFrom: configMapKeyRef: @@ -168,6 +180,18 @@ spec: key: reposerver.enable.git.submodule name: argocd-cmd-params-cm optional: true + - name: ARGOCD_GIT_LS_REMOTE_PARALLELISM_LIMIT + valueFrom: + configMapKeyRef: + key: reposerver.git.lsremote.parallelism.limit + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_GIT_REQUEST_TIMEOUT + valueFrom: + configMapKeyRef: + key: reposerver.git.request.timeout + name: argocd-cmd-params-cm + optional: true - name: HELM_CACHE_HOME value: /helm-working-dir - name: HELM_CONFIG_HOME diff --git a/manifests/base/server/argocd-server-deployment.yaml b/manifests/base/server/argocd-server-deployment.yaml index 66c6ed384b1d2..0ebeb70e08531 100644 --- a/manifests/base/server/argocd-server-deployment.yaml +++ b/manifests/base/server/argocd-server-deployment.yaml @@ -25,136 +25,136 @@ spec: env: - name: ARGOCD_SERVER_INSECURE valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: server.insecure - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: server.insecure + optional: true - name: ARGOCD_SERVER_BASEHREF valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: server.basehref - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: server.basehref + optional: true - name: ARGOCD_SERVER_ROOTPATH valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: server.rootpath - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: server.rootpath + optional: true - name: ARGOCD_SERVER_LOGFORMAT valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: server.log.format - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: server.log.format + optional: true - name: ARGOCD_SERVER_LOG_LEVEL valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: server.log.level - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: server.log.level + optional: true - name: ARGOCD_SERVER_REPO_SERVER valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: repo.server - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: repo.server + optional: true - name: ARGOCD_SERVER_DEX_SERVER valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: server.dex.server - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: server.dex.server + optional: true - name: ARGOCD_SERVER_DISABLE_AUTH valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: server.disable.auth - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: server.disable.auth + optional: true - name: ARGOCD_SERVER_ENABLE_GZIP valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: server.enable.gzip - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: server.enable.gzip + optional: true - name: ARGOCD_SERVER_REPO_SERVER_TIMEOUT_SECONDS valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: server.repo.server.timeout.seconds - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: server.repo.server.timeout.seconds + optional: true - name: ARGOCD_SERVER_X_FRAME_OPTIONS valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: server.x.frame.options - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: server.x.frame.options + optional: true - name: ARGOCD_SERVER_CONTENT_SECURITY_POLICY valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: server.content.security.policy - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: server.content.security.policy + optional: true - name: ARGOCD_SERVER_REPO_SERVER_PLAINTEXT valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: server.repo.server.plaintext - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: server.repo.server.plaintext + optional: true - name: ARGOCD_SERVER_REPO_SERVER_STRICT_TLS valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: server.repo.server.strict.tls - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: server.repo.server.strict.tls + optional: true - name: ARGOCD_SERVER_DEX_SERVER_PLAINTEXT valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: server.dex.server.plaintext - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: server.dex.server.plaintext + optional: true - name: ARGOCD_SERVER_DEX_SERVER_STRICT_TLS valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: server.dex.server.strict.tls - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: server.dex.server.strict.tls + optional: true - name: ARGOCD_TLS_MIN_VERSION valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: server.tls.minversion - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: server.tls.minversion + optional: true - name: ARGOCD_TLS_MAX_VERSION valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: server.tls.maxversion - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: server.tls.maxversion + optional: true - name: ARGOCD_TLS_CIPHERS valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: server.tls.ciphers - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: server.tls.ciphers + optional: true - name: ARGOCD_SERVER_CONNECTION_STATUS_CACHE_EXPIRATION valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: server.connection.status.cache.expiration - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: server.connection.status.cache.expiration + optional: true - name: ARGOCD_SERVER_OIDC_CACHE_EXPIRATION valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: server.oidc.cache.expiration - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: server.oidc.cache.expiration + optional: true - name: ARGOCD_SERVER_LOGIN_ATTEMPTS_EXPIRATION valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: server.login.attempts.expiration - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: server.login.attempts.expiration + optional: true - name: ARGOCD_SERVER_STATIC_ASSETS valueFrom: configMapKeyRef: @@ -163,16 +163,16 @@ spec: optional: true - name: ARGOCD_APP_STATE_CACHE_EXPIRATION valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: server.app.state.cache.expiration - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: server.app.state.cache.expiration + optional: true - name: REDIS_SERVER valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: redis.server - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: redis.server + optional: true - name: REDIS_COMPRESSION valueFrom: configMapKeyRef: @@ -181,52 +181,82 @@ spec: optional: true - name: REDISDB valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: redis.db - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: redis.db + optional: true - name: ARGOCD_DEFAULT_CACHE_EXPIRATION valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: server.default.cache.expiration - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: server.default.cache.expiration + optional: true - name: ARGOCD_MAX_COOKIE_NUMBER valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: server.http.cookie.maxnumber - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: server.http.cookie.maxnumber + optional: true - name: ARGOCD_SERVER_LISTEN_ADDRESS valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: server.listen.address - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: server.listen.address + optional: true - name: ARGOCD_SERVER_METRICS_LISTEN_ADDRESS valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: server.metrics.listen.address - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: server.metrics.listen.address + optional: true - name: ARGOCD_SERVER_OTLP_ADDRESS valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: otlp.address - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: otlp.address + optional: true + - name: ARGOCD_SERVER_OTLP_INSECURE + valueFrom: + configMapKeyRef: + name: argocd-cmd-params-cm + key: otlp.insecure + optional: true + - name: ARGOCD_SERVER_OTLP_HEADERS + valueFrom: + configMapKeyRef: + name: argocd-cmd-params-cm + key: otlp.headers + optional: true - name: ARGOCD_APPLICATION_NAMESPACES valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: application.namespaces - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: application.namespaces + optional: true - name: ARGOCD_SERVER_ENABLE_PROXY_EXTENSION valueFrom: - configMapKeyRef: - name: argocd-cmd-params-cm - key: server.enable.proxy.extension - optional: true + configMapKeyRef: + name: argocd-cmd-params-cm + key: server.enable.proxy.extension + optional: true + - name: ARGOCD_K8SCLIENT_RETRY_MAX + valueFrom: + configMapKeyRef: + name: argocd-cmd-params-cm + key: server.k8sclient.retry.max + optional: true + - name: ARGOCD_K8SCLIENT_RETRY_BASE_BACKOFF + valueFrom: + configMapKeyRef: + name: argocd-cmd-params-cm + key: server.k8sclient.retry.base.backoff + optional: true + - name: ARGOCD_API_CONTENT_TYPES + valueFrom: + configMapKeyRef: + name: argocd-cmd-params-cm + key: server.api.content.types + optional: true volumeMounts: - name: ssh-known-hosts mountPath: /app/config/ssh diff --git a/manifests/cluster-rbac/applicationset-controller/argocd-applicationset-controller-clusterrole.yaml b/manifests/cluster-rbac/applicationset-controller/argocd-applicationset-controller-clusterrole.yaml new file mode 100644 index 0000000000000..259a48e7aee9e --- /dev/null +++ b/manifests/cluster-rbac/applicationset-controller/argocd-applicationset-controller-clusterrole.yaml @@ -0,0 +1,88 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: argocd-applicationset-controller + app.kubernetes.io/part-of: argocd + app.kubernetes.io/component: applicationset-controller + name: argocd-applicationset-controller +rules: +- apiGroups: + - argoproj.io + resources: + - applications + - applicationsets + - applicationsets/finalizers + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - argoproj.io + resources: + - applicationsets/status + verbs: + - get + - patch + - update +- apiGroups: + - argoproj.io + resources: + - appprojects + verbs: + - get +- apiGroups: + - "" + resources: + - events + verbs: + - create + - get + - list + - patch + - watch +- apiGroups: + - "" + resources: + - configmaps + verbs: + - create + - update + - delete + - get + - list + - patch + - watch +- apiGroups: + - "" + resources: + - secrets + verbs: + - get + - list + - watch +- apiGroups: + - apps + - extensions + resources: + - deployments + verbs: + - get + - list + - watch +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - create + - delete + - get + - list + - patch + - update + - watch diff --git a/manifests/cluster-rbac/applicationset-controller/argocd-applicationset-controller-clusterrolebinding.yaml b/manifests/cluster-rbac/applicationset-controller/argocd-applicationset-controller-clusterrolebinding.yaml new file mode 100644 index 0000000000000..820f16f472e4e --- /dev/null +++ b/manifests/cluster-rbac/applicationset-controller/argocd-applicationset-controller-clusterrolebinding.yaml @@ -0,0 +1,16 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + app.kubernetes.io/name: argocd-applicationset-controller + app.kubernetes.io/part-of: argocd + app.kubernetes.io/component: applicationset-controller + name: argocd-applicationset-controller +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: argocd-applicationset-controller +subjects: +- kind: ServiceAccount + name: argocd-applicationset-controller + namespace: argocd diff --git a/manifests/cluster-rbac/applicationset-controller/kustomization.yaml b/manifests/cluster-rbac/applicationset-controller/kustomization.yaml new file mode 100644 index 0000000000000..b8f18c57a14f7 --- /dev/null +++ b/manifests/cluster-rbac/applicationset-controller/kustomization.yaml @@ -0,0 +1,6 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: +- argocd-applicationset-controller-clusterrole.yaml +- argocd-applicationset-controller-clusterrolebinding.yaml diff --git a/manifests/cluster-rbac/kustomization.yaml b/manifests/cluster-rbac/kustomization.yaml index 7f791905b661b..55e6e2d72df9e 100644 --- a/manifests/cluster-rbac/kustomization.yaml +++ b/manifests/cluster-rbac/kustomization.yaml @@ -3,4 +3,5 @@ kind: Kustomization resources: - ./application-controller +- ./applicationset-controller - ./server diff --git a/manifests/cluster-rbac/server/argocd-server-clusterrole.yaml b/manifests/cluster-rbac/server/argocd-server-clusterrole.yaml index f81f529086fb5..b33820950fcb6 100644 --- a/manifests/cluster-rbac/server/argocd-server-clusterrole.yaml +++ b/manifests/cluster-rbac/server/argocd-server-clusterrole.yaml @@ -32,6 +32,7 @@ rules: - "argoproj.io" resources: - "applications" + - "applicationsets" verbs: - get - list diff --git a/manifests/core-install.yaml b/manifests/core-install.yaml index 8456f5c3ef430..254cd6e22044f 100644 --- a/manifests/core-install.yaml +++ b/manifests/core-install.yaml @@ -320,6 +320,12 @@ spec: description: CommonLabels is a list of additional labels to add to rendered manifests type: object + components: + description: Components specifies a list of kustomize + components to add to the kustomization before building + items: + type: string + type: array forceCommonAnnotations: description: ForceCommonAnnotations specifies whether to force applying common annotations to resources for @@ -648,6 +654,12 @@ spec: description: CommonLabels is a list of additional labels to add to rendered manifests type: object + components: + description: Components specifies a list of kustomize + components to add to the kustomization before building + items: + type: string + type: array forceCommonAnnotations: description: ForceCommonAnnotations specifies whether to force applying common annotations to resources @@ -1093,6 +1105,12 @@ spec: description: CommonLabels is a list of additional labels to add to rendered manifests type: object + components: + description: Components specifies a list of kustomize components + to add to the kustomization before building + items: + type: string + type: array forceCommonAnnotations: description: ForceCommonAnnotations specifies whether to force applying common annotations to resources for Kustomize apps @@ -1411,6 +1429,12 @@ spec: description: CommonLabels is a list of additional labels to add to rendered manifests type: object + components: + description: Components specifies a list of kustomize components + to add to the kustomization before building + items: + type: string + type: array forceCommonAnnotations: description: ForceCommonAnnotations specifies whether to force applying common annotations to resources for Kustomize @@ -1702,6 +1726,19 @@ spec: description: ID is an auto incrementing identifier of the RevisionHistory format: int64 type: integer + initiatedBy: + description: InitiatedBy contains information about who initiated + the operations + properties: + automated: + description: Automated is set to true if operation was initiated + automatically by the application controller. + type: boolean + username: + description: Username contains the name of a user who started + operation + type: string + type: object revision: description: Revision holds the revision the sync was performed against @@ -1882,6 +1919,12 @@ spec: description: CommonLabels is a list of additional labels to add to rendered manifests type: object + components: + description: Components specifies a list of kustomize + components to add to the kustomization before building + items: + type: string + type: array forceCommonAnnotations: description: ForceCommonAnnotations specifies whether to force applying common annotations to resources @@ -2214,6 +2257,12 @@ spec: description: CommonLabels is a list of additional labels to add to rendered manifests type: object + components: + description: Components specifies a list of kustomize + components to add to the kustomization before building + items: + type: string + type: array forceCommonAnnotations: description: ForceCommonAnnotations specifies whether to force applying common annotations to resources @@ -2690,6 +2739,13 @@ spec: description: CommonLabels is a list of additional labels to add to rendered manifests type: object + components: + description: Components specifies a list of kustomize + components to add to the kustomization before + building + items: + type: string + type: array forceCommonAnnotations: description: ForceCommonAnnotations specifies whether to force applying common annotations @@ -3039,6 +3095,13 @@ spec: description: CommonLabels is a list of additional labels to add to rendered manifests type: object + components: + description: Components specifies a list of + kustomize components to add to the kustomization + before building + items: + type: string + type: array forceCommonAnnotations: description: ForceCommonAnnotations specifies whether to force applying common annotations @@ -3503,6 +3566,12 @@ spec: description: CommonLabels is a list of additional labels to add to rendered manifests type: object + components: + description: Components specifies a list of kustomize + components to add to the kustomization before building + items: + type: string + type: array forceCommonAnnotations: description: ForceCommonAnnotations specifies whether to force applying common annotations to resources @@ -3845,6 +3914,13 @@ spec: description: CommonLabels is a list of additional labels to add to rendered manifests type: object + components: + description: Components specifies a list of kustomize + components to add to the kustomization before + building + items: + type: string + type: array forceCommonAnnotations: description: ForceCommonAnnotations specifies whether to force applying common annotations to resources @@ -4331,6 +4407,12 @@ spec: description: CommonLabels is a list of additional labels to add to rendered manifests type: object + components: + description: Components specifies a list of kustomize + components to add to the kustomization before building + items: + type: string + type: array forceCommonAnnotations: description: ForceCommonAnnotations specifies whether to force applying common annotations to resources @@ -4673,6 +4755,13 @@ spec: description: CommonLabels is a list of additional labels to add to rendered manifests type: object + components: + description: Components specifies a list of kustomize + components to add to the kustomization before + building + items: + type: string + type: array forceCommonAnnotations: description: ForceCommonAnnotations specifies whether to force applying common annotations to resources @@ -5108,6 +5197,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -5318,6 +5411,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -5687,6 +5784,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -5897,6 +5998,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -6270,6 +6375,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -6480,6 +6589,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -6833,6 +6946,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -7043,6 +7160,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -7420,6 +7541,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -7630,6 +7755,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -7999,6 +8128,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -8209,6 +8342,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -8582,6 +8719,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -8792,6 +8933,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -9145,6 +9290,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -9355,6 +9504,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -9718,6 +9871,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -9928,6 +10085,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -10471,6 +10632,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -10681,6 +10846,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -11219,6 +11388,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -11429,6 +11602,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -11796,6 +11973,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -12006,6 +12187,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -12383,6 +12568,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -12593,6 +12782,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -12962,6 +13155,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -13172,6 +13369,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -13545,6 +13746,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -13755,6 +13960,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -14108,6 +14317,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -14318,6 +14531,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -14681,6 +14898,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -14891,6 +15112,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -15434,6 +15659,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -15644,6 +15873,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -16182,6 +16415,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -16392,6 +16629,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -16763,6 +17004,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -16973,6 +17218,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -17333,6 +17582,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -17543,6 +17796,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -18086,6 +18343,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -18296,6 +18557,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -18834,6 +19099,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -19044,6 +19313,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -19486,6 +19759,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -19696,6 +19973,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -19855,6 +20136,8 @@ spec: - metadata - spec type: object + templatePatch: + type: string required: - generators - template @@ -20312,6 +20595,14 @@ rules: verbs: - create - list +- apiGroups: + - apps + resources: + - deployments + verbs: + - get + - list + - watch --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role @@ -20843,7 +21134,7 @@ spec: - "" - --appendonly - "no" - image: redis:7.0.11-alpine + image: redis:7.0.14-alpine imagePullPolicy: Always name: redis ports: @@ -20994,6 +21285,18 @@ spec: key: otlp.address name: argocd-cmd-params-cm optional: true + - name: ARGOCD_REPO_SERVER_OTLP_INSECURE + valueFrom: + configMapKeyRef: + key: otlp.insecure + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_REPO_SERVER_OTLP_HEADERS + valueFrom: + configMapKeyRef: + key: otlp.headers + name: argocd-cmd-params-cm + optional: true - name: ARGOCD_REPO_SERVER_MAX_COMBINED_DIRECTORY_MANIFESTS_SIZE valueFrom: configMapKeyRef: @@ -21042,6 +21345,18 @@ spec: key: reposerver.enable.git.submodule name: argocd-cmd-params-cm optional: true + - name: ARGOCD_GIT_LS_REMOTE_PARALLELISM_LIMIT + valueFrom: + configMapKeyRef: + key: reposerver.git.lsremote.parallelism.limit + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_GIT_REQUEST_TIMEOUT + valueFrom: + configMapKeyRef: + key: reposerver.git.request.timeout + name: argocd-cmd-params-cm + optional: true - name: HELM_CACHE_HOME value: /helm-working-dir - name: HELM_CONFIG_HOME @@ -21199,6 +21514,18 @@ spec: key: timeout.hard.reconciliation name: argocd-cm optional: true + - name: ARGOCD_RECONCILIATION_JITTER + valueFrom: + configMapKeyRef: + key: timeout.reconciliation.jitter + name: argocd-cm + optional: true + - name: ARGOCD_REPO_ERROR_GRACE_PERIOD_SECONDS + valueFrom: + configMapKeyRef: + key: controller.repo.error.grace.period.seconds + name: argocd-cmd-params-cm + optional: true - name: ARGOCD_APPLICATION_CONTROLLER_REPO_SERVER valueFrom: configMapKeyRef: @@ -21301,6 +21628,18 @@ spec: key: otlp.address name: argocd-cmd-params-cm optional: true + - name: ARGOCD_APPLICATION_CONTROLLER_OTLP_INSECURE + valueFrom: + configMapKeyRef: + key: otlp.insecure + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATION_CONTROLLER_OTLP_HEADERS + valueFrom: + configMapKeyRef: + key: otlp.headers + name: argocd-cmd-params-cm + optional: true - name: ARGOCD_APPLICATION_NAMESPACES valueFrom: configMapKeyRef: @@ -21319,6 +21658,24 @@ spec: key: controller.kubectl.parallelism.limit name: argocd-cmd-params-cm optional: true + - name: ARGOCD_K8SCLIENT_RETRY_MAX + valueFrom: + configMapKeyRef: + key: controller.k8sclient.retry.max + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_K8SCLIENT_RETRY_BASE_BACKOFF + valueFrom: + configMapKeyRef: + key: controller.k8sclient.retry.base.backoff + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATION_CONTROLLER_SERVER_SIDE_DIFF + valueFrom: + configMapKeyRef: + key: controller.diff.server.side + name: argocd-cmd-params-cm + optional: true image: quay.io/argoproj/argocd:latest imagePullPolicy: Always name: argocd-application-controller diff --git a/manifests/crds/application-crd.yaml b/manifests/crds/application-crd.yaml index f1833e22a95da..f325dda7da6f7 100644 --- a/manifests/crds/application-crd.yaml +++ b/manifests/crds/application-crd.yaml @@ -319,6 +319,12 @@ spec: description: CommonLabels is a list of additional labels to add to rendered manifests type: object + components: + description: Components specifies a list of kustomize + components to add to the kustomization before building + items: + type: string + type: array forceCommonAnnotations: description: ForceCommonAnnotations specifies whether to force applying common annotations to resources for @@ -647,6 +653,12 @@ spec: description: CommonLabels is a list of additional labels to add to rendered manifests type: object + components: + description: Components specifies a list of kustomize + components to add to the kustomization before building + items: + type: string + type: array forceCommonAnnotations: description: ForceCommonAnnotations specifies whether to force applying common annotations to resources @@ -1092,6 +1104,12 @@ spec: description: CommonLabels is a list of additional labels to add to rendered manifests type: object + components: + description: Components specifies a list of kustomize components + to add to the kustomization before building + items: + type: string + type: array forceCommonAnnotations: description: ForceCommonAnnotations specifies whether to force applying common annotations to resources for Kustomize apps @@ -1410,6 +1428,12 @@ spec: description: CommonLabels is a list of additional labels to add to rendered manifests type: object + components: + description: Components specifies a list of kustomize components + to add to the kustomization before building + items: + type: string + type: array forceCommonAnnotations: description: ForceCommonAnnotations specifies whether to force applying common annotations to resources for Kustomize @@ -1701,6 +1725,19 @@ spec: description: ID is an auto incrementing identifier of the RevisionHistory format: int64 type: integer + initiatedBy: + description: InitiatedBy contains information about who initiated + the operations + properties: + automated: + description: Automated is set to true if operation was initiated + automatically by the application controller. + type: boolean + username: + description: Username contains the name of a user who started + operation + type: string + type: object revision: description: Revision holds the revision the sync was performed against @@ -1881,6 +1918,12 @@ spec: description: CommonLabels is a list of additional labels to add to rendered manifests type: object + components: + description: Components specifies a list of kustomize + components to add to the kustomization before building + items: + type: string + type: array forceCommonAnnotations: description: ForceCommonAnnotations specifies whether to force applying common annotations to resources @@ -2213,6 +2256,12 @@ spec: description: CommonLabels is a list of additional labels to add to rendered manifests type: object + components: + description: Components specifies a list of kustomize + components to add to the kustomization before building + items: + type: string + type: array forceCommonAnnotations: description: ForceCommonAnnotations specifies whether to force applying common annotations to resources @@ -2689,6 +2738,13 @@ spec: description: CommonLabels is a list of additional labels to add to rendered manifests type: object + components: + description: Components specifies a list of kustomize + components to add to the kustomization before + building + items: + type: string + type: array forceCommonAnnotations: description: ForceCommonAnnotations specifies whether to force applying common annotations @@ -3038,6 +3094,13 @@ spec: description: CommonLabels is a list of additional labels to add to rendered manifests type: object + components: + description: Components specifies a list of + kustomize components to add to the kustomization + before building + items: + type: string + type: array forceCommonAnnotations: description: ForceCommonAnnotations specifies whether to force applying common annotations @@ -3502,6 +3565,12 @@ spec: description: CommonLabels is a list of additional labels to add to rendered manifests type: object + components: + description: Components specifies a list of kustomize + components to add to the kustomization before building + items: + type: string + type: array forceCommonAnnotations: description: ForceCommonAnnotations specifies whether to force applying common annotations to resources @@ -3844,6 +3913,13 @@ spec: description: CommonLabels is a list of additional labels to add to rendered manifests type: object + components: + description: Components specifies a list of kustomize + components to add to the kustomization before + building + items: + type: string + type: array forceCommonAnnotations: description: ForceCommonAnnotations specifies whether to force applying common annotations to resources @@ -4330,6 +4406,12 @@ spec: description: CommonLabels is a list of additional labels to add to rendered manifests type: object + components: + description: Components specifies a list of kustomize + components to add to the kustomization before building + items: + type: string + type: array forceCommonAnnotations: description: ForceCommonAnnotations specifies whether to force applying common annotations to resources @@ -4672,6 +4754,13 @@ spec: description: CommonLabels is a list of additional labels to add to rendered manifests type: object + components: + description: Components specifies a list of kustomize + components to add to the kustomization before + building + items: + type: string + type: array forceCommonAnnotations: description: ForceCommonAnnotations specifies whether to force applying common annotations to resources diff --git a/manifests/crds/applicationset-crd.yaml b/manifests/crds/applicationset-crd.yaml index 9348368951811..758785832ea78 100644 --- a/manifests/crds/applicationset-crd.yaml +++ b/manifests/crds/applicationset-crd.yaml @@ -244,6 +244,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -454,6 +458,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -823,6 +831,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -1033,6 +1045,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -1406,6 +1422,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -1616,6 +1636,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -1969,6 +1993,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -2179,6 +2207,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -2556,6 +2588,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -2766,6 +2802,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -3135,6 +3175,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -3345,6 +3389,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -3718,6 +3766,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -3928,6 +3980,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -4281,6 +4337,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -4491,6 +4551,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -4854,6 +4918,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -5064,6 +5132,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -5607,6 +5679,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -5817,6 +5893,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -6355,6 +6435,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -6565,6 +6649,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -6932,6 +7020,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -7142,6 +7234,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -7519,6 +7615,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -7729,6 +7829,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -8098,6 +8202,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -8308,6 +8416,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -8681,6 +8793,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -8891,6 +9007,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -9244,6 +9364,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -9454,6 +9578,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -9817,6 +9945,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -10027,6 +10159,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -10570,6 +10706,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -10780,6 +10920,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -11318,6 +11462,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -11528,6 +11676,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -11899,6 +12051,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -12109,6 +12265,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -12469,6 +12629,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -12679,6 +12843,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -13222,6 +13390,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -13432,6 +13604,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -13970,6 +14146,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -14180,6 +14360,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -14622,6 +14806,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -14832,6 +15020,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -14991,6 +15183,8 @@ spec: - metadata - spec type: object + templatePatch: + type: string required: - generators - template diff --git a/manifests/ha/base/controller-deployment/kustomization.yaml b/manifests/ha/base/controller-deployment/kustomization.yaml index d6d20d99b4516..e98bd250d699e 100644 --- a/manifests/ha/base/controller-deployment/kustomization.yaml +++ b/manifests/ha/base/controller-deployment/kustomization.yaml @@ -1,20 +1,17 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization - patches: +- path: argocd-application-controller-statefulset.yaml - path: argocd-repo-server-deployment.yaml - path: argocd-server-deployment.yaml -- path: argocd-application-controller-statefulset.yaml - path: argocd-cmd-params-cm.yaml - images: - name: quay.io/argoproj/argocd newName: quay.io/argoproj/argocd newTag: latest resources: -- ../../../base/application-controller - ../../../base/application-controller-deployment - ../../../base/applicationset-controller - ../../../base/dex diff --git a/manifests/ha/base/redis-ha/chart/upstream.yaml b/manifests/ha/base/redis-ha/chart/upstream.yaml index 80e3bfa21dcdf..1d0e4b3c247f8 100644 --- a/manifests/ha/base/redis-ha/chart/upstream.yaml +++ b/manifests/ha/base/redis-ha/chart/upstream.yaml @@ -1207,7 +1207,7 @@ spec: automountServiceAccountToken: false initContainers: - name: config-init - image: redis:7.0.11-alpine + image: redis:7.0.14-alpine imagePullPolicy: IfNotPresent resources: {} @@ -1241,7 +1241,7 @@ spec: containers: - name: redis - image: redis:7.0.11-alpine + image: redis:7.0.14-alpine imagePullPolicy: IfNotPresent command: - redis-server @@ -1298,7 +1298,7 @@ spec: - /bin/sh - /readonly-config/trigger-failover-if-master.sh - name: sentinel - image: redis:7.0.11-alpine + image: redis:7.0.14-alpine imagePullPolicy: IfNotPresent command: - redis-sentinel @@ -1349,7 +1349,7 @@ spec: {} - name: split-brain-fix - image: redis:7.0.11-alpine + image: redis:7.0.14-alpine imagePullPolicy: IfNotPresent command: - sh diff --git a/manifests/ha/base/redis-ha/chart/values.yaml b/manifests/ha/base/redis-ha/chart/values.yaml index e2788777e980d..5606daac34bb3 100644 --- a/manifests/ha/base/redis-ha/chart/values.yaml +++ b/manifests/ha/base/redis-ha/chart/values.yaml @@ -20,7 +20,7 @@ redis-ha: metrics: enabled: true image: - tag: 7.0.11-alpine + tag: 7.0.14-alpine containerSecurityContext: null sentinel: bind: "0.0.0.0" diff --git a/manifests/ha/install.yaml b/manifests/ha/install.yaml index a2e1e5b91b668..83fc7a0f1c864 100644 --- a/manifests/ha/install.yaml +++ b/manifests/ha/install.yaml @@ -320,6 +320,12 @@ spec: description: CommonLabels is a list of additional labels to add to rendered manifests type: object + components: + description: Components specifies a list of kustomize + components to add to the kustomization before building + items: + type: string + type: array forceCommonAnnotations: description: ForceCommonAnnotations specifies whether to force applying common annotations to resources for @@ -648,6 +654,12 @@ spec: description: CommonLabels is a list of additional labels to add to rendered manifests type: object + components: + description: Components specifies a list of kustomize + components to add to the kustomization before building + items: + type: string + type: array forceCommonAnnotations: description: ForceCommonAnnotations specifies whether to force applying common annotations to resources @@ -1093,6 +1105,12 @@ spec: description: CommonLabels is a list of additional labels to add to rendered manifests type: object + components: + description: Components specifies a list of kustomize components + to add to the kustomization before building + items: + type: string + type: array forceCommonAnnotations: description: ForceCommonAnnotations specifies whether to force applying common annotations to resources for Kustomize apps @@ -1411,6 +1429,12 @@ spec: description: CommonLabels is a list of additional labels to add to rendered manifests type: object + components: + description: Components specifies a list of kustomize components + to add to the kustomization before building + items: + type: string + type: array forceCommonAnnotations: description: ForceCommonAnnotations specifies whether to force applying common annotations to resources for Kustomize @@ -1702,6 +1726,19 @@ spec: description: ID is an auto incrementing identifier of the RevisionHistory format: int64 type: integer + initiatedBy: + description: InitiatedBy contains information about who initiated + the operations + properties: + automated: + description: Automated is set to true if operation was initiated + automatically by the application controller. + type: boolean + username: + description: Username contains the name of a user who started + operation + type: string + type: object revision: description: Revision holds the revision the sync was performed against @@ -1882,6 +1919,12 @@ spec: description: CommonLabels is a list of additional labels to add to rendered manifests type: object + components: + description: Components specifies a list of kustomize + components to add to the kustomization before building + items: + type: string + type: array forceCommonAnnotations: description: ForceCommonAnnotations specifies whether to force applying common annotations to resources @@ -2214,6 +2257,12 @@ spec: description: CommonLabels is a list of additional labels to add to rendered manifests type: object + components: + description: Components specifies a list of kustomize + components to add to the kustomization before building + items: + type: string + type: array forceCommonAnnotations: description: ForceCommonAnnotations specifies whether to force applying common annotations to resources @@ -2690,6 +2739,13 @@ spec: description: CommonLabels is a list of additional labels to add to rendered manifests type: object + components: + description: Components specifies a list of kustomize + components to add to the kustomization before + building + items: + type: string + type: array forceCommonAnnotations: description: ForceCommonAnnotations specifies whether to force applying common annotations @@ -3039,6 +3095,13 @@ spec: description: CommonLabels is a list of additional labels to add to rendered manifests type: object + components: + description: Components specifies a list of + kustomize components to add to the kustomization + before building + items: + type: string + type: array forceCommonAnnotations: description: ForceCommonAnnotations specifies whether to force applying common annotations @@ -3503,6 +3566,12 @@ spec: description: CommonLabels is a list of additional labels to add to rendered manifests type: object + components: + description: Components specifies a list of kustomize + components to add to the kustomization before building + items: + type: string + type: array forceCommonAnnotations: description: ForceCommonAnnotations specifies whether to force applying common annotations to resources @@ -3845,6 +3914,13 @@ spec: description: CommonLabels is a list of additional labels to add to rendered manifests type: object + components: + description: Components specifies a list of kustomize + components to add to the kustomization before + building + items: + type: string + type: array forceCommonAnnotations: description: ForceCommonAnnotations specifies whether to force applying common annotations to resources @@ -4331,6 +4407,12 @@ spec: description: CommonLabels is a list of additional labels to add to rendered manifests type: object + components: + description: Components specifies a list of kustomize + components to add to the kustomization before building + items: + type: string + type: array forceCommonAnnotations: description: ForceCommonAnnotations specifies whether to force applying common annotations to resources @@ -4673,6 +4755,13 @@ spec: description: CommonLabels is a list of additional labels to add to rendered manifests type: object + components: + description: Components specifies a list of kustomize + components to add to the kustomization before + building + items: + type: string + type: array forceCommonAnnotations: description: ForceCommonAnnotations specifies whether to force applying common annotations to resources @@ -5108,6 +5197,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -5318,6 +5411,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -5687,6 +5784,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -5897,6 +5998,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -6270,6 +6375,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -6480,6 +6589,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -6833,6 +6946,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -7043,6 +7160,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -7420,6 +7541,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -7630,6 +7755,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -7999,6 +8128,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -8209,6 +8342,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -8582,6 +8719,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -8792,6 +8933,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -9145,6 +9290,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -9355,6 +9504,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -9718,6 +9871,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -9928,6 +10085,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -10471,6 +10632,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -10681,6 +10846,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -11219,6 +11388,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -11429,6 +11602,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -11796,6 +11973,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -12006,6 +12187,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -12383,6 +12568,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -12593,6 +12782,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -12962,6 +13155,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -13172,6 +13369,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -13545,6 +13746,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -13755,6 +13960,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -14108,6 +14317,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -14318,6 +14531,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -14681,6 +14898,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -14891,6 +15112,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -15434,6 +15659,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -15644,6 +15873,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -16182,6 +16415,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -16392,6 +16629,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -16763,6 +17004,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -16973,6 +17218,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -17333,6 +17582,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -17543,6 +17796,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -18086,6 +18343,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -18296,6 +18557,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -18834,6 +19099,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -19044,6 +19313,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -19486,6 +19759,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -19696,6 +19973,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -19855,6 +20136,8 @@ spec: - metadata - spec type: object + templatePatch: + type: string required: - generators - template @@ -20348,6 +20631,14 @@ rules: verbs: - create - list +- apiGroups: + - apps + resources: + - deployments + verbs: + - get + - list + - watch --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role @@ -20577,6 +20868,95 @@ rules: --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole +metadata: + labels: + app.kubernetes.io/component: applicationset-controller + app.kubernetes.io/name: argocd-applicationset-controller + app.kubernetes.io/part-of: argocd + name: argocd-applicationset-controller +rules: +- apiGroups: + - argoproj.io + resources: + - applications + - applicationsets + - applicationsets/finalizers + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - argoproj.io + resources: + - applicationsets/status + verbs: + - get + - patch + - update +- apiGroups: + - argoproj.io + resources: + - appprojects + verbs: + - get +- apiGroups: + - "" + resources: + - events + verbs: + - create + - get + - list + - patch + - watch +- apiGroups: + - "" + resources: + - configmaps + verbs: + - create + - update + - delete + - get + - list + - patch + - watch +- apiGroups: + - "" + resources: + - secrets + verbs: + - get + - list + - watch +- apiGroups: + - apps + - extensions + resources: + - deployments + verbs: + - get + - list + - watch +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole metadata: labels: app.kubernetes.io/component: server @@ -20609,6 +20989,7 @@ rules: - argoproj.io resources: - applications + - applicationsets verbs: - get - list @@ -20757,6 +21138,23 @@ subjects: --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding +metadata: + labels: + app.kubernetes.io/component: applicationset-controller + app.kubernetes.io/name: argocd-applicationset-controller + app.kubernetes.io/part-of: argocd + name: argocd-applicationset-controller +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: argocd-applicationset-controller +subjects: +- kind: ServiceAccount + name: argocd-applicationset-controller + namespace: argocd +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding metadata: labels: app.kubernetes.io/component: server @@ -22098,7 +22496,7 @@ spec: key: dexserver.disable.tls name: argocd-cmd-params-cm optional: true - image: ghcr.io/dexidp/dex:v2.37.0 + image: ghcr.io/dexidp/dex:v2.38.0 imagePullPolicy: Always name: dex ports: @@ -22203,6 +22601,12 @@ spec: key: application.namespaces name: argocd-cmd-params-cm optional: true + - name: ARGOCD_NOTIFICATION_CONTROLLER_SELF_SERVICE_NOTIFICATION_ENABLED + valueFrom: + configMapKeyRef: + key: notificationscontroller.selfservice.enabled + name: argocd-cmd-params-cm + optional: true image: quay.io/argoproj/argocd:latest imagePullPolicy: Always livenessProbe: @@ -22480,6 +22884,18 @@ spec: key: otlp.address name: argocd-cmd-params-cm optional: true + - name: ARGOCD_REPO_SERVER_OTLP_INSECURE + valueFrom: + configMapKeyRef: + key: otlp.insecure + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_REPO_SERVER_OTLP_HEADERS + valueFrom: + configMapKeyRef: + key: otlp.headers + name: argocd-cmd-params-cm + optional: true - name: ARGOCD_REPO_SERVER_MAX_COMBINED_DIRECTORY_MANIFESTS_SIZE valueFrom: configMapKeyRef: @@ -22528,6 +22944,18 @@ spec: key: reposerver.enable.git.submodule name: argocd-cmd-params-cm optional: true + - name: ARGOCD_GIT_LS_REMOTE_PARALLELISM_LIMIT + valueFrom: + configMapKeyRef: + key: reposerver.git.lsremote.parallelism.limit + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_GIT_REQUEST_TIMEOUT + valueFrom: + configMapKeyRef: + key: reposerver.git.request.timeout + name: argocd-cmd-params-cm + optional: true - name: HELM_CACHE_HOME value: /helm-working-dir - name: HELM_CONFIG_HOME @@ -22863,6 +23291,18 @@ spec: key: otlp.address name: argocd-cmd-params-cm optional: true + - name: ARGOCD_SERVER_OTLP_INSECURE + valueFrom: + configMapKeyRef: + key: otlp.insecure + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_SERVER_OTLP_HEADERS + valueFrom: + configMapKeyRef: + key: otlp.headers + name: argocd-cmd-params-cm + optional: true - name: ARGOCD_APPLICATION_NAMESPACES valueFrom: configMapKeyRef: @@ -22875,6 +23315,24 @@ spec: key: server.enable.proxy.extension name: argocd-cmd-params-cm optional: true + - name: ARGOCD_K8SCLIENT_RETRY_MAX + valueFrom: + configMapKeyRef: + key: server.k8sclient.retry.max + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_K8SCLIENT_RETRY_BASE_BACKOFF + valueFrom: + configMapKeyRef: + key: server.k8sclient.retry.base.backoff + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_API_CONTENT_TYPES + valueFrom: + configMapKeyRef: + key: server.api.content.types + name: argocd-cmd-params-cm + optional: true image: quay.io/argoproj/argocd:latest imagePullPolicy: Always livenessProbe: @@ -23001,6 +23459,18 @@ spec: key: timeout.hard.reconciliation name: argocd-cm optional: true + - name: ARGOCD_RECONCILIATION_JITTER + valueFrom: + configMapKeyRef: + key: timeout.reconciliation.jitter + name: argocd-cm + optional: true + - name: ARGOCD_REPO_ERROR_GRACE_PERIOD_SECONDS + valueFrom: + configMapKeyRef: + key: controller.repo.error.grace.period.seconds + name: argocd-cmd-params-cm + optional: true - name: ARGOCD_APPLICATION_CONTROLLER_REPO_SERVER valueFrom: configMapKeyRef: @@ -23103,6 +23573,18 @@ spec: key: otlp.address name: argocd-cmd-params-cm optional: true + - name: ARGOCD_APPLICATION_CONTROLLER_OTLP_INSECURE + valueFrom: + configMapKeyRef: + key: otlp.insecure + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATION_CONTROLLER_OTLP_HEADERS + valueFrom: + configMapKeyRef: + key: otlp.headers + name: argocd-cmd-params-cm + optional: true - name: ARGOCD_APPLICATION_NAMESPACES valueFrom: configMapKeyRef: @@ -23121,6 +23603,24 @@ spec: key: controller.kubectl.parallelism.limit name: argocd-cmd-params-cm optional: true + - name: ARGOCD_K8SCLIENT_RETRY_MAX + valueFrom: + configMapKeyRef: + key: controller.k8sclient.retry.max + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_K8SCLIENT_RETRY_BASE_BACKOFF + valueFrom: + configMapKeyRef: + key: controller.k8sclient.retry.base.backoff + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATION_CONTROLLER_SERVER_SIDE_DIFF + valueFrom: + configMapKeyRef: + key: controller.diff.server.side + name: argocd-cmd-params-cm + optional: true image: quay.io/argoproj/argocd:latest imagePullPolicy: Always name: argocd-application-controller @@ -23198,7 +23698,7 @@ spec: - /data/conf/redis.conf command: - redis-server - image: redis:7.0.11-alpine + image: redis:7.0.14-alpine imagePullPolicy: IfNotPresent lifecycle: preStop: @@ -23252,7 +23752,7 @@ spec: - /data/conf/sentinel.conf command: - redis-sentinel - image: redis:7.0.11-alpine + image: redis:7.0.14-alpine imagePullPolicy: IfNotPresent lifecycle: {} livenessProbe: @@ -23305,7 +23805,7 @@ spec: value: 40000915ab58c3fa8fd888fb8b24711944e6cbb4 - name: SENTINEL_ID_2 value: 2bbec7894d954a8af3bb54d13eaec53cb024e2ca - image: redis:7.0.11-alpine + image: redis:7.0.14-alpine imagePullPolicy: IfNotPresent name: split-brain-fix resources: {} @@ -23335,7 +23835,7 @@ spec: value: 40000915ab58c3fa8fd888fb8b24711944e6cbb4 - name: SENTINEL_ID_2 value: 2bbec7894d954a8af3bb54d13eaec53cb024e2ca - image: redis:7.0.11-alpine + image: redis:7.0.14-alpine imagePullPolicy: IfNotPresent name: config-init securityContext: diff --git a/manifests/ha/namespace-install.yaml b/manifests/ha/namespace-install.yaml index ea123ef2e50ef..044a061bf0cb1 100644 --- a/manifests/ha/namespace-install.yaml +++ b/manifests/ha/namespace-install.yaml @@ -109,6 +109,14 @@ rules: verbs: - create - list +- apiGroups: + - apps + resources: + - deployments + verbs: + - get + - list + - watch --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role @@ -1754,7 +1762,7 @@ spec: key: dexserver.disable.tls name: argocd-cmd-params-cm optional: true - image: ghcr.io/dexidp/dex:v2.37.0 + image: ghcr.io/dexidp/dex:v2.38.0 imagePullPolicy: Always name: dex ports: @@ -1859,6 +1867,12 @@ spec: key: application.namespaces name: argocd-cmd-params-cm optional: true + - name: ARGOCD_NOTIFICATION_CONTROLLER_SELF_SERVICE_NOTIFICATION_ENABLED + valueFrom: + configMapKeyRef: + key: notificationscontroller.selfservice.enabled + name: argocd-cmd-params-cm + optional: true image: quay.io/argoproj/argocd:latest imagePullPolicy: Always livenessProbe: @@ -2136,6 +2150,18 @@ spec: key: otlp.address name: argocd-cmd-params-cm optional: true + - name: ARGOCD_REPO_SERVER_OTLP_INSECURE + valueFrom: + configMapKeyRef: + key: otlp.insecure + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_REPO_SERVER_OTLP_HEADERS + valueFrom: + configMapKeyRef: + key: otlp.headers + name: argocd-cmd-params-cm + optional: true - name: ARGOCD_REPO_SERVER_MAX_COMBINED_DIRECTORY_MANIFESTS_SIZE valueFrom: configMapKeyRef: @@ -2184,6 +2210,18 @@ spec: key: reposerver.enable.git.submodule name: argocd-cmd-params-cm optional: true + - name: ARGOCD_GIT_LS_REMOTE_PARALLELISM_LIMIT + valueFrom: + configMapKeyRef: + key: reposerver.git.lsremote.parallelism.limit + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_GIT_REQUEST_TIMEOUT + valueFrom: + configMapKeyRef: + key: reposerver.git.request.timeout + name: argocd-cmd-params-cm + optional: true - name: HELM_CACHE_HOME value: /helm-working-dir - name: HELM_CONFIG_HOME @@ -2519,6 +2557,18 @@ spec: key: otlp.address name: argocd-cmd-params-cm optional: true + - name: ARGOCD_SERVER_OTLP_INSECURE + valueFrom: + configMapKeyRef: + key: otlp.insecure + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_SERVER_OTLP_HEADERS + valueFrom: + configMapKeyRef: + key: otlp.headers + name: argocd-cmd-params-cm + optional: true - name: ARGOCD_APPLICATION_NAMESPACES valueFrom: configMapKeyRef: @@ -2531,6 +2581,24 @@ spec: key: server.enable.proxy.extension name: argocd-cmd-params-cm optional: true + - name: ARGOCD_K8SCLIENT_RETRY_MAX + valueFrom: + configMapKeyRef: + key: server.k8sclient.retry.max + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_K8SCLIENT_RETRY_BASE_BACKOFF + valueFrom: + configMapKeyRef: + key: server.k8sclient.retry.base.backoff + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_API_CONTENT_TYPES + valueFrom: + configMapKeyRef: + key: server.api.content.types + name: argocd-cmd-params-cm + optional: true image: quay.io/argoproj/argocd:latest imagePullPolicy: Always livenessProbe: @@ -2657,6 +2725,18 @@ spec: key: timeout.hard.reconciliation name: argocd-cm optional: true + - name: ARGOCD_RECONCILIATION_JITTER + valueFrom: + configMapKeyRef: + key: timeout.reconciliation.jitter + name: argocd-cm + optional: true + - name: ARGOCD_REPO_ERROR_GRACE_PERIOD_SECONDS + valueFrom: + configMapKeyRef: + key: controller.repo.error.grace.period.seconds + name: argocd-cmd-params-cm + optional: true - name: ARGOCD_APPLICATION_CONTROLLER_REPO_SERVER valueFrom: configMapKeyRef: @@ -2759,6 +2839,18 @@ spec: key: otlp.address name: argocd-cmd-params-cm optional: true + - name: ARGOCD_APPLICATION_CONTROLLER_OTLP_INSECURE + valueFrom: + configMapKeyRef: + key: otlp.insecure + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATION_CONTROLLER_OTLP_HEADERS + valueFrom: + configMapKeyRef: + key: otlp.headers + name: argocd-cmd-params-cm + optional: true - name: ARGOCD_APPLICATION_NAMESPACES valueFrom: configMapKeyRef: @@ -2777,6 +2869,24 @@ spec: key: controller.kubectl.parallelism.limit name: argocd-cmd-params-cm optional: true + - name: ARGOCD_K8SCLIENT_RETRY_MAX + valueFrom: + configMapKeyRef: + key: controller.k8sclient.retry.max + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_K8SCLIENT_RETRY_BASE_BACKOFF + valueFrom: + configMapKeyRef: + key: controller.k8sclient.retry.base.backoff + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATION_CONTROLLER_SERVER_SIDE_DIFF + valueFrom: + configMapKeyRef: + key: controller.diff.server.side + name: argocd-cmd-params-cm + optional: true image: quay.io/argoproj/argocd:latest imagePullPolicy: Always name: argocd-application-controller @@ -2854,7 +2964,7 @@ spec: - /data/conf/redis.conf command: - redis-server - image: redis:7.0.11-alpine + image: redis:7.0.14-alpine imagePullPolicy: IfNotPresent lifecycle: preStop: @@ -2908,7 +3018,7 @@ spec: - /data/conf/sentinel.conf command: - redis-sentinel - image: redis:7.0.11-alpine + image: redis:7.0.14-alpine imagePullPolicy: IfNotPresent lifecycle: {} livenessProbe: @@ -2961,7 +3071,7 @@ spec: value: 40000915ab58c3fa8fd888fb8b24711944e6cbb4 - name: SENTINEL_ID_2 value: 2bbec7894d954a8af3bb54d13eaec53cb024e2ca - image: redis:7.0.11-alpine + image: redis:7.0.14-alpine imagePullPolicy: IfNotPresent name: split-brain-fix resources: {} @@ -2991,7 +3101,7 @@ spec: value: 40000915ab58c3fa8fd888fb8b24711944e6cbb4 - name: SENTINEL_ID_2 value: 2bbec7894d954a8af3bb54d13eaec53cb024e2ca - image: redis:7.0.11-alpine + image: redis:7.0.14-alpine imagePullPolicy: IfNotPresent name: config-init securityContext: diff --git a/manifests/install.yaml b/manifests/install.yaml index 6783484ed0150..6f9c88dbb9d57 100644 --- a/manifests/install.yaml +++ b/manifests/install.yaml @@ -320,6 +320,12 @@ spec: description: CommonLabels is a list of additional labels to add to rendered manifests type: object + components: + description: Components specifies a list of kustomize + components to add to the kustomization before building + items: + type: string + type: array forceCommonAnnotations: description: ForceCommonAnnotations specifies whether to force applying common annotations to resources for @@ -648,6 +654,12 @@ spec: description: CommonLabels is a list of additional labels to add to rendered manifests type: object + components: + description: Components specifies a list of kustomize + components to add to the kustomization before building + items: + type: string + type: array forceCommonAnnotations: description: ForceCommonAnnotations specifies whether to force applying common annotations to resources @@ -1093,6 +1105,12 @@ spec: description: CommonLabels is a list of additional labels to add to rendered manifests type: object + components: + description: Components specifies a list of kustomize components + to add to the kustomization before building + items: + type: string + type: array forceCommonAnnotations: description: ForceCommonAnnotations specifies whether to force applying common annotations to resources for Kustomize apps @@ -1411,6 +1429,12 @@ spec: description: CommonLabels is a list of additional labels to add to rendered manifests type: object + components: + description: Components specifies a list of kustomize components + to add to the kustomization before building + items: + type: string + type: array forceCommonAnnotations: description: ForceCommonAnnotations specifies whether to force applying common annotations to resources for Kustomize @@ -1702,6 +1726,19 @@ spec: description: ID is an auto incrementing identifier of the RevisionHistory format: int64 type: integer + initiatedBy: + description: InitiatedBy contains information about who initiated + the operations + properties: + automated: + description: Automated is set to true if operation was initiated + automatically by the application controller. + type: boolean + username: + description: Username contains the name of a user who started + operation + type: string + type: object revision: description: Revision holds the revision the sync was performed against @@ -1882,6 +1919,12 @@ spec: description: CommonLabels is a list of additional labels to add to rendered manifests type: object + components: + description: Components specifies a list of kustomize + components to add to the kustomization before building + items: + type: string + type: array forceCommonAnnotations: description: ForceCommonAnnotations specifies whether to force applying common annotations to resources @@ -2214,6 +2257,12 @@ spec: description: CommonLabels is a list of additional labels to add to rendered manifests type: object + components: + description: Components specifies a list of kustomize + components to add to the kustomization before building + items: + type: string + type: array forceCommonAnnotations: description: ForceCommonAnnotations specifies whether to force applying common annotations to resources @@ -2690,6 +2739,13 @@ spec: description: CommonLabels is a list of additional labels to add to rendered manifests type: object + components: + description: Components specifies a list of kustomize + components to add to the kustomization before + building + items: + type: string + type: array forceCommonAnnotations: description: ForceCommonAnnotations specifies whether to force applying common annotations @@ -3039,6 +3095,13 @@ spec: description: CommonLabels is a list of additional labels to add to rendered manifests type: object + components: + description: Components specifies a list of + kustomize components to add to the kustomization + before building + items: + type: string + type: array forceCommonAnnotations: description: ForceCommonAnnotations specifies whether to force applying common annotations @@ -3503,6 +3566,12 @@ spec: description: CommonLabels is a list of additional labels to add to rendered manifests type: object + components: + description: Components specifies a list of kustomize + components to add to the kustomization before building + items: + type: string + type: array forceCommonAnnotations: description: ForceCommonAnnotations specifies whether to force applying common annotations to resources @@ -3845,6 +3914,13 @@ spec: description: CommonLabels is a list of additional labels to add to rendered manifests type: object + components: + description: Components specifies a list of kustomize + components to add to the kustomization before + building + items: + type: string + type: array forceCommonAnnotations: description: ForceCommonAnnotations specifies whether to force applying common annotations to resources @@ -4331,6 +4407,12 @@ spec: description: CommonLabels is a list of additional labels to add to rendered manifests type: object + components: + description: Components specifies a list of kustomize + components to add to the kustomization before building + items: + type: string + type: array forceCommonAnnotations: description: ForceCommonAnnotations specifies whether to force applying common annotations to resources @@ -4673,6 +4755,13 @@ spec: description: CommonLabels is a list of additional labels to add to rendered manifests type: object + components: + description: Components specifies a list of kustomize + components to add to the kustomization before + building + items: + type: string + type: array forceCommonAnnotations: description: ForceCommonAnnotations specifies whether to force applying common annotations to resources @@ -5108,6 +5197,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -5318,6 +5411,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -5687,6 +5784,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -5897,6 +5998,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -6270,6 +6375,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -6480,6 +6589,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -6833,6 +6946,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -7043,6 +7160,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -7420,6 +7541,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -7630,6 +7755,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -7999,6 +8128,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -8209,6 +8342,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -8582,6 +8719,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -8792,6 +8933,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -9145,6 +9290,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -9355,6 +9504,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -9718,6 +9871,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -9928,6 +10085,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -10471,6 +10632,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -10681,6 +10846,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -11219,6 +11388,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -11429,6 +11602,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -11796,6 +11973,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -12006,6 +12187,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -12383,6 +12568,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -12593,6 +12782,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -12962,6 +13155,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -13172,6 +13369,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -13545,6 +13746,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -13755,6 +13960,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -14108,6 +14317,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -14318,6 +14531,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -14681,6 +14898,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -14891,6 +15112,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -15434,6 +15659,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -15644,6 +15873,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -16182,6 +16415,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -16392,6 +16629,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -16763,6 +17004,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -16973,6 +17218,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -17333,6 +17582,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -17543,6 +17796,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -18086,6 +18343,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -18296,6 +18557,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -18834,6 +19099,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -19044,6 +19313,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -19486,6 +19759,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -19696,6 +19973,10 @@ spec: additionalProperties: type: string type: object + components: + items: + type: string + type: array forceCommonAnnotations: type: boolean forceCommonLabels: @@ -19855,6 +20136,8 @@ spec: - metadata - spec type: object + templatePatch: + type: string required: - generators - template @@ -20339,6 +20622,14 @@ rules: verbs: - create - list +- apiGroups: + - apps + resources: + - deployments + verbs: + - get + - list + - watch --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role @@ -20536,6 +20827,95 @@ rules: --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole +metadata: + labels: + app.kubernetes.io/component: applicationset-controller + app.kubernetes.io/name: argocd-applicationset-controller + app.kubernetes.io/part-of: argocd + name: argocd-applicationset-controller +rules: +- apiGroups: + - argoproj.io + resources: + - applications + - applicationsets + - applicationsets/finalizers + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - argoproj.io + resources: + - applicationsets/status + verbs: + - get + - patch + - update +- apiGroups: + - argoproj.io + resources: + - appprojects + verbs: + - get +- apiGroups: + - "" + resources: + - events + verbs: + - create + - get + - list + - patch + - watch +- apiGroups: + - "" + resources: + - configmaps + verbs: + - create + - update + - delete + - get + - list + - patch + - watch +- apiGroups: + - "" + resources: + - secrets + verbs: + - get + - list + - watch +- apiGroups: + - apps + - extensions + resources: + - deployments + verbs: + - get + - list + - watch +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole metadata: labels: app.kubernetes.io/component: server @@ -20568,6 +20948,7 @@ rules: - argoproj.io resources: - applications + - applicationsets verbs: - get - list @@ -20684,6 +21065,23 @@ subjects: --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding +metadata: + labels: + app.kubernetes.io/component: applicationset-controller + app.kubernetes.io/name: argocd-applicationset-controller + app.kubernetes.io/part-of: argocd + name: argocd-applicationset-controller +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: argocd-applicationset-controller +subjects: +- kind: ServiceAccount + name: argocd-applicationset-controller + namespace: argocd +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding metadata: labels: app.kubernetes.io/component: server @@ -21193,7 +21591,7 @@ spec: key: dexserver.disable.tls name: argocd-cmd-params-cm optional: true - image: ghcr.io/dexidp/dex:v2.37.0 + image: ghcr.io/dexidp/dex:v2.38.0 imagePullPolicy: Always name: dex ports: @@ -21298,6 +21696,12 @@ spec: key: application.namespaces name: argocd-cmd-params-cm optional: true + - name: ARGOCD_NOTIFICATION_CONTROLLER_SELF_SERVICE_NOTIFICATION_ENABLED + valueFrom: + configMapKeyRef: + key: notificationscontroller.selfservice.enabled + name: argocd-cmd-params-cm + optional: true image: quay.io/argoproj/argocd:latest imagePullPolicy: Always livenessProbe: @@ -21375,7 +21779,7 @@ spec: - "" - --appendonly - "no" - image: redis:7.0.11-alpine + image: redis:7.0.14-alpine imagePullPolicy: Always name: redis ports: @@ -21526,6 +21930,18 @@ spec: key: otlp.address name: argocd-cmd-params-cm optional: true + - name: ARGOCD_REPO_SERVER_OTLP_INSECURE + valueFrom: + configMapKeyRef: + key: otlp.insecure + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_REPO_SERVER_OTLP_HEADERS + valueFrom: + configMapKeyRef: + key: otlp.headers + name: argocd-cmd-params-cm + optional: true - name: ARGOCD_REPO_SERVER_MAX_COMBINED_DIRECTORY_MANIFESTS_SIZE valueFrom: configMapKeyRef: @@ -21574,6 +21990,18 @@ spec: key: reposerver.enable.git.submodule name: argocd-cmd-params-cm optional: true + - name: ARGOCD_GIT_LS_REMOTE_PARALLELISM_LIMIT + valueFrom: + configMapKeyRef: + key: reposerver.git.lsremote.parallelism.limit + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_GIT_REQUEST_TIMEOUT + valueFrom: + configMapKeyRef: + key: reposerver.git.request.timeout + name: argocd-cmd-params-cm + optional: true - name: HELM_CACHE_HOME value: /helm-working-dir - name: HELM_CONFIG_HOME @@ -21907,6 +22335,18 @@ spec: key: otlp.address name: argocd-cmd-params-cm optional: true + - name: ARGOCD_SERVER_OTLP_INSECURE + valueFrom: + configMapKeyRef: + key: otlp.insecure + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_SERVER_OTLP_HEADERS + valueFrom: + configMapKeyRef: + key: otlp.headers + name: argocd-cmd-params-cm + optional: true - name: ARGOCD_APPLICATION_NAMESPACES valueFrom: configMapKeyRef: @@ -21919,6 +22359,24 @@ spec: key: server.enable.proxy.extension name: argocd-cmd-params-cm optional: true + - name: ARGOCD_K8SCLIENT_RETRY_MAX + valueFrom: + configMapKeyRef: + key: server.k8sclient.retry.max + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_K8SCLIENT_RETRY_BASE_BACKOFF + valueFrom: + configMapKeyRef: + key: server.k8sclient.retry.base.backoff + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_API_CONTENT_TYPES + valueFrom: + configMapKeyRef: + key: server.api.content.types + name: argocd-cmd-params-cm + optional: true image: quay.io/argoproj/argocd:latest imagePullPolicy: Always livenessProbe: @@ -22045,6 +22503,18 @@ spec: key: timeout.hard.reconciliation name: argocd-cm optional: true + - name: ARGOCD_RECONCILIATION_JITTER + valueFrom: + configMapKeyRef: + key: timeout.reconciliation.jitter + name: argocd-cm + optional: true + - name: ARGOCD_REPO_ERROR_GRACE_PERIOD_SECONDS + valueFrom: + configMapKeyRef: + key: controller.repo.error.grace.period.seconds + name: argocd-cmd-params-cm + optional: true - name: ARGOCD_APPLICATION_CONTROLLER_REPO_SERVER valueFrom: configMapKeyRef: @@ -22147,6 +22617,18 @@ spec: key: otlp.address name: argocd-cmd-params-cm optional: true + - name: ARGOCD_APPLICATION_CONTROLLER_OTLP_INSECURE + valueFrom: + configMapKeyRef: + key: otlp.insecure + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATION_CONTROLLER_OTLP_HEADERS + valueFrom: + configMapKeyRef: + key: otlp.headers + name: argocd-cmd-params-cm + optional: true - name: ARGOCD_APPLICATION_NAMESPACES valueFrom: configMapKeyRef: @@ -22165,6 +22647,24 @@ spec: key: controller.kubectl.parallelism.limit name: argocd-cmd-params-cm optional: true + - name: ARGOCD_K8SCLIENT_RETRY_MAX + valueFrom: + configMapKeyRef: + key: controller.k8sclient.retry.max + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_K8SCLIENT_RETRY_BASE_BACKOFF + valueFrom: + configMapKeyRef: + key: controller.k8sclient.retry.base.backoff + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATION_CONTROLLER_SERVER_SIDE_DIFF + valueFrom: + configMapKeyRef: + key: controller.diff.server.side + name: argocd-cmd-params-cm + optional: true image: quay.io/argoproj/argocd:latest imagePullPolicy: Always name: argocd-application-controller diff --git a/manifests/namespace-install.yaml b/manifests/namespace-install.yaml index 0490434f4046c..cb58228423c11 100644 --- a/manifests/namespace-install.yaml +++ b/manifests/namespace-install.yaml @@ -100,6 +100,14 @@ rules: verbs: - create - list +- apiGroups: + - apps + resources: + - deployments + verbs: + - get + - list + - watch --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role @@ -849,7 +857,7 @@ spec: key: dexserver.disable.tls name: argocd-cmd-params-cm optional: true - image: ghcr.io/dexidp/dex:v2.37.0 + image: ghcr.io/dexidp/dex:v2.38.0 imagePullPolicy: Always name: dex ports: @@ -954,6 +962,12 @@ spec: key: application.namespaces name: argocd-cmd-params-cm optional: true + - name: ARGOCD_NOTIFICATION_CONTROLLER_SELF_SERVICE_NOTIFICATION_ENABLED + valueFrom: + configMapKeyRef: + key: notificationscontroller.selfservice.enabled + name: argocd-cmd-params-cm + optional: true image: quay.io/argoproj/argocd:latest imagePullPolicy: Always livenessProbe: @@ -1031,7 +1045,7 @@ spec: - "" - --appendonly - "no" - image: redis:7.0.11-alpine + image: redis:7.0.14-alpine imagePullPolicy: Always name: redis ports: @@ -1182,6 +1196,18 @@ spec: key: otlp.address name: argocd-cmd-params-cm optional: true + - name: ARGOCD_REPO_SERVER_OTLP_INSECURE + valueFrom: + configMapKeyRef: + key: otlp.insecure + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_REPO_SERVER_OTLP_HEADERS + valueFrom: + configMapKeyRef: + key: otlp.headers + name: argocd-cmd-params-cm + optional: true - name: ARGOCD_REPO_SERVER_MAX_COMBINED_DIRECTORY_MANIFESTS_SIZE valueFrom: configMapKeyRef: @@ -1230,6 +1256,18 @@ spec: key: reposerver.enable.git.submodule name: argocd-cmd-params-cm optional: true + - name: ARGOCD_GIT_LS_REMOTE_PARALLELISM_LIMIT + valueFrom: + configMapKeyRef: + key: reposerver.git.lsremote.parallelism.limit + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_GIT_REQUEST_TIMEOUT + valueFrom: + configMapKeyRef: + key: reposerver.git.request.timeout + name: argocd-cmd-params-cm + optional: true - name: HELM_CACHE_HOME value: /helm-working-dir - name: HELM_CONFIG_HOME @@ -1563,6 +1601,18 @@ spec: key: otlp.address name: argocd-cmd-params-cm optional: true + - name: ARGOCD_SERVER_OTLP_INSECURE + valueFrom: + configMapKeyRef: + key: otlp.insecure + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_SERVER_OTLP_HEADERS + valueFrom: + configMapKeyRef: + key: otlp.headers + name: argocd-cmd-params-cm + optional: true - name: ARGOCD_APPLICATION_NAMESPACES valueFrom: configMapKeyRef: @@ -1575,6 +1625,24 @@ spec: key: server.enable.proxy.extension name: argocd-cmd-params-cm optional: true + - name: ARGOCD_K8SCLIENT_RETRY_MAX + valueFrom: + configMapKeyRef: + key: server.k8sclient.retry.max + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_K8SCLIENT_RETRY_BASE_BACKOFF + valueFrom: + configMapKeyRef: + key: server.k8sclient.retry.base.backoff + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_API_CONTENT_TYPES + valueFrom: + configMapKeyRef: + key: server.api.content.types + name: argocd-cmd-params-cm + optional: true image: quay.io/argoproj/argocd:latest imagePullPolicy: Always livenessProbe: @@ -1701,6 +1769,18 @@ spec: key: timeout.hard.reconciliation name: argocd-cm optional: true + - name: ARGOCD_RECONCILIATION_JITTER + valueFrom: + configMapKeyRef: + key: timeout.reconciliation.jitter + name: argocd-cm + optional: true + - name: ARGOCD_REPO_ERROR_GRACE_PERIOD_SECONDS + valueFrom: + configMapKeyRef: + key: controller.repo.error.grace.period.seconds + name: argocd-cmd-params-cm + optional: true - name: ARGOCD_APPLICATION_CONTROLLER_REPO_SERVER valueFrom: configMapKeyRef: @@ -1803,6 +1883,18 @@ spec: key: otlp.address name: argocd-cmd-params-cm optional: true + - name: ARGOCD_APPLICATION_CONTROLLER_OTLP_INSECURE + valueFrom: + configMapKeyRef: + key: otlp.insecure + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATION_CONTROLLER_OTLP_HEADERS + valueFrom: + configMapKeyRef: + key: otlp.headers + name: argocd-cmd-params-cm + optional: true - name: ARGOCD_APPLICATION_NAMESPACES valueFrom: configMapKeyRef: @@ -1821,6 +1913,24 @@ spec: key: controller.kubectl.parallelism.limit name: argocd-cmd-params-cm optional: true + - name: ARGOCD_K8SCLIENT_RETRY_MAX + valueFrom: + configMapKeyRef: + key: controller.k8sclient.retry.max + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_K8SCLIENT_RETRY_BASE_BACKOFF + valueFrom: + configMapKeyRef: + key: controller.k8sclient.retry.base.backoff + name: argocd-cmd-params-cm + optional: true + - name: ARGOCD_APPLICATION_CONTROLLER_SERVER_SIDE_DIFF + valueFrom: + configMapKeyRef: + key: controller.diff.server.side + name: argocd-cmd-params-cm + optional: true image: quay.io/argoproj/argocd:latest imagePullPolicy: Always name: argocd-application-controller diff --git a/mkdocs.yml b/mkdocs.yml index 35b0b30c10345..a7e8f86e216cc 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -40,6 +40,7 @@ nav: - operator-manual/user-management/openunison.md - operator-manual/user-management/google.md - operator-manual/user-management/zitadel.md + - operator-manual/user-management/identity-center.md - operator-manual/rbac.md - Security: - Overview: operator-manual/security.md @@ -127,6 +128,9 @@ nav: - operator-manual/server-commands/additional-configuration-method.md - Upgrading: - operator-manual/upgrading/overview.md + - operator-manual/upgrading/2.10-2.11.md + - operator-manual/upgrading/2.9-2.10.md + - operator-manual/upgrading/2.8-2.9.md - operator-manual/upgrading/2.7-2.8.md - operator-manual/upgrading/2.6-2.7.md - operator-manual/upgrading/2.5-2.6.md @@ -159,7 +163,9 @@ nav: - user-guide/multiple_sources.md - GnuPG verification: user-guide/gpg-verification.md - user-guide/auto_sync.md - - user-guide/diffing.md + - Diffing: + - Diff Strategies: user-guide/diff-strategies.md + - Diff Customization: user-guide/diffing.md - user-guide/orphaned-resources.md - user-guide/compare-options.md - user-guide/sync-options.md diff --git a/notification_controller/controller/controller.go b/notification_controller/controller/controller.go index 1ad2ab361ab93..7d871af4c44a3 100644 --- a/notification_controller/controller/controller.go +++ b/notification_controller/controller/controller.go @@ -12,6 +12,8 @@ import ( service "github.com/argoproj/argo-cd/v2/util/notification/argocd" + argocert "github.com/argoproj/argo-cd/v2/util/cert" + "k8s.io/apimachinery/pkg/runtime/schema" "github.com/argoproj/argo-cd/v2/util/notification/settings" @@ -21,6 +23,7 @@ import ( "github.com/argoproj/notifications-engine/pkg/controller" "github.com/argoproj/notifications-engine/pkg/services" "github.com/argoproj/notifications-engine/pkg/subscriptions" + httputil "github.com/argoproj/notifications-engine/pkg/util/http" log "github.com/sirupsen/logrus" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -60,13 +63,27 @@ func NewController( registry *controller.MetricsRegistry, secretName string, configMapName string, + selfServiceNotificationEnabled bool, ) *notificationController { - appClient := client.Resource(applications) + var appClient dynamic.ResourceInterface + + namespaceableAppClient := client.Resource(applications) + appClient = namespaceableAppClient + + if len(applicationNamespaces) == 0 { + appClient = namespaceableAppClient.Namespace(namespace) + } appInformer := newInformer(appClient, namespace, applicationNamespaces, appLabelSelector) appProjInformer := newInformer(newAppProjClient(client, namespace), namespace, []string{namespace}, "") - secretInformer := k8s.NewSecretInformer(k8sClient, namespace, secretName) - configMapInformer := k8s.NewConfigMapInformer(k8sClient, namespace, configMapName) - apiFactory := api.NewFactory(settings.GetFactorySettings(argocdService, secretName, configMapName), namespace, secretInformer, configMapInformer) + var notificationConfigNamespace string + if selfServiceNotificationEnabled { + notificationConfigNamespace = v1.NamespaceAll + } else { + notificationConfigNamespace = namespace + } + secretInformer := k8s.NewSecretInformer(k8sClient, notificationConfigNamespace, secretName) + configMapInformer := k8s.NewConfigMapInformer(k8sClient, notificationConfigNamespace, configMapName) + apiFactory := api.NewFactory(settings.GetFactorySettings(argocdService, secretName, configMapName, selfServiceNotificationEnabled), namespace, secretInformer, configMapInformer) res := ¬ificationController{ secretInformer: secretInformer, @@ -74,19 +91,30 @@ func NewController( appInformer: appInformer, appProjInformer: appProjInformer, apiFactory: apiFactory} - res.ctrl = controller.NewController(appClient, appInformer, apiFactory, - controller.WithSkipProcessing(func(obj v1.Object) (bool, string) { - app, ok := (obj).(*unstructured.Unstructured) - if !ok { - return false, "" - } - if checkAppNotInAdditionalNamespaces(app, namespace, applicationNamespaces) { - return true, "app is not in one of the application-namespaces, nor the notification controller namespace" - } - return !isAppSyncStatusRefreshed(app, log.WithField("app", obj.GetName())), "sync status out of date" - }), - controller.WithMetricsRegistry(registry), - controller.WithAlterDestinations(res.alterDestinations)) + skipProcessingOpt := controller.WithSkipProcessing(func(obj v1.Object) (bool, string) { + app, ok := (obj).(*unstructured.Unstructured) + if !ok { + return false, "" + } + if checkAppNotInAdditionalNamespaces(app, namespace, applicationNamespaces) { + return true, "app is not in one of the application-namespaces, nor the notification controller namespace" + } + return !isAppSyncStatusRefreshed(app, log.WithField("app", obj.GetName())), "sync status out of date" + }) + metricsRegistryOpt := controller.WithMetricsRegistry(registry) + alterDestinationsOpt := controller.WithAlterDestinations(res.alterDestinations) + + if !selfServiceNotificationEnabled { + res.ctrl = controller.NewController(namespaceableAppClient, appInformer, apiFactory, + skipProcessingOpt, + metricsRegistryOpt, + alterDestinationsOpt) + } else { + res.ctrl = controller.NewControllerWithNamespaceSupport(namespaceableAppClient, appInformer, apiFactory, + skipProcessingOpt, + metricsRegistryOpt, + alterDestinationsOpt) + } return res } @@ -109,6 +137,7 @@ func (c *notificationController) alterDestinations(obj v1.Object, destinations s } func newInformer(resClient dynamic.ResourceInterface, controllerNamespace string, applicationNamespaces []string, selector string) cache.SharedIndexInformer { + informer := cache.NewSharedIndexInformer( &cache.ListWatch{ ListFunc: func(options v1.ListOptions) (runtime.Object, error) { @@ -154,6 +183,9 @@ type notificationController struct { } func (c *notificationController) Init(ctx context.Context) error { + // resolve certificates using injected "argocd-tls-certs-cm" ConfigMap + httputil.SetCertResolver(argocert.GetCertificateForConnect) + go c.appInformer.Run(ctx.Done()) go c.appProjInformer.Run(ctx.Done()) go c.secretInformer.Run(ctx.Done()) diff --git a/notification_controller/controller/controller_test.go b/notification_controller/controller/controller_test.go index 5ad1e520502a3..4eedb28f5e001 100644 --- a/notification_controller/controller/controller_test.go +++ b/notification_controller/controller/controller_test.go @@ -110,26 +110,30 @@ func TestInit(t *testing.T) { k8sClient := k8sfake.NewSimpleClientset() appLabelSelector := "app=test" - nc := NewController( - k8sClient, - dynamicClient, - nil, - "default", - []string{}, - appLabelSelector, - nil, - "my-secret", - "my-configmap", - ) - - assert.NotNil(t, nc) - - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - - err = nc.Init(ctx) - - assert.NoError(t, err) + selfServiceNotificationEnabledFlags := []bool{false, true} + for _, selfServiceNotificationEnabled := range selfServiceNotificationEnabledFlags { + nc := NewController( + k8sClient, + dynamicClient, + nil, + "default", + []string{}, + appLabelSelector, + nil, + "my-secret", + "my-configmap", + selfServiceNotificationEnabled, + ) + + assert.NotNil(t, nc) + + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + err = nc.Init(ctx) + + assert.NoError(t, err) + } } func TestInitTimeout(t *testing.T) { @@ -152,6 +156,7 @@ func TestInitTimeout(t *testing.T) { nil, "my-secret", "my-configmap", + false, ) assert.NotNil(t, nc) diff --git a/pkg/apiclient/application/application.pb.go b/pkg/apiclient/application/application.pb.go index 8fd016ee36f68..70c63c36bc333 100644 --- a/pkg/apiclient/application/application.pb.go +++ b/pkg/apiclient/application/application.pb.go @@ -44,7 +44,7 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package type ApplicationQuery struct { // the application's name Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` - // forces application reconciliation if set to true + // forces application reconciliation if set to 'hard' Refresh *string `protobuf:"bytes,2,opt,name=refresh" json:"refresh,omitempty"` // the project names to restrict returned list applications Projects []string `protobuf:"bytes,3,rep,name=projects" json:"projects,omitempty"` diff --git a/pkg/apiclient/grpcproxy.go b/pkg/apiclient/grpcproxy.go index 9e5b841ae273a..28af7b62783df 100644 --- a/pkg/apiclient/grpcproxy.go +++ b/pkg/apiclient/grpcproxy.go @@ -13,9 +13,11 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/codes" + "google.golang.org/grpc/keepalive" "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" + "github.com/argoproj/argo-cd/v2/common" argocderrors "github.com/argoproj/argo-cd/v2/util/errors" argoio "github.com/argoproj/argo-cd/v2/util/io" "github.com/argoproj/argo-cd/v2/util/rand" @@ -112,6 +114,11 @@ func (c *client) startGRPCProxy() (*grpc.Server, net.Listener, error) { } proxySrv := grpc.NewServer( grpc.ForceServerCodec(&noopCodec{}), + grpc.KeepaliveEnforcementPolicy( + keepalive.EnforcementPolicy{ + MinTime: common.GetGRPCKeepAliveEnforcementMinimum(), + }, + ), grpc.UnknownServiceHandler(func(srv interface{}, stream grpc.ServerStream) error { fullMethodName, ok := grpc.MethodFromServerStream(stream) if !ok { diff --git a/pkg/apiclient/settings/settings.pb.go b/pkg/apiclient/settings/settings.pb.go index be5d129f6834f..b74110f9005d7 100644 --- a/pkg/apiclient/settings/settings.pb.go +++ b/pkg/apiclient/settings/settings.pb.go @@ -628,15 +628,16 @@ func (m *Connector) GetType() string { } type OIDCConfig struct { - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - Issuer string `protobuf:"bytes,2,opt,name=issuer,proto3" json:"issuer,omitempty"` - ClientID string `protobuf:"bytes,3,opt,name=clientID,proto3" json:"clientID,omitempty"` - CLIClientID string `protobuf:"bytes,4,opt,name=cliClientID,proto3" json:"cliClientID,omitempty"` - Scopes []string `protobuf:"bytes,5,rep,name=scopes,proto3" json:"scopes,omitempty"` - IDTokenClaims map[string]*oidc.Claim `protobuf:"bytes,6,rep,name=idTokenClaims,proto3" json:"idTokenClaims,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Issuer string `protobuf:"bytes,2,opt,name=issuer,proto3" json:"issuer,omitempty"` + ClientID string `protobuf:"bytes,3,opt,name=clientID,proto3" json:"clientID,omitempty"` + CLIClientID string `protobuf:"bytes,4,opt,name=cliClientID,proto3" json:"cliClientID,omitempty"` + Scopes []string `protobuf:"bytes,5,rep,name=scopes,proto3" json:"scopes,omitempty"` + IDTokenClaims map[string]*oidc.Claim `protobuf:"bytes,6,rep,name=idTokenClaims,proto3" json:"idTokenClaims,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + EnablePKCEAuthentication bool `protobuf:"varint,7,opt,name=enablePKCEAuthentication,proto3" json:"enablePKCEAuthentication,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *OIDCConfig) Reset() { *m = OIDCConfig{} } @@ -714,6 +715,13 @@ func (m *OIDCConfig) GetIDTokenClaims() map[string]*oidc.Claim { return nil } +func (m *OIDCConfig) GetEnablePKCEAuthentication() bool { + if m != nil { + return m.EnablePKCEAuthentication + } + return false +} + func init() { proto.RegisterType((*SettingsQuery)(nil), "cluster.SettingsQuery") proto.RegisterType((*Settings)(nil), "cluster.Settings") @@ -732,82 +740,83 @@ func init() { func init() { proto.RegisterFile("server/settings/settings.proto", fileDescriptor_a480d494da040caa) } var fileDescriptor_a480d494da040caa = []byte{ - // 1194 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x56, 0xcf, 0x6f, 0x1b, 0xc5, - 0x17, 0xd7, 0xd6, 0x69, 0x62, 0x3f, 0x37, 0x75, 0x32, 0x6d, 0xd3, 0xad, 0xd5, 0x6f, 0xe2, 0xaf, - 0x0f, 0x95, 0x41, 0xb0, 0x6e, 0x52, 0x21, 0x10, 0xa2, 0x82, 0xda, 0xae, 0x5a, 0xd3, 0xb4, 0x0d, - 0xdb, 0xa6, 0x07, 0x2e, 0xd5, 0x64, 0xf7, 0xb1, 0x59, 0xb2, 0x9e, 0x59, 0xcd, 0xcc, 0x9a, 0xba, - 0x47, 0x6e, 0x5c, 0xb8, 0xc0, 0xdf, 0xc2, 0x81, 0x7f, 0x00, 0x8e, 0x48, 0xdc, 0x23, 0x64, 0xf1, - 0x87, 0xa0, 0x99, 0xfd, 0x91, 0xcd, 0xda, 0x2d, 0x48, 0xbd, 0xcd, 0x7c, 0x3e, 0xef, 0xd7, 0xbc, - 0x79, 0xf3, 0xe6, 0xc1, 0xb6, 0x44, 0x31, 0x45, 0xd1, 0x97, 0xa8, 0x54, 0xc8, 0x02, 0x59, 0x2c, - 0x9c, 0x58, 0x70, 0xc5, 0xc9, 0x9a, 0x17, 0x25, 0x52, 0xa1, 0x68, 0x5f, 0x0d, 0x78, 0xc0, 0x0d, - 0xd6, 0xd7, 0xab, 0x94, 0x6e, 0xdf, 0x0c, 0x38, 0x0f, 0x22, 0xec, 0xd3, 0x38, 0xec, 0x53, 0xc6, - 0xb8, 0xa2, 0x2a, 0xe4, 0x2c, 0x53, 0x6e, 0xef, 0x07, 0xa1, 0x3a, 0x4e, 0x8e, 0x1c, 0x8f, 0x4f, - 0xfa, 0x54, 0x18, 0xf5, 0x6f, 0xcd, 0xe2, 0x43, 0xcf, 0xef, 0x4f, 0xf7, 0xfa, 0xf1, 0x49, 0xa0, - 0x35, 0x65, 0x9f, 0xc6, 0x71, 0x14, 0x7a, 0x46, 0xb7, 0x3f, 0xdd, 0xa5, 0x51, 0x7c, 0x4c, 0x77, - 0xfb, 0x01, 0x32, 0x14, 0x54, 0xa1, 0x9f, 0x59, 0xfb, 0xe2, 0x5f, 0xac, 0x55, 0x4f, 0xc2, 0x43, - 0xdf, 0xeb, 0x7b, 0x11, 0x0d, 0x27, 0x59, 0x3c, 0xdd, 0x16, 0xac, 0x3f, 0xcb, 0xd8, 0xaf, 0x12, - 0x14, 0xb3, 0xee, 0x2f, 0x4d, 0xa8, 0xe7, 0x08, 0xb9, 0x01, 0xb5, 0x44, 0x44, 0xb6, 0xd5, 0xb1, - 0x7a, 0x8d, 0xc1, 0xda, 0xfc, 0x74, 0xa7, 0x76, 0xe8, 0xee, 0xbb, 0x1a, 0x23, 0xb7, 0xa1, 0xe1, - 0xe3, 0xab, 0x21, 0x67, 0xdf, 0x84, 0x81, 0x7d, 0xa1, 0x63, 0xf5, 0x9a, 0x7b, 0xc4, 0xc9, 0x32, - 0xe3, 0x8c, 0x72, 0xc6, 0x3d, 0x13, 0x22, 0x43, 0x00, 0xed, 0x3f, 0x53, 0xa9, 0x19, 0x95, 0x2b, - 0x85, 0xca, 0xd3, 0xf1, 0x68, 0x98, 0x52, 0x83, 0xcb, 0xf3, 0xd3, 0x1d, 0x38, 0xdb, 0xbb, 0x25, - 0x35, 0xd2, 0x81, 0x26, 0x8d, 0xe3, 0x7d, 0x7a, 0x84, 0xd1, 0x23, 0x9c, 0xd9, 0x2b, 0x3a, 0x32, - 0xb7, 0x0c, 0x91, 0x17, 0xb0, 0x29, 0x50, 0xf2, 0x44, 0x78, 0xf8, 0x74, 0x8a, 0x42, 0x84, 0x3e, - 0x4a, 0xfb, 0x62, 0xa7, 0xd6, 0x6b, 0xee, 0xf5, 0x0a, 0x6f, 0xf9, 0x09, 0x1d, 0xb7, 0x2a, 0x7a, - 0x9f, 0x29, 0x31, 0x73, 0x17, 0x4d, 0x10, 0x07, 0x88, 0x54, 0x54, 0x25, 0x72, 0x40, 0xfd, 0x00, - 0xef, 0x33, 0x7a, 0x14, 0xa1, 0x6f, 0xaf, 0x76, 0xac, 0x5e, 0xdd, 0x5d, 0xc2, 0x90, 0x87, 0xd0, - 0x4a, 0x2b, 0xe1, 0x1e, 0xa3, 0xd1, 0x4c, 0x85, 0x9e, 0xb4, 0xd7, 0xcc, 0x99, 0xb7, 0x8b, 0x28, - 0x1e, 0x9c, 0xe7, 0xb3, 0xe3, 0x56, 0xd5, 0xc8, 0x6b, 0xd8, 0x38, 0x49, 0xa4, 0xe2, 0x93, 0xf0, - 0x35, 0x3e, 0x8d, 0x4d, 0x35, 0xd9, 0x75, 0x63, 0xea, 0x89, 0x73, 0x56, 0x00, 0x4e, 0x5e, 0x00, - 0x66, 0xf1, 0xd2, 0xf3, 0x9d, 0xe9, 0x9e, 0x13, 0x9f, 0x04, 0x8e, 0x2e, 0x27, 0xa7, 0x54, 0x4e, - 0x4e, 0x5e, 0x4e, 0xce, 0xa3, 0x8a, 0x55, 0x77, 0xc1, 0x0f, 0xf9, 0x3f, 0xac, 0x1c, 0x63, 0x14, - 0xdb, 0x0d, 0xe3, 0x6f, 0xbd, 0x08, 0xfd, 0x21, 0x46, 0xb1, 0x6b, 0x28, 0xf2, 0x1e, 0xac, 0xc5, - 0x51, 0x12, 0x84, 0x4c, 0xda, 0x60, 0xd2, 0xdc, 0x2a, 0xa4, 0x0e, 0x0c, 0xee, 0xe6, 0xbc, 0xce, - 0x61, 0x22, 0x51, 0xec, 0x73, 0xbd, 0x1b, 0x85, 0x32, 0xcd, 0x61, 0x33, 0xcd, 0xe1, 0x22, 0x43, - 0x7e, 0xb4, 0xe0, 0xba, 0x67, 0xb2, 0xf2, 0x98, 0x32, 0x1a, 0xe0, 0x04, 0x99, 0x3a, 0xc8, 0x7c, - 0x5d, 0x32, 0xbe, 0x9e, 0xbf, 0x5b, 0x06, 0x86, 0x4b, 0x8d, 0xbb, 0x6f, 0x72, 0x4a, 0x3e, 0x80, - 0xcd, 0x22, 0x45, 0x2f, 0x50, 0x48, 0x73, 0x17, 0xeb, 0x9d, 0x5a, 0xaf, 0xe1, 0x2e, 0x12, 0xa4, - 0x0d, 0xf5, 0x24, 0x1c, 0x4a, 0x79, 0xe8, 0xee, 0xdb, 0x97, 0x4d, 0xa5, 0x16, 0x7b, 0xd2, 0x83, - 0x56, 0x12, 0x0e, 0x28, 0x63, 0x28, 0x86, 0x9c, 0x29, 0x64, 0xca, 0x6e, 0x19, 0x91, 0x2a, 0xac, - 0x4b, 0x3e, 0x87, 0xb4, 0xa1, 0x8d, 0xb4, 0xe4, 0x4b, 0x90, 0xb6, 0x15, 0x53, 0x29, 0xbf, 0xe3, - 0xc2, 0x3f, 0xa0, 0x4a, 0xa1, 0x60, 0xf6, 0x66, 0x6a, 0xab, 0x02, 0x93, 0x5b, 0x70, 0x59, 0x09, - 0xea, 0x9d, 0x84, 0x2c, 0x78, 0x8c, 0xea, 0x98, 0xfb, 0x36, 0x31, 0x82, 0x15, 0x54, 0x9f, 0x33, - 0x77, 0x70, 0x80, 0x62, 0x42, 0x99, 0x8e, 0xef, 0x8a, 0xb9, 0xa7, 0x45, 0x82, 0xbc, 0x0f, 0x1b, - 0x05, 0xc8, 0x65, 0xa8, 0x53, 0x6c, 0x5f, 0x35, 0x76, 0x17, 0xf0, 0xca, 0x33, 0x72, 0x39, 0x57, - 0x87, 0x22, 0xb2, 0xaf, 0x19, 0xe9, 0x25, 0x8c, 0x3e, 0x3d, 0xbe, 0x42, 0x2f, 0x7f, 0x6f, 0x5b, - 0x26, 0x86, 0x32, 0x44, 0x6e, 0xc3, 0x15, 0x8f, 0x33, 0x25, 0x78, 0x14, 0xa1, 0x78, 0x42, 0x27, - 0x28, 0x63, 0xea, 0xa1, 0x7d, 0xdd, 0x98, 0x5c, 0x46, 0x91, 0xcf, 0xe0, 0x06, 0x8d, 0x63, 0x39, - 0x66, 0xf7, 0xd8, 0xac, 0x40, 0x73, 0x0f, 0xb6, 0xf1, 0xf0, 0x66, 0x81, 0xf6, 0xcf, 0x16, 0x6c, - 0x2d, 0x6f, 0x1b, 0x64, 0x03, 0x6a, 0x27, 0x38, 0x4b, 0xfb, 0xa5, 0xab, 0x97, 0xc4, 0x87, 0x8b, - 0x53, 0x1a, 0x25, 0x98, 0xb5, 0xc8, 0x77, 0x7c, 0xb0, 0x55, 0xb7, 0x6e, 0x6a, 0xfc, 0xd3, 0x0b, - 0x9f, 0x58, 0xdd, 0x97, 0x70, 0x6d, 0x69, 0x3f, 0x21, 0xdb, 0x00, 0xf9, 0xed, 0x8e, 0x47, 0x59, - 0x6c, 0x25, 0x44, 0xd7, 0x04, 0x65, 0x9c, 0xcd, 0x74, 0xe9, 0x1e, 0x4a, 0x14, 0xd2, 0xc4, 0x5a, - 0x77, 0x2b, 0x68, 0x77, 0x04, 0xd7, 0xf3, 0xb6, 0x99, 0x3d, 0x07, 0x17, 0x65, 0xcc, 0x99, 0xc4, - 0x72, 0x0b, 0xb0, 0xde, 0xde, 0x02, 0xba, 0xbf, 0x5a, 0xb0, 0xa2, 0x9b, 0x07, 0xb1, 0x61, 0xcd, - 0x3b, 0xa6, 0xe6, 0xf6, 0xd3, 0x98, 0xf2, 0xad, 0x7e, 0x36, 0x7a, 0xf9, 0x1c, 0x5f, 0x29, 0x13, - 0x4a, 0xc3, 0x2d, 0xf6, 0xe4, 0x2e, 0xc0, 0x51, 0xc8, 0xa8, 0x98, 0x1d, 0x8a, 0x48, 0xda, 0x35, - 0xe3, 0xec, 0x7f, 0xe7, 0xba, 0x92, 0x33, 0x28, 0xf8, 0xb4, 0x97, 0x97, 0x14, 0xda, 0x77, 0xa1, - 0x55, 0xa1, 0x97, 0xdc, 0xd9, 0xd5, 0xf2, 0x9d, 0x35, 0xca, 0x39, 0xbe, 0x09, 0xab, 0xe9, 0x79, - 0x08, 0x81, 0x15, 0x46, 0x27, 0x98, 0xa9, 0x99, 0x75, 0xf7, 0x73, 0x68, 0x14, 0x1f, 0x1f, 0xd9, - 0x03, 0xf0, 0x38, 0x63, 0xe8, 0x29, 0x2e, 0xf2, 0xac, 0x9c, 0x7d, 0x90, 0xc3, 0x9c, 0x72, 0x4b, - 0x52, 0xdd, 0x3b, 0xd0, 0x28, 0x88, 0x65, 0x1e, 0x34, 0xa6, 0x66, 0x71, 0x1e, 0x98, 0x59, 0x77, - 0x7f, 0xa8, 0x41, 0xe9, 0xb3, 0x5c, 0xaa, 0xb6, 0x05, 0xab, 0xa1, 0x94, 0x09, 0x8a, 0x4c, 0x31, - 0xdb, 0x91, 0x1e, 0xd4, 0xbd, 0x28, 0x44, 0xa6, 0xc6, 0x23, 0xf3, 0x1f, 0x37, 0x06, 0x97, 0xe6, - 0xa7, 0x3b, 0xf5, 0x61, 0x86, 0xb9, 0x05, 0x4b, 0x76, 0xa1, 0xe9, 0x45, 0x61, 0x4e, 0xa4, 0xdf, - 0xee, 0xa0, 0x35, 0x3f, 0xdd, 0x69, 0x0e, 0xf7, 0xc7, 0x85, 0x7c, 0x59, 0x46, 0x3b, 0x95, 0x1e, - 0x8f, 0xb3, 0xcf, 0xb7, 0xe1, 0x66, 0x3b, 0xf2, 0x12, 0xd6, 0x43, 0xff, 0x39, 0x3f, 0x41, 0x36, - 0x34, 0x83, 0x88, 0xbd, 0x6a, 0x72, 0x73, 0x6b, 0xc9, 0x24, 0xe0, 0x8c, 0xcb, 0x82, 0xe6, 0xba, - 0x06, 0x9b, 0xf3, 0xd3, 0x9d, 0xf5, 0xf1, 0xa8, 0x84, 0xbb, 0xe7, 0xed, 0xb5, 0x67, 0x40, 0x16, - 0xf5, 0x96, 0x5c, 0xf3, 0xe3, 0xf3, 0x4f, 0xf3, 0xe3, 0xb7, 0x3e, 0xcd, 0x74, 0x92, 0x72, 0x8a, - 0x51, 0x50, 0x8f, 0x24, 0x8e, 0xb1, 0x5f, 0xaa, 0x8f, 0xbd, 0xdf, 0x2c, 0x68, 0xe5, 0x6f, 0xe4, - 0x19, 0x8a, 0x69, 0xe8, 0x21, 0xf9, 0x12, 0x6a, 0x0f, 0x50, 0x91, 0xad, 0x85, 0xd9, 0xc3, 0xcc, - 0x5b, 0xed, 0xcd, 0x05, 0xbc, 0x6b, 0x7f, 0xff, 0xe7, 0xdf, 0x3f, 0x5d, 0x20, 0x64, 0xc3, 0xcc, - 0x90, 0xd3, 0xdd, 0x62, 0x7e, 0x23, 0xc7, 0x00, 0x0f, 0xb0, 0xf8, 0x8c, 0xde, 0x64, 0xb2, 0xb3, - 0x80, 0x57, 0xde, 0x6b, 0xb7, 0x63, 0x3c, 0xb4, 0x89, 0x5d, 0xf5, 0xd0, 0xcf, 0x9e, 0xe9, 0x60, - 0xf8, 0xfb, 0x7c, 0xdb, 0xfa, 0x63, 0xbe, 0x6d, 0xfd, 0x35, 0xdf, 0xb6, 0xbe, 0xfe, 0xe8, 0xbf, - 0x4d, 0xad, 0x69, 0xb9, 0x14, 0xc6, 0x8e, 0x56, 0xcd, 0x8c, 0x79, 0xe7, 0x9f, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xc5, 0x72, 0xeb, 0x5e, 0x52, 0x0b, 0x00, 0x00, + // 1215 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x56, 0x4f, 0x6f, 0x1b, 0x45, + 0x14, 0xd7, 0xd6, 0x69, 0x62, 0x3f, 0x37, 0x75, 0x32, 0x6d, 0xd3, 0xad, 0x55, 0x12, 0xe3, 0x43, + 0x65, 0x10, 0xac, 0x9b, 0x54, 0x08, 0x54, 0x51, 0x41, 0x6d, 0x57, 0xad, 0x69, 0xda, 0x86, 0x69, + 0xd3, 0x03, 0x97, 0x6a, 0xb2, 0x7e, 0xac, 0x97, 0xac, 0x67, 0x56, 0x33, 0xb3, 0xa6, 0xee, 0x91, + 0x0f, 0xc0, 0x05, 0x3e, 0x0b, 0x07, 0xee, 0x08, 0x8e, 0x48, 0xdc, 0x23, 0x64, 0xf1, 0x41, 0xd0, + 0xce, 0xfe, 0xc9, 0x66, 0xed, 0x14, 0xa4, 0xde, 0x66, 0x7e, 0xbf, 0xf7, 0x6f, 0xde, 0xbc, 0x37, + 0xf3, 0x60, 0x5b, 0xa1, 0x9c, 0xa2, 0xec, 0x2a, 0xd4, 0xda, 0xe7, 0x9e, 0xca, 0x17, 0x4e, 0x28, + 0x85, 0x16, 0x64, 0xcd, 0x0d, 0x22, 0xa5, 0x51, 0x36, 0xaf, 0x7a, 0xc2, 0x13, 0x06, 0xeb, 0xc6, + 0xab, 0x84, 0x6e, 0xde, 0xf4, 0x84, 0xf0, 0x02, 0xec, 0xb2, 0xd0, 0xef, 0x32, 0xce, 0x85, 0x66, + 0xda, 0x17, 0x3c, 0x55, 0x6e, 0xee, 0x7b, 0xbe, 0x1e, 0x47, 0x47, 0x8e, 0x2b, 0x26, 0x5d, 0x26, + 0x8d, 0xfa, 0x77, 0x66, 0xf1, 0xb1, 0x3b, 0xea, 0x4e, 0xf7, 0xba, 0xe1, 0xb1, 0x17, 0x6b, 0xaa, + 0x2e, 0x0b, 0xc3, 0xc0, 0x77, 0x8d, 0x6e, 0x77, 0xba, 0xcb, 0x82, 0x70, 0xcc, 0x76, 0xbb, 0x1e, + 0x72, 0x94, 0x4c, 0xe3, 0x28, 0xb5, 0xf6, 0xe5, 0x7f, 0x58, 0x2b, 0x9f, 0x44, 0xf8, 0x23, 0xb7, + 0xeb, 0x06, 0xcc, 0x9f, 0xa4, 0xf1, 0xb4, 0x1b, 0xb0, 0xfe, 0x3c, 0x65, 0xbf, 0x8e, 0x50, 0xce, + 0xda, 0xbf, 0xd4, 0xa1, 0x9a, 0x21, 0xe4, 0x06, 0x54, 0x22, 0x19, 0xd8, 0x56, 0xcb, 0xea, 0xd4, + 0x7a, 0x6b, 0xf3, 0x93, 0x9d, 0xca, 0x21, 0xdd, 0xa7, 0x31, 0x46, 0x6e, 0x43, 0x6d, 0x84, 0xaf, + 0xfb, 0x82, 0x7f, 0xeb, 0x7b, 0xf6, 0x85, 0x96, 0xd5, 0xa9, 0xef, 0x11, 0x27, 0xcd, 0x8c, 0x33, + 0xc8, 0x18, 0x7a, 0x2a, 0x44, 0xfa, 0x00, 0xb1, 0xff, 0x54, 0xa5, 0x62, 0x54, 0xae, 0xe4, 0x2a, + 0xcf, 0x86, 0x83, 0x7e, 0x42, 0xf5, 0x2e, 0xcf, 0x4f, 0x76, 0xe0, 0x74, 0x4f, 0x0b, 0x6a, 0xa4, + 0x05, 0x75, 0x16, 0x86, 0xfb, 0xec, 0x08, 0x83, 0xc7, 0x38, 0xb3, 0x57, 0xe2, 0xc8, 0x68, 0x11, + 0x22, 0x2f, 0x61, 0x53, 0xa2, 0x12, 0x91, 0x74, 0xf1, 0xd9, 0x14, 0xa5, 0xf4, 0x47, 0xa8, 0xec, + 0x8b, 0xad, 0x4a, 0xa7, 0xbe, 0xd7, 0xc9, 0xbd, 0x65, 0x27, 0x74, 0x68, 0x59, 0xf4, 0x01, 0xd7, + 0x72, 0x46, 0x17, 0x4d, 0x10, 0x07, 0x88, 0xd2, 0x4c, 0x47, 0xaa, 0xc7, 0x46, 0x1e, 0x3e, 0xe0, + 0xec, 0x28, 0xc0, 0x91, 0xbd, 0xda, 0xb2, 0x3a, 0x55, 0xba, 0x84, 0x21, 0x8f, 0xa0, 0x91, 0x54, + 0xc2, 0x7d, 0xce, 0x82, 0x99, 0xf6, 0x5d, 0x65, 0xaf, 0x99, 0x33, 0x6f, 0xe7, 0x51, 0x3c, 0x3c, + 0xcb, 0xa7, 0xc7, 0x2d, 0xab, 0x91, 0x37, 0xb0, 0x71, 0x1c, 0x29, 0x2d, 0x26, 0xfe, 0x1b, 0x7c, + 0x16, 0x9a, 0x6a, 0xb2, 0xab, 0xc6, 0xd4, 0x53, 0xe7, 0xb4, 0x00, 0x9c, 0xac, 0x00, 0xcc, 0xe2, + 0x95, 0x3b, 0x72, 0xa6, 0x7b, 0x4e, 0x78, 0xec, 0x39, 0x71, 0x39, 0x39, 0x85, 0x72, 0x72, 0xb2, + 0x72, 0x72, 0x1e, 0x97, 0xac, 0xd2, 0x05, 0x3f, 0xe4, 0x7d, 0x58, 0x19, 0x63, 0x10, 0xda, 0x35, + 0xe3, 0x6f, 0x3d, 0x0f, 0xfd, 0x11, 0x06, 0x21, 0x35, 0x14, 0xf9, 0x00, 0xd6, 0xc2, 0x20, 0xf2, + 0x7c, 0xae, 0x6c, 0x30, 0x69, 0x6e, 0xe4, 0x52, 0x07, 0x06, 0xa7, 0x19, 0x1f, 0xe7, 0x30, 0x52, + 0x28, 0xf7, 0x45, 0xbc, 0x1b, 0xf8, 0x2a, 0xc9, 0x61, 0x3d, 0xc9, 0xe1, 0x22, 0x43, 0x7e, 0xb4, + 0xe0, 0xba, 0x6b, 0xb2, 0xf2, 0x84, 0x71, 0xe6, 0xe1, 0x04, 0xb9, 0x3e, 0x48, 0x7d, 0x5d, 0x32, + 0xbe, 0x5e, 0xbc, 0x5b, 0x06, 0xfa, 0x4b, 0x8d, 0xd3, 0xf3, 0x9c, 0x92, 0x8f, 0x60, 0x33, 0x4f, + 0xd1, 0x4b, 0x94, 0xca, 0xdc, 0xc5, 0x7a, 0xab, 0xd2, 0xa9, 0xd1, 0x45, 0x82, 0x34, 0xa1, 0x1a, + 0xf9, 0x7d, 0xa5, 0x0e, 0xe9, 0xbe, 0x7d, 0xd9, 0x54, 0x6a, 0xbe, 0x27, 0x1d, 0x68, 0x44, 0x7e, + 0x8f, 0x71, 0x8e, 0xb2, 0x2f, 0xb8, 0x46, 0xae, 0xed, 0x86, 0x11, 0x29, 0xc3, 0x71, 0xc9, 0x67, + 0x50, 0x6c, 0x68, 0x23, 0x29, 0xf9, 0x02, 0x14, 0xdb, 0x0a, 0x99, 0x52, 0xdf, 0x0b, 0x39, 0x3a, + 0x60, 0x5a, 0xa3, 0xe4, 0xf6, 0x66, 0x62, 0xab, 0x04, 0x93, 0x5b, 0x70, 0x59, 0x4b, 0xe6, 0x1e, + 0xfb, 0xdc, 0x7b, 0x82, 0x7a, 0x2c, 0x46, 0x36, 0x31, 0x82, 0x25, 0x34, 0x3e, 0x67, 0xe6, 0xe0, + 0x00, 0xe5, 0x84, 0xf1, 0x38, 0xbe, 0x2b, 0xe6, 0x9e, 0x16, 0x09, 0xf2, 0x21, 0x6c, 0xe4, 0xa0, + 0x50, 0x7e, 0x9c, 0x62, 0xfb, 0xaa, 0xb1, 0xbb, 0x80, 0x97, 0xda, 0x88, 0x0a, 0xa1, 0x0f, 0x65, + 0x60, 0x5f, 0x33, 0xd2, 0x4b, 0x98, 0xf8, 0xf4, 0xf8, 0x1a, 0xdd, 0xac, 0xdf, 0xb6, 0x4c, 0x0c, + 0x45, 0x88, 0xdc, 0x86, 0x2b, 0xae, 0xe0, 0x5a, 0x8a, 0x20, 0x40, 0xf9, 0x94, 0x4d, 0x50, 0x85, + 0xcc, 0x45, 0xfb, 0xba, 0x31, 0xb9, 0x8c, 0x22, 0x9f, 0xc3, 0x0d, 0x16, 0x86, 0x6a, 0xc8, 0xef, + 0xf3, 0x59, 0x8e, 0x66, 0x1e, 0x6c, 0xe3, 0xe1, 0x7c, 0x81, 0xe6, 0xcf, 0x16, 0x6c, 0x2d, 0x7f, + 0x36, 0xc8, 0x06, 0x54, 0x8e, 0x71, 0x96, 0xbc, 0x97, 0x34, 0x5e, 0x92, 0x11, 0x5c, 0x9c, 0xb2, + 0x20, 0xc2, 0xf4, 0x89, 0x7c, 0xc7, 0x86, 0x2d, 0xbb, 0xa5, 0x89, 0xf1, 0xbb, 0x17, 0x3e, 0xb3, + 0xda, 0xaf, 0xe0, 0xda, 0xd2, 0xf7, 0x84, 0x6c, 0x03, 0x64, 0xb7, 0x3b, 0x1c, 0xa4, 0xb1, 0x15, + 0x90, 0xb8, 0x26, 0x18, 0x17, 0x7c, 0x16, 0x97, 0xee, 0xa1, 0x42, 0xa9, 0x4c, 0xac, 0x55, 0x5a, + 0x42, 0xdb, 0x03, 0xb8, 0x9e, 0x3d, 0x9b, 0x69, 0x3b, 0x50, 0x54, 0xa1, 0xe0, 0x0a, 0x8b, 0x4f, + 0x80, 0xf5, 0xf6, 0x27, 0xa0, 0xfd, 0xab, 0x05, 0x2b, 0xf1, 0xe3, 0x41, 0x6c, 0x58, 0x73, 0xc7, + 0xcc, 0xdc, 0x7e, 0x12, 0x53, 0xb6, 0x8d, 0xdb, 0x26, 0x5e, 0xbe, 0xc0, 0xd7, 0xda, 0x84, 0x52, + 0xa3, 0xf9, 0x9e, 0xdc, 0x03, 0x38, 0xf2, 0x39, 0x93, 0xb3, 0x43, 0x19, 0x28, 0xbb, 0x62, 0x9c, + 0xbd, 0x77, 0xe6, 0x55, 0x72, 0x7a, 0x39, 0x9f, 0xbc, 0xe5, 0x05, 0x85, 0xe6, 0x3d, 0x68, 0x94, + 0xe8, 0x25, 0x77, 0x76, 0xb5, 0x78, 0x67, 0xb5, 0x62, 0x8e, 0x6f, 0xc2, 0x6a, 0x72, 0x1e, 0x42, + 0x60, 0x85, 0xb3, 0x09, 0xa6, 0x6a, 0x66, 0xdd, 0xfe, 0x02, 0x6a, 0xf9, 0xc7, 0x47, 0xf6, 0x00, + 0x5c, 0xc1, 0x39, 0xba, 0x5a, 0xc8, 0x2c, 0x2b, 0xa7, 0x1f, 0x64, 0x3f, 0xa3, 0x68, 0x41, 0xaa, + 0x7d, 0x07, 0x6a, 0x39, 0xb1, 0xcc, 0x43, 0x8c, 0xe9, 0x59, 0x98, 0x05, 0x66, 0xd6, 0xed, 0xdf, + 0x2a, 0x50, 0xf8, 0x2c, 0x97, 0xaa, 0x6d, 0xc1, 0xaa, 0xaf, 0x54, 0x84, 0x32, 0x55, 0x4c, 0x77, + 0xa4, 0x03, 0x55, 0x37, 0xf0, 0x91, 0xeb, 0xe1, 0xc0, 0xfc, 0xc7, 0xb5, 0xde, 0xa5, 0xf9, 0xc9, + 0x4e, 0xb5, 0x9f, 0x62, 0x34, 0x67, 0xc9, 0x2e, 0xd4, 0xdd, 0xc0, 0xcf, 0x88, 0xe4, 0xdb, 0xed, + 0x35, 0xe6, 0x27, 0x3b, 0xf5, 0xfe, 0xfe, 0x30, 0x97, 0x2f, 0xca, 0xc4, 0x4e, 0x95, 0x2b, 0xc2, + 0xf4, 0xf3, 0xad, 0xd1, 0x74, 0x47, 0x5e, 0xc1, 0xba, 0x3f, 0x7a, 0x21, 0x8e, 0x91, 0xf7, 0xcd, + 0x20, 0x62, 0xaf, 0x9a, 0xdc, 0xdc, 0x5a, 0x32, 0x09, 0x38, 0xc3, 0xa2, 0xa0, 0xb9, 0xae, 0xde, + 0xe6, 0xfc, 0x64, 0x67, 0x7d, 0x38, 0x28, 0xe0, 0xf4, 0xac, 0x3d, 0x72, 0x17, 0x6c, 0x34, 0xad, + 0x7a, 0xf0, 0xb8, 0xff, 0xe0, 0x7e, 0xa4, 0xc7, 0xc8, 0x75, 0xda, 0x49, 0xe6, 0x07, 0xae, 0xd2, + 0x73, 0xf9, 0xe6, 0x0c, 0xc8, 0xa2, 0xcf, 0x25, 0x25, 0xf2, 0xe4, 0x6c, 0x5b, 0x7f, 0xfa, 0xd6, + 0xb6, 0x4e, 0xa6, 0x30, 0x27, 0x1f, 0x23, 0xe3, 0x71, 0xc6, 0x31, 0xf6, 0x0b, 0xb5, 0xb5, 0xf7, + 0xbb, 0x05, 0x8d, 0xac, 0xbf, 0x9e, 0xa3, 0x9c, 0xfa, 0x2e, 0x92, 0xaf, 0xa0, 0xf2, 0x10, 0x35, + 0xd9, 0x5a, 0x98, 0x5b, 0xcc, 0xac, 0xd6, 0xdc, 0x5c, 0xc0, 0xdb, 0xf6, 0x0f, 0x7f, 0xfd, 0xf3, + 0xd3, 0x05, 0x42, 0x36, 0xcc, 0xfc, 0x39, 0xdd, 0xcd, 0x67, 0x3f, 0x32, 0x06, 0x78, 0x88, 0xf9, + 0x47, 0x76, 0x9e, 0xc9, 0xd6, 0x02, 0x5e, 0xea, 0xf5, 0x76, 0xcb, 0x78, 0x68, 0x12, 0xbb, 0xec, + 0xa1, 0x9b, 0xb6, 0x78, 0xaf, 0xff, 0xc7, 0x7c, 0xdb, 0xfa, 0x73, 0xbe, 0x6d, 0xfd, 0x3d, 0xdf, + 0xb6, 0xbe, 0xf9, 0xe4, 0xff, 0x4d, 0xbc, 0x49, 0xa9, 0xe5, 0xc6, 0x8e, 0x56, 0xcd, 0x7c, 0x7a, + 0xe7, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf1, 0x4f, 0xb0, 0x2d, 0x8e, 0x0b, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1530,6 +1539,16 @@ func (m *OIDCConfig) MarshalToSizedBuffer(dAtA []byte) (int, error) { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if m.EnablePKCEAuthentication { + i-- + if m.EnablePKCEAuthentication { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x38 + } if len(m.IDTokenClaims) > 0 { for k := range m.IDTokenClaims { v := m.IDTokenClaims[k] @@ -1897,6 +1916,9 @@ func (m *OIDCConfig) Size() (n int) { n += mapEntrySize + 1 + sovSettings(uint64(mapEntrySize)) } } + if m.EnablePKCEAuthentication { + n += 2 + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -3871,6 +3893,26 @@ func (m *OIDCConfig) Unmarshal(dAtA []byte) error { } m.IDTokenClaims[mapkey] = mapvalue iNdEx = postIndex + case 7: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field EnablePKCEAuthentication", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowSettings + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.EnablePKCEAuthentication = bool(v != 0) default: iNdEx = preIndex skippy, err := skipSettings(dAtA[iNdEx:]) diff --git a/pkg/apis/api-rules/violation_exceptions.list b/pkg/apis/api-rules/violation_exceptions.list index a4f9a79767ac9..2b0f2e90d00a9 100644 --- a/pkg/apis/api-rules/violation_exceptions.list +++ b/pkg/apis/api-rules/violation_exceptions.list @@ -25,6 +25,7 @@ API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/ap API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,ApplicationSourceJsonnet,ExtVars API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,ApplicationSourceJsonnet,Libs API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,ApplicationSourceJsonnet,TLAs +API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,ApplicationSourceKustomize,Components API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,ApplicationSpec,Info API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,ApplicationStatus,Conditions API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,ApplicationStatus,Resources diff --git a/pkg/apis/application/v1alpha1/application_defaults.go b/pkg/apis/application/v1alpha1/application_defaults.go index 2bc9b1bd0d744..ad8112af8c88d 100644 --- a/pkg/apis/application/v1alpha1/application_defaults.go +++ b/pkg/apis/application/v1alpha1/application_defaults.go @@ -9,6 +9,9 @@ const ( // ResourcesFinalizerName is the finalizer value which we inject to finalize deletion of an application ResourcesFinalizerName string = "resources-finalizer.argocd.argoproj.io" + // PostDeleteFinalizerName is the finalizer that controls post-delete hooks execution + PostDeleteFinalizerName string = "post-delete-finalizer.argocd.argoproj.io" + // ForegroundPropagationPolicyFinalizer is the finalizer we inject to delete application with foreground propagation policy ForegroundPropagationPolicyFinalizer string = "resources-finalizer.argocd.argoproj.io/foreground" diff --git a/pkg/apis/application/v1alpha1/applicationset_types.go b/pkg/apis/application/v1alpha1/applicationset_types.go index 99db8124e51ea..41721d0c2287c 100644 --- a/pkg/apis/application/v1alpha1/applicationset_types.go +++ b/pkg/apis/application/v1alpha1/applicationset_types.go @@ -65,6 +65,7 @@ type ApplicationSetSpec struct { // ApplyNestedSelectors enables selectors defined within the generators of two level-nested matrix or merge generators ApplyNestedSelectors bool `json:"applyNestedSelectors,omitempty" protobuf:"bytes,8,name=applyNestedSelectors"` IgnoreApplicationDifferences ApplicationSetIgnoreDifferences `json:"ignoreApplicationDifferences,omitempty" protobuf:"bytes,9,name=ignoreApplicationDifferences"` + TemplatePatch *string `json:"templatePatch,omitempty" protobuf:"bytes,10,name=templatePatch"` } type ApplicationPreservedFields struct { diff --git a/pkg/apis/application/v1alpha1/applicationset_types_test.go b/pkg/apis/application/v1alpha1/applicationset_types_test.go index 1f9dc64b1fdb3..282cc1ca9a423 100644 --- a/pkg/apis/application/v1alpha1/applicationset_types_test.go +++ b/pkg/apis/application/v1alpha1/applicationset_types_test.go @@ -173,9 +173,9 @@ func TestSCMProviderGeneratorGitlab_WillIncludeSharedProjects(t *testing.T) { settings := SCMProviderGeneratorGitlab{} assert.True(t, settings.WillIncludeSharedProjects()) - settings.IncludeSharedProjects = pointer.BoolPtr(false) + settings.IncludeSharedProjects = pointer.Bool(false) assert.False(t, settings.WillIncludeSharedProjects()) - settings.IncludeSharedProjects = pointer.BoolPtr(true) + settings.IncludeSharedProjects = pointer.Bool(true) assert.True(t, settings.WillIncludeSharedProjects()) } diff --git a/pkg/apis/application/v1alpha1/generated.pb.go b/pkg/apis/application/v1alpha1/generated.pb.go index 91e8f8d42963b..cade795dcebd7 100644 --- a/pkg/apis/application/v1alpha1/generated.pb.go +++ b/pkg/apis/application/v1alpha1/generated.pb.go @@ -4448,692 +4448,695 @@ func init() { } var fileDescriptor_030104ce3b95bcac = []byte{ - // 10945 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0xbd, 0x6f, 0x70, 0x1c, 0xc9, - 0x75, 0x18, 0xae, 0xd9, 0x3f, 0xc0, 0xee, 0x03, 0x08, 0x92, 0x4d, 0xf2, 0x0e, 0xa4, 0xee, 0x0e, - 0xf4, 0xdc, 0xcf, 0xa7, 0xf3, 0x4f, 0x77, 0x80, 0x8f, 0xba, 0x53, 0x2e, 0x3a, 0x5b, 0x32, 0xfe, - 0x90, 0x20, 0x48, 0x80, 0xc0, 0x35, 0x40, 0x52, 0x3a, 0xf9, 0x74, 0x1a, 0xec, 0x36, 0x16, 0x43, - 0xcc, 0xce, 0xcc, 0xcd, 0xcc, 0x82, 0xc0, 0x59, 0x92, 0x25, 0x4b, 0xb6, 0x95, 0xe8, 0xcf, 0x29, - 0x52, 0x52, 0x3e, 0x27, 0x91, 0x23, 0x5b, 0x4e, 0x2a, 0xae, 0x44, 0x15, 0x27, 0xf9, 0x10, 0x27, - 0x4e, 0xca, 0x65, 0x3b, 0x95, 0x52, 0x4a, 0x49, 0xd9, 0x95, 0x72, 0x59, 0x4e, 0x62, 0x23, 0x12, - 0x52, 0xae, 0xa4, 0x52, 0x15, 0x57, 0x39, 0xf1, 0x07, 0x87, 0xc9, 0x87, 0x54, 0xff, 0xef, 0x99, - 0x9d, 0x05, 0x16, 0xc0, 0x80, 0xa4, 0x94, 0xfb, 0xb6, 0xdb, 0xef, 0xcd, 0x7b, 0x3d, 0x3d, 0xdd, - 0xef, 0xbd, 0x7e, 0xfd, 0xde, 0x6b, 0x98, 0x6f, 0xb9, 0xc9, 0x7a, 0x67, 0x75, 0xbc, 0x11, 0xb4, - 0x27, 0x9c, 0xa8, 0x15, 0x84, 0x51, 0x70, 0x87, 0xfd, 0x78, 0xb6, 0xd1, 0x9c, 0xd8, 0xbc, 0x34, - 0x11, 0x6e, 0xb4, 0x26, 0x9c, 0xd0, 0x8d, 0x27, 0x9c, 0x30, 0xf4, 0xdc, 0x86, 0x93, 0xb8, 0x81, - 0x3f, 0xb1, 0xf9, 0x9c, 0xe3, 0x85, 0xeb, 0xce, 0x73, 0x13, 0x2d, 0xe2, 0x93, 0xc8, 0x49, 0x48, - 0x73, 0x3c, 0x8c, 0x82, 0x24, 0x40, 0x3f, 0xa2, 0xa9, 0x8d, 0x4b, 0x6a, 0xec, 0xc7, 0x6b, 0x8d, - 0xe6, 0xf8, 0xe6, 0xa5, 0xf1, 0x70, 0xa3, 0x35, 0x4e, 0xa9, 0x8d, 0x1b, 0xd4, 0xc6, 0x25, 0xb5, - 0x0b, 0xcf, 0x1a, 0x7d, 0x69, 0x05, 0xad, 0x60, 0x82, 0x11, 0x5d, 0xed, 0xac, 0xb1, 0x7f, 0xec, - 0x0f, 0xfb, 0xc5, 0x99, 0x5d, 0xb0, 0x37, 0x5e, 0x8c, 0xc7, 0xdd, 0x80, 0x76, 0x6f, 0xa2, 0x11, - 0x44, 0x64, 0x62, 0xb3, 0xab, 0x43, 0x17, 0xae, 0x6a, 0x1c, 0xb2, 0x95, 0x10, 0x3f, 0x76, 0x03, - 0x3f, 0x7e, 0x96, 0x76, 0x81, 0x44, 0x9b, 0x24, 0x32, 0x5f, 0xcf, 0x40, 0xc8, 0xa3, 0xf4, 0xbc, - 0xa6, 0xd4, 0x76, 0x1a, 0xeb, 0xae, 0x4f, 0xa2, 0x6d, 0xfd, 0x78, 0x9b, 0x24, 0x4e, 0xde, 0x53, - 0x13, 0xbd, 0x9e, 0x8a, 0x3a, 0x7e, 0xe2, 0xb6, 0x49, 0xd7, 0x03, 0xef, 0xdd, 0xef, 0x81, 0xb8, - 0xb1, 0x4e, 0xda, 0x4e, 0xd7, 0x73, 0xef, 0xe9, 0xf5, 0x5c, 0x27, 0x71, 0xbd, 0x09, 0xd7, 0x4f, - 0xe2, 0x24, 0xca, 0x3e, 0x64, 0xbf, 0x0e, 0x27, 0x26, 0x6f, 0x2f, 0x4f, 0x76, 0x92, 0xf5, 0xe9, - 0xc0, 0x5f, 0x73, 0x5b, 0xe8, 0x05, 0x18, 0x6a, 0x78, 0x9d, 0x38, 0x21, 0xd1, 0x0d, 0xa7, 0x4d, - 0x46, 0xad, 0x8b, 0xd6, 0xd3, 0xf5, 0xa9, 0x33, 0xdf, 0xdc, 0x19, 0x7b, 0xc7, 0xee, 0xce, 0xd8, - 0xd0, 0xb4, 0x06, 0x61, 0x13, 0x0f, 0xfd, 0x10, 0x0c, 0x46, 0x81, 0x47, 0x26, 0xf1, 0x8d, 0xd1, - 0x12, 0x7b, 0xe4, 0xa4, 0x78, 0x64, 0x10, 0xf3, 0x66, 0x2c, 0xe1, 0xf6, 0xef, 0x97, 0x00, 0x26, - 0xc3, 0x70, 0x29, 0x0a, 0xee, 0x90, 0x46, 0x82, 0x3e, 0x0a, 0x35, 0x3a, 0x74, 0x4d, 0x27, 0x71, - 0x18, 0xb7, 0xa1, 0x4b, 0x3f, 0x3c, 0xce, 0xdf, 0x64, 0xdc, 0x7c, 0x13, 0x3d, 0x71, 0x28, 0xf6, - 0xf8, 0xe6, 0x73, 0xe3, 0x8b, 0xab, 0xf4, 0xf9, 0x05, 0x92, 0x38, 0x53, 0x48, 0x30, 0x03, 0xdd, - 0x86, 0x15, 0x55, 0xe4, 0x43, 0x25, 0x0e, 0x49, 0x83, 0x75, 0x6c, 0xe8, 0xd2, 0xfc, 0xf8, 0x51, - 0x66, 0xe8, 0xb8, 0xee, 0xf9, 0x72, 0x48, 0x1a, 0x53, 0xc3, 0x82, 0x73, 0x85, 0xfe, 0xc3, 0x8c, - 0x0f, 0xda, 0x84, 0x81, 0x38, 0x71, 0x92, 0x4e, 0x3c, 0x5a, 0x66, 0x1c, 0x6f, 0x14, 0xc6, 0x91, - 0x51, 0x9d, 0x1a, 0x11, 0x3c, 0x07, 0xf8, 0x7f, 0x2c, 0xb8, 0xd9, 0x7f, 0x64, 0xc1, 0x88, 0x46, - 0x9e, 0x77, 0xe3, 0x04, 0xfd, 0x78, 0xd7, 0xe0, 0x8e, 0xf7, 0x37, 0xb8, 0xf4, 0x69, 0x36, 0xb4, - 0xa7, 0x04, 0xb3, 0x9a, 0x6c, 0x31, 0x06, 0xb6, 0x0d, 0x55, 0x37, 0x21, 0xed, 0x78, 0xb4, 0x74, - 0xb1, 0xfc, 0xf4, 0xd0, 0xa5, 0xab, 0x45, 0xbd, 0xe7, 0xd4, 0x09, 0xc1, 0xb4, 0x3a, 0x47, 0xc9, - 0x63, 0xce, 0xc5, 0xfe, 0x95, 0x61, 0xf3, 0xfd, 0xe8, 0x80, 0xa3, 0xe7, 0x60, 0x28, 0x0e, 0x3a, - 0x51, 0x83, 0x60, 0x12, 0x06, 0xf1, 0xa8, 0x75, 0xb1, 0x4c, 0xa7, 0x1e, 0x9d, 0xa9, 0xcb, 0xba, - 0x19, 0x9b, 0x38, 0xe8, 0x8b, 0x16, 0x0c, 0x37, 0x49, 0x9c, 0xb8, 0x3e, 0xe3, 0x2f, 0x3b, 0xbf, - 0x72, 0xe4, 0xce, 0xcb, 0xc6, 0x19, 0x4d, 0x7c, 0xea, 0xac, 0x78, 0x91, 0x61, 0xa3, 0x31, 0xc6, - 0x29, 0xfe, 0x74, 0xc5, 0x35, 0x49, 0xdc, 0x88, 0xdc, 0x90, 0xfe, 0x67, 0x73, 0xc6, 0x58, 0x71, - 0x33, 0x1a, 0x84, 0x4d, 0x3c, 0xe4, 0x43, 0x95, 0xae, 0xa8, 0x78, 0xb4, 0xc2, 0xfa, 0x3f, 0x77, - 0xb4, 0xfe, 0x8b, 0x41, 0xa5, 0x8b, 0x55, 0x8f, 0x3e, 0xfd, 0x17, 0x63, 0xce, 0x06, 0x7d, 0xc1, - 0x82, 0x51, 0xb1, 0xe2, 0x31, 0xe1, 0x03, 0x7a, 0x7b, 0xdd, 0x4d, 0x88, 0xe7, 0xc6, 0xc9, 0x68, - 0x95, 0xf5, 0x61, 0xa2, 0xbf, 0xb9, 0x35, 0x1b, 0x05, 0x9d, 0xf0, 0xba, 0xeb, 0x37, 0xa7, 0x2e, - 0x0a, 0x4e, 0xa3, 0xd3, 0x3d, 0x08, 0xe3, 0x9e, 0x2c, 0xd1, 0x57, 0x2c, 0xb8, 0xe0, 0x3b, 0x6d, - 0x12, 0x87, 0x0e, 0xfd, 0xb4, 0x1c, 0x3c, 0xe5, 0x39, 0x8d, 0x0d, 0xd6, 0xa3, 0x81, 0xc3, 0xf5, - 0xc8, 0x16, 0x3d, 0xba, 0x70, 0xa3, 0x27, 0x69, 0xbc, 0x07, 0x5b, 0xf4, 0x75, 0x0b, 0x4e, 0x07, - 0x51, 0xb8, 0xee, 0xf8, 0xa4, 0x29, 0xa1, 0xf1, 0xe8, 0x20, 0x5b, 0x7a, 0x1f, 0x39, 0xda, 0x27, - 0x5a, 0xcc, 0x92, 0x5d, 0x08, 0x7c, 0x37, 0x09, 0xa2, 0x65, 0x92, 0x24, 0xae, 0xdf, 0x8a, 0xa7, - 0xce, 0xed, 0xee, 0x8c, 0x9d, 0xee, 0xc2, 0xc2, 0xdd, 0xfd, 0x41, 0x3f, 0x01, 0x43, 0xf1, 0xb6, - 0xdf, 0xb8, 0xed, 0xfa, 0xcd, 0xe0, 0x6e, 0x3c, 0x5a, 0x2b, 0x62, 0xf9, 0x2e, 0x2b, 0x82, 0x62, - 0x01, 0x6a, 0x06, 0xd8, 0xe4, 0x96, 0xff, 0xe1, 0xf4, 0x54, 0xaa, 0x17, 0xfd, 0xe1, 0xf4, 0x64, - 0xda, 0x83, 0x2d, 0xfa, 0x59, 0x0b, 0x4e, 0xc4, 0x6e, 0xcb, 0x77, 0x92, 0x4e, 0x44, 0xae, 0x93, - 0xed, 0x78, 0x14, 0x58, 0x47, 0xae, 0x1d, 0x71, 0x54, 0x0c, 0x92, 0x53, 0xe7, 0x44, 0x1f, 0x4f, - 0x98, 0xad, 0x31, 0x4e, 0xf3, 0xcd, 0x5b, 0x68, 0x7a, 0x5a, 0x0f, 0x15, 0xbb, 0xd0, 0xf4, 0xa4, - 0xee, 0xc9, 0x12, 0xfd, 0x18, 0x9c, 0xe2, 0x4d, 0x6a, 0x64, 0xe3, 0xd1, 0x61, 0x26, 0x68, 0xcf, - 0xee, 0xee, 0x8c, 0x9d, 0x5a, 0xce, 0xc0, 0x70, 0x17, 0x36, 0x7a, 0x1d, 0xc6, 0x42, 0x12, 0xb5, - 0xdd, 0x64, 0xd1, 0xf7, 0xb6, 0xa5, 0xf8, 0x6e, 0x04, 0x21, 0x69, 0x8a, 0xee, 0xc4, 0xa3, 0x27, - 0x2e, 0x5a, 0x4f, 0xd7, 0xa6, 0xde, 0x25, 0xba, 0x39, 0xb6, 0xb4, 0x37, 0x3a, 0xde, 0x8f, 0x9e, - 0xfd, 0xaf, 0x4b, 0x70, 0x2a, 0xab, 0x38, 0xd1, 0xdf, 0xb1, 0xe0, 0xe4, 0x9d, 0xbb, 0xc9, 0x4a, - 0xb0, 0x41, 0xfc, 0x78, 0x6a, 0x9b, 0x8a, 0x37, 0xa6, 0x32, 0x86, 0x2e, 0x35, 0x8a, 0x55, 0xd1, - 0xe3, 0xd7, 0xd2, 0x5c, 0x2e, 0xfb, 0x49, 0xb4, 0x3d, 0xf5, 0xa8, 0x78, 0xbb, 0x93, 0xd7, 0x6e, - 0xaf, 0x98, 0x50, 0x9c, 0xed, 0xd4, 0x85, 0xcf, 0x59, 0x70, 0x36, 0x8f, 0x04, 0x3a, 0x05, 0xe5, - 0x0d, 0xb2, 0xcd, 0xad, 0x32, 0x4c, 0x7f, 0xa2, 0x57, 0xa1, 0xba, 0xe9, 0x78, 0x1d, 0x22, 0xac, - 0x9b, 0xd9, 0xa3, 0xbd, 0x88, 0xea, 0x19, 0xe6, 0x54, 0xdf, 0x57, 0x7a, 0xd1, 0xb2, 0x7f, 0xa7, - 0x0c, 0x43, 0x86, 0x7e, 0xbb, 0x0f, 0x16, 0x5b, 0x90, 0xb2, 0xd8, 0x16, 0x0a, 0x53, 0xcd, 0x3d, - 0x4d, 0xb6, 0xbb, 0x19, 0x93, 0x6d, 0xb1, 0x38, 0x96, 0x7b, 0xda, 0x6c, 0x28, 0x81, 0x7a, 0x10, - 0x52, 0x8b, 0x9c, 0xaa, 0xfe, 0x4a, 0x11, 0x9f, 0x70, 0x51, 0x92, 0x9b, 0x3a, 0xb1, 0xbb, 0x33, - 0x56, 0x57, 0x7f, 0xb1, 0x66, 0x64, 0x7f, 0xdb, 0x82, 0xb3, 0x46, 0x1f, 0xa7, 0x03, 0xbf, 0xe9, - 0xb2, 0x4f, 0x7b, 0x11, 0x2a, 0xc9, 0x76, 0x28, 0xcd, 0x7e, 0x35, 0x52, 0x2b, 0xdb, 0x21, 0xc1, - 0x0c, 0x42, 0x0d, 0xfd, 0x36, 0x89, 0x63, 0xa7, 0x45, 0xb2, 0x86, 0xfe, 0x02, 0x6f, 0xc6, 0x12, - 0x8e, 0x22, 0x40, 0x9e, 0x13, 0x27, 0x2b, 0x91, 0xe3, 0xc7, 0x8c, 0xfc, 0x8a, 0xdb, 0x26, 0x62, - 0x80, 0xff, 0xff, 0xfe, 0x66, 0x0c, 0x7d, 0x62, 0xea, 0x91, 0xdd, 0x9d, 0x31, 0x34, 0xdf, 0x45, - 0x09, 0xe7, 0x50, 0xb7, 0xbf, 0x62, 0xc1, 0x23, 0xf9, 0xb6, 0x18, 0x7a, 0x0a, 0x06, 0xf8, 0x96, - 0x4f, 0xbc, 0x9d, 0xfe, 0x24, 0xac, 0x15, 0x0b, 0x28, 0x9a, 0x80, 0xba, 0xd2, 0x13, 0xe2, 0x1d, - 0x4f, 0x0b, 0xd4, 0xba, 0x56, 0x2e, 0x1a, 0x87, 0x0e, 0x1a, 0xfd, 0x23, 0x2c, 0x37, 0x35, 0x68, - 0x6c, 0x93, 0xc4, 0x20, 0xf6, 0x7f, 0xb2, 0xe0, 0xa4, 0xd1, 0xab, 0xfb, 0x60, 0x9a, 0xfb, 0x69, - 0xd3, 0x7c, 0xae, 0xb0, 0xf9, 0xdc, 0xc3, 0x36, 0xff, 0x82, 0x05, 0x17, 0x0c, 0xac, 0x05, 0x27, - 0x69, 0xac, 0x5f, 0xde, 0x0a, 0x23, 0x12, 0xd3, 0xed, 0x34, 0x7a, 0xdc, 0x90, 0x5b, 0x53, 0x43, - 0x82, 0x42, 0xf9, 0x3a, 0xd9, 0xe6, 0x42, 0xec, 0x19, 0xa8, 0xf1, 0xc9, 0x19, 0x44, 0x62, 0xc4, - 0xd5, 0xbb, 0x2d, 0x8a, 0x76, 0xac, 0x30, 0x90, 0x0d, 0x03, 0x4c, 0x38, 0xd1, 0xc5, 0x4a, 0xd5, - 0x10, 0xd0, 0x8f, 0x78, 0x8b, 0xb5, 0x60, 0x01, 0xb1, 0xe3, 0x54, 0x77, 0x96, 0x22, 0xc2, 0x3e, - 0x6e, 0xf3, 0x8a, 0x4b, 0xbc, 0x66, 0x4c, 0xb7, 0x0d, 0x8e, 0xef, 0x07, 0x89, 0xd8, 0x01, 0x18, - 0xdb, 0x86, 0x49, 0xdd, 0x8c, 0x4d, 0x1c, 0xca, 0xd4, 0x73, 0x56, 0x89, 0xc7, 0x47, 0x54, 0x30, - 0x9d, 0x67, 0x2d, 0x58, 0x40, 0xec, 0xdd, 0x12, 0xdb, 0xa0, 0xa8, 0xa5, 0x4f, 0xee, 0xc7, 0xee, - 0x36, 0x4a, 0xc9, 0xca, 0xa5, 0xe2, 0x04, 0x17, 0xe9, 0xbd, 0xc3, 0x7d, 0x23, 0x23, 0x2e, 0x71, - 0xa1, 0x5c, 0xf7, 0xde, 0xe5, 0xfe, 0x66, 0x09, 0xc6, 0xd2, 0x0f, 0x74, 0x49, 0x5b, 0xba, 0xa5, - 0x32, 0x18, 0x65, 0x9d, 0x18, 0x06, 0x3e, 0x36, 0xf1, 0x7a, 0x08, 0xac, 0xd2, 0x71, 0x0a, 0x2c, - 0x53, 0x9e, 0x96, 0xf7, 0x91, 0xa7, 0x4f, 0xa9, 0x51, 0xaf, 0x64, 0x04, 0x58, 0x5a, 0xa7, 0x5c, - 0x84, 0x4a, 0x9c, 0x90, 0x70, 0xb4, 0x9a, 0x96, 0x47, 0xcb, 0x09, 0x09, 0x31, 0x83, 0xd8, 0xff, - 0xad, 0x04, 0x8f, 0xa6, 0xc7, 0x50, 0xab, 0x80, 0x0f, 0xa4, 0x54, 0xc0, 0xbb, 0x4d, 0x15, 0x70, - 0x6f, 0x67, 0xec, 0x9d, 0x3d, 0x1e, 0xfb, 0x9e, 0xd1, 0x10, 0x68, 0x36, 0x33, 0x8a, 0x13, 0xe9, - 0x51, 0xbc, 0xb7, 0x33, 0xf6, 0x78, 0x8f, 0x77, 0xcc, 0x0c, 0xf3, 0x53, 0x30, 0x10, 0x11, 0x27, - 0x0e, 0x7c, 0x31, 0xd0, 0xea, 0x73, 0x60, 0xd6, 0x8a, 0x05, 0xd4, 0xfe, 0x77, 0xf5, 0xec, 0x60, - 0xcf, 0x72, 0x27, 0x5c, 0x10, 0x21, 0x17, 0x2a, 0xcc, 0xac, 0xe7, 0xa2, 0xe1, 0xfa, 0xd1, 0x96, - 0x11, 0x55, 0x03, 0x8a, 0xf4, 0x54, 0x8d, 0x7e, 0x35, 0xda, 0x84, 0x19, 0x0b, 0xb4, 0x05, 0xb5, - 0x86, 0xb4, 0xb6, 0x4b, 0x45, 0xf8, 0xa5, 0x84, 0xad, 0xad, 0x39, 0x0e, 0x53, 0x79, 0xad, 0x4c, - 0x74, 0xc5, 0x0d, 0x11, 0x28, 0xb7, 0xdc, 0x44, 0x7c, 0xd6, 0x23, 0xee, 0xa7, 0x66, 0x5d, 0xe3, - 0x15, 0x07, 0xa9, 0x12, 0x99, 0x75, 0x13, 0x4c, 0xe9, 0xa3, 0x9f, 0xb6, 0x60, 0x28, 0x6e, 0xb4, - 0x97, 0xa2, 0x60, 0xd3, 0x6d, 0x92, 0x48, 0x58, 0x53, 0x47, 0x14, 0x4d, 0xcb, 0xd3, 0x0b, 0x92, - 0xa0, 0xe6, 0xcb, 0xf7, 0xb7, 0x1a, 0x82, 0x4d, 0xbe, 0x74, 0x97, 0xf1, 0xa8, 0x78, 0xf7, 0x19, - 0xd2, 0x70, 0xa9, 0xfe, 0x93, 0x9b, 0x2a, 0x36, 0x53, 0x8e, 0x6c, 0x5d, 0xce, 0x74, 0x1a, 0x1b, - 0x74, 0xbd, 0xe9, 0x0e, 0xbd, 0x73, 0x77, 0x67, 0xec, 0xd1, 0xe9, 0x7c, 0x9e, 0xb8, 0x57, 0x67, - 0xd8, 0x80, 0x85, 0x1d, 0xcf, 0xc3, 0xe4, 0xf5, 0x0e, 0x61, 0x2e, 0x93, 0x02, 0x06, 0x6c, 0x49, - 0x13, 0xcc, 0x0c, 0x98, 0x01, 0xc1, 0x26, 0x5f, 0xf4, 0x3a, 0x0c, 0xb4, 0x9d, 0x24, 0x72, 0xb7, - 0x84, 0x9f, 0xe4, 0x88, 0xf6, 0xfe, 0x02, 0xa3, 0xa5, 0x99, 0x33, 0x4d, 0xcd, 0x1b, 0xb1, 0x60, - 0x84, 0xda, 0x50, 0x6d, 0x93, 0xa8, 0x45, 0x46, 0x6b, 0x45, 0xf8, 0x84, 0x17, 0x28, 0x29, 0xcd, - 0xb0, 0x4e, 0xad, 0x23, 0xd6, 0x86, 0x39, 0x17, 0xf4, 0x2a, 0xd4, 0x62, 0xe2, 0x91, 0x06, 0xb5, - 0x6f, 0xea, 0x8c, 0xe3, 0x7b, 0xfa, 0xb4, 0xf5, 0xa8, 0x61, 0xb1, 0x2c, 0x1e, 0xe5, 0x0b, 0x4c, - 0xfe, 0xc3, 0x8a, 0x24, 0x1d, 0xc0, 0xd0, 0xeb, 0xb4, 0x5c, 0x7f, 0x14, 0x8a, 0x18, 0xc0, 0x25, - 0x46, 0x2b, 0x33, 0x80, 0xbc, 0x11, 0x0b, 0x46, 0xf6, 0x1f, 0x5b, 0x80, 0xd2, 0x42, 0xed, 0x3e, - 0x18, 0xb5, 0xaf, 0xa7, 0x8d, 0xda, 0xf9, 0x22, 0xad, 0x8e, 0x1e, 0x76, 0xed, 0xaf, 0xd7, 0x21, - 0xa3, 0x0e, 0x6e, 0x90, 0x38, 0x21, 0xcd, 0xb7, 0x45, 0xf8, 0xdb, 0x22, 0xfc, 0x6d, 0x11, 0xae, - 0x44, 0xf8, 0x6a, 0x46, 0x84, 0xbf, 0xdf, 0x58, 0xf5, 0xfa, 0x50, 0xf5, 0x35, 0x75, 0xea, 0x6a, - 0xf6, 0xc0, 0x40, 0xa0, 0x92, 0xe0, 0xda, 0xf2, 0xe2, 0x8d, 0x5c, 0x99, 0xfd, 0x5a, 0x5a, 0x66, - 0x1f, 0x95, 0xc5, 0xff, 0x0b, 0x52, 0xfa, 0x5f, 0x59, 0xf0, 0xae, 0xb4, 0xf4, 0x92, 0x33, 0x67, - 0xae, 0xe5, 0x07, 0x11, 0x99, 0x71, 0xd7, 0xd6, 0x48, 0x44, 0xfc, 0x06, 0x89, 0x95, 0x17, 0xc3, - 0xea, 0xe5, 0xc5, 0x40, 0xcf, 0xc3, 0xf0, 0x9d, 0x38, 0xf0, 0x97, 0x02, 0xd7, 0x17, 0x22, 0x88, - 0x6e, 0x84, 0x4f, 0xed, 0xee, 0x8c, 0x0d, 0xd3, 0x11, 0x95, 0xed, 0x38, 0x85, 0x85, 0xa6, 0xe1, - 0xf4, 0x9d, 0xd7, 0x97, 0x9c, 0xc4, 0x70, 0x07, 0xc8, 0x8d, 0x3b, 0x3b, 0xb0, 0xb8, 0xf6, 0x72, - 0x06, 0x88, 0xbb, 0xf1, 0xed, 0xbf, 0x51, 0x82, 0xf3, 0x99, 0x17, 0x09, 0x3c, 0x2f, 0xe8, 0x24, - 0x74, 0x53, 0x83, 0x7e, 0xc1, 0x82, 0x53, 0xed, 0xb4, 0xc7, 0x21, 0x16, 0x8e, 0xdd, 0x0f, 0x16, - 0xa6, 0x23, 0x32, 0x2e, 0x8d, 0xa9, 0x51, 0x31, 0x42, 0xa7, 0x32, 0x80, 0x18, 0x77, 0xf5, 0x05, - 0xbd, 0x0a, 0xf5, 0xb6, 0xb3, 0x75, 0x33, 0x6c, 0x3a, 0x89, 0xdc, 0x4f, 0xf6, 0x76, 0x03, 0x74, - 0x12, 0xd7, 0x1b, 0xe7, 0xc7, 0xf5, 0xe3, 0x73, 0x7e, 0xb2, 0x18, 0x2d, 0x27, 0x91, 0xeb, 0xb7, - 0xb8, 0x3b, 0x6f, 0x41, 0x92, 0xc1, 0x9a, 0xa2, 0xfd, 0x55, 0x2b, 0xab, 0xa4, 0xd4, 0xe8, 0x44, - 0x4e, 0x42, 0x5a, 0xdb, 0xe8, 0x63, 0x50, 0xa5, 0x1b, 0x3f, 0x39, 0x2a, 0xb7, 0x8b, 0xd4, 0x9c, - 0xc6, 0x97, 0xd0, 0x4a, 0x94, 0xfe, 0x8b, 0x31, 0x67, 0x6a, 0xff, 0x71, 0x2d, 0x6b, 0x2c, 0xb0, - 0xc3, 0xdb, 0x4b, 0x00, 0xad, 0x60, 0x85, 0xb4, 0x43, 0x8f, 0x0e, 0x8b, 0xc5, 0x4e, 0x00, 0x94, - 0xaf, 0x63, 0x56, 0x41, 0xb0, 0x81, 0x85, 0xfe, 0x92, 0x05, 0xd0, 0x92, 0x73, 0x5e, 0x1a, 0x02, - 0x37, 0x8b, 0x7c, 0x1d, 0xbd, 0xa2, 0x74, 0x5f, 0x14, 0x43, 0x6c, 0x30, 0x47, 0x3f, 0x65, 0x41, - 0x2d, 0x91, 0xdd, 0xe7, 0xaa, 0x71, 0xa5, 0xc8, 0x9e, 0xc8, 0x97, 0xd6, 0x36, 0x91, 0x1a, 0x12, - 0xc5, 0x17, 0xfd, 0x8c, 0x05, 0x10, 0x6f, 0xfb, 0x8d, 0xa5, 0xc0, 0x73, 0x1b, 0xdb, 0x42, 0x63, - 0xde, 0x2a, 0xd4, 0x1f, 0xa3, 0xa8, 0x4f, 0x8d, 0xd0, 0xd1, 0xd0, 0xff, 0xb1, 0xc1, 0x19, 0x7d, - 0x02, 0x6a, 0xb1, 0x98, 0x6e, 0x42, 0x47, 0xae, 0x14, 0xeb, 0x15, 0xe2, 0xb4, 0x85, 0x78, 0x15, - 0xff, 0xb0, 0xe2, 0x89, 0x7e, 0xce, 0x82, 0x93, 0x61, 0xda, 0xcf, 0x27, 0xd4, 0x61, 0x71, 0x32, - 0x20, 0xe3, 0x47, 0x9c, 0x3a, 0xb3, 0xbb, 0x33, 0x76, 0x32, 0xd3, 0x88, 0xb3, 0xbd, 0xa0, 0x12, - 0x50, 0xcf, 0xe0, 0xc5, 0x90, 0xfb, 0x1c, 0x07, 0xb5, 0x04, 0x9c, 0xcd, 0x02, 0x71, 0x37, 0x3e, - 0x5a, 0x82, 0xb3, 0xb4, 0x77, 0xdb, 0xdc, 0xfc, 0x94, 0xea, 0x25, 0x66, 0xca, 0xb0, 0x36, 0xf5, - 0x98, 0x98, 0x21, 0xcc, 0xab, 0x9f, 0xc5, 0xc1, 0xb9, 0x4f, 0xa2, 0xdf, 0xb1, 0xe0, 0x31, 0x97, - 0xa9, 0x01, 0xd3, 0x61, 0xae, 0x35, 0x82, 0x38, 0x89, 0x25, 0x85, 0xca, 0x8a, 0x5e, 0xea, 0x67, - 0xea, 0xff, 0x13, 0x6f, 0xf0, 0xd8, 0xdc, 0x1e, 0x5d, 0xc2, 0x7b, 0x76, 0xd8, 0xfe, 0x56, 0x29, - 0x75, 0xac, 0xa1, 0x7c, 0x89, 0x4c, 0x6a, 0x34, 0xa4, 0x1b, 0x47, 0x0a, 0xc1, 0x42, 0xa5, 0x86, - 0x72, 0x12, 0x69, 0xa9, 0xa1, 0x9a, 0x62, 0x6c, 0x30, 0xa7, 0xb6, 0xe5, 0x69, 0x27, 0xeb, 0xb1, - 0x14, 0x82, 0xec, 0xd5, 0x22, 0xbb, 0xd4, 0x7d, 0x08, 0x75, 0x5e, 0x74, 0xed, 0x74, 0x17, 0x08, - 0x77, 0x77, 0xc9, 0xfe, 0x56, 0xfa, 0x28, 0xc5, 0x58, 0x83, 0x7d, 0x1c, 0x13, 0x7d, 0xd1, 0x82, - 0xa1, 0x28, 0xf0, 0x3c, 0xd7, 0x6f, 0x51, 0x79, 0x21, 0x94, 0xde, 0x87, 0x8f, 0x45, 0xef, 0x08, - 0xc1, 0xc0, 0x2c, 0x54, 0xac, 0x79, 0x62, 0xb3, 0x03, 0xf6, 0x1f, 0x59, 0x30, 0xda, 0x4b, 0xae, - 0x21, 0x02, 0xef, 0x94, 0x8b, 0x56, 0x05, 0x49, 0x2c, 0xfa, 0x33, 0xc4, 0x23, 0xca, 0x7f, 0x5c, - 0x9b, 0x7a, 0x52, 0xbc, 0xe6, 0x3b, 0x97, 0x7a, 0xa3, 0xe2, 0xbd, 0xe8, 0xa0, 0x57, 0xe0, 0x94, - 0xf1, 0x5e, 0xb1, 0x1a, 0x98, 0xfa, 0xd4, 0x38, 0x35, 0x24, 0x26, 0x33, 0xb0, 0x7b, 0x3b, 0x63, - 0x8f, 0x64, 0xdb, 0x84, 0xe0, 0xed, 0xa2, 0x63, 0xff, 0x72, 0x29, 0xfb, 0xb5, 0x94, 0xce, 0x7c, - 0xcb, 0xea, 0xda, 0x95, 0x7f, 0xf0, 0x38, 0xf4, 0x14, 0xdb, 0xbf, 0xab, 0x38, 0x8c, 0xde, 0x38, - 0x0f, 0xf0, 0xa0, 0xd7, 0xfe, 0x37, 0x15, 0xd8, 0xa3, 0x67, 0x7d, 0x18, 0xc1, 0x07, 0x3e, 0x1d, - 0xfc, 0xbc, 0xa5, 0x4e, 0x8e, 0xca, 0x6c, 0x91, 0x37, 0x8f, 0x6b, 0xec, 0xf9, 0x3e, 0x24, 0xe6, - 0xc1, 0x06, 0xca, 0x1b, 0x9d, 0x3e, 0xa3, 0x42, 0x5f, 0xb3, 0xd2, 0x67, 0x5f, 0x3c, 0x7a, 0xcc, - 0x3d, 0xb6, 0x3e, 0x19, 0x07, 0x6a, 0xbc, 0x63, 0xfa, 0x18, 0xa6, 0xd7, 0x51, 0xdb, 0x38, 0xc0, - 0x9a, 0xeb, 0x3b, 0x9e, 0xfb, 0x06, 0xdd, 0x65, 0x54, 0x99, 0xa2, 0x64, 0x96, 0xc7, 0x15, 0xd5, - 0x8a, 0x0d, 0x8c, 0x0b, 0x7f, 0x11, 0x86, 0x8c, 0x37, 0xcf, 0x89, 0x91, 0x38, 0x6b, 0xc6, 0x48, - 0xd4, 0x8d, 0xd0, 0x86, 0x0b, 0xef, 0x87, 0x53, 0xd9, 0x0e, 0x1e, 0xe4, 0x79, 0xfb, 0xcf, 0x07, - 0xb3, 0x87, 0x51, 0x2b, 0x24, 0x6a, 0xd3, 0xae, 0xbd, 0xed, 0x20, 0x7a, 0xdb, 0x41, 0xf4, 0xb6, - 0x83, 0xc8, 0xf4, 0xf1, 0x0b, 0xe7, 0xc7, 0xe0, 0x7d, 0x72, 0x7e, 0xa4, 0xdc, 0x39, 0xb5, 0xc2, - 0xdd, 0x39, 0xf6, 0x6e, 0x15, 0x52, 0x76, 0x14, 0x1f, 0xef, 0x1f, 0x82, 0xc1, 0x88, 0x84, 0xc1, - 0x4d, 0x3c, 0x2f, 0x74, 0x88, 0x8e, 0x83, 0xe7, 0xcd, 0x58, 0xc2, 0xa9, 0xae, 0x09, 0x9d, 0x64, - 0x5d, 0x28, 0x11, 0xa5, 0x6b, 0x96, 0x9c, 0x64, 0x1d, 0x33, 0x08, 0x7a, 0x3f, 0x8c, 0x24, 0x4e, - 0xd4, 0xa2, 0x66, 0xf3, 0x26, 0xfb, 0xac, 0xe2, 0xc8, 0xf2, 0x11, 0x81, 0x3b, 0xb2, 0x92, 0x82, - 0xe2, 0x0c, 0x36, 0x7a, 0x1d, 0x2a, 0xeb, 0xc4, 0x6b, 0x8b, 0x21, 0x5f, 0x2e, 0x4e, 0xc6, 0xb3, - 0x77, 0xbd, 0x4a, 0xbc, 0x36, 0x97, 0x40, 0xf4, 0x17, 0x66, 0xac, 0xe8, 0x7c, 0xab, 0x6f, 0x74, - 0xe2, 0x24, 0x68, 0xbb, 0x6f, 0x48, 0x4f, 0xdd, 0x07, 0x0b, 0x66, 0x7c, 0x5d, 0xd2, 0xe7, 0x2e, - 0x11, 0xf5, 0x17, 0x6b, 0xce, 0xac, 0x1f, 0x4d, 0x37, 0x62, 0x9f, 0x6a, 0x5b, 0x38, 0xdc, 0x8a, - 0xee, 0xc7, 0x8c, 0xa4, 0xcf, 0xfb, 0xa1, 0xfe, 0x62, 0xcd, 0x19, 0x6d, 0xab, 0x79, 0x3f, 0xc4, - 0xfa, 0x70, 0xb3, 0xe0, 0x3e, 0xf0, 0x39, 0x9f, 0x3b, 0xff, 0x9f, 0x84, 0x6a, 0x63, 0xdd, 0x89, - 0x92, 0xd1, 0x61, 0x36, 0x69, 0x94, 0x6b, 0x66, 0x9a, 0x36, 0x62, 0x0e, 0x43, 0x8f, 0x43, 0x39, - 0x22, 0x6b, 0x2c, 0xfc, 0xd2, 0x08, 0xcc, 0xc1, 0x64, 0x0d, 0xd3, 0x76, 0xfb, 0x17, 0x4b, 0x69, - 0x73, 0x29, 0xfd, 0xde, 0x7c, 0xb6, 0x37, 0x3a, 0x51, 0x2c, 0xdd, 0x37, 0xc6, 0x6c, 0x67, 0xcd, - 0x58, 0xc2, 0xd1, 0xa7, 0x2c, 0x18, 0xbc, 0x13, 0x07, 0xbe, 0x4f, 0x12, 0xa1, 0x9a, 0x6e, 0x15, - 0x3c, 0x14, 0xd7, 0x38, 0x75, 0xdd, 0x07, 0xd1, 0x80, 0x25, 0x5f, 0xda, 0x5d, 0xb2, 0xd5, 0xf0, - 0x3a, 0xcd, 0xae, 0x58, 0x8b, 0xcb, 0xbc, 0x19, 0x4b, 0x38, 0x45, 0x75, 0x7d, 0x8e, 0x5a, 0x49, - 0xa3, 0xce, 0xf9, 0x02, 0x55, 0xc0, 0xed, 0xbf, 0x36, 0x00, 0xe7, 0x72, 0x17, 0x07, 0x35, 0x64, - 0x98, 0xa9, 0x70, 0xc5, 0xf5, 0x88, 0x8c, 0x32, 0x62, 0x86, 0xcc, 0x2d, 0xd5, 0x8a, 0x0d, 0x0c, - 0xf4, 0x93, 0x00, 0xa1, 0x13, 0x39, 0x6d, 0xa2, 0xdc, 0xab, 0x47, 0xb6, 0x17, 0x68, 0x3f, 0x96, - 0x24, 0x4d, 0xbd, 0x37, 0x55, 0x4d, 0x31, 0x36, 0x58, 0xa2, 0x17, 0x60, 0x28, 0x22, 0x1e, 0x71, - 0x62, 0x16, 0xbd, 0x9b, 0x4d, 0x45, 0xc0, 0x1a, 0x84, 0x4d, 0x3c, 0xf4, 0x94, 0x0a, 0xc8, 0xca, - 0x04, 0xa6, 0xa4, 0x83, 0xb2, 0xd0, 0x9b, 0x16, 0x8c, 0xac, 0xb9, 0x1e, 0xd1, 0xdc, 0x45, 0xe2, - 0xc0, 0xe2, 0xd1, 0x5f, 0xf2, 0x8a, 0x49, 0x57, 0x4b, 0xc8, 0x54, 0x73, 0x8c, 0x33, 0xec, 0xe9, - 0x67, 0xde, 0x24, 0x11, 0x13, 0xad, 0x03, 0xe9, 0xcf, 0x7c, 0x8b, 0x37, 0x63, 0x09, 0x47, 0x93, - 0x70, 0x32, 0x74, 0xe2, 0x78, 0x3a, 0x22, 0x4d, 0xe2, 0x27, 0xae, 0xe3, 0xf1, 0xb0, 0xfe, 0x9a, - 0x0e, 0xeb, 0x5d, 0x4a, 0x83, 0x71, 0x16, 0x1f, 0x7d, 0x08, 0x1e, 0xe5, 0xfe, 0x8b, 0x05, 0x37, - 0x8e, 0x5d, 0xbf, 0xa5, 0xa7, 0x81, 0x70, 0xe3, 0x8c, 0x09, 0x52, 0x8f, 0xce, 0xe5, 0xa3, 0xe1, - 0x5e, 0xcf, 0xa3, 0x67, 0xa0, 0x16, 0x6f, 0xb8, 0xe1, 0x74, 0xd4, 0x8c, 0xd9, 0xd9, 0x45, 0x4d, - 0x3b, 0x0d, 0x97, 0x45, 0x3b, 0x56, 0x18, 0xa8, 0x01, 0xc3, 0xfc, 0x93, 0xf0, 0x88, 0x32, 0x21, - 0x1f, 0x9f, 0xed, 0xa9, 0x1e, 0x45, 0xe6, 0xd9, 0x38, 0x76, 0xee, 0x5e, 0x96, 0x27, 0x29, 0xdc, - 0xf1, 0x7f, 0xcb, 0x20, 0x83, 0x53, 0x44, 0xed, 0x9f, 0x2f, 0xa5, 0x77, 0xdc, 0xe6, 0x22, 0x45, - 0x31, 0x5d, 0x8a, 0xc9, 0x2d, 0x27, 0x92, 0xde, 0x98, 0x23, 0x66, 0x1f, 0x08, 0xba, 0xb7, 0x9c, - 0xc8, 0x5c, 0xd4, 0x8c, 0x01, 0x96, 0x9c, 0xd0, 0x1d, 0xa8, 0x24, 0x9e, 0x53, 0x50, 0xba, 0x92, - 0xc1, 0x51, 0x3b, 0x40, 0xe6, 0x27, 0x63, 0xcc, 0x78, 0xa0, 0xc7, 0xa8, 0xd5, 0xbf, 0x2a, 0x4f, - 0x3a, 0x84, 0xa1, 0xbe, 0x1a, 0x63, 0xd6, 0x6a, 0xff, 0x79, 0x3d, 0x47, 0xae, 0x2a, 0x45, 0x86, - 0x2e, 0x01, 0xd0, 0x0d, 0xe4, 0x52, 0x44, 0xd6, 0xdc, 0x2d, 0x61, 0x48, 0xa8, 0xb5, 0x7b, 0x43, - 0x41, 0xb0, 0x81, 0x25, 0x9f, 0x59, 0xee, 0xac, 0xd1, 0x67, 0x4a, 0xdd, 0xcf, 0x70, 0x08, 0x36, - 0xb0, 0xd0, 0xf3, 0x30, 0xe0, 0xb6, 0x9d, 0x96, 0x8a, 0xa4, 0x7c, 0x8c, 0x2e, 0xda, 0x39, 0xd6, - 0x72, 0x6f, 0x67, 0x6c, 0x44, 0x75, 0x88, 0x35, 0x61, 0x81, 0x8b, 0x7e, 0xd9, 0x82, 0xe1, 0x46, - 0xd0, 0x6e, 0x07, 0x3e, 0xdf, 0x76, 0x89, 0x3d, 0xe4, 0x9d, 0xe3, 0x52, 0xf3, 0xe3, 0xd3, 0x06, - 0x33, 0xbe, 0x89, 0x54, 0x79, 0x55, 0x26, 0x08, 0xa7, 0x7a, 0x65, 0xae, 0xed, 0xea, 0x3e, 0x6b, - 0xfb, 0xd7, 0x2c, 0x38, 0xcd, 0x9f, 0x35, 0x76, 0x83, 0x22, 0x85, 0x28, 0x38, 0xe6, 0xd7, 0xea, - 0xda, 0x20, 0x2b, 0x2f, 0x5d, 0x17, 0x1c, 0x77, 0x77, 0x12, 0xcd, 0xc2, 0xe9, 0xb5, 0x20, 0x6a, - 0x10, 0x73, 0x20, 0x84, 0x60, 0x52, 0x84, 0xae, 0x64, 0x11, 0x70, 0xf7, 0x33, 0xe8, 0x16, 0x3c, - 0x62, 0x34, 0x9a, 0xe3, 0xc0, 0x65, 0xd3, 0x13, 0x82, 0xda, 0x23, 0x57, 0x72, 0xb1, 0x70, 0x8f, - 0xa7, 0xd3, 0x0e, 0x93, 0x7a, 0x1f, 0x0e, 0x93, 0xd7, 0xe0, 0x7c, 0xa3, 0x7b, 0x64, 0x36, 0xe3, - 0xce, 0x6a, 0xcc, 0x25, 0x55, 0x6d, 0xea, 0x07, 0x04, 0x81, 0xf3, 0xd3, 0xbd, 0x10, 0x71, 0x6f, - 0x1a, 0xe8, 0x63, 0x50, 0x8b, 0x08, 0xfb, 0x2a, 0xb1, 0xc8, 0xa7, 0x39, 0xe2, 0x2e, 0x59, 0x5b, - 0xa0, 0x9c, 0xac, 0x96, 0xbd, 0xa2, 0x21, 0xc6, 0x8a, 0x23, 0xba, 0x0b, 0x83, 0xa1, 0x93, 0x34, - 0xd6, 0x45, 0x16, 0xcd, 0x91, 0xc3, 0x58, 0x14, 0xf3, 0x25, 0x4a, 0x55, 0x4f, 0xf2, 0x25, 0xce, - 0x04, 0x4b, 0x6e, 0x17, 0x3e, 0x00, 0xa7, 0xbb, 0x16, 0xd2, 0x81, 0x9c, 0x25, 0x33, 0xf0, 0x48, - 0xfe, 0x94, 0x3d, 0x90, 0xcb, 0xe4, 0x1f, 0x67, 0x62, 0x4f, 0x0d, 0x33, 0xb6, 0x0f, 0xf7, 0x9b, - 0x03, 0x65, 0xe2, 0x6f, 0x0a, 0x09, 0x7e, 0xe5, 0x68, 0x23, 0x77, 0xd9, 0xdf, 0xe4, 0x2b, 0x8e, - 0xf9, 0x18, 0x2e, 0xfb, 0x9b, 0x98, 0xd2, 0x46, 0x5f, 0xb6, 0x52, 0x66, 0x18, 0x77, 0xda, 0x7d, - 0xe4, 0x58, 0xec, 0xf6, 0xbe, 0x2d, 0x33, 0xfb, 0xdf, 0x96, 0xe0, 0xe2, 0x7e, 0x44, 0xfa, 0x18, - 0xbe, 0x27, 0x61, 0x20, 0x66, 0xa7, 0xc9, 0x42, 0x24, 0x0e, 0xd1, 0x99, 0xc2, 0xcf, 0x97, 0x5f, - 0xc3, 0x02, 0x84, 0x3c, 0x28, 0xb7, 0x9d, 0x50, 0xf8, 0x72, 0xe6, 0x8e, 0x9a, 0x8d, 0x42, 0xff, - 0x3b, 0xde, 0x82, 0x13, 0x72, 0x0f, 0x81, 0xd1, 0x80, 0x29, 0x1b, 0x94, 0x40, 0xd5, 0x89, 0x22, - 0x47, 0x1e, 0x5d, 0x5e, 0x2f, 0x86, 0xdf, 0x24, 0x25, 0x39, 0x75, 0x7a, 0x77, 0x67, 0xec, 0x44, - 0xaa, 0x09, 0x73, 0x66, 0xf6, 0xe7, 0x07, 0x53, 0x19, 0x19, 0xec, 0x3c, 0x3a, 0x86, 0x01, 0xe1, - 0xc2, 0xb1, 0x8a, 0x4e, 0x02, 0xe2, 0x29, 0x75, 0x6c, 0x97, 0x26, 0x12, 0x93, 0x05, 0x2b, 0xf4, - 0x39, 0x8b, 0xa5, 0xff, 0xca, 0x2c, 0x15, 0xb1, 0x37, 0x3a, 0x9e, 0x6c, 0x64, 0x33, 0xa9, 0x58, - 0x36, 0x62, 0x93, 0x3b, 0xd5, 0x99, 0x21, 0x4f, 0x64, 0xcb, 0xee, 0x90, 0x64, 0x82, 0xb0, 0x84, - 0xa3, 0xad, 0x9c, 0x73, 0xe7, 0x02, 0x52, 0x48, 0xfb, 0x38, 0x69, 0xfe, 0x9a, 0x05, 0xa7, 0xdd, - 0xec, 0x01, 0xa2, 0xd8, 0x49, 0x1c, 0x31, 0xb2, 0xa1, 0xf7, 0xf9, 0xa4, 0x52, 0xa6, 0x5d, 0x20, - 0xdc, 0xdd, 0x19, 0xd4, 0x84, 0x8a, 0xeb, 0xaf, 0x05, 0xc2, 0x84, 0x98, 0x3a, 0x5a, 0xa7, 0xe6, - 0xfc, 0xb5, 0x40, 0xaf, 0x66, 0xfa, 0x0f, 0x33, 0xea, 0x68, 0x1e, 0xce, 0x46, 0xc2, 0xd7, 0x73, - 0xd5, 0x8d, 0xe9, 0x8e, 0x7c, 0xde, 0x6d, 0xbb, 0x09, 0x53, 0xff, 0xe5, 0xa9, 0xd1, 0xdd, 0x9d, - 0xb1, 0xb3, 0x38, 0x07, 0x8e, 0x73, 0x9f, 0x42, 0x6f, 0xc0, 0xa0, 0xcc, 0x57, 0xae, 0x15, 0xb1, - 0x2b, 0xeb, 0x9e, 0xff, 0x6a, 0x32, 0x2d, 0x8b, 0xd4, 0x64, 0xc9, 0xd0, 0x7e, 0x73, 0x08, 0xba, - 0x0f, 0x25, 0xd1, 0xc7, 0xa1, 0x1e, 0xa9, 0x1c, 0x6a, 0xab, 0x08, 0x65, 0x29, 0xbf, 0xaf, 0x38, - 0x10, 0x55, 0x86, 0x88, 0xce, 0x96, 0xd6, 0x1c, 0xe9, 0x76, 0x21, 0xd6, 0x67, 0x97, 0x05, 0xcc, - 0x6d, 0xc1, 0x55, 0x9f, 0x4b, 0x6d, 0xfb, 0x0d, 0xcc, 0x78, 0xa0, 0x08, 0x06, 0xd6, 0x89, 0xe3, - 0x25, 0xeb, 0xc5, 0xb8, 0xd0, 0xaf, 0x32, 0x5a, 0xd9, 0x4c, 0x1a, 0xde, 0x8a, 0x05, 0x27, 0xb4, - 0x05, 0x83, 0xeb, 0x7c, 0x02, 0x08, 0x0b, 0x7e, 0xe1, 0xa8, 0x83, 0x9b, 0x9a, 0x55, 0xfa, 0x73, - 0x8b, 0x06, 0x2c, 0xd9, 0xb1, 0xa0, 0x15, 0xe3, 0x3c, 0x9e, 0x2f, 0xdd, 0xe2, 0x92, 0x88, 0xfa, - 0x3f, 0x8c, 0xff, 0x28, 0x0c, 0x47, 0xa4, 0x11, 0xf8, 0x0d, 0xd7, 0x23, 0xcd, 0x49, 0xe9, 0x1e, - 0x3f, 0x48, 0xea, 0x09, 0xdb, 0x05, 0x63, 0x83, 0x06, 0x4e, 0x51, 0x44, 0x9f, 0xb5, 0x60, 0x44, - 0x25, 0x5e, 0xd2, 0x0f, 0x42, 0x84, 0x3b, 0x76, 0xbe, 0xa0, 0x34, 0x4f, 0x46, 0x73, 0x0a, 0xed, - 0xee, 0x8c, 0x8d, 0xa4, 0xdb, 0x70, 0x86, 0x2f, 0x7a, 0x05, 0x20, 0x58, 0xe5, 0x91, 0x29, 0x93, - 0x89, 0xf0, 0xcd, 0x1e, 0xe4, 0x55, 0x47, 0x78, 0x0e, 0x9a, 0xa4, 0x80, 0x0d, 0x6a, 0xe8, 0x3a, - 0x00, 0x5f, 0x36, 0x2b, 0xdb, 0xa1, 0x34, 0xf3, 0x65, 0xee, 0x10, 0x2c, 0x2b, 0xc8, 0xbd, 0x9d, - 0xb1, 0x6e, 0x5f, 0x19, 0x0b, 0x1b, 0x30, 0x1e, 0x47, 0x3f, 0x01, 0x83, 0x71, 0xa7, 0xdd, 0x76, - 0x94, 0xe7, 0xb6, 0xc0, 0xac, 0x36, 0x4e, 0xd7, 0x10, 0x45, 0xbc, 0x01, 0x4b, 0x8e, 0xe8, 0x0e, - 0x15, 0xaa, 0xb1, 0x70, 0xe2, 0xb1, 0x55, 0xc4, 0x6d, 0x82, 0x21, 0xf6, 0x4e, 0xef, 0x95, 0x81, - 0x36, 0x38, 0x07, 0xe7, 0xde, 0xce, 0xd8, 0x23, 0xe9, 0xf6, 0xf9, 0x40, 0xe4, 0x99, 0xe5, 0xd2, - 0x44, 0xd7, 0x64, 0xf9, 0x12, 0xfa, 0xda, 0x32, 0xab, 0xfe, 0x69, 0x5d, 0xbe, 0x84, 0x35, 0xf7, - 0x1e, 0x33, 0xf3, 0x61, 0xb4, 0x00, 0x67, 0x1a, 0x81, 0x9f, 0x44, 0x81, 0xe7, 0xf1, 0x9a, 0x3c, - 0x7c, 0xc7, 0xc5, 0x3d, 0xbb, 0xef, 0x14, 0xdd, 0x3e, 0x33, 0xdd, 0x8d, 0x82, 0xf3, 0x9e, 0xb3, - 0xfd, 0x74, 0xc8, 0x9e, 0x18, 0x9c, 0xe7, 0x61, 0x98, 0x6c, 0x25, 0x24, 0xf2, 0x1d, 0xef, 0x26, - 0x9e, 0x97, 0x3e, 0x4d, 0xb6, 0x06, 0x2e, 0x1b, 0xed, 0x38, 0x85, 0x85, 0x6c, 0xe5, 0x66, 0x30, - 0x72, 0x27, 0xb9, 0x9b, 0x41, 0x3a, 0x15, 0xec, 0xff, 0x55, 0x4a, 0x19, 0x64, 0x2b, 0x11, 0x21, - 0x28, 0x80, 0xaa, 0x1f, 0x34, 0x95, 0xec, 0xbf, 0x56, 0x8c, 0xec, 0xbf, 0x11, 0x34, 0x8d, 0x1a, - 0x27, 0xf4, 0x5f, 0x8c, 0x39, 0x1f, 0x56, 0x04, 0x42, 0x56, 0xcb, 0x60, 0x00, 0xb1, 0xd1, 0x28, - 0x92, 0xb3, 0x2a, 0x02, 0xb1, 0x68, 0x32, 0xc2, 0x69, 0xbe, 0x68, 0x03, 0xaa, 0xeb, 0x41, 0x9c, - 0xc8, 0xed, 0xc7, 0x11, 0x77, 0x3a, 0x57, 0x83, 0x38, 0x61, 0x56, 0x84, 0x7a, 0x6d, 0xda, 0x12, - 0x63, 0xce, 0xc3, 0xfe, 0x2f, 0x56, 0xca, 0x83, 0x7d, 0x9b, 0x85, 0xaf, 0x6e, 0x12, 0x9f, 0x2e, - 0x6b, 0x33, 0xd0, 0xe7, 0x2f, 0x64, 0x92, 0x01, 0xdf, 0xd5, 0xab, 0xe2, 0xd4, 0x5d, 0x4a, 0x61, - 0x9c, 0x91, 0x30, 0x62, 0x82, 0x3e, 0x69, 0xa5, 0xd3, 0x32, 0x4b, 0x45, 0x6c, 0x30, 0xcc, 0xd4, - 0xe4, 0x7d, 0x33, 0x3c, 0xed, 0x2f, 0x5b, 0x30, 0x38, 0xe5, 0x34, 0x36, 0x82, 0xb5, 0x35, 0xf4, - 0x0c, 0xd4, 0x9a, 0x9d, 0xc8, 0xcc, 0x10, 0x55, 0xdb, 0xf6, 0x19, 0xd1, 0x8e, 0x15, 0x06, 0x9d, - 0xc3, 0x6b, 0x4e, 0x43, 0x26, 0x28, 0x97, 0xf9, 0x1c, 0xbe, 0xc2, 0x5a, 0xb0, 0x80, 0xa0, 0x17, - 0x60, 0xa8, 0xed, 0x6c, 0xc9, 0x87, 0xb3, 0xee, 0xf3, 0x05, 0x0d, 0xc2, 0x26, 0x9e, 0xfd, 0x2f, - 0x2d, 0x18, 0x9d, 0x72, 0x62, 0xb7, 0x31, 0xd9, 0x49, 0xd6, 0xa7, 0xdc, 0x64, 0xb5, 0xd3, 0xd8, - 0x20, 0x09, 0xcf, 0x4a, 0xa7, 0xbd, 0xec, 0xc4, 0x74, 0x29, 0xa9, 0x7d, 0x9d, 0xea, 0xe5, 0x4d, - 0xd1, 0x8e, 0x15, 0x06, 0x7a, 0x03, 0x86, 0x42, 0x27, 0x8e, 0xef, 0x06, 0x51, 0x13, 0x93, 0xb5, - 0x62, 0x6a, 0x42, 0x2c, 0x93, 0x46, 0x44, 0x12, 0x4c, 0xd6, 0xc4, 0x11, 0xaf, 0xa6, 0x8f, 0x4d, - 0x66, 0xf6, 0x17, 0x2d, 0x38, 0x3f, 0x45, 0x9c, 0x88, 0x44, 0xac, 0x84, 0x84, 0x7a, 0x91, 0x69, - 0x2f, 0xe8, 0x34, 0xd1, 0xeb, 0x50, 0x4b, 0x68, 0x33, 0xed, 0x96, 0x55, 0x6c, 0xb7, 0xd8, 0x09, - 0xed, 0x8a, 0x20, 0x8e, 0x15, 0x1b, 0xfb, 0xaf, 0x5b, 0x30, 0xcc, 0x0e, 0xbb, 0x66, 0x48, 0xe2, - 0xb8, 0x5e, 0x57, 0xa5, 0x25, 0xab, 0xcf, 0x4a, 0x4b, 0x17, 0xa1, 0xb2, 0x1e, 0xb4, 0x49, 0xf6, - 0xa0, 0xf6, 0x6a, 0x40, 0xb7, 0xd5, 0x14, 0x82, 0x9e, 0xa3, 0x1f, 0xde, 0xf5, 0x13, 0x87, 0x2e, - 0x01, 0xe9, 0x4c, 0x3d, 0xc9, 0x3f, 0xba, 0x6a, 0xc6, 0x26, 0x8e, 0xfd, 0x9b, 0x75, 0x18, 0x14, - 0xa7, 0xf9, 0x7d, 0x57, 0x26, 0x90, 0xfb, 0xfb, 0x52, 0xcf, 0xfd, 0x7d, 0x0c, 0x03, 0x0d, 0x56, - 0xc7, 0x4d, 0x98, 0x91, 0xd7, 0x0b, 0x09, 0xff, 0xe0, 0xa5, 0xe1, 0x74, 0xb7, 0xf8, 0x7f, 0x2c, - 0x58, 0xa1, 0x2f, 0x59, 0x70, 0xb2, 0x11, 0xf8, 0x3e, 0x69, 0x68, 0x1b, 0xa7, 0x52, 0xc4, 0x29, - 0xff, 0x74, 0x9a, 0xa8, 0x3e, 0x69, 0xc9, 0x00, 0x70, 0x96, 0x3d, 0x7a, 0x09, 0x4e, 0xf0, 0x31, - 0xbb, 0x95, 0xf2, 0x00, 0xeb, 0x02, 0x3c, 0x26, 0x10, 0xa7, 0x71, 0xd1, 0x38, 0xf7, 0xa4, 0x8b, - 0x52, 0x37, 0x03, 0xfa, 0xd8, 0xce, 0x28, 0x72, 0x63, 0x60, 0xa0, 0x08, 0x50, 0x44, 0xd6, 0x22, - 0x12, 0xaf, 0x8b, 0x68, 0x07, 0x66, 0x5f, 0x0d, 0x1e, 0x2e, 0x8b, 0x19, 0x77, 0x51, 0xc2, 0x39, - 0xd4, 0xd1, 0x86, 0xd8, 0x60, 0xd6, 0x8a, 0x90, 0xa1, 0xe2, 0x33, 0xf7, 0xdc, 0x67, 0x8e, 0x41, - 0x35, 0x5e, 0x77, 0xa2, 0x26, 0xb3, 0xeb, 0xca, 0x3c, 0x73, 0x66, 0x99, 0x36, 0x60, 0xde, 0x8e, - 0x66, 0xe0, 0x54, 0xa6, 0x7c, 0x50, 0x2c, 0x3c, 0xb5, 0x2a, 0x4b, 0x22, 0x53, 0x78, 0x28, 0xc6, - 0x5d, 0x4f, 0x98, 0xce, 0x87, 0xa1, 0x7d, 0x9c, 0x0f, 0xdb, 0x2a, 0xa6, 0x8e, 0xfb, 0x50, 0x5f, - 0x2e, 0x64, 0x00, 0xfa, 0x0a, 0xa0, 0xfb, 0x42, 0x26, 0x80, 0xee, 0x04, 0xeb, 0xc0, 0xad, 0x62, - 0x3a, 0x70, 0xf0, 0x68, 0xb9, 0x07, 0x19, 0xfd, 0xf6, 0x67, 0x16, 0xc8, 0xef, 0x3a, 0xed, 0x34, - 0xd6, 0x09, 0x9d, 0x32, 0xe8, 0xfd, 0x30, 0xa2, 0xb6, 0xd0, 0xd3, 0x41, 0xc7, 0xe7, 0x81, 0x6f, - 0x65, 0x7d, 0x24, 0x8b, 0x53, 0x50, 0x9c, 0xc1, 0x46, 0x13, 0x50, 0xa7, 0xe3, 0xc4, 0x1f, 0xe5, - 0xba, 0x56, 0x6d, 0xd3, 0x27, 0x97, 0xe6, 0xc4, 0x53, 0x1a, 0x07, 0x05, 0x70, 0xda, 0x73, 0xe2, - 0x84, 0xf5, 0x80, 0xee, 0xa8, 0x0f, 0x59, 0x43, 0x80, 0x85, 0xe2, 0xcf, 0x67, 0x09, 0xe1, 0x6e, - 0xda, 0xf6, 0xb7, 0x2b, 0x70, 0x22, 0x25, 0x19, 0x0f, 0xa8, 0xa4, 0x9f, 0x81, 0x9a, 0xd4, 0x9b, - 0xd9, 0x6a, 0x27, 0x4a, 0xb9, 0x2a, 0x0c, 0xaa, 0xb4, 0x56, 0xb5, 0x56, 0xcd, 0x1a, 0x15, 0x86, - 0xc2, 0xc5, 0x26, 0x1e, 0x13, 0xca, 0x89, 0x17, 0x4f, 0x7b, 0x2e, 0xf1, 0x13, 0xde, 0xcd, 0x62, - 0x84, 0xf2, 0xca, 0xfc, 0xb2, 0x49, 0x54, 0x0b, 0xe5, 0x0c, 0x00, 0x67, 0xd9, 0xa3, 0xcf, 0x58, - 0x70, 0xc2, 0xb9, 0x1b, 0xeb, 0x62, 0xa3, 0x22, 0x54, 0xee, 0x88, 0x4a, 0x2a, 0x55, 0xbf, 0x94, - 0xbb, 0x7c, 0x53, 0x4d, 0x38, 0xcd, 0x14, 0xbd, 0x65, 0x01, 0x22, 0x5b, 0xa4, 0x21, 0x83, 0xf9, - 0x44, 0x5f, 0x06, 0x8a, 0xd8, 0x69, 0x5e, 0xee, 0xa2, 0xcb, 0xa5, 0x7a, 0x77, 0x3b, 0xce, 0xe9, - 0x83, 0xfd, 0xcf, 0xca, 0x6a, 0x41, 0xe9, 0xf8, 0x51, 0xc7, 0x88, 0x63, 0xb3, 0x0e, 0x1f, 0xc7, - 0xa6, 0xe3, 0x01, 0xba, 0x53, 0x13, 0x53, 0x99, 0x4c, 0xa5, 0x07, 0x94, 0xc9, 0xf4, 0x53, 0x56, - 0xaa, 0xae, 0xcf, 0xd0, 0xa5, 0x57, 0x8a, 0x8d, 0x5d, 0x1d, 0xe7, 0xb1, 0x0a, 0x19, 0xe9, 0x9e, - 0x0e, 0x51, 0xa1, 0xd2, 0xd4, 0x40, 0x3b, 0x90, 0x34, 0xfc, 0x0f, 0x65, 0x18, 0x32, 0x34, 0x69, - 0xae, 0x59, 0x64, 0x3d, 0x64, 0x66, 0x51, 0xe9, 0x00, 0x66, 0xd1, 0x4f, 0x42, 0xbd, 0x21, 0xa5, - 0x7c, 0x31, 0x95, 0x6d, 0xb3, 0xba, 0x43, 0x0b, 0x7a, 0xd5, 0x84, 0x35, 0x4f, 0x34, 0x9b, 0x4a, - 0x9c, 0x11, 0x1a, 0xa2, 0xc2, 0x34, 0x44, 0x5e, 0x66, 0x8b, 0xd0, 0x14, 0xdd, 0xcf, 0xb0, 0xf2, - 0x4f, 0xa1, 0x2b, 0xde, 0x4b, 0x46, 0x98, 0xf3, 0xf2, 0x4f, 0x4b, 0x73, 0xb2, 0x19, 0x9b, 0x38, - 0xf6, 0xb7, 0x2d, 0xf5, 0x71, 0xef, 0x43, 0xa1, 0x83, 0x3b, 0xe9, 0x42, 0x07, 0x97, 0x0b, 0x19, - 0xe6, 0x1e, 0x15, 0x0e, 0x6e, 0xc0, 0xe0, 0x74, 0xd0, 0x6e, 0x3b, 0x7e, 0x13, 0xfd, 0x20, 0x0c, - 0x36, 0xf8, 0x4f, 0xe1, 0xd8, 0x61, 0xc7, 0x83, 0x02, 0x8a, 0x25, 0x0c, 0x3d, 0x06, 0x15, 0x27, - 0x6a, 0x49, 0x67, 0x0e, 0x0b, 0x6d, 0x99, 0x8c, 0x5a, 0x31, 0x66, 0xad, 0xf6, 0x3f, 0xaa, 0x00, - 0x4c, 0x07, 0xed, 0xd0, 0x89, 0x48, 0x73, 0x25, 0x60, 0x95, 0xf5, 0x8e, 0xf5, 0x50, 0x4d, 0x6f, - 0x96, 0x1e, 0xe6, 0x83, 0x35, 0xe3, 0x70, 0xa5, 0x7c, 0x9f, 0x0f, 0x57, 0x7a, 0x9c, 0x97, 0x55, - 0x1e, 0xa2, 0xf3, 0x32, 0xfb, 0xf3, 0x16, 0x20, 0x3a, 0x69, 0x02, 0x9f, 0xf8, 0x89, 0x3e, 0xd0, - 0x9e, 0x80, 0x7a, 0x43, 0xb6, 0x0a, 0xc3, 0x4a, 0x8b, 0x08, 0x09, 0xc0, 0x1a, 0xa7, 0x8f, 0x1d, - 0xf2, 0x93, 0x52, 0x7e, 0x97, 0xd3, 0x51, 0xb1, 0x4c, 0xea, 0x0b, 0x71, 0x6e, 0xff, 0x56, 0x09, - 0x1e, 0xe1, 0x2a, 0x79, 0xc1, 0xf1, 0x9d, 0x16, 0x69, 0xd3, 0x5e, 0xf5, 0x1b, 0xa2, 0xd0, 0xa0, - 0x5b, 0x33, 0x57, 0x46, 0xb9, 0x1e, 0x75, 0xed, 0xf2, 0x35, 0xc7, 0x57, 0xd9, 0x9c, 0xef, 0x26, - 0x98, 0x11, 0x47, 0x31, 0xd4, 0x64, 0x29, 0x77, 0x21, 0x8b, 0x0b, 0x62, 0xa4, 0xc4, 0x92, 0xd0, - 0x9b, 0x04, 0x2b, 0x46, 0xd4, 0x70, 0xf5, 0x82, 0xc6, 0x06, 0x26, 0x61, 0xc0, 0xe4, 0xae, 0x11, - 0x64, 0x38, 0x2f, 0xda, 0xb1, 0xc2, 0xb0, 0x7f, 0xcb, 0x82, 0xac, 0x46, 0x32, 0x4a, 0x98, 0x59, - 0x7b, 0x96, 0x30, 0x3b, 0x40, 0x0d, 0xb1, 0x1f, 0x87, 0x21, 0x27, 0xa1, 0x46, 0x04, 0xdf, 0x76, - 0x97, 0x0f, 0x77, 0xac, 0xb1, 0x10, 0x34, 0xdd, 0x35, 0x97, 0x6d, 0xb7, 0x4d, 0x72, 0xf6, 0xff, - 0xa8, 0xc0, 0xe9, 0xae, 0x5c, 0x0c, 0xf4, 0x22, 0x0c, 0x37, 0xc4, 0xf4, 0x08, 0xa5, 0x43, 0xab, - 0x6e, 0x06, 0xa5, 0x69, 0x18, 0x4e, 0x61, 0xf6, 0x31, 0x41, 0xe7, 0xe0, 0x4c, 0x44, 0x37, 0xfa, - 0x1d, 0x32, 0xb9, 0x96, 0x90, 0x68, 0x99, 0x34, 0x02, 0xbf, 0xc9, 0x0b, 0xed, 0x95, 0xa7, 0x1e, - 0xdd, 0xdd, 0x19, 0x3b, 0x83, 0xbb, 0xc1, 0x38, 0xef, 0x19, 0x14, 0xc2, 0x09, 0xcf, 0xb4, 0x01, - 0xc5, 0x06, 0xe0, 0x50, 0xe6, 0xa3, 0xb2, 0x11, 0x52, 0xcd, 0x38, 0xcd, 0x20, 0x6d, 0x48, 0x56, - 0x1f, 0x90, 0x21, 0xf9, 0x69, 0x6d, 0x48, 0xf2, 0xf3, 0xf7, 0x0f, 0x17, 0x9c, 0x8b, 0x73, 0xdc, - 0x96, 0xe4, 0xcb, 0x50, 0x93, 0xb1, 0x49, 0x7d, 0xc5, 0xf4, 0x98, 0x74, 0x7a, 0x48, 0xb4, 0x7b, - 0x25, 0xc8, 0xd9, 0x84, 0xd0, 0x75, 0xa6, 0x35, 0x7e, 0x6a, 0x9d, 0x1d, 0x4c, 0xeb, 0xa3, 0x2d, - 0x1e, 0x97, 0xc5, 0x75, 0xdb, 0x87, 0x8a, 0xde, 0x44, 0xe9, 0x50, 0x2d, 0x95, 0xa2, 0xa0, 0xc2, - 0xb5, 0x2e, 0x01, 0x68, 0x43, 0x4d, 0x04, 0xa0, 0xab, 0x63, 0x5f, 0x6d, 0xcf, 0x61, 0x03, 0x8b, - 0xee, 0xa9, 0x5d, 0x3f, 0x4e, 0x1c, 0xcf, 0xbb, 0xea, 0xfa, 0x89, 0x70, 0x0e, 0x2a, 0x25, 0x3e, - 0xa7, 0x41, 0xd8, 0xc4, 0xbb, 0xf0, 0x5e, 0xe3, 0xbb, 0x1c, 0xe4, 0x7b, 0xae, 0xc3, 0xf9, 0x59, - 0x37, 0x51, 0x69, 0x13, 0x6a, 0x1e, 0x51, 0x3b, 0x4c, 0xa5, 0x01, 0x59, 0x3d, 0xd3, 0x80, 0x8c, - 0xb4, 0x85, 0x52, 0x3a, 0xcb, 0x22, 0x9b, 0xb6, 0x60, 0xbf, 0x08, 0x67, 0x67, 0xdd, 0xe4, 0x8a, - 0xeb, 0x91, 0x03, 0x32, 0xb1, 0x7f, 0x63, 0x00, 0x86, 0xcd, 0xc4, 0xbb, 0x83, 0x64, 0x32, 0x7d, - 0x91, 0x9a, 0x5a, 0xe2, 0xed, 0x5c, 0x75, 0x68, 0x76, 0xfb, 0xc8, 0x59, 0x80, 0xf9, 0x23, 0x66, - 0x58, 0x5b, 0x9a, 0x27, 0x36, 0x3b, 0x80, 0xee, 0x42, 0x75, 0x8d, 0x85, 0xd5, 0x97, 0x8b, 0x88, - 0x2c, 0xc8, 0x1b, 0x51, 0xbd, 0xcc, 0x78, 0x60, 0x3e, 0xe7, 0x47, 0x35, 0x64, 0x94, 0xce, 0xd5, - 0x32, 0x42, 0x41, 0x45, 0x96, 0x96, 0xc2, 0xe8, 0x25, 0xea, 0xab, 0x87, 0x10, 0xf5, 0x29, 0xc1, - 0x3b, 0xf0, 0x80, 0x04, 0x2f, 0x4b, 0x91, 0x48, 0xd6, 0x99, 0xfd, 0x26, 0x62, 0xd7, 0x07, 0xd9, - 0x20, 0x18, 0x29, 0x12, 0x29, 0x30, 0xce, 0xe2, 0xa3, 0x4f, 0x28, 0xd1, 0x5d, 0x2b, 0xc2, 0xaf, - 0x6a, 0xce, 0xe8, 0xe3, 0x96, 0xda, 0x9f, 0x2f, 0xc1, 0xc8, 0xac, 0xdf, 0x59, 0x9a, 0x5d, 0xea, - 0xac, 0x7a, 0x6e, 0xe3, 0x3a, 0xd9, 0xa6, 0xa2, 0x79, 0x83, 0x6c, 0xcf, 0xcd, 0x88, 0x15, 0xa4, - 0xe6, 0xcc, 0x75, 0xda, 0x88, 0x39, 0x8c, 0x0a, 0xa3, 0x35, 0xd7, 0x6f, 0x91, 0x28, 0x8c, 0x5c, - 0xe1, 0xf2, 0x34, 0x84, 0xd1, 0x15, 0x0d, 0xc2, 0x26, 0x1e, 0xa5, 0x1d, 0xdc, 0xf5, 0x49, 0x94, - 0x35, 0x64, 0x17, 0x69, 0x23, 0xe6, 0x30, 0x8a, 0x94, 0x44, 0x9d, 0x38, 0x11, 0x93, 0x51, 0x21, - 0xad, 0xd0, 0x46, 0xcc, 0x61, 0x74, 0xa5, 0xc7, 0x9d, 0x55, 0x16, 0xb8, 0x91, 0x09, 0x94, 0x5f, - 0xe6, 0xcd, 0x58, 0xc2, 0x29, 0xea, 0x06, 0xd9, 0x9e, 0xa1, 0xbb, 0xde, 0x4c, 0xbe, 0xcc, 0x75, - 0xde, 0x8c, 0x25, 0x9c, 0x55, 0x08, 0x4c, 0x0f, 0xc7, 0xf7, 0x5c, 0x85, 0xc0, 0x74, 0xf7, 0x7b, - 0xec, 0x9f, 0x7f, 0xc9, 0x82, 0x61, 0x33, 0xdc, 0x0a, 0xb5, 0x32, 0x36, 0xee, 0x62, 0x57, 0x81, - 0xd9, 0x1f, 0xcd, 0xbb, 0x71, 0xab, 0xe5, 0x26, 0x41, 0x18, 0x3f, 0x4b, 0xfc, 0x96, 0xeb, 0x13, - 0x76, 0x8a, 0xce, 0xc3, 0xb4, 0x52, 0xb1, 0x5c, 0xd3, 0x41, 0x93, 0x1c, 0xc2, 0x48, 0xb6, 0x6f, - 0xc3, 0xe9, 0xae, 0x24, 0xa9, 0x3e, 0x4c, 0x8b, 0x7d, 0x53, 0x54, 0x6d, 0x0c, 0x43, 0x94, 0xb0, - 0xac, 0x52, 0x33, 0x0d, 0xa7, 0xf9, 0x42, 0xa2, 0x9c, 0x96, 0x1b, 0xeb, 0xa4, 0xad, 0x12, 0xdf, - 0x98, 0x7f, 0xfd, 0x56, 0x16, 0x88, 0xbb, 0xf1, 0xed, 0x2f, 0x58, 0x70, 0x22, 0x95, 0xb7, 0x56, - 0x90, 0x11, 0xc4, 0x56, 0x5a, 0xc0, 0xa2, 0xff, 0x58, 0x08, 0x74, 0x99, 0x29, 0x53, 0xbd, 0xd2, - 0x34, 0x08, 0x9b, 0x78, 0xf6, 0x97, 0x4b, 0x50, 0x93, 0x11, 0x14, 0x7d, 0x74, 0xe5, 0x73, 0x16, - 0x9c, 0x50, 0x67, 0x1a, 0xcc, 0x59, 0x56, 0x2a, 0x22, 0xc9, 0x80, 0xf6, 0x40, 0x6d, 0xb7, 0xfd, - 0xb5, 0x40, 0x5b, 0xe4, 0xd8, 0x64, 0x86, 0xd3, 0xbc, 0xd1, 0x2d, 0x80, 0x78, 0x3b, 0x4e, 0x48, - 0xdb, 0x70, 0xdb, 0xd9, 0xc6, 0x8a, 0x1b, 0x6f, 0x04, 0x11, 0xa1, 0xeb, 0xeb, 0x46, 0xd0, 0x24, - 0xcb, 0x0a, 0x53, 0x9b, 0x50, 0xba, 0x0d, 0x1b, 0x94, 0xec, 0x7f, 0x50, 0x82, 0x53, 0xd9, 0x2e, - 0xa1, 0x0f, 0xc3, 0xb0, 0xe4, 0x6e, 0xdc, 0x1e, 0x26, 0xc3, 0x46, 0x86, 0xb1, 0x01, 0xbb, 0xb7, - 0x33, 0x36, 0xd6, 0x7d, 0x7b, 0xdb, 0xb8, 0x89, 0x82, 0x53, 0xc4, 0xf8, 0xc1, 0x92, 0x38, 0x01, - 0x9d, 0xda, 0x9e, 0x0c, 0x43, 0x71, 0x3a, 0x64, 0x1c, 0x2c, 0x99, 0x50, 0x9c, 0xc1, 0x46, 0x4b, - 0x70, 0xd6, 0x68, 0xb9, 0x41, 0xdc, 0xd6, 0xfa, 0x6a, 0x10, 0xc9, 0x9d, 0xd5, 0x63, 0x3a, 0xb0, - 0xab, 0x1b, 0x07, 0xe7, 0x3e, 0x49, 0xb5, 0x7d, 0xc3, 0x09, 0x9d, 0x86, 0x9b, 0x6c, 0x0b, 0x3f, - 0xa4, 0x92, 0x4d, 0xd3, 0xa2, 0x1d, 0x2b, 0x0c, 0x7b, 0x01, 0x2a, 0x7d, 0xce, 0xa0, 0xbe, 0x2c, - 0xfa, 0x97, 0xa1, 0x46, 0xc9, 0x49, 0xf3, 0xae, 0x08, 0x92, 0x01, 0xd4, 0xe4, 0x05, 0x20, 0xc8, - 0x86, 0xb2, 0xeb, 0xc8, 0xb3, 0x3b, 0xf5, 0x5a, 0x73, 0x71, 0xdc, 0x61, 0x9b, 0x64, 0x0a, 0x44, - 0x4f, 0x42, 0x99, 0x6c, 0x85, 0xd9, 0x43, 0xba, 0xcb, 0x5b, 0xa1, 0x1b, 0x91, 0x98, 0x22, 0x91, - 0xad, 0x10, 0x5d, 0x80, 0x92, 0xdb, 0x14, 0x4a, 0x0a, 0x04, 0x4e, 0x69, 0x6e, 0x06, 0x97, 0xdc, - 0xa6, 0xbd, 0x05, 0x75, 0x75, 0xe3, 0x08, 0xda, 0x90, 0xb2, 0xdb, 0x2a, 0x22, 0xe4, 0x49, 0xd2, - 0xed, 0x21, 0xb5, 0x3b, 0x00, 0x3a, 0x81, 0xaf, 0x28, 0xf9, 0x72, 0x11, 0x2a, 0x8d, 0x40, 0x24, - 0x17, 0xd7, 0x34, 0x19, 0x26, 0xb4, 0x19, 0xc4, 0xbe, 0x0d, 0x23, 0xd7, 0xfd, 0xe0, 0x2e, 0x2b, - 0x97, 0xce, 0xaa, 0x83, 0x51, 0xc2, 0x6b, 0xf4, 0x47, 0xd6, 0x44, 0x60, 0x50, 0xcc, 0x61, 0xaa, - 0xde, 0x52, 0xa9, 0x57, 0xbd, 0x25, 0xfb, 0x93, 0x16, 0x0c, 0xab, 0x4c, 0xa0, 0xd9, 0xcd, 0x0d, - 0x4a, 0xb7, 0x15, 0x05, 0x9d, 0x30, 0x4b, 0x97, 0xdd, 0x09, 0x84, 0x39, 0xcc, 0x4c, 0x91, 0x2b, - 0xed, 0x93, 0x22, 0x77, 0x11, 0x2a, 0x1b, 0xae, 0xdf, 0xcc, 0x5e, 0x72, 0x71, 0xdd, 0xf5, 0x9b, - 0x98, 0x41, 0x68, 0x17, 0x4e, 0xa9, 0x2e, 0x48, 0x85, 0xf0, 0x22, 0x0c, 0xaf, 0x76, 0x5c, 0xaf, - 0x29, 0xcb, 0x9e, 0x65, 0x3c, 0x25, 0x53, 0x06, 0x0c, 0xa7, 0x30, 0xe9, 0xbe, 0x6e, 0xd5, 0xf5, - 0x9d, 0x68, 0x7b, 0x49, 0x6b, 0x20, 0x25, 0x94, 0xa6, 0x14, 0x04, 0x1b, 0x58, 0xf6, 0x9b, 0x65, - 0x18, 0x49, 0xe7, 0x43, 0xf5, 0xb1, 0xbd, 0x7a, 0x12, 0xaa, 0x2c, 0x45, 0x2a, 0xfb, 0x69, 0xd9, - 0xf3, 0x98, 0xc3, 0x50, 0x0c, 0x03, 0xbc, 0xb8, 0x42, 0x31, 0x17, 0xc4, 0xa8, 0x4e, 0x2a, 0xff, - 0x0a, 0x8b, 0x27, 0x13, 0xf5, 0x1c, 0x04, 0x2b, 0xf4, 0x19, 0x0b, 0x06, 0x83, 0xd0, 0xac, 0xd3, - 0xf3, 0xa1, 0x22, 0x73, 0xc5, 0x44, 0xb2, 0x8c, 0xb0, 0x88, 0xd5, 0xa7, 0x97, 0x9f, 0x43, 0xb2, - 0xbe, 0xf0, 0x3e, 0x18, 0x36, 0x31, 0xf7, 0x33, 0x8a, 0x6b, 0xa6, 0x51, 0xfc, 0x39, 0x73, 0x52, - 0x88, 0x6c, 0xb8, 0x3e, 0x96, 0xdb, 0x4d, 0xa8, 0x36, 0x54, 0x00, 0xc0, 0xa1, 0x8a, 0x65, 0xaa, - 0x6a, 0x07, 0xec, 0x10, 0x88, 0x53, 0xb3, 0xbf, 0x6d, 0x19, 0xf3, 0x03, 0x93, 0x78, 0xae, 0x89, - 0x22, 0x28, 0xb7, 0x36, 0x37, 0x84, 0x29, 0x7a, 0xad, 0xa0, 0xe1, 0x9d, 0xdd, 0xdc, 0xd0, 0x73, - 0xdc, 0x6c, 0xc5, 0x94, 0x59, 0x1f, 0x4e, 0xc0, 0x54, 0xd2, 0x64, 0x79, 0xff, 0xa4, 0x49, 0xfb, - 0xad, 0x12, 0x9c, 0xee, 0x9a, 0x54, 0xe8, 0x0d, 0xa8, 0x46, 0xf4, 0x2d, 0xc5, 0xeb, 0xcd, 0x17, - 0x96, 0xe6, 0x18, 0xcf, 0x35, 0xb5, 0xde, 0x4d, 0xb7, 0x63, 0xce, 0x12, 0x5d, 0x03, 0xa4, 0xc3, - 0x54, 0x94, 0x07, 0x92, 0xbf, 0xf2, 0x05, 0xf1, 0x28, 0x9a, 0xec, 0xc2, 0xc0, 0x39, 0x4f, 0xa1, - 0x97, 0xb2, 0x8e, 0xcc, 0x72, 0xfa, 0xdc, 0x72, 0x2f, 0x9f, 0xa4, 0xfd, 0xcf, 0x4b, 0x70, 0x22, - 0x55, 0x36, 0x09, 0x79, 0x50, 0x23, 0x1e, 0x73, 0xea, 0x4b, 0x65, 0x73, 0xd4, 0x62, 0xc2, 0x4a, - 0x41, 0x5e, 0x16, 0x74, 0xb1, 0xe2, 0xf0, 0x70, 0x1c, 0xae, 0xbf, 0x08, 0xc3, 0xb2, 0x43, 0x1f, - 0x72, 0xda, 0x9e, 0x18, 0x40, 0x35, 0x47, 0x2f, 0x1b, 0x30, 0x9c, 0xc2, 0xb4, 0x7f, 0xbb, 0x0c, - 0xa3, 0xfc, 0x14, 0xa4, 0xa9, 0x66, 0xde, 0x82, 0xdc, 0x6f, 0xfd, 0x65, 0x5d, 0xdc, 0x8c, 0x0f, - 0xe4, 0xea, 0x51, 0x6b, 0xf7, 0xe7, 0x33, 0xea, 0x2b, 0x32, 0xeb, 0x17, 0x32, 0x91, 0x59, 0xdc, - 0xec, 0x6e, 0x1d, 0x53, 0x8f, 0xbe, 0xb7, 0x42, 0xb5, 0xfe, 0x6e, 0x09, 0x4e, 0x66, 0x2e, 0x46, - 0x40, 0x6f, 0xa6, 0x6b, 0xe9, 0x5a, 0x45, 0xf8, 0xca, 0xf7, 0xac, 0x95, 0x7f, 0xb0, 0x8a, 0xba, - 0x0f, 0x68, 0xa9, 0xd8, 0xbf, 0x57, 0x82, 0x91, 0xf4, 0x8d, 0x0e, 0x0f, 0xe1, 0x48, 0xbd, 0x1b, - 0xea, 0xac, 0x68, 0x39, 0xbb, 0xa9, 0x92, 0xbb, 0xe4, 0x79, 0x7d, 0x68, 0xd9, 0x88, 0x35, 0xfc, - 0xa1, 0x28, 0x54, 0x6c, 0xff, 0x3d, 0x0b, 0xce, 0xf1, 0xb7, 0xcc, 0xce, 0xc3, 0xbf, 0x92, 0x37, - 0xba, 0xaf, 0x16, 0xdb, 0xc1, 0x4c, 0x51, 0xbe, 0xfd, 0xc6, 0x97, 0xdd, 0x90, 0x27, 0x7a, 0x9b, - 0x9e, 0x0a, 0x0f, 0x61, 0x67, 0x0f, 0x34, 0x19, 0xec, 0xdf, 0x2b, 0x83, 0xbe, 0x14, 0x10, 0xb9, - 0x22, 0xc7, 0xb1, 0x90, 0xe2, 0x84, 0xcb, 0xdb, 0x7e, 0x43, 0x5f, 0x3f, 0x58, 0xcb, 0xa4, 0x38, - 0xfe, 0xac, 0x05, 0x43, 0xae, 0xef, 0x26, 0xae, 0xc3, 0xb6, 0xd1, 0xc5, 0x5c, 0x58, 0xa6, 0xd8, - 0xcd, 0x71, 0xca, 0x41, 0x64, 0x9e, 0xe3, 0x28, 0x66, 0xd8, 0xe4, 0x8c, 0x3e, 0x2a, 0x82, 0xa7, - 0xcb, 0x85, 0x65, 0xe7, 0xd6, 0x32, 0x11, 0xd3, 0x21, 0x35, 0xbc, 0x92, 0xa8, 0xa0, 0xa4, 0x76, - 0x4c, 0x49, 0xa9, 0x3a, 0xb7, 0xfa, 0x7a, 0x66, 0xda, 0x8c, 0x39, 0x23, 0x3b, 0x06, 0xd4, 0x3d, - 0x16, 0x07, 0x0c, 0x4c, 0x9d, 0x80, 0xba, 0xd3, 0x49, 0x82, 0x36, 0x1d, 0x26, 0x71, 0xd4, 0xa4, - 0x43, 0x6f, 0x25, 0x00, 0x6b, 0x1c, 0xfb, 0xcd, 0x2a, 0x64, 0x92, 0x0e, 0xd1, 0x96, 0x79, 0xa1, - 0xa5, 0x55, 0xec, 0x85, 0x96, 0xaa, 0x33, 0x79, 0x97, 0x5a, 0xa2, 0x16, 0x54, 0xc3, 0x75, 0x27, - 0x96, 0x66, 0xf5, 0xcb, 0x6a, 0x1f, 0x47, 0x1b, 0xef, 0xed, 0x8c, 0xfd, 0x58, 0x7f, 0x5e, 0x57, - 0x3a, 0x57, 0x27, 0x78, 0xf1, 0x10, 0xcd, 0x9a, 0xd1, 0xc0, 0x9c, 0xfe, 0x41, 0xae, 0x6c, 0xfb, - 0x94, 0xa8, 0xce, 0x8e, 0x49, 0xdc, 0xf1, 0x12, 0x31, 0x1b, 0x5e, 0x2e, 0x70, 0x95, 0x71, 0xc2, - 0x3a, 0x5d, 0x9e, 0xff, 0xc7, 0x06, 0x53, 0xf4, 0x61, 0xa8, 0xc7, 0x89, 0x13, 0x25, 0x87, 0x4c, - 0x70, 0x55, 0x83, 0xbe, 0x2c, 0x89, 0x60, 0x4d, 0x0f, 0xbd, 0xc2, 0x6a, 0xb5, 0xba, 0xf1, 0xfa, - 0x21, 0x73, 0x1e, 0x64, 0x5d, 0x57, 0x41, 0x01, 0x1b, 0xd4, 0xd0, 0x25, 0x00, 0x36, 0xb7, 0x79, - 0xa0, 0x5f, 0x8d, 0x79, 0x99, 0x94, 0x28, 0xc4, 0x0a, 0x82, 0x0d, 0x2c, 0xfb, 0x87, 0x21, 0x5d, - 0xef, 0x01, 0x8d, 0xc9, 0xf2, 0x12, 0xdc, 0x0b, 0xcd, 0x72, 0x17, 0x52, 0x95, 0x20, 0x7e, 0xcd, - 0x02, 0xb3, 0x28, 0x05, 0x7a, 0x9d, 0x57, 0xbf, 0xb0, 0x8a, 0x38, 0x39, 0x34, 0xe8, 0x8e, 0x2f, - 0x38, 0x61, 0xe6, 0x08, 0x5b, 0x96, 0xc0, 0xb8, 0xf0, 0x5e, 0xa8, 0x49, 0xe8, 0x81, 0x8c, 0xba, - 0x4f, 0xc0, 0x99, 0xec, 0x75, 0xdf, 0xe2, 0xd4, 0x69, 0x7f, 0xd7, 0x8f, 0xf4, 0xe7, 0x94, 0x7a, - 0xf9, 0x73, 0xfa, 0xb8, 0xd6, 0xf4, 0xd7, 0x2d, 0xb8, 0xb8, 0xdf, 0xad, 0xe4, 0xe8, 0x31, 0xa8, - 0xdc, 0x75, 0x22, 0x59, 0x44, 0x9b, 0x09, 0xca, 0xdb, 0x4e, 0xe4, 0x63, 0xd6, 0x8a, 0xb6, 0x61, - 0x80, 0x47, 0x83, 0x09, 0x6b, 0xfd, 0xe5, 0x62, 0xef, 0x48, 0xbf, 0x4e, 0x8c, 0xed, 0x02, 0x8f, - 0x44, 0xc3, 0x82, 0xa1, 0xfd, 0x1d, 0x0b, 0xd0, 0xe2, 0x26, 0x89, 0x22, 0xb7, 0x69, 0xc4, 0xaf, - 0xb1, 0x5b, 0x4e, 0x8c, 0xdb, 0x4c, 0xcc, 0x14, 0xd7, 0xcc, 0x2d, 0x27, 0xc6, 0xbf, 0xfc, 0x5b, - 0x4e, 0x4a, 0x07, 0xbb, 0xe5, 0x04, 0x2d, 0xc2, 0xb9, 0x36, 0xdf, 0x6e, 0xf0, 0x9b, 0x03, 0xf8, - 0xde, 0x43, 0x25, 0x94, 0x9d, 0xdf, 0xdd, 0x19, 0x3b, 0xb7, 0x90, 0x87, 0x80, 0xf3, 0x9f, 0xb3, - 0xdf, 0x0b, 0x88, 0x87, 0xad, 0x4d, 0xe7, 0xc5, 0x20, 0xf5, 0x74, 0xbf, 0xd8, 0x5f, 0xad, 0xc2, - 0xc9, 0x4c, 0x89, 0x55, 0xba, 0xd5, 0xeb, 0x0e, 0x7a, 0x3a, 0xb2, 0xfe, 0xee, 0xee, 0x5e, 0x5f, - 0x61, 0x54, 0x3e, 0x54, 0x5d, 0x3f, 0xec, 0x24, 0xc5, 0xe4, 0x90, 0xf2, 0x4e, 0xcc, 0x51, 0x82, - 0x86, 0xbb, 0x98, 0xfe, 0xc5, 0x9c, 0x4d, 0x91, 0x41, 0x59, 0x29, 0x63, 0xbc, 0xf2, 0x80, 0xdc, - 0x01, 0x9f, 0xd2, 0x21, 0x52, 0xd5, 0x22, 0x1c, 0x8b, 0x99, 0xc9, 0x72, 0xdc, 0x47, 0xed, 0xbf, - 0x5a, 0x82, 0x21, 0xe3, 0xa3, 0xa1, 0x5f, 0x4c, 0x97, 0x6c, 0xb2, 0x8a, 0x7b, 0x25, 0x46, 0x7f, - 0x5c, 0x17, 0x65, 0xe2, 0xaf, 0xf4, 0x54, 0x77, 0xb5, 0xa6, 0x7b, 0x3b, 0x63, 0xa7, 0x32, 0xf5, - 0x98, 0x52, 0x15, 0x9c, 0x2e, 0x7c, 0x1c, 0x4e, 0x66, 0xc8, 0xe4, 0xbc, 0xf2, 0x4a, 0xfa, 0x36, - 0xf7, 0x23, 0xba, 0xa5, 0xcc, 0x21, 0xfb, 0x06, 0x1d, 0x32, 0x91, 0x46, 0x17, 0x78, 0xa4, 0x0f, - 0x1f, 0x6c, 0x26, 0x5b, 0xb6, 0xd4, 0x67, 0xb6, 0xec, 0xd3, 0x50, 0x0b, 0x03, 0xcf, 0x6d, 0xb8, - 0xaa, 0xaa, 0x20, 0xcb, 0xcf, 0x5d, 0x12, 0x6d, 0x58, 0x41, 0xd1, 0x5d, 0xa8, 0xab, 0x8b, 0xef, - 0x85, 0x7f, 0xbb, 0xa8, 0x43, 0x1f, 0x65, 0xb4, 0xe8, 0x0b, 0xed, 0x35, 0x2f, 0x64, 0xc3, 0x00, - 0x53, 0x82, 0x32, 0xf4, 0x9f, 0xf9, 0xde, 0x99, 0x76, 0x8c, 0xb1, 0x80, 0xd8, 0x5f, 0xaf, 0xc3, - 0xd9, 0xbc, 0x3a, 0xd7, 0xe8, 0x63, 0x30, 0xc0, 0xfb, 0x58, 0xcc, 0x55, 0x0a, 0x79, 0x3c, 0x66, - 0x19, 0x41, 0xd1, 0x2d, 0xf6, 0x1b, 0x0b, 0x9e, 0x82, 0xbb, 0xe7, 0xac, 0x8a, 0x19, 0x72, 0x3c, - 0xdc, 0xe7, 0x1d, 0xcd, 0x7d, 0xde, 0xe1, 0xdc, 0x3d, 0x67, 0x15, 0x6d, 0x41, 0xb5, 0xe5, 0x26, - 0xc4, 0x11, 0x4e, 0x84, 0xdb, 0xc7, 0xc2, 0x9c, 0x38, 0xdc, 0x4a, 0x63, 0x3f, 0x31, 0x67, 0x88, - 0xbe, 0x66, 0xc1, 0xc9, 0xd5, 0x74, 0x6a, 0xbc, 0x10, 0x9e, 0xce, 0x31, 0xd4, 0x32, 0x4f, 0x33, - 0xe2, 0xd7, 0xfc, 0x64, 0x1a, 0x71, 0xb6, 0x3b, 0xe8, 0xd3, 0x16, 0x0c, 0xae, 0xb9, 0x9e, 0x51, - 0xd6, 0xf6, 0x18, 0x3e, 0xce, 0x15, 0xc6, 0x40, 0xef, 0x38, 0xf8, 0xff, 0x18, 0x4b, 0xce, 0xbd, - 0x34, 0xd5, 0xc0, 0x51, 0x35, 0xd5, 0xe0, 0x03, 0xd2, 0x54, 0x9f, 0xb5, 0xa0, 0xae, 0x46, 0x5a, - 0xa4, 0x3b, 0x7f, 0xf8, 0x18, 0x3f, 0x39, 0xf7, 0x9c, 0xa8, 0xbf, 0x58, 0x33, 0x47, 0x5f, 0xb2, - 0x60, 0xc8, 0x79, 0xa3, 0x13, 0x91, 0x26, 0xd9, 0x0c, 0xc2, 0x58, 0xdc, 0x11, 0xf8, 0x6a, 0xf1, - 0x9d, 0x99, 0xa4, 0x4c, 0x66, 0xc8, 0xe6, 0x62, 0x18, 0x8b, 0xb4, 0x24, 0xdd, 0x80, 0xcd, 0x2e, - 0xd8, 0x3b, 0x25, 0x18, 0xdb, 0x87, 0x02, 0x7a, 0x11, 0x86, 0x83, 0xa8, 0xe5, 0xf8, 0xee, 0x1b, - 0x66, 0xad, 0x0b, 0x65, 0x65, 0x2d, 0x1a, 0x30, 0x9c, 0xc2, 0x34, 0x13, 0xb2, 0x4b, 0xfb, 0x24, - 0x64, 0x5f, 0x84, 0x4a, 0x44, 0xc2, 0x20, 0xbb, 0x59, 0x60, 0x29, 0x01, 0x0c, 0x82, 0x1e, 0x87, - 0xb2, 0x13, 0xba, 0x22, 0x10, 0x4d, 0xed, 0x81, 0x26, 0x97, 0xe6, 0x30, 0x6d, 0x4f, 0xd5, 0x87, - 0xa8, 0xde, 0x97, 0xfa, 0x10, 0xc6, 0x95, 0xfe, 0x03, 0x3d, 0xaf, 0xf4, 0x7f, 0xab, 0x0c, 0x8f, - 0xef, 0x39, 0x5f, 0x74, 0x1c, 0x9e, 0xb5, 0x47, 0x1c, 0x9e, 0x1c, 0x9e, 0xd2, 0x7e, 0xc3, 0x53, - 0xee, 0x31, 0x3c, 0x9f, 0xa6, 0xcb, 0x40, 0xd6, 0x08, 0x29, 0xe6, 0x96, 0xb7, 0x5e, 0x25, 0x47, - 0xc4, 0x0a, 0x90, 0x50, 0xac, 0xf9, 0xd2, 0x3d, 0x40, 0x2a, 0x19, 0xb9, 0x5a, 0x84, 0x1a, 0xe8, - 0x59, 0x33, 0x84, 0xcf, 0xfd, 0x5e, 0x19, 0xce, 0xf6, 0xcf, 0x95, 0xe0, 0xc9, 0x3e, 0xa4, 0xb7, - 0x39, 0x8b, 0xad, 0x3e, 0x67, 0xf1, 0xf7, 0xf6, 0x67, 0xb2, 0xff, 0xaa, 0x05, 0x17, 0x7a, 0x2b, - 0x0f, 0xf4, 0x1c, 0x0c, 0xad, 0x46, 0x8e, 0xdf, 0x58, 0x67, 0x37, 0x57, 0xca, 0x41, 0x61, 0x63, - 0xad, 0x9b, 0xb1, 0x89, 0x43, 0xb7, 0xb7, 0x3c, 0x26, 0xc1, 0xc0, 0x90, 0xc9, 0xa3, 0x74, 0x7b, - 0xbb, 0x92, 0x05, 0xe2, 0x6e, 0x7c, 0xfb, 0x4f, 0x4b, 0xf9, 0xdd, 0xe2, 0x46, 0xc6, 0x41, 0xbe, - 0x93, 0xf8, 0x0a, 0xa5, 0x3e, 0x64, 0x49, 0xf9, 0x7e, 0xcb, 0x92, 0x4a, 0x2f, 0x59, 0x82, 0x66, - 0xe0, 0x94, 0x71, 0x25, 0x0a, 0x4f, 0x08, 0xe6, 0x01, 0xb7, 0xaa, 0x4a, 0xc6, 0x52, 0x06, 0x8e, - 0xbb, 0x9e, 0x40, 0xcf, 0x40, 0xcd, 0xf5, 0x63, 0xd2, 0xe8, 0x44, 0x3c, 0xd0, 0xdb, 0x48, 0xc2, - 0x9a, 0x13, 0xed, 0x58, 0x61, 0xd8, 0xbf, 0x54, 0x82, 0xf3, 0x3d, 0xed, 0xac, 0xfb, 0x24, 0xbb, - 0xcc, 0xcf, 0x51, 0xb9, 0x3f, 0x9f, 0xc3, 0x1c, 0xa4, 0xea, 0xbe, 0x83, 0xf4, 0xfb, 0xbd, 0x27, - 0x26, 0xb5, 0xb9, 0xbf, 0x6f, 0x47, 0xe9, 0x25, 0x38, 0xe1, 0x84, 0x21, 0xc7, 0x63, 0xf1, 0x9a, - 0x99, 0x2a, 0x39, 0x93, 0x26, 0x10, 0xa7, 0x71, 0xfb, 0xd2, 0x9e, 0x7f, 0x68, 0x41, 0x1d, 0x93, - 0x35, 0x2e, 0x1d, 0xd0, 0x1d, 0x31, 0x44, 0x56, 0x11, 0xf5, 0x34, 0xe9, 0xc0, 0xc6, 0x2e, 0xab, - 0x33, 0x99, 0x37, 0xd8, 0xdd, 0x57, 0xe7, 0x94, 0x0e, 0x74, 0x75, 0x8e, 0xba, 0x3c, 0xa5, 0xdc, - 0xfb, 0xf2, 0x14, 0xfb, 0x1b, 0x83, 0xf4, 0xf5, 0xc2, 0x60, 0x3a, 0x22, 0xcd, 0x98, 0x7e, 0xdf, - 0x4e, 0xe4, 0x89, 0x49, 0xa2, 0xbe, 0xef, 0x4d, 0x3c, 0x8f, 0x69, 0x7b, 0xea, 0x28, 0xa6, 0x74, - 0xa0, 0x1a, 0x21, 0xe5, 0x7d, 0x6b, 0x84, 0xbc, 0x04, 0x27, 0xe2, 0x78, 0x7d, 0x29, 0x72, 0x37, - 0x9d, 0x84, 0x5c, 0x27, 0xdb, 0xc2, 0xca, 0xd2, 0x79, 0xfd, 0xcb, 0x57, 0x35, 0x10, 0xa7, 0x71, - 0xd1, 0x2c, 0x9c, 0xd6, 0x95, 0x3a, 0x48, 0x94, 0xb0, 0xe8, 0x7e, 0x3e, 0x13, 0x54, 0x12, 0xaf, - 0xae, 0xed, 0x21, 0x10, 0x70, 0xf7, 0x33, 0x54, 0xbe, 0xa5, 0x1a, 0x69, 0x47, 0x06, 0xd2, 0xf2, - 0x2d, 0x45, 0x87, 0xf6, 0xa5, 0xeb, 0x09, 0xb4, 0x00, 0x67, 0xf8, 0xc4, 0x98, 0x0c, 0x43, 0xe3, - 0x8d, 0x06, 0xd3, 0x75, 0x0c, 0x67, 0xbb, 0x51, 0x70, 0xde, 0x73, 0xe8, 0x05, 0x18, 0x52, 0xcd, - 0x73, 0x33, 0xe2, 0x14, 0x41, 0x79, 0x31, 0x14, 0x99, 0xb9, 0x26, 0x36, 0xf1, 0xd0, 0x87, 0xe0, - 0x51, 0xfd, 0x97, 0xa7, 0x80, 0xf1, 0xa3, 0xb5, 0x19, 0x51, 0x04, 0x49, 0x5d, 0xd5, 0x31, 0x9b, - 0x8b, 0xd6, 0xc4, 0xbd, 0x9e, 0x47, 0xab, 0x70, 0x41, 0x81, 0x2e, 0xfb, 0x09, 0xcb, 0xe7, 0x88, - 0xc9, 0x94, 0x13, 0x93, 0x9b, 0x91, 0xc7, 0xca, 0x26, 0xd5, 0xf5, 0x2d, 0x8a, 0xb3, 0x6e, 0x72, - 0x35, 0x0f, 0x13, 0xcf, 0xe3, 0x3d, 0xa8, 0xa0, 0x09, 0xa8, 0x13, 0xdf, 0x59, 0xf5, 0xc8, 0xe2, - 0xf4, 0x1c, 0x2b, 0xa6, 0x64, 0x9c, 0xe4, 0x5d, 0x96, 0x00, 0xac, 0x71, 0x54, 0x84, 0xe9, 0x70, - 0xcf, 0x1b, 0x3d, 0x97, 0xe0, 0x6c, 0xab, 0x11, 0x52, 0xdb, 0xc3, 0x6d, 0x90, 0xc9, 0x06, 0x0b, - 0xa8, 0xa3, 0x1f, 0x86, 0x17, 0x98, 0x54, 0xe1, 0xd3, 0xb3, 0xd3, 0x4b, 0x5d, 0x38, 0x38, 0xf7, - 0x49, 0x16, 0x78, 0x19, 0x05, 0x5b, 0xdb, 0xa3, 0x67, 0x32, 0x81, 0x97, 0xb4, 0x11, 0x73, 0x18, - 0xba, 0x06, 0x88, 0xc5, 0xe2, 0x5f, 0x4d, 0x92, 0x50, 0x19, 0x3b, 0xa3, 0x67, 0xd9, 0x2b, 0xa9, - 0x30, 0xb2, 0x2b, 0x5d, 0x18, 0x38, 0xe7, 0x29, 0xfb, 0x3f, 0x5a, 0x70, 0x42, 0xad, 0xd7, 0xfb, - 0x90, 0x8d, 0xe2, 0xa5, 0xb3, 0x51, 0x66, 0x8f, 0x2e, 0xf1, 0x58, 0xcf, 0x7b, 0x84, 0x34, 0xff, - 0xf4, 0x10, 0x80, 0x96, 0x8a, 0x4a, 0x21, 0x59, 0x3d, 0x15, 0xd2, 0x43, 0x2b, 0x91, 0xf2, 0x2a, - 0xa7, 0x54, 0x1f, 0x6c, 0xe5, 0x94, 0x65, 0x38, 0x27, 0xcd, 0x05, 0x7e, 0x56, 0x74, 0x35, 0x88, - 0x95, 0x80, 0xab, 0x4d, 0x3d, 0x2e, 0x08, 0x9d, 0x9b, 0xcb, 0x43, 0xc2, 0xf9, 0xcf, 0xa6, 0xac, - 0x94, 0xc1, 0xfd, 0xac, 0x14, 0xbd, 0xa6, 0xe7, 0xd7, 0xe4, 0x9d, 0x1c, 0x99, 0x35, 0x3d, 0x7f, - 0x65, 0x19, 0x6b, 0x9c, 0x7c, 0xc1, 0x5e, 0x2f, 0x48, 0xb0, 0xc3, 0x81, 0x05, 0xbb, 0x14, 0x31, - 0x43, 0x3d, 0x45, 0x8c, 0xf4, 0x49, 0x0f, 0xf7, 0xf4, 0x49, 0xbf, 0x1f, 0x46, 0x5c, 0x7f, 0x9d, - 0x44, 0x6e, 0x42, 0x9a, 0x6c, 0x2d, 0x30, 0xf1, 0x53, 0xd3, 0x6a, 0x7d, 0x2e, 0x05, 0xc5, 0x19, - 0xec, 0xb4, 0x5c, 0x1c, 0xe9, 0x43, 0x2e, 0xf6, 0xd0, 0x46, 0x27, 0x8b, 0xd1, 0x46, 0xa7, 0x8e, - 0xae, 0x8d, 0x4e, 0x1f, 0xab, 0x36, 0x42, 0x85, 0x68, 0xa3, 0xbe, 0x04, 0xbd, 0xb1, 0xfd, 0x3b, - 0xbb, 0xcf, 0xf6, 0xaf, 0x97, 0x2a, 0x3a, 0x77, 0x68, 0x55, 0x94, 0xaf, 0x65, 0x1e, 0x39, 0x94, - 0x96, 0xf9, 0x6c, 0x09, 0xce, 0x69, 0x39, 0x4c, 0x67, 0xbf, 0xbb, 0x46, 0x25, 0x11, 0xbb, 0xd6, - 0x89, 0x9f, 0xdb, 0x18, 0xc9, 0x51, 0x3a, 0xcf, 0x4a, 0x41, 0xb0, 0x81, 0xc5, 0x72, 0x8c, 0x48, - 0xc4, 0xca, 0xe8, 0x66, 0x85, 0xf4, 0xb4, 0x68, 0xc7, 0x0a, 0x83, 0xce, 0x2f, 0xfa, 0x5b, 0xe4, - 0x6d, 0x66, 0x8b, 0xc5, 0x4d, 0x6b, 0x10, 0x36, 0xf1, 0xd0, 0xd3, 0x9c, 0x09, 0x13, 0x10, 0x54, - 0x50, 0x0f, 0x8b, 0x7b, 0x5e, 0xa5, 0x4c, 0x50, 0x50, 0xd9, 0x1d, 0x96, 0x4c, 0x56, 0xed, 0xee, - 0x0e, 0x0b, 0x81, 0x52, 0x18, 0xf6, 0xff, 0xb4, 0xe0, 0x7c, 0xee, 0x50, 0xdc, 0x07, 0xe5, 0xbb, - 0x95, 0x56, 0xbe, 0xcb, 0x45, 0x6d, 0x37, 0x8c, 0xb7, 0xe8, 0xa1, 0x88, 0xff, 0xbd, 0x05, 0x23, - 0x1a, 0xff, 0x3e, 0xbc, 0xaa, 0x9b, 0x7e, 0xd5, 0xe2, 0x76, 0x56, 0xf5, 0xae, 0x77, 0xfb, 0xed, - 0x12, 0xa8, 0x02, 0x8e, 0x93, 0x0d, 0x59, 0x1e, 0x77, 0x9f, 0x93, 0xc4, 0x6d, 0x18, 0x60, 0x07, - 0xa1, 0x71, 0x31, 0x41, 0x1e, 0x69, 0xfe, 0xec, 0x50, 0x55, 0x1f, 0x32, 0xb3, 0xbf, 0x31, 0x16, - 0x0c, 0x59, 0x91, 0x67, 0x37, 0xa6, 0xd2, 0xbc, 0x29, 0xd2, 0xb2, 0x74, 0x91, 0x67, 0xd1, 0x8e, - 0x15, 0x06, 0x55, 0x0f, 0x6e, 0x23, 0xf0, 0xa7, 0x3d, 0x27, 0x96, 0x77, 0x19, 0x2a, 0xf5, 0x30, - 0x27, 0x01, 0x58, 0xe3, 0xb0, 0x33, 0x52, 0x37, 0x0e, 0x3d, 0x67, 0xdb, 0xd8, 0x3f, 0x1b, 0xf5, - 0x09, 0x14, 0x08, 0x9b, 0x78, 0x76, 0x1b, 0x46, 0xd3, 0x2f, 0x31, 0x43, 0xd6, 0x58, 0x80, 0x62, - 0x5f, 0xc3, 0x39, 0x01, 0x75, 0x87, 0x3d, 0x35, 0xdf, 0x71, 0xb2, 0x57, 0x90, 0x4f, 0x4a, 0x00, - 0xd6, 0x38, 0xf6, 0xaf, 0x58, 0x70, 0x26, 0x67, 0xd0, 0x0a, 0x4c, 0x7b, 0x4b, 0xb4, 0xb4, 0xc9, - 0x53, 0xec, 0x3f, 0x04, 0x83, 0x4d, 0xb2, 0xe6, 0xc8, 0x10, 0x38, 0x43, 0xb6, 0xcf, 0xf0, 0x66, - 0x2c, 0xe1, 0xf6, 0x7f, 0xb7, 0xe0, 0x64, 0xba, 0xaf, 0x31, 0x4b, 0x25, 0xe1, 0xc3, 0xe4, 0xc6, - 0x8d, 0x60, 0x93, 0x44, 0xdb, 0xf4, 0xcd, 0xad, 0x4c, 0x2a, 0x49, 0x17, 0x06, 0xce, 0x79, 0x8a, - 0x95, 0x6f, 0x6d, 0xaa, 0xd1, 0x96, 0x33, 0xf2, 0x56, 0x91, 0x33, 0x52, 0x7f, 0x4c, 0xf3, 0xb8, - 0x5c, 0xb1, 0xc4, 0x26, 0x7f, 0xfb, 0x3b, 0x15, 0x50, 0x79, 0xb1, 0x2c, 0xfe, 0xa8, 0xa0, 0xe8, - 0xad, 0x83, 0x66, 0x10, 0xa9, 0xc9, 0x50, 0xd9, 0x2b, 0x20, 0x80, 0x7b, 0x49, 0x4c, 0xd7, 0xa5, - 0x7a, 0xc3, 0x15, 0x0d, 0xc2, 0x26, 0x1e, 0xed, 0x89, 0xe7, 0x6e, 0x12, 0xfe, 0xd0, 0x40, 0xba, - 0x27, 0xf3, 0x12, 0x80, 0x35, 0x0e, 0xed, 0x49, 0xd3, 0x5d, 0x5b, 0x13, 0x5b, 0x7e, 0xd5, 0x13, - 0x3a, 0x3a, 0x98, 0x41, 0x78, 0x45, 0xee, 0x60, 0x43, 0x58, 0xc1, 0x46, 0x45, 0xee, 0x60, 0x03, - 0x33, 0x08, 0xb5, 0xdb, 0xfc, 0x20, 0x6a, 0xb3, 0x2b, 0xe2, 0x9b, 0x8a, 0x8b, 0xb0, 0x7e, 0x95, - 0xdd, 0x76, 0xa3, 0x1b, 0x05, 0xe7, 0x3d, 0x47, 0x67, 0x60, 0x18, 0x91, 0xa6, 0xdb, 0x48, 0x4c, - 0x6a, 0x90, 0x9e, 0x81, 0x4b, 0x5d, 0x18, 0x38, 0xe7, 0x29, 0x34, 0x09, 0x27, 0x65, 0x5e, 0xb3, - 0xac, 0x5a, 0x33, 0x94, 0xae, 0x92, 0x81, 0xd3, 0x60, 0x9c, 0xc5, 0xa7, 0x52, 0xad, 0x2d, 0x0a, - 0x56, 0x31, 0x63, 0xd9, 0x90, 0x6a, 0xb2, 0x90, 0x15, 0x56, 0x18, 0xf6, 0xa7, 0xca, 0x54, 0x0b, - 0xf7, 0x28, 0xd4, 0x76, 0xdf, 0xa2, 0x05, 0xd3, 0x33, 0xb2, 0xd2, 0xc7, 0x8c, 0x7c, 0x1e, 0x86, - 0xef, 0xc4, 0x81, 0xaf, 0x22, 0xf1, 0xaa, 0x3d, 0x23, 0xf1, 0x0c, 0xac, 0xfc, 0x48, 0xbc, 0x81, - 0xa2, 0x22, 0xf1, 0x06, 0x0f, 0x19, 0x89, 0xf7, 0xad, 0x2a, 0xa8, 0xab, 0x41, 0x6e, 0x90, 0xe4, - 0x6e, 0x10, 0x6d, 0xb8, 0x7e, 0x8b, 0xe5, 0x83, 0x7f, 0xcd, 0x82, 0x61, 0xbe, 0x5e, 0xe6, 0xcd, - 0x4c, 0xaa, 0xb5, 0x82, 0xee, 0x9c, 0x48, 0x31, 0x1b, 0x5f, 0x31, 0x18, 0x65, 0xae, 0xd2, 0x34, - 0x41, 0x38, 0xd5, 0x23, 0xf4, 0x71, 0x00, 0xe9, 0x1f, 0x5d, 0x93, 0x22, 0x73, 0xae, 0x98, 0xfe, - 0x61, 0xb2, 0xa6, 0x6d, 0xe0, 0x15, 0xc5, 0x04, 0x1b, 0x0c, 0xd1, 0x67, 0x75, 0x96, 0x19, 0x0f, - 0xd9, 0xff, 0xe8, 0xb1, 0x8c, 0x4d, 0x3f, 0x39, 0x66, 0x18, 0x06, 0x5d, 0xbf, 0x45, 0xe7, 0x89, - 0x88, 0x58, 0x7a, 0x57, 0x5e, 0x2d, 0x85, 0xf9, 0xc0, 0x69, 0x4e, 0x39, 0x9e, 0xe3, 0x37, 0x48, - 0x34, 0xc7, 0xd1, 0xcd, 0x0b, 0xa4, 0x59, 0x03, 0x96, 0x84, 0xba, 0x2e, 0x55, 0xa9, 0xf6, 0x73, - 0xa9, 0xca, 0x85, 0x0f, 0xc0, 0xe9, 0xae, 0x8f, 0x79, 0xa0, 0x94, 0xb2, 0xc3, 0x67, 0xa3, 0xd9, - 0xff, 0x62, 0x40, 0x2b, 0xad, 0x1b, 0x41, 0x93, 0x5f, 0xed, 0x11, 0xe9, 0x2f, 0x2a, 0x6c, 0xdc, - 0x02, 0xa7, 0x88, 0x71, 0x09, 0xb5, 0x6a, 0xc4, 0x26, 0x4b, 0x3a, 0x47, 0x43, 0x27, 0x22, 0xfe, - 0x71, 0xcf, 0xd1, 0x25, 0xc5, 0x04, 0x1b, 0x0c, 0xd1, 0x7a, 0x2a, 0xa7, 0xe4, 0xca, 0xd1, 0x73, - 0x4a, 0x58, 0x95, 0xa9, 0xbc, 0x6a, 0xfc, 0x5f, 0xb2, 0x60, 0xc4, 0x4f, 0xcd, 0xdc, 0x62, 0xc2, - 0x48, 0xf3, 0x57, 0x05, 0xbf, 0x59, 0x2a, 0xdd, 0x86, 0x33, 0xfc, 0xf3, 0x54, 0x5a, 0xf5, 0x80, - 0x2a, 0x4d, 0xdf, 0x11, 0x34, 0xd0, 0xeb, 0x8e, 0x20, 0xe4, 0xab, 0x4b, 0xd2, 0x06, 0x0b, 0xbf, - 0x24, 0x0d, 0x72, 0x2e, 0x48, 0xbb, 0x0d, 0xf5, 0x46, 0x44, 0x9c, 0xe4, 0x90, 0xf7, 0x65, 0xb1, - 0x03, 0xfa, 0x69, 0x49, 0x00, 0x6b, 0x5a, 0xf6, 0xff, 0xae, 0xc0, 0x29, 0x39, 0x22, 0x32, 0x04, - 0x9d, 0xea, 0x47, 0xce, 0x57, 0x1b, 0xb7, 0x4a, 0x3f, 0x5e, 0x95, 0x00, 0xac, 0x71, 0xa8, 0x3d, - 0xd6, 0x89, 0xc9, 0x62, 0x48, 0xfc, 0x79, 0x77, 0x35, 0x16, 0xe7, 0x9c, 0x6a, 0xa1, 0xdc, 0xd4, - 0x20, 0x6c, 0xe2, 0x51, 0x63, 0x9c, 0xdb, 0xc5, 0x71, 0x36, 0x7d, 0x45, 0xd8, 0xdb, 0x58, 0xc2, - 0xd1, 0xcf, 0xe7, 0x56, 0x8e, 0x2d, 0x26, 0x71, 0xab, 0x2b, 0xf2, 0xfe, 0x80, 0x57, 0x2c, 0xfe, - 0x6d, 0x0b, 0xce, 0xf1, 0x56, 0x39, 0x92, 0x37, 0xc3, 0xa6, 0x93, 0x90, 0xb8, 0x98, 0x4a, 0xee, - 0x39, 0xfd, 0xd3, 0x4e, 0xde, 0x3c, 0xb6, 0x38, 0xbf, 0x37, 0xe8, 0x4d, 0x0b, 0x4e, 0x6e, 0xa4, - 0x6a, 0x7e, 0x48, 0xd5, 0x71, 0xd4, 0x74, 0xfc, 0x14, 0x51, 0xbd, 0xd4, 0xd2, 0xed, 0x31, 0xce, - 0x72, 0xb7, 0xff, 0xd4, 0x02, 0x53, 0x8c, 0xde, 0xff, 0x52, 0x21, 0x07, 0x37, 0x05, 0xa5, 0x75, - 0x59, 0xed, 0x69, 0x5d, 0x3e, 0x0e, 0xe5, 0x8e, 0xdb, 0x14, 0xfb, 0x0b, 0x7d, 0xfa, 0x3a, 0x37, - 0x83, 0x69, 0xbb, 0xfd, 0x4f, 0xab, 0xda, 0x6f, 0x21, 0xf2, 0xa2, 0xbe, 0x2f, 0x5e, 0x7b, 0x4d, - 0x15, 0x1b, 0xe3, 0x6f, 0x7e, 0xa3, 0xab, 0xd8, 0xd8, 0x8f, 0x1c, 0x3c, 0xed, 0x8d, 0x0f, 0x50, - 0xaf, 0x5a, 0x63, 0x83, 0xfb, 0xe4, 0xbc, 0xdd, 0x81, 0x1a, 0xdd, 0x82, 0x31, 0x07, 0x64, 0x2d, - 0xd5, 0xa9, 0xda, 0x55, 0xd1, 0x7e, 0x6f, 0x67, 0xec, 0x7d, 0x07, 0xef, 0x96, 0x7c, 0x1a, 0x2b, - 0xfa, 0x28, 0x86, 0x3a, 0xfd, 0xcd, 0xd2, 0xf3, 0xc4, 0xe6, 0xee, 0xa6, 0x92, 0x99, 0x12, 0x50, - 0x48, 0xee, 0x9f, 0xe6, 0x83, 0x7c, 0xa8, 0xb3, 0xdb, 0x68, 0x19, 0x53, 0xbe, 0x07, 0x5c, 0x52, - 0x49, 0x72, 0x12, 0x70, 0x6f, 0x67, 0xec, 0xa5, 0x83, 0x33, 0x55, 0x8f, 0x63, 0xcd, 0xc2, 0xfe, - 0x72, 0x45, 0xcf, 0x5d, 0x51, 0x63, 0xee, 0xfb, 0x62, 0xee, 0xbe, 0x98, 0x99, 0xbb, 0x17, 0xbb, - 0xe6, 0xee, 0x88, 0xbe, 0x35, 0x35, 0x35, 0x1b, 0xef, 0xb7, 0x21, 0xb0, 0xbf, 0xbf, 0x81, 0x59, - 0x40, 0xaf, 0x77, 0xdc, 0x88, 0xc4, 0x4b, 0x51, 0xc7, 0x77, 0xfd, 0x16, 0x9b, 0x8e, 0x35, 0xd3, - 0x02, 0x4a, 0x81, 0x71, 0x16, 0x9f, 0x6e, 0xea, 0xe9, 0x37, 0xbf, 0xed, 0x6c, 0xf2, 0x59, 0x65, - 0x94, 0xdd, 0x5a, 0x16, 0xed, 0x58, 0x61, 0xd8, 0xdf, 0x60, 0x67, 0xd9, 0x46, 0x5e, 0x30, 0x9d, - 0x13, 0x1e, 0xbb, 0xfe, 0x97, 0xd7, 0xec, 0x52, 0x73, 0x82, 0xdf, 0xf9, 0xcb, 0x61, 0xe8, 0x2e, - 0x0c, 0xae, 0xf2, 0xfb, 0xef, 0x8a, 0xa9, 0x4f, 0x2e, 0x2e, 0xd3, 0x63, 0xb7, 0x9c, 0xc8, 0x9b, - 0xf5, 0xee, 0xe9, 0x9f, 0x58, 0x72, 0xb3, 0xbf, 0x59, 0x81, 0x93, 0x99, 0x0b, 0x62, 0x53, 0xd5, - 0x52, 0x4b, 0xfb, 0x56, 0x4b, 0xfd, 0x08, 0x40, 0x93, 0x84, 0x5e, 0xb0, 0xcd, 0xcc, 0xb1, 0xca, - 0x81, 0xcd, 0x31, 0x65, 0xc1, 0xcf, 0x28, 0x2a, 0xd8, 0xa0, 0x28, 0x0a, 0x95, 0xf1, 0xe2, 0xab, - 0x99, 0x42, 0x65, 0xc6, 0x2d, 0x06, 0x03, 0xf7, 0xf7, 0x16, 0x03, 0x17, 0x4e, 0xf2, 0x2e, 0xaa, - 0xec, 0xdb, 0x43, 0x24, 0xd9, 0xb2, 0xfc, 0x85, 0x99, 0x34, 0x19, 0x9c, 0xa5, 0xfb, 0x20, 0xef, - 0x7f, 0x46, 0xef, 0x86, 0xba, 0xfc, 0xce, 0xf1, 0x68, 0x5d, 0x57, 0x30, 0x90, 0xd3, 0x80, 0xdd, - 0xcb, 0x2c, 0x7e, 0xda, 0x5f, 0x2c, 0x51, 0xeb, 0x99, 0xff, 0x53, 0x95, 0x68, 0x9e, 0x82, 0x01, - 0xa7, 0x93, 0xac, 0x07, 0x5d, 0x77, 0xe8, 0x4d, 0xb2, 0x56, 0x2c, 0xa0, 0x68, 0x1e, 0x2a, 0x4d, - 0x5d, 0x5d, 0xe4, 0x20, 0xa3, 0xa8, 0x1d, 0x91, 0x4e, 0x42, 0x30, 0xa3, 0x82, 0x1e, 0x83, 0x4a, - 0xe2, 0xb4, 0x64, 0xa2, 0x13, 0x4b, 0x6e, 0x5d, 0x71, 0x5a, 0x31, 0x66, 0xad, 0xa6, 0xd2, 0xac, - 0xec, 0xa3, 0x34, 0x5f, 0x82, 0x13, 0xb1, 0xdb, 0xf2, 0x9d, 0xa4, 0x13, 0x11, 0xe3, 0x70, 0x4d, - 0xc7, 0x4b, 0x98, 0x40, 0x9c, 0xc6, 0xb5, 0x7f, 0x63, 0x18, 0xce, 0x2e, 0x4f, 0x2f, 0xc8, 0x9a, - 0xd9, 0xc7, 0x96, 0xab, 0x94, 0xc7, 0xe3, 0xfe, 0xe5, 0x2a, 0xf5, 0xe0, 0xee, 0x19, 0xb9, 0x4a, - 0x9e, 0x91, 0xab, 0x94, 0x4e, 0x1c, 0x29, 0x17, 0x91, 0x38, 0x92, 0xd7, 0x83, 0x7e, 0x12, 0x47, - 0x8e, 0x2d, 0x79, 0x69, 0xcf, 0x0e, 0x1d, 0x28, 0x79, 0x49, 0x65, 0x76, 0x15, 0x12, 0xd2, 0xdf, - 0xe3, 0x53, 0xe5, 0x66, 0x76, 0xa9, 0xac, 0x1a, 0x9e, 0xae, 0x22, 0x04, 0xec, 0xab, 0xc5, 0x77, - 0xa0, 0x8f, 0xac, 0x1a, 0x91, 0x31, 0x63, 0x66, 0x72, 0x0d, 0x16, 0x91, 0xc9, 0x95, 0xd7, 0x9d, - 0x7d, 0x33, 0xb9, 0x5e, 0x82, 0x13, 0x0d, 0x2f, 0xf0, 0xc9, 0x52, 0x14, 0x24, 0x41, 0x23, 0xf0, - 0x84, 0x31, 0xad, 0x44, 0xc2, 0xb4, 0x09, 0xc4, 0x69, 0xdc, 0x5e, 0x69, 0x60, 0xf5, 0xa3, 0xa6, - 0x81, 0xc1, 0x03, 0x4a, 0x03, 0xfb, 0x19, 0x9d, 0xb0, 0x3c, 0xc4, 0xbe, 0xc8, 0x47, 0x8a, 0xff, - 0x22, 0xfd, 0x64, 0x2d, 0xa3, 0xb7, 0xf8, 0x25, 0x76, 0xd4, 0x1c, 0x9d, 0x0e, 0xda, 0xd4, 0xdc, - 0x1a, 0x66, 0x43, 0xf2, 0xda, 0x31, 0x4c, 0xd8, 0xdb, 0xcb, 0x9a, 0x8d, 0xba, 0xd8, 0x4e, 0x37, - 0xe1, 0x74, 0x47, 0x8e, 0x92, 0x50, 0xfd, 0xd5, 0x12, 0xfc, 0xc0, 0xbe, 0x5d, 0x40, 0x77, 0x01, - 0x12, 0xa7, 0x25, 0x26, 0xaa, 0x38, 0xa6, 0x38, 0x62, 0x50, 0xe3, 0x8a, 0xa4, 0xc7, 0x2b, 0x81, - 0xa8, 0xbf, 0xec, 0x00, 0x40, 0xfe, 0x66, 0xb1, 0x8c, 0x81, 0xd7, 0x55, 0x30, 0x11, 0x07, 0x1e, - 0xc1, 0x0c, 0x42, 0xd5, 0x7f, 0x44, 0x5a, 0xfa, 0xd6, 0x65, 0xf5, 0xf9, 0x30, 0x6b, 0xc5, 0x02, - 0x8a, 0x5e, 0x80, 0x21, 0xc7, 0xf3, 0x78, 0x56, 0x0a, 0x89, 0xc5, 0x2d, 0x36, 0xba, 0x72, 0x9b, - 0x06, 0x61, 0x13, 0xcf, 0xfe, 0x93, 0x12, 0x8c, 0xed, 0x23, 0x53, 0xba, 0xf2, 0xec, 0xaa, 0x7d, - 0xe7, 0xd9, 0x89, 0xcc, 0x80, 0x81, 0x1e, 0x99, 0x01, 0x2f, 0xc0, 0x50, 0x42, 0x9c, 0xb6, 0x08, - 0x83, 0x12, 0xfb, 0x6f, 0x7d, 0xee, 0xaa, 0x41, 0xd8, 0xc4, 0xa3, 0x52, 0x6c, 0xc4, 0x69, 0x34, - 0x48, 0x1c, 0xcb, 0xd0, 0x7f, 0xe1, 0xc3, 0x2c, 0x2c, 0xaf, 0x80, 0xb9, 0x86, 0x27, 0x53, 0x2c, - 0x70, 0x86, 0x65, 0x76, 0xc0, 0xeb, 0x7d, 0x0e, 0xf8, 0xd7, 0x4b, 0xf0, 0xf8, 0x9e, 0xda, 0xad, - 0xef, 0xac, 0x8c, 0x4e, 0x4c, 0xa2, 0xec, 0xc4, 0xb9, 0x19, 0x93, 0x08, 0x33, 0x08, 0x1f, 0xa5, - 0x30, 0x34, 0x6e, 0xb5, 0x2e, 0x3a, 0x65, 0x88, 0x8f, 0x52, 0x8a, 0x05, 0xce, 0xb0, 0x3c, 0xec, - 0xb4, 0xfc, 0xfb, 0x25, 0x78, 0xb2, 0x0f, 0x1b, 0xa0, 0xc0, 0xd4, 0xaa, 0x74, 0x82, 0x5b, 0xf9, - 0x01, 0xe5, 0x21, 0x1e, 0x72, 0xb8, 0xbe, 0x51, 0x82, 0x0b, 0xbd, 0x55, 0x31, 0xfa, 0x51, 0xba, - 0x87, 0x97, 0xb1, 0x4f, 0x66, 0x6e, 0xdc, 0x19, 0xbe, 0x7f, 0x4f, 0x81, 0x70, 0x16, 0x17, 0x8d, - 0x03, 0x84, 0x4e, 0xb2, 0x1e, 0x5f, 0xde, 0x72, 0xe3, 0x44, 0xd4, 0x7e, 0x19, 0xe1, 0x27, 0x46, - 0xb2, 0x15, 0x1b, 0x18, 0x94, 0x1d, 0xfb, 0x37, 0x13, 0xdc, 0x08, 0x12, 0xfe, 0x10, 0xdf, 0x46, - 0x9c, 0x91, 0x37, 0x65, 0x18, 0x20, 0x9c, 0xc5, 0xa5, 0xec, 0xd8, 0x99, 0x24, 0xef, 0x28, 0xdf, - 0x5f, 0x30, 0x76, 0xf3, 0xaa, 0x15, 0x1b, 0x18, 0xd9, 0xac, 0xbf, 0xea, 0xfe, 0x59, 0x7f, 0xf6, - 0x3f, 0x29, 0xc1, 0xf9, 0x9e, 0xa6, 0x5c, 0x7f, 0x0b, 0xf0, 0xe1, 0xcb, 0xd4, 0x3b, 0xdc, 0xdc, - 0x39, 0x60, 0x46, 0xd9, 0x1f, 0xf6, 0x98, 0x69, 0x22, 0xa3, 0xec, 0xf0, 0x29, 0xd9, 0x0f, 0xdf, - 0x78, 0x76, 0x25, 0x91, 0x55, 0x0e, 0x90, 0x44, 0x96, 0xf9, 0x18, 0xd5, 0x3e, 0x17, 0xf2, 0x9f, - 0x95, 0x7b, 0x0e, 0x2f, 0xdd, 0xfa, 0xf5, 0xe5, 0x1d, 0x9d, 0x81, 0x53, 0xae, 0xcf, 0x6e, 0x4d, - 0x5a, 0xee, 0xac, 0x8a, 0x72, 0x20, 0xa5, 0xf4, 0x9d, 0xe5, 0x73, 0x19, 0x38, 0xee, 0x7a, 0xe2, - 0x21, 0x4c, 0xea, 0x3b, 0xdc, 0x90, 0x1e, 0x2c, 0xad, 0x14, 0x2d, 0xc2, 0x39, 0x39, 0x14, 0xeb, - 0x4e, 0x44, 0x9a, 0x42, 0x8d, 0xc4, 0x22, 0x8d, 0xe1, 0x3c, 0x4f, 0x85, 0xc8, 0x41, 0xc0, 0xf9, - 0xcf, 0xb1, 0x8b, 0x6a, 0x82, 0xd0, 0x6d, 0x88, 0x4d, 0x8e, 0xbe, 0xa8, 0x86, 0x36, 0x62, 0x0e, - 0xb3, 0x3f, 0x02, 0x75, 0xf5, 0xfe, 0x3c, 0x98, 0x5a, 0x4d, 0xba, 0xae, 0x60, 0x6a, 0x35, 0xe3, - 0x0c, 0x2c, 0xfa, 0xb5, 0xa8, 0x49, 0x9c, 0x59, 0x3d, 0xd7, 0xc9, 0x36, 0xb3, 0x8f, 0xed, 0xf7, - 0xc0, 0xb0, 0xf2, 0xb3, 0xf4, 0x7b, 0x7d, 0x8f, 0xfd, 0xe5, 0x01, 0x38, 0x91, 0x2a, 0xc9, 0x97, - 0x72, 0x6b, 0x5a, 0xfb, 0xba, 0x35, 0x59, 0x70, 0x7c, 0xc7, 0x97, 0x77, 0x7b, 0x19, 0xc1, 0xf1, - 0x1d, 0x9f, 0x60, 0x0e, 0xa3, 0xe6, 0x6d, 0x33, 0xda, 0xc6, 0x1d, 0x5f, 0x04, 0xb1, 0x2a, 0xf3, - 0x76, 0x86, 0xb5, 0x62, 0x01, 0x45, 0x9f, 0xb4, 0x60, 0x38, 0x66, 0x3e, 0x73, 0xee, 0x14, 0x16, - 0x93, 0xee, 0xda, 0xd1, 0x2b, 0x0e, 0xaa, 0xf2, 0x93, 0x2c, 0x2e, 0xc5, 0x6c, 0xc1, 0x29, 0x8e, - 0xe8, 0x33, 0x16, 0xd4, 0xd5, 0x15, 0x24, 0xe2, 0x02, 0xbe, 0xe5, 0x62, 0x2b, 0x1e, 0x72, 0x6f, - 0xa2, 0x3a, 0x7e, 0x50, 0xa5, 0xe7, 0xb0, 0x66, 0x8c, 0x62, 0xe5, 0xb1, 0x1d, 0x3c, 0x1e, 0x8f, - 0x2d, 0xe4, 0x78, 0x6b, 0xdf, 0x0d, 0xf5, 0xb6, 0xe3, 0xbb, 0x6b, 0x24, 0x4e, 0xb8, 0x13, 0x55, - 0x16, 0x62, 0x95, 0x8d, 0x58, 0xc3, 0xa9, 0x42, 0x8e, 0xd9, 0x8b, 0x25, 0x86, 0xd7, 0x93, 0x29, - 0xe4, 0x65, 0xdd, 0x8c, 0x4d, 0x1c, 0xd3, 0x45, 0x0b, 0x0f, 0xd4, 0x45, 0x3b, 0xb4, 0x8f, 0x8b, - 0xf6, 0x1f, 0x5a, 0x70, 0x2e, 0xf7, 0xab, 0x3d, 0xbc, 0xe1, 0x86, 0xf6, 0x57, 0xaa, 0x70, 0x26, - 0xa7, 0xb6, 0x26, 0xda, 0x36, 0xe7, 0xb3, 0x55, 0xc4, 0xc9, 0x7d, 0xfa, 0x20, 0x5a, 0x0e, 0x63, - 0xce, 0x24, 0x3e, 0xd8, 0x01, 0x89, 0x3e, 0xa4, 0x28, 0xdf, 0xdf, 0x43, 0x0a, 0x63, 0x5a, 0x56, - 0x1e, 0xe8, 0xb4, 0xac, 0xee, 0x3d, 0x2d, 0xd1, 0xaf, 0x5a, 0x30, 0xda, 0xee, 0x51, 0xd0, 0x5d, - 0x38, 0x1e, 0x6f, 0x1d, 0x4f, 0xb9, 0xf8, 0xa9, 0xc7, 0x76, 0x77, 0xc6, 0x7a, 0xd6, 0xd1, 0xc7, - 0x3d, 0x7b, 0x65, 0x7f, 0xa7, 0x0c, 0xac, 0xb0, 0x2b, 0xab, 0x9f, 0xb6, 0x8d, 0x3e, 0x61, 0x96, - 0xe8, 0xb5, 0x8a, 0x2a, 0x27, 0xcb, 0x89, 0xab, 0x12, 0xbf, 0x7c, 0x04, 0xf3, 0x2a, 0xfe, 0x66, - 0x85, 0x56, 0xa9, 0x0f, 0xa1, 0xe5, 0xc9, 0x5a, 0xc8, 0xe5, 0xe2, 0x6b, 0x21, 0xd7, 0xb3, 0x75, - 0x90, 0xf7, 0xfe, 0xc4, 0x95, 0x87, 0xf2, 0x13, 0xff, 0x4d, 0x8b, 0x0b, 0x9e, 0xcc, 0x57, 0xd0, - 0x96, 0x81, 0xb5, 0x87, 0x65, 0xf0, 0x0c, 0xd4, 0x62, 0xe2, 0xad, 0x5d, 0x25, 0x8e, 0x27, 0x2c, - 0x08, 0x7d, 0x6a, 0x2c, 0xda, 0xb1, 0xc2, 0x60, 0x97, 0xa5, 0x7a, 0x5e, 0x70, 0xf7, 0x72, 0x3b, - 0x4c, 0xb6, 0x85, 0x2d, 0xa1, 0x2f, 0x4b, 0x55, 0x10, 0x6c, 0x60, 0xd9, 0x7f, 0xab, 0xc4, 0x67, - 0xa0, 0x08, 0x3d, 0x78, 0x31, 0x73, 0xbd, 0x5d, 0xff, 0xa7, 0xf6, 0x1f, 0x03, 0x68, 0xa8, 0x8b, - 0xe1, 0xc5, 0x99, 0xd0, 0xd5, 0x23, 0xdf, 0x5a, 0x2d, 0xe8, 0xe9, 0xd7, 0xd0, 0x6d, 0xd8, 0xe0, - 0x97, 0x92, 0xa5, 0xe5, 0x7d, 0x65, 0x69, 0x4a, 0xac, 0x54, 0xf6, 0xd1, 0x76, 0x7f, 0x62, 0x41, - 0xca, 0x22, 0x42, 0x21, 0x54, 0x69, 0x77, 0xb7, 0x8b, 0xb9, 0xf3, 0xde, 0x24, 0x4d, 0x45, 0xa3, - 0x98, 0xf6, 0xec, 0x27, 0xe6, 0x8c, 0x90, 0x27, 0x22, 0x14, 0xf8, 0xa8, 0xde, 0x28, 0x8e, 0xe1, - 0xd5, 0x20, 0xd8, 0xe0, 0x07, 0x9b, 0x3a, 0xda, 0xc1, 0x7e, 0x11, 0x4e, 0x77, 0x75, 0x8a, 0xdd, - 0x64, 0x15, 0xc8, 0x8b, 0xfe, 0x8d, 0xe9, 0xca, 0xd2, 0x26, 0x31, 0x87, 0xd9, 0xdf, 0xb0, 0xe0, - 0x54, 0x96, 0x3c, 0x7a, 0xcb, 0x82, 0xd3, 0x71, 0x96, 0xde, 0x71, 0x8d, 0x9d, 0x8a, 0x32, 0xec, - 0x02, 0xe1, 0xee, 0x4e, 0xd8, 0xff, 0x47, 0x4c, 0xfe, 0xdb, 0xae, 0xdf, 0x0c, 0xee, 0x2a, 0xc3, - 0xc4, 0xea, 0x69, 0x98, 0xd0, 0xf5, 0xd8, 0x58, 0x27, 0xcd, 0x8e, 0xd7, 0x95, 0xaf, 0xb9, 0x2c, - 0xda, 0xb1, 0xc2, 0x60, 0xe9, 0x69, 0x1d, 0x51, 0x2c, 0x3d, 0x33, 0x29, 0x67, 0x44, 0x3b, 0x56, - 0x18, 0xe8, 0x79, 0x18, 0x36, 0x5e, 0x52, 0xce, 0x4b, 0x66, 0x90, 0x1b, 0x2a, 0x33, 0xc6, 0x29, - 0x2c, 0x34, 0x0e, 0xa0, 0x8c, 0x1c, 0xa9, 0x22, 0x99, 0xa3, 0x48, 0x49, 0xa2, 0x18, 0x1b, 0x18, - 0x2c, 0x19, 0xd4, 0xeb, 0xc4, 0xcc, 0xc7, 0x3f, 0xa0, 0x0b, 0x78, 0x4e, 0x8b, 0x36, 0xac, 0xa0, - 0x54, 0x9a, 0xb4, 0x1d, 0xbf, 0xe3, 0x78, 0x74, 0x84, 0xc4, 0xd6, 0x4f, 0x2d, 0xc3, 0x05, 0x05, - 0xc1, 0x06, 0x16, 0x7d, 0xe3, 0xc4, 0x6d, 0x93, 0x57, 0x02, 0x5f, 0x46, 0x87, 0xe9, 0x63, 0x1f, - 0xd1, 0x8e, 0x15, 0x86, 0xfd, 0x5f, 0x2d, 0x38, 0xa9, 0x53, 0xcb, 0xf9, 0x9d, 0xd5, 0xe6, 0x4e, - 0xd5, 0xda, 0x77, 0xa7, 0x9a, 0xce, 0xb9, 0x2d, 0xf5, 0x95, 0x73, 0x6b, 0xa6, 0xc3, 0x96, 0xf7, - 0x4c, 0x87, 0xfd, 0x41, 0x7d, 0x1f, 0x2a, 0xcf, 0x9b, 0x1d, 0xca, 0xbb, 0x0b, 0x15, 0xd9, 0x30, - 0xd0, 0x70, 0x54, 0x5d, 0x95, 0x61, 0xbe, 0x77, 0x98, 0x9e, 0x64, 0x48, 0x02, 0x62, 0x2f, 0x42, - 0x5d, 0x9d, 0x7e, 0xc8, 0x8d, 0xaa, 0x95, 0xbf, 0x51, 0xed, 0x2b, 0x2d, 0x6f, 0x6a, 0xf5, 0x9b, - 0xdf, 0x7d, 0xe2, 0x1d, 0xbf, 0xfb, 0xdd, 0x27, 0xde, 0xf1, 0x07, 0xdf, 0x7d, 0xe2, 0x1d, 0x9f, - 0xdc, 0x7d, 0xc2, 0xfa, 0xe6, 0xee, 0x13, 0xd6, 0xef, 0xee, 0x3e, 0x61, 0xfd, 0xc1, 0xee, 0x13, - 0xd6, 0x77, 0x76, 0x9f, 0xb0, 0xbe, 0xf4, 0x9f, 0x9f, 0x78, 0xc7, 0x2b, 0xb9, 0xe1, 0x81, 0xf4, - 0xc7, 0xb3, 0x8d, 0xe6, 0xc4, 0xe6, 0x25, 0x16, 0xa1, 0x46, 0x97, 0xd7, 0x84, 0x31, 0xa7, 0x26, - 0xe4, 0xf2, 0xfa, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0xa1, 0x4f, 0x88, 0x2f, 0x3c, 0xe0, 0x00, - 0x00, + // 11006 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x7d, 0x6d, 0x70, 0x24, 0xc7, + 0x75, 0x98, 0x66, 0x17, 0x0b, 0xec, 0x3e, 0x7c, 0xdc, 0x5d, 0xdf, 0x1d, 0x09, 0x9e, 0x48, 0xe2, + 0x3c, 0x8c, 0x29, 0x2a, 0x22, 0x01, 0xf3, 0x44, 0xca, 0x8c, 0x68, 0x4b, 0xc6, 0x02, 0x77, 0x38, + 0xdc, 0x01, 0x07, 0xb0, 0x81, 0xbb, 0x93, 0x28, 0x53, 0xd4, 0x60, 0xb7, 0xb1, 0x98, 0xc3, 0xec, + 0xcc, 0x70, 0x66, 0x16, 0x07, 0xd0, 0x92, 0x2c, 0x59, 0xb2, 0xad, 0x44, 0x1f, 0x54, 0xa4, 0xa4, + 0x4c, 0x27, 0x96, 0x22, 0x5b, 0x4e, 0xca, 0xae, 0x44, 0x15, 0x27, 0xf9, 0x11, 0x27, 0x4e, 0xca, + 0x65, 0x3b, 0x95, 0x52, 0x4a, 0x49, 0xd9, 0xe5, 0x72, 0x59, 0x4e, 0x62, 0x23, 0xd2, 0xa5, 0x52, + 0x49, 0xa5, 0x2a, 0xae, 0x72, 0xe2, 0x1f, 0xc9, 0x25, 0x3f, 0x52, 0xfd, 0xdd, 0x33, 0x3b, 0x0b, + 0x2c, 0x80, 0xc1, 0xdd, 0x49, 0xe6, 0xbf, 0xdd, 0x7e, 0x6f, 0xde, 0xeb, 0xe9, 0xe9, 0x7e, 0xef, + 0xf5, 0xeb, 0xf7, 0x5e, 0xc3, 0x42, 0xcb, 0x4d, 0x36, 0x3a, 0x6b, 0x93, 0x8d, 0xa0, 0x3d, 0xe5, + 0x44, 0xad, 0x20, 0x8c, 0x82, 0x5b, 0xec, 0xc7, 0x33, 0x8d, 0xe6, 0xd4, 0xd6, 0x85, 0xa9, 0x70, + 0xb3, 0x35, 0xe5, 0x84, 0x6e, 0x3c, 0xe5, 0x84, 0xa1, 0xe7, 0x36, 0x9c, 0xc4, 0x0d, 0xfc, 0xa9, + 0xad, 0x67, 0x1d, 0x2f, 0xdc, 0x70, 0x9e, 0x9d, 0x6a, 0x11, 0x9f, 0x44, 0x4e, 0x42, 0x9a, 0x93, + 0x61, 0x14, 0x24, 0x01, 0xfa, 0x11, 0x4d, 0x6d, 0x52, 0x52, 0x63, 0x3f, 0x5e, 0x6d, 0x34, 0x27, + 0xb7, 0x2e, 0x4c, 0x86, 0x9b, 0xad, 0x49, 0x4a, 0x6d, 0xd2, 0xa0, 0x36, 0x29, 0xa9, 0x9d, 0x7b, + 0xc6, 0xe8, 0x4b, 0x2b, 0x68, 0x05, 0x53, 0x8c, 0xe8, 0x5a, 0x67, 0x9d, 0xfd, 0x63, 0x7f, 0xd8, + 0x2f, 0xce, 0xec, 0x9c, 0xbd, 0xf9, 0x42, 0x3c, 0xe9, 0x06, 0xb4, 0x7b, 0x53, 0x8d, 0x20, 0x22, + 0x53, 0x5b, 0x5d, 0x1d, 0x3a, 0x77, 0x59, 0xe3, 0x90, 0xed, 0x84, 0xf8, 0xb1, 0x1b, 0xf8, 0xf1, + 0x33, 0xb4, 0x0b, 0x24, 0xda, 0x22, 0x91, 0xf9, 0x7a, 0x06, 0x42, 0x1e, 0xa5, 0xe7, 0x34, 0xa5, + 0xb6, 0xd3, 0xd8, 0x70, 0x7d, 0x12, 0xed, 0xe8, 0xc7, 0xdb, 0x24, 0x71, 0xf2, 0x9e, 0x9a, 0xea, + 0xf5, 0x54, 0xd4, 0xf1, 0x13, 0xb7, 0x4d, 0xba, 0x1e, 0x78, 0xcf, 0x7e, 0x0f, 0xc4, 0x8d, 0x0d, + 0xd2, 0x76, 0xba, 0x9e, 0x7b, 0x77, 0xaf, 0xe7, 0x3a, 0x89, 0xeb, 0x4d, 0xb9, 0x7e, 0x12, 0x27, + 0x51, 0xf6, 0x21, 0xfb, 0x17, 0x2c, 0x18, 0x9d, 0xbe, 0xb9, 0x32, 0xdd, 0x49, 0x36, 0x66, 0x02, + 0x7f, 0xdd, 0x6d, 0xa1, 0xe7, 0x61, 0xb8, 0xe1, 0x75, 0xe2, 0x84, 0x44, 0xd7, 0x9c, 0x36, 0x19, + 0xb7, 0xce, 0x5b, 0x4f, 0xd5, 0xea, 0xa7, 0xbf, 0xb9, 0x3b, 0xf1, 0xb6, 0x3b, 0xbb, 0x13, 0xc3, + 0x33, 0x1a, 0x84, 0x4d, 0x3c, 0xf4, 0x4e, 0x18, 0x8a, 0x02, 0x8f, 0x4c, 0xe3, 0x6b, 0xe3, 0x25, + 0xf6, 0xc8, 0x09, 0xf1, 0xc8, 0x10, 0xe6, 0xcd, 0x58, 0xc2, 0x29, 0x6a, 0x18, 0x05, 0xeb, 0xae, + 0x47, 0xc6, 0xcb, 0x69, 0xd4, 0x65, 0xde, 0x8c, 0x25, 0xdc, 0xfe, 0xc3, 0x12, 0xc0, 0x74, 0x18, + 0x2e, 0x47, 0xc1, 0x2d, 0xd2, 0x48, 0xd0, 0x47, 0xa0, 0x4a, 0x87, 0xb9, 0xe9, 0x24, 0x0e, 0xeb, + 0xd8, 0xf0, 0x85, 0x1f, 0x9a, 0xe4, 0x6f, 0x3d, 0x69, 0xbe, 0xb5, 0x9e, 0x64, 0x14, 0x7b, 0x72, + 0xeb, 0xd9, 0xc9, 0xa5, 0x35, 0xfa, 0xfc, 0x22, 0x49, 0x9c, 0x3a, 0x12, 0xcc, 0x40, 0xb7, 0x61, + 0x45, 0x15, 0xf9, 0x30, 0x10, 0x87, 0xa4, 0xc1, 0xde, 0x61, 0xf8, 0xc2, 0xc2, 0xe4, 0x51, 0x66, + 0xf3, 0xa4, 0xee, 0xf9, 0x4a, 0x48, 0x1a, 0xf5, 0x11, 0xc1, 0x79, 0x80, 0xfe, 0xc3, 0x8c, 0x0f, + 0xda, 0x82, 0xc1, 0x38, 0x71, 0x92, 0x4e, 0xcc, 0x86, 0x62, 0xf8, 0xc2, 0xb5, 0xc2, 0x38, 0x32, + 0xaa, 0xf5, 0x31, 0xc1, 0x73, 0x90, 0xff, 0xc7, 0x82, 0x9b, 0xfd, 0x27, 0x16, 0x8c, 0x69, 0xe4, + 0x05, 0x37, 0x4e, 0xd0, 0x8f, 0x77, 0x0d, 0xee, 0x64, 0x7f, 0x83, 0x4b, 0x9f, 0x66, 0x43, 0x7b, + 0x52, 0x30, 0xab, 0xca, 0x16, 0x63, 0x60, 0xdb, 0x50, 0x71, 0x13, 0xd2, 0x8e, 0xc7, 0x4b, 0xe7, + 0xcb, 0x4f, 0x0d, 0x5f, 0xb8, 0x5c, 0xd4, 0x7b, 0xd6, 0x47, 0x05, 0xd3, 0xca, 0x3c, 0x25, 0x8f, + 0x39, 0x17, 0xfb, 0x57, 0x47, 0xcc, 0xf7, 0xa3, 0x03, 0x8e, 0x9e, 0x85, 0xe1, 0x38, 0xe8, 0x44, + 0x0d, 0x82, 0x49, 0x18, 0xc4, 0xe3, 0xd6, 0xf9, 0x32, 0x9d, 0x7a, 0x74, 0x52, 0xaf, 0xe8, 0x66, + 0x6c, 0xe2, 0xa0, 0x2f, 0x58, 0x30, 0xd2, 0x24, 0x71, 0xe2, 0xfa, 0x8c, 0xbf, 0xec, 0xfc, 0xea, + 0x91, 0x3b, 0x2f, 0x1b, 0x67, 0x35, 0xf1, 0xfa, 0x19, 0xf1, 0x22, 0x23, 0x46, 0x63, 0x8c, 0x53, + 0xfc, 0xe9, 0xe2, 0x6c, 0x92, 0xb8, 0x11, 0xb9, 0x21, 0xfd, 0x2f, 0x96, 0x8f, 0x5a, 0x9c, 0xb3, + 0x1a, 0x84, 0x4d, 0x3c, 0xe4, 0x43, 0x85, 0x2e, 0xbe, 0x78, 0x7c, 0x80, 0xf5, 0x7f, 0xfe, 0x68, + 0xfd, 0x17, 0x83, 0x4a, 0xd7, 0xb5, 0x1e, 0x7d, 0xfa, 0x2f, 0xc6, 0x9c, 0x0d, 0xfa, 0xbc, 0x05, + 0xe3, 0x42, 0x38, 0x60, 0xc2, 0x07, 0xf4, 0xe6, 0x86, 0x9b, 0x10, 0xcf, 0x8d, 0x93, 0xf1, 0x0a, + 0xeb, 0xc3, 0x54, 0x7f, 0x73, 0x6b, 0x2e, 0x0a, 0x3a, 0xe1, 0x55, 0xd7, 0x6f, 0xd6, 0xcf, 0x0b, + 0x4e, 0xe3, 0x33, 0x3d, 0x08, 0xe3, 0x9e, 0x2c, 0xd1, 0x97, 0x2d, 0x38, 0xe7, 0x3b, 0x6d, 0x12, + 0x87, 0x0e, 0xfd, 0xb4, 0x1c, 0x5c, 0xf7, 0x9c, 0xc6, 0x26, 0xeb, 0xd1, 0xe0, 0xe1, 0x7a, 0x64, + 0x8b, 0x1e, 0x9d, 0xbb, 0xd6, 0x93, 0x34, 0xde, 0x83, 0x2d, 0xfa, 0xba, 0x05, 0xa7, 0x82, 0x28, + 0xdc, 0x70, 0x7c, 0xd2, 0x94, 0xd0, 0x78, 0x7c, 0x88, 0x2d, 0xbd, 0x0f, 0x1f, 0xed, 0x13, 0x2d, + 0x65, 0xc9, 0x2e, 0x06, 0xbe, 0x9b, 0x04, 0xd1, 0x0a, 0x49, 0x12, 0xd7, 0x6f, 0xc5, 0xf5, 0xb3, + 0x77, 0x76, 0x27, 0x4e, 0x75, 0x61, 0xe1, 0xee, 0xfe, 0xa0, 0x9f, 0x80, 0xe1, 0x78, 0xc7, 0x6f, + 0xdc, 0x74, 0xfd, 0x66, 0x70, 0x3b, 0x1e, 0xaf, 0x16, 0xb1, 0x7c, 0x57, 0x14, 0x41, 0xb1, 0x00, + 0x35, 0x03, 0x6c, 0x72, 0xcb, 0xff, 0x70, 0x7a, 0x2a, 0xd5, 0x8a, 0xfe, 0x70, 0x7a, 0x32, 0xed, + 0xc1, 0x16, 0xfd, 0xac, 0x05, 0xa3, 0xb1, 0xdb, 0xf2, 0x9d, 0xa4, 0x13, 0x91, 0xab, 0x64, 0x27, + 0x1e, 0x07, 0xd6, 0x91, 0x2b, 0x47, 0x1c, 0x15, 0x83, 0x64, 0xfd, 0xac, 0xe8, 0xe3, 0xa8, 0xd9, + 0x1a, 0xe3, 0x34, 0xdf, 0xbc, 0x85, 0xa6, 0xa7, 0xf5, 0x70, 0xb1, 0x0b, 0x4d, 0x4f, 0xea, 0x9e, + 0x2c, 0xd1, 0x8f, 0xc1, 0x49, 0xde, 0xa4, 0x46, 0x36, 0x1e, 0x1f, 0x61, 0x82, 0xf6, 0xcc, 0x9d, + 0xdd, 0x89, 0x93, 0x2b, 0x19, 0x18, 0xee, 0xc2, 0x46, 0xaf, 0xc1, 0x44, 0x48, 0xa2, 0xb6, 0x9b, + 0x2c, 0xf9, 0xde, 0x8e, 0x14, 0xdf, 0x8d, 0x20, 0x24, 0x4d, 0xd1, 0x9d, 0x78, 0x7c, 0xf4, 0xbc, + 0xf5, 0x54, 0xb5, 0xfe, 0x0e, 0xd1, 0xcd, 0x89, 0xe5, 0xbd, 0xd1, 0xf1, 0x7e, 0xf4, 0xec, 0x7f, + 0x53, 0x82, 0x93, 0x59, 0xc5, 0x89, 0xfe, 0x9e, 0x05, 0x27, 0x6e, 0xdd, 0x4e, 0x56, 0x83, 0x4d, + 0xe2, 0xc7, 0xf5, 0x1d, 0x2a, 0xde, 0x98, 0xca, 0x18, 0xbe, 0xd0, 0x28, 0x56, 0x45, 0x4f, 0x5e, + 0x49, 0x73, 0xb9, 0xe8, 0x27, 0xd1, 0x4e, 0xfd, 0x61, 0xf1, 0x76, 0x27, 0xae, 0xdc, 0x5c, 0x35, + 0xa1, 0x38, 0xdb, 0xa9, 0x73, 0x9f, 0xb5, 0xe0, 0x4c, 0x1e, 0x09, 0x74, 0x12, 0xca, 0x9b, 0x64, + 0x87, 0x1b, 0x70, 0x98, 0xfe, 0x44, 0xaf, 0x40, 0x65, 0xcb, 0xf1, 0x3a, 0x44, 0x58, 0x37, 0x73, + 0x47, 0x7b, 0x11, 0xd5, 0x33, 0xcc, 0xa9, 0xbe, 0xb7, 0xf4, 0x82, 0x65, 0xff, 0x6e, 0x19, 0x86, + 0x0d, 0xfd, 0x76, 0x0f, 0x2c, 0xb6, 0x20, 0x65, 0xb1, 0x2d, 0x16, 0xa6, 0x9a, 0x7b, 0x9a, 0x6c, + 0xb7, 0x33, 0x26, 0xdb, 0x52, 0x71, 0x2c, 0xf7, 0xb4, 0xd9, 0x50, 0x02, 0xb5, 0x20, 0xa4, 0xd6, + 0x3b, 0x55, 0xfd, 0x03, 0x45, 0x7c, 0xc2, 0x25, 0x49, 0xae, 0x3e, 0x7a, 0x67, 0x77, 0xa2, 0xa6, + 0xfe, 0x62, 0xcd, 0xc8, 0xfe, 0xb6, 0x05, 0x67, 0x8c, 0x3e, 0xce, 0x04, 0x7e, 0xd3, 0x65, 0x9f, + 0xf6, 0x3c, 0x0c, 0x24, 0x3b, 0xa1, 0xdc, 0x21, 0xa8, 0x91, 0x5a, 0xdd, 0x09, 0x09, 0x66, 0x10, + 0x6a, 0xe8, 0xb7, 0x49, 0x1c, 0x3b, 0x2d, 0x92, 0xdd, 0x13, 0x2c, 0xf2, 0x66, 0x2c, 0xe1, 0x28, + 0x02, 0xe4, 0x39, 0x71, 0xb2, 0x1a, 0x39, 0x7e, 0xcc, 0xc8, 0xaf, 0xba, 0x6d, 0x22, 0x06, 0xf8, + 0x2f, 0xf7, 0x37, 0x63, 0xe8, 0x13, 0xf5, 0x87, 0xee, 0xec, 0x4e, 0xa0, 0x85, 0x2e, 0x4a, 0x38, + 0x87, 0xba, 0xfd, 0x65, 0x0b, 0x1e, 0xca, 0xb7, 0xc5, 0xd0, 0x93, 0x30, 0xc8, 0xb7, 0x87, 0xe2, + 0xed, 0xf4, 0x27, 0x61, 0xad, 0x58, 0x40, 0xd1, 0x14, 0xd4, 0x94, 0x9e, 0x10, 0xef, 0x78, 0x4a, + 0xa0, 0xd6, 0xb4, 0x72, 0xd1, 0x38, 0x74, 0xd0, 0xe8, 0x1f, 0x61, 0xb9, 0xa9, 0x41, 0x63, 0xfb, + 0x29, 0x06, 0xb1, 0xff, 0x93, 0x05, 0x27, 0x8c, 0x5e, 0xdd, 0x03, 0xd3, 0xdc, 0x4f, 0x9b, 0xe6, + 0xf3, 0x85, 0xcd, 0xe7, 0x1e, 0xb6, 0xf9, 0xe7, 0x2d, 0x38, 0x67, 0x60, 0x2d, 0x3a, 0x49, 0x63, + 0xe3, 0xe2, 0x76, 0x18, 0x91, 0x98, 0x6e, 0xbd, 0xd1, 0x63, 0x86, 0xdc, 0xaa, 0x0f, 0x0b, 0x0a, + 0xe5, 0xab, 0x64, 0x87, 0x0b, 0xb1, 0xa7, 0xa1, 0xca, 0x27, 0x67, 0x10, 0x89, 0x11, 0x57, 0xef, + 0xb6, 0x24, 0xda, 0xb1, 0xc2, 0x40, 0x36, 0x0c, 0x32, 0xe1, 0x44, 0x17, 0x2b, 0x55, 0x43, 0x40, + 0x3f, 0xe2, 0x0d, 0xd6, 0x82, 0x05, 0xc4, 0x8e, 0x53, 0xdd, 0x59, 0x8e, 0x08, 0xfb, 0xb8, 0xcd, + 0x4b, 0x2e, 0xf1, 0x9a, 0x31, 0xdd, 0x36, 0x38, 0xbe, 0x1f, 0x24, 0x62, 0x07, 0x60, 0x6c, 0x1b, + 0xa6, 0x75, 0x33, 0x36, 0x71, 0x28, 0x53, 0xcf, 0x59, 0x23, 0x1e, 0x1f, 0x51, 0xc1, 0x74, 0x81, + 0xb5, 0x60, 0x01, 0xb1, 0xef, 0x94, 0xd8, 0x06, 0x45, 0x2d, 0x7d, 0x72, 0x2f, 0x76, 0xb7, 0x51, + 0x4a, 0x56, 0x2e, 0x17, 0x27, 0xb8, 0x48, 0xef, 0x1d, 0xee, 0xeb, 0x19, 0x71, 0x89, 0x0b, 0xe5, + 0xba, 0xf7, 0x2e, 0xf7, 0xb7, 0x4a, 0x30, 0x91, 0x7e, 0xa0, 0x4b, 0xda, 0xd2, 0x2d, 0x95, 0xc1, + 0x28, 0xeb, 0xef, 0x30, 0xf0, 0xb1, 0x89, 0xd7, 0x43, 0x60, 0x95, 0x8e, 0x53, 0x60, 0x99, 0xf2, + 0xb4, 0xbc, 0x8f, 0x3c, 0x7d, 0x52, 0x8d, 0xfa, 0x40, 0x46, 0x80, 0xa5, 0x75, 0xca, 0x79, 0x18, + 0x88, 0x13, 0x12, 0x8e, 0x57, 0xd2, 0xf2, 0x68, 0x25, 0x21, 0x21, 0x66, 0x10, 0xfb, 0xbf, 0x97, + 0xe0, 0xe1, 0xf4, 0x18, 0x6a, 0x15, 0xf0, 0xfe, 0x94, 0x0a, 0x78, 0x97, 0xa9, 0x02, 0xee, 0xee, + 0x4e, 0xbc, 0xbd, 0xc7, 0x63, 0xdf, 0x33, 0x1a, 0x02, 0xcd, 0x65, 0x46, 0x71, 0x2a, 0x3d, 0x8a, + 0x77, 0x77, 0x27, 0x1e, 0xeb, 0xf1, 0x8e, 0x99, 0x61, 0x7e, 0x12, 0x06, 0x23, 0xe2, 0xc4, 0x81, + 0x2f, 0x06, 0x5a, 0x7d, 0x0e, 0xcc, 0x5a, 0xb1, 0x80, 0xda, 0xbf, 0x5f, 0xcb, 0x0e, 0xf6, 0x1c, + 0x77, 0xd8, 0x05, 0x11, 0x72, 0x61, 0x80, 0x99, 0xf5, 0x5c, 0x34, 0x5c, 0x3d, 0xda, 0x32, 0xa2, + 0x6a, 0x40, 0x91, 0xae, 0x57, 0xe9, 0x57, 0xa3, 0x4d, 0x98, 0xb1, 0x40, 0xdb, 0x50, 0x6d, 0x48, + 0x6b, 0xbb, 0x54, 0x84, 0x5f, 0x4a, 0xd8, 0xda, 0x9a, 0xe3, 0x08, 0x95, 0xd7, 0xca, 0x44, 0x57, + 0xdc, 0x10, 0x81, 0x72, 0xcb, 0x4d, 0xc4, 0x67, 0x3d, 0xe2, 0x7e, 0x6a, 0xce, 0x35, 0x5e, 0x71, + 0x88, 0x2a, 0x91, 0x39, 0x37, 0xc1, 0x94, 0x3e, 0xfa, 0x69, 0x0b, 0x86, 0xe3, 0x46, 0x7b, 0x39, + 0x0a, 0xb6, 0xdc, 0x26, 0x89, 0x84, 0x35, 0x75, 0x44, 0xd1, 0xb4, 0x32, 0xb3, 0x28, 0x09, 0x6a, + 0xbe, 0x7c, 0x7f, 0xab, 0x21, 0xd8, 0xe4, 0x4b, 0x77, 0x19, 0x0f, 0x8b, 0x77, 0x9f, 0x25, 0x0d, + 0x97, 0xea, 0x3f, 0xb9, 0xa9, 0x62, 0x33, 0xe5, 0xc8, 0xd6, 0xe5, 0x6c, 0xa7, 0xb1, 0x49, 0xd7, + 0x9b, 0xee, 0xd0, 0xdb, 0xef, 0xec, 0x4e, 0x3c, 0x3c, 0x93, 0xcf, 0x13, 0xf7, 0xea, 0x0c, 0x1b, + 0xb0, 0xb0, 0xe3, 0x79, 0x98, 0xbc, 0xd6, 0x21, 0xcc, 0x65, 0x52, 0xc0, 0x80, 0x2d, 0x6b, 0x82, + 0x99, 0x01, 0x33, 0x20, 0xd8, 0xe4, 0x8b, 0x5e, 0x83, 0xc1, 0xb6, 0x93, 0x44, 0xee, 0xb6, 0xf0, + 0x93, 0x1c, 0xd1, 0xde, 0x5f, 0x64, 0xb4, 0x34, 0x73, 0xa6, 0xa9, 0x79, 0x23, 0x16, 0x8c, 0x50, + 0x1b, 0x2a, 0x6d, 0x12, 0xb5, 0xc8, 0x78, 0xb5, 0x08, 0x9f, 0xf0, 0x22, 0x25, 0xa5, 0x19, 0xd6, + 0xa8, 0x75, 0xc4, 0xda, 0x30, 0xe7, 0x82, 0x5e, 0x81, 0x6a, 0x4c, 0x3c, 0xd2, 0xa0, 0xf6, 0x4d, + 0x8d, 0x71, 0x7c, 0x77, 0x9f, 0xb6, 0x1e, 0x35, 0x2c, 0x56, 0xc4, 0xa3, 0x7c, 0x81, 0xc9, 0x7f, + 0x58, 0x91, 0xa4, 0x03, 0x18, 0x7a, 0x9d, 0x96, 0xeb, 0x8f, 0x43, 0x11, 0x03, 0xb8, 0xcc, 0x68, + 0x65, 0x06, 0x90, 0x37, 0x62, 0xc1, 0xc8, 0xfe, 0x2f, 0x16, 0xa0, 0xb4, 0x50, 0xbb, 0x07, 0x46, + 0xed, 0x6b, 0x69, 0xa3, 0x76, 0xa1, 0x48, 0xab, 0xa3, 0x87, 0x5d, 0xfb, 0x1b, 0x35, 0xc8, 0xa8, + 0x83, 0x6b, 0x24, 0x4e, 0x48, 0xf3, 0x2d, 0x11, 0xfe, 0x96, 0x08, 0x7f, 0x4b, 0x84, 0x2b, 0x11, + 0xbe, 0x96, 0x11, 0xe1, 0xef, 0x33, 0x56, 0xbd, 0x3e, 0x80, 0x7d, 0x55, 0x9d, 0xd0, 0x9a, 0x3d, + 0x30, 0x10, 0xa8, 0x24, 0xb8, 0xb2, 0xb2, 0x74, 0x2d, 0x57, 0x66, 0xbf, 0x9a, 0x96, 0xd9, 0x47, + 0x65, 0xf1, 0x17, 0x41, 0x4a, 0xff, 0x6b, 0x0b, 0xde, 0x91, 0x96, 0x5e, 0x72, 0xe6, 0xcc, 0xb7, + 0xfc, 0x20, 0x22, 0xb3, 0xee, 0xfa, 0x3a, 0x89, 0x88, 0xdf, 0x20, 0xb1, 0xf2, 0x62, 0x58, 0xbd, + 0xbc, 0x18, 0xe8, 0x39, 0x18, 0xb9, 0x15, 0x07, 0xfe, 0x72, 0xe0, 0xfa, 0x42, 0x04, 0xd1, 0x8d, + 0xf0, 0xc9, 0x3b, 0xbb, 0x13, 0x23, 0x74, 0x44, 0x65, 0x3b, 0x4e, 0x61, 0xa1, 0x19, 0x38, 0x75, + 0xeb, 0xb5, 0x65, 0x27, 0x31, 0xdc, 0x01, 0x72, 0xe3, 0xce, 0x0e, 0x2c, 0xae, 0xbc, 0x94, 0x01, + 0xe2, 0x6e, 0x7c, 0xfb, 0x6f, 0x97, 0xe0, 0x91, 0xcc, 0x8b, 0x04, 0x9e, 0x17, 0x74, 0x12, 0xba, + 0xa9, 0x41, 0x5f, 0xb5, 0xe0, 0x64, 0x3b, 0xed, 0x71, 0x88, 0x85, 0x63, 0xf7, 0x03, 0x85, 0xe9, + 0x88, 0x8c, 0x4b, 0xa3, 0x3e, 0x2e, 0x46, 0xe8, 0x64, 0x06, 0x10, 0xe3, 0xae, 0xbe, 0xa0, 0x57, + 0xa0, 0xd6, 0x76, 0xb6, 0xaf, 0x87, 0x4d, 0x27, 0x91, 0xfb, 0xc9, 0xde, 0x6e, 0x80, 0x4e, 0xe2, + 0x7a, 0x93, 0xfc, 0x68, 0x7f, 0x72, 0xde, 0x4f, 0x96, 0xa2, 0x95, 0x24, 0x72, 0xfd, 0x16, 0x77, + 0xe7, 0x2d, 0x4a, 0x32, 0x58, 0x53, 0xb4, 0xbf, 0x62, 0x65, 0x95, 0x94, 0x1a, 0x9d, 0xc8, 0x49, + 0x48, 0x6b, 0x07, 0x7d, 0x14, 0x2a, 0x74, 0xe3, 0x27, 0x47, 0xe5, 0x66, 0x91, 0x9a, 0xd3, 0xf8, + 0x12, 0x5a, 0x89, 0xd2, 0x7f, 0x31, 0xe6, 0x4c, 0xed, 0xaf, 0xd6, 0xb2, 0xc6, 0x02, 0x3b, 0xbc, + 0xbd, 0x00, 0xd0, 0x0a, 0x56, 0x49, 0x3b, 0xf4, 0xe8, 0xb0, 0x58, 0xec, 0x04, 0x40, 0xf9, 0x3a, + 0xe6, 0x14, 0x04, 0x1b, 0x58, 0xe8, 0xaf, 0x5a, 0x00, 0x2d, 0x39, 0xe7, 0xa5, 0x21, 0x70, 0xbd, + 0xc8, 0xd7, 0xd1, 0x2b, 0x4a, 0xf7, 0x45, 0x31, 0xc4, 0x06, 0x73, 0xf4, 0x53, 0x16, 0x54, 0x13, + 0xd9, 0x7d, 0xae, 0x1a, 0x57, 0x8b, 0xec, 0x89, 0x7c, 0x69, 0x6d, 0x13, 0xa9, 0x21, 0x51, 0x7c, + 0xd1, 0xcf, 0x58, 0x00, 0xf1, 0x8e, 0xdf, 0x58, 0x0e, 0x3c, 0xb7, 0xb1, 0x23, 0x34, 0xe6, 0x8d, + 0x42, 0xfd, 0x31, 0x8a, 0x7a, 0x7d, 0x8c, 0x8e, 0x86, 0xfe, 0x8f, 0x0d, 0xce, 0xe8, 0xe3, 0x50, + 0x8d, 0xc5, 0x74, 0x13, 0x3a, 0x72, 0xb5, 0x58, 0xaf, 0x10, 0xa7, 0x2d, 0xc4, 0xab, 0xf8, 0x87, + 0x15, 0x4f, 0xf4, 0x73, 0x16, 0x9c, 0x08, 0xd3, 0x7e, 0x3e, 0xa1, 0x0e, 0x8b, 0x93, 0x01, 0x19, + 0x3f, 0x62, 0xfd, 0xf4, 0x9d, 0xdd, 0x89, 0x13, 0x99, 0x46, 0x9c, 0xed, 0x05, 0x95, 0x80, 0x7a, + 0x06, 0x2f, 0x85, 0xdc, 0xe7, 0x38, 0xa4, 0x25, 0xe0, 0x5c, 0x16, 0x88, 0xbb, 0xf1, 0xd1, 0x32, + 0x9c, 0xa1, 0xbd, 0xdb, 0xe1, 0xe6, 0xa7, 0x54, 0x2f, 0x31, 0x53, 0x86, 0xd5, 0xfa, 0xa3, 0x62, + 0x86, 0x30, 0xaf, 0x7e, 0x16, 0x07, 0xe7, 0x3e, 0x89, 0x7e, 0xd7, 0x82, 0x47, 0x5d, 0xa6, 0x06, + 0x4c, 0x87, 0xb9, 0xd6, 0x08, 0xe2, 0x24, 0x96, 0x14, 0x2a, 0x2b, 0x7a, 0xa9, 0x9f, 0xfa, 0x5f, + 0x12, 0x6f, 0xf0, 0xe8, 0xfc, 0x1e, 0x5d, 0xc2, 0x7b, 0x76, 0x18, 0xfd, 0x30, 0x8c, 0xca, 0x75, + 0xb1, 0x4c, 0x45, 0x30, 0x53, 0xb4, 0xb5, 0xfa, 0xa9, 0x3b, 0xbb, 0x13, 0xa3, 0xab, 0x26, 0x00, + 0xa7, 0xf1, 0xec, 0x6f, 0x95, 0x52, 0xe7, 0x21, 0xca, 0x09, 0xc9, 0xc4, 0x4d, 0x43, 0xfa, 0x7f, + 0xa4, 0xf4, 0x2c, 0x54, 0xdc, 0x28, 0xef, 0x92, 0x16, 0x37, 0xaa, 0x29, 0xc6, 0x06, 0x73, 0x6a, + 0x94, 0x9e, 0x72, 0xb2, 0xae, 0x4e, 0x21, 0x01, 0x5f, 0x29, 0xb2, 0x4b, 0xdd, 0xa7, 0x57, 0x8f, + 0x88, 0xae, 0x9d, 0xea, 0x02, 0xe1, 0xee, 0x2e, 0xd9, 0xdf, 0x4a, 0x9f, 0xc1, 0x18, 0x8b, 0xb7, + 0x8f, 0xf3, 0xa5, 0x2f, 0x58, 0x30, 0x1c, 0x05, 0x9e, 0xe7, 0xfa, 0x2d, 0x2a, 0x68, 0x84, 0xb6, + 0xfc, 0xd0, 0xb1, 0x28, 0x2c, 0x21, 0x51, 0x98, 0x69, 0x8b, 0x35, 0x4f, 0x6c, 0x76, 0xc0, 0xfe, + 0x13, 0x0b, 0xc6, 0x7b, 0x09, 0x44, 0x44, 0xe0, 0xed, 0x72, 0xb5, 0xab, 0xe8, 0x8a, 0x25, 0x7f, + 0x96, 0x78, 0x44, 0x39, 0x9e, 0xab, 0xf5, 0x27, 0xc4, 0x6b, 0xbe, 0x7d, 0xb9, 0x37, 0x2a, 0xde, + 0x8b, 0x0e, 0x7a, 0x19, 0x4e, 0x1a, 0xef, 0x15, 0xab, 0x81, 0xa9, 0xd5, 0x27, 0xa9, 0x05, 0x32, + 0x9d, 0x81, 0xdd, 0xdd, 0x9d, 0x78, 0x28, 0xdb, 0x26, 0x24, 0x76, 0x17, 0x1d, 0xfb, 0x97, 0x4b, + 0xd9, 0xaf, 0xa5, 0x94, 0xed, 0x9b, 0x56, 0xd7, 0x76, 0xfe, 0x03, 0xc7, 0xa1, 0xe0, 0xd8, 0xc6, + 0x5f, 0x05, 0x70, 0xf4, 0xc6, 0xb9, 0x8f, 0x27, 0xc4, 0xf6, 0xbf, 0x1d, 0x80, 0x3d, 0x7a, 0xd6, + 0x87, 0xf5, 0x7c, 0xe0, 0x63, 0xc5, 0xcf, 0x59, 0xea, 0xc8, 0xa9, 0xcc, 0x16, 0x79, 0xf3, 0xb8, + 0xc6, 0x9e, 0x6f, 0x60, 0x62, 0x1e, 0xa5, 0xa0, 0xdc, 0xd8, 0xe9, 0xc3, 0x2d, 0xf4, 0x35, 0x2b, + 0x7d, 0x68, 0xc6, 0xc3, 0xce, 0xdc, 0x63, 0xeb, 0x93, 0x71, 0x12, 0xc7, 0x3b, 0xa6, 0xcf, 0x6f, + 0x7a, 0x9d, 0xd1, 0x4d, 0x02, 0xac, 0xbb, 0xbe, 0xe3, 0xb9, 0xaf, 0xd3, 0xed, 0x49, 0x85, 0x69, + 0x58, 0x66, 0xb2, 0x5c, 0x52, 0xad, 0xd8, 0xc0, 0x38, 0xf7, 0x57, 0x60, 0xd8, 0x78, 0xf3, 0x9c, + 0xe0, 0x8a, 0x33, 0x66, 0x70, 0x45, 0xcd, 0x88, 0x89, 0x38, 0xf7, 0x3e, 0x38, 0x99, 0xed, 0xe0, + 0x41, 0x9e, 0xb7, 0xff, 0xf7, 0x50, 0xf6, 0x14, 0x6b, 0x95, 0x44, 0x6d, 0xda, 0xb5, 0xb7, 0x3c, + 0x4b, 0x6f, 0x79, 0x96, 0xde, 0xf2, 0x2c, 0x99, 0x87, 0x03, 0xc2, 0x6b, 0x32, 0x74, 0x8f, 0xbc, + 0x26, 0x29, 0x3f, 0x50, 0xb5, 0x70, 0x3f, 0x90, 0x7d, 0xa7, 0x02, 0x29, 0x3b, 0x8a, 0x8f, 0xf7, + 0x3b, 0x61, 0x28, 0x22, 0x61, 0x70, 0x1d, 0x2f, 0x08, 0x1d, 0xa2, 0x63, 0xed, 0x79, 0x33, 0x96, + 0x70, 0xaa, 0x6b, 0x42, 0x27, 0xd9, 0x10, 0x4a, 0x44, 0xe9, 0x9a, 0x65, 0x27, 0xd9, 0xc0, 0x0c, + 0x82, 0xde, 0x07, 0x63, 0x89, 0x13, 0xb5, 0xa8, 0xbd, 0xbd, 0xc5, 0x3e, 0xab, 0x38, 0xeb, 0x7c, + 0x48, 0xe0, 0x8e, 0xad, 0xa6, 0xa0, 0x38, 0x83, 0x8d, 0x5e, 0x83, 0x81, 0x0d, 0xe2, 0xb5, 0xc5, + 0x90, 0xaf, 0x14, 0x27, 0xe3, 0xd9, 0xbb, 0x5e, 0x26, 0x5e, 0x9b, 0x4b, 0x20, 0xfa, 0x0b, 0x33, + 0x56, 0x74, 0xbe, 0xd5, 0x36, 0x3b, 0x71, 0x12, 0xb4, 0xdd, 0xd7, 0xa5, 0x8b, 0xef, 0x03, 0x05, + 0x33, 0xbe, 0x2a, 0xe9, 0x73, 0x5f, 0x8a, 0xfa, 0x8b, 0x35, 0x67, 0xd6, 0x8f, 0xa6, 0x1b, 0xb1, + 0x4f, 0xb5, 0x23, 0x3c, 0x75, 0x45, 0xf7, 0x63, 0x56, 0xd2, 0xe7, 0xfd, 0x50, 0x7f, 0xb1, 0xe6, + 0x8c, 0x76, 0xd4, 0xbc, 0x1f, 0x66, 0x7d, 0xb8, 0x5e, 0x70, 0x1f, 0xf8, 0x9c, 0xcf, 0x9d, 0xff, + 0x4f, 0x40, 0xa5, 0xb1, 0xe1, 0x44, 0xc9, 0xf8, 0x08, 0x9b, 0x34, 0xca, 0xa7, 0x33, 0x43, 0x1b, + 0x31, 0x87, 0xa1, 0xc7, 0xa0, 0x1c, 0x91, 0x75, 0x16, 0xb7, 0x69, 0x44, 0xf4, 0x60, 0xb2, 0x8e, + 0x69, 0xbb, 0xfd, 0x8b, 0xa5, 0xb4, 0xb9, 0x94, 0x7e, 0x6f, 0x3e, 0xdb, 0x1b, 0x9d, 0x28, 0x96, + 0x7e, 0x1f, 0x63, 0xb6, 0xb3, 0x66, 0x2c, 0xe1, 0xe8, 0x93, 0x16, 0x0c, 0xdd, 0x8a, 0x03, 0xdf, + 0x27, 0x89, 0x50, 0x4d, 0x37, 0x0a, 0x1e, 0x8a, 0x2b, 0x9c, 0xba, 0xee, 0x83, 0x68, 0xc0, 0x92, + 0x2f, 0xed, 0x2e, 0xd9, 0x6e, 0x78, 0x9d, 0x66, 0x57, 0x90, 0xc6, 0x45, 0xde, 0x8c, 0x25, 0x9c, + 0xa2, 0xba, 0x3e, 0x47, 0x1d, 0x48, 0xa3, 0xce, 0xfb, 0x02, 0x55, 0xc0, 0xed, 0xbf, 0x39, 0x08, + 0x67, 0x73, 0x17, 0x07, 0x35, 0x64, 0x98, 0xa9, 0x70, 0xc9, 0xf5, 0x88, 0x0c, 0x4f, 0x62, 0x86, + 0xcc, 0x0d, 0xd5, 0x8a, 0x0d, 0x0c, 0xf4, 0x93, 0x00, 0xa1, 0x13, 0x39, 0x6d, 0xa2, 0xfc, 0xb2, + 0x47, 0xb6, 0x17, 0x68, 0x3f, 0x96, 0x25, 0x4d, 0xbd, 0x37, 0x55, 0x4d, 0x31, 0x36, 0x58, 0xa2, + 0xe7, 0x61, 0x38, 0x22, 0x1e, 0x71, 0x62, 0x16, 0xf6, 0x9b, 0xcd, 0x61, 0xc0, 0x1a, 0x84, 0x4d, + 0x3c, 0xf4, 0xa4, 0x8a, 0xe4, 0xca, 0x44, 0xb4, 0xa4, 0xa3, 0xb9, 0xd0, 0x1b, 0x16, 0x8c, 0xad, + 0xbb, 0x1e, 0xd1, 0xdc, 0x45, 0xc6, 0xc1, 0xd2, 0xd1, 0x5f, 0xf2, 0x92, 0x49, 0x57, 0x4b, 0xc8, + 0x54, 0x73, 0x8c, 0x33, 0xec, 0xe9, 0x67, 0xde, 0x22, 0x11, 0x13, 0xad, 0x83, 0xe9, 0xcf, 0x7c, + 0x83, 0x37, 0x63, 0x09, 0x47, 0xd3, 0x70, 0x22, 0x74, 0xe2, 0x78, 0x26, 0x22, 0x4d, 0xe2, 0x27, + 0xae, 0xe3, 0xf1, 0x7c, 0x80, 0xaa, 0x8e, 0x07, 0x5e, 0x4e, 0x83, 0x71, 0x16, 0x1f, 0x7d, 0x10, + 0x1e, 0xe6, 0x8e, 0x8f, 0x45, 0x37, 0x8e, 0x5d, 0xbf, 0xa5, 0xa7, 0x81, 0xf0, 0xff, 0x4c, 0x08, + 0x52, 0x0f, 0xcf, 0xe7, 0xa3, 0xe1, 0x5e, 0xcf, 0xa3, 0xa7, 0xa1, 0x1a, 0x6f, 0xba, 0xe1, 0x4c, + 0xd4, 0x8c, 0xd9, 0xa1, 0x47, 0x55, 0x7b, 0x1b, 0x57, 0x44, 0x3b, 0x56, 0x18, 0xa8, 0x01, 0x23, + 0xfc, 0x93, 0xf0, 0x50, 0x34, 0x21, 0x1f, 0x9f, 0xe9, 0xa9, 0x1e, 0x45, 0x7a, 0xdb, 0x24, 0x76, + 0x6e, 0x5f, 0x94, 0x47, 0x30, 0xfc, 0xc4, 0xe0, 0x86, 0x41, 0x06, 0xa7, 0x88, 0xda, 0x3f, 0x5f, + 0x4a, 0xef, 0xb8, 0xcd, 0x45, 0x8a, 0x62, 0xba, 0x14, 0x93, 0x1b, 0x4e, 0x24, 0xbd, 0x31, 0x47, + 0x4c, 0x5b, 0x10, 0x74, 0x6f, 0x38, 0x91, 0xb9, 0xa8, 0x19, 0x03, 0x2c, 0x39, 0xa1, 0x5b, 0x30, + 0x90, 0x78, 0x4e, 0x41, 0x79, 0x4e, 0x06, 0x47, 0xed, 0x00, 0x59, 0x98, 0x8e, 0x31, 0xe3, 0x81, + 0x1e, 0xa5, 0x56, 0xff, 0x9a, 0x3c, 0x22, 0x11, 0x86, 0xfa, 0x5a, 0x8c, 0x59, 0xab, 0xfd, 0x2b, + 0x90, 0x23, 0x57, 0x95, 0x22, 0x43, 0x17, 0x00, 0xe8, 0x06, 0x72, 0x39, 0x22, 0xeb, 0xee, 0xb6, + 0x30, 0x24, 0xd4, 0xda, 0xbd, 0xa6, 0x20, 0xd8, 0xc0, 0x92, 0xcf, 0xac, 0x74, 0xd6, 0xe9, 0x33, + 0xa5, 0xee, 0x67, 0x38, 0x04, 0x1b, 0x58, 0xe8, 0x39, 0x18, 0x74, 0xdb, 0x4e, 0x4b, 0x85, 0x60, + 0x3e, 0x4a, 0x17, 0xed, 0x3c, 0x6b, 0xb9, 0xbb, 0x3b, 0x31, 0xa6, 0x3a, 0xc4, 0x9a, 0xb0, 0xc0, + 0x45, 0xbf, 0x6c, 0xc1, 0x48, 0x23, 0x68, 0xb7, 0x03, 0x9f, 0x6f, 0xbb, 0xc4, 0x1e, 0xf2, 0xd6, + 0x71, 0xa9, 0xf9, 0xc9, 0x19, 0x83, 0x19, 0xdf, 0x44, 0xaa, 0x84, 0x2c, 0x13, 0x84, 0x53, 0xbd, + 0x32, 0xd7, 0x76, 0x65, 0x9f, 0xb5, 0xfd, 0xeb, 0x16, 0x9c, 0xe2, 0xcf, 0x1a, 0xbb, 0x41, 0x91, + 0x7b, 0x14, 0x1c, 0xf3, 0x6b, 0x75, 0x6d, 0x90, 0x95, 0x97, 0xae, 0x0b, 0x8e, 0xbb, 0x3b, 0x89, + 0xe6, 0xe0, 0xd4, 0x7a, 0x10, 0x35, 0x88, 0x39, 0x10, 0x42, 0x30, 0x29, 0x42, 0x97, 0xb2, 0x08, + 0xb8, 0xfb, 0x19, 0x74, 0x03, 0x1e, 0x32, 0x1a, 0xcd, 0x71, 0xe0, 0xb2, 0xe9, 0x71, 0x41, 0xed, + 0xa1, 0x4b, 0xb9, 0x58, 0xb8, 0xc7, 0xd3, 0x69, 0x87, 0x49, 0xad, 0x0f, 0x87, 0xc9, 0xab, 0xf0, + 0x48, 0xa3, 0x7b, 0x64, 0xb6, 0xe2, 0xce, 0x5a, 0xcc, 0x25, 0x55, 0xb5, 0xfe, 0x03, 0x82, 0xc0, + 0x23, 0x33, 0xbd, 0x10, 0x71, 0x6f, 0x1a, 0xe8, 0xa3, 0x50, 0x8d, 0x08, 0xfb, 0x2a, 0xb1, 0x48, + 0xc4, 0x39, 0xe2, 0x2e, 0x59, 0x5b, 0xa0, 0x9c, 0xac, 0x96, 0xbd, 0xa2, 0x21, 0xc6, 0x8a, 0x23, + 0xba, 0x0d, 0x43, 0xa1, 0x93, 0x34, 0x36, 0x44, 0xfa, 0xcd, 0x91, 0xe3, 0x5f, 0x14, 0x73, 0xe6, + 0x03, 0x37, 0x12, 0x76, 0x39, 0x13, 0x2c, 0xb9, 0x51, 0x6b, 0xa4, 0x11, 0xb4, 0xc3, 0xc0, 0x27, + 0x7e, 0x12, 0x8f, 0x8f, 0x6a, 0x6b, 0x64, 0x46, 0xb5, 0x62, 0x03, 0xe3, 0xdc, 0xfb, 0xe1, 0x54, + 0xd7, 0xc2, 0x3b, 0x90, 0x73, 0x65, 0x16, 0x1e, 0xca, 0x9f, 0xe2, 0x07, 0x72, 0xb1, 0xfc, 0x93, + 0x4c, 0x90, 0xab, 0x61, 0xf6, 0xf6, 0xe1, 0xae, 0x73, 0xa0, 0x4c, 0xfc, 0x2d, 0x21, 0xf1, 0x2f, + 0x1d, 0x6d, 0xa4, 0x2f, 0xfa, 0x5b, 0x7c, 0x85, 0x32, 0x9f, 0xc4, 0x45, 0x7f, 0x0b, 0x53, 0xda, + 0xe8, 0x4b, 0x56, 0xca, 0x6c, 0xe3, 0x4e, 0xbe, 0x0f, 0x1f, 0x8b, 0x9d, 0xdf, 0xb7, 0x25, 0x67, + 0xff, 0xbb, 0x12, 0x9c, 0xdf, 0x8f, 0x48, 0x1f, 0xc3, 0xf7, 0x04, 0x0c, 0xc6, 0xec, 0xd8, 0x5a, + 0x88, 0xd0, 0x61, 0x3a, 0xb3, 0xf8, 0x41, 0xf6, 0xab, 0x58, 0x80, 0x90, 0x07, 0xe5, 0xb6, 0x13, + 0x0a, 0xdf, 0xcf, 0xfc, 0x51, 0xd3, 0x5e, 0xe8, 0x7f, 0xc7, 0x5b, 0x74, 0x42, 0xee, 0x51, 0x30, + 0x1a, 0x30, 0x65, 0x83, 0x12, 0xa8, 0x38, 0x51, 0xe4, 0xc8, 0x33, 0xd2, 0xab, 0xc5, 0xf0, 0x9b, + 0xa6, 0x24, 0xf9, 0x11, 0x53, 0xaa, 0x09, 0x73, 0x66, 0xf6, 0xe7, 0x86, 0x52, 0xa9, 0x1f, 0xec, + 0xe0, 0x3b, 0x86, 0x41, 0xe1, 0xf2, 0xb1, 0x8a, 0xce, 0x36, 0xe2, 0xb9, 0x7b, 0x6c, 0x57, 0x27, + 0x32, 0xa0, 0x05, 0x2b, 0xf4, 0x59, 0x8b, 0xe5, 0x19, 0xcb, 0x74, 0x18, 0xb1, 0x97, 0x3a, 0x9e, + 0xb4, 0x67, 0x33, 0x7b, 0x59, 0x36, 0x62, 0x93, 0xbb, 0xa8, 0x17, 0xc0, 0x6c, 0xc8, 0xee, 0x7a, + 0x01, 0xcc, 0x26, 0x94, 0x70, 0xb4, 0x9d, 0x73, 0xc0, 0x5d, 0x40, 0xae, 0x6a, 0x1f, 0x47, 0xda, + 0x5f, 0xb3, 0xe0, 0x94, 0x9b, 0x3d, 0xa9, 0x14, 0x3b, 0x8f, 0x23, 0x86, 0x50, 0xf4, 0x3e, 0x08, + 0x55, 0xca, 0xb7, 0x0b, 0x84, 0xbb, 0x3b, 0x83, 0x9a, 0x30, 0xe0, 0xfa, 0xeb, 0x81, 0x30, 0x39, + 0xea, 0x47, 0xeb, 0xd4, 0xbc, 0xbf, 0x1e, 0xe8, 0xd5, 0x4c, 0xff, 0x61, 0x46, 0x1d, 0x2d, 0xc0, + 0x99, 0x48, 0xf8, 0x86, 0x2e, 0xbb, 0x31, 0xdd, 0xc1, 0x2f, 0xb8, 0x6d, 0x37, 0x61, 0xe6, 0x42, + 0xb9, 0x3e, 0x7e, 0x67, 0x77, 0xe2, 0x0c, 0xce, 0x81, 0xe3, 0xdc, 0xa7, 0xd0, 0xeb, 0x30, 0x24, + 0x13, 0xa3, 0xab, 0x45, 0xec, 0xe2, 0xba, 0xe7, 0xbf, 0x9a, 0x4c, 0x2b, 0x22, 0x07, 0x5a, 0x32, + 0xb4, 0xdf, 0x18, 0x86, 0xee, 0x43, 0x4c, 0xf4, 0x31, 0xa8, 0x45, 0x2a, 0x59, 0xdb, 0x2a, 0x42, + 0xb9, 0xca, 0xef, 0x2b, 0x0e, 0x50, 0x95, 0xe1, 0xa2, 0xd3, 0xb2, 0x35, 0x47, 0xba, 0xbd, 0x88, + 0xf5, 0x59, 0x67, 0x01, 0x73, 0x5b, 0x70, 0xd5, 0xe7, 0x58, 0x3b, 0x7e, 0x03, 0x33, 0x1e, 0x28, + 0x82, 0xc1, 0x0d, 0xe2, 0x78, 0xc9, 0x46, 0x31, 0x2e, 0xf7, 0xcb, 0x8c, 0x56, 0x36, 0x65, 0x87, + 0xb7, 0x62, 0xc1, 0x09, 0x6d, 0xc3, 0xd0, 0x06, 0x9f, 0x00, 0xc2, 0xe2, 0x5f, 0x3c, 0xea, 0xe0, + 0xa6, 0x66, 0x95, 0xfe, 0xdc, 0xa2, 0x01, 0x4b, 0x76, 0x2c, 0x3a, 0xc6, 0x38, 0xbf, 0xe7, 0x4b, + 0xb7, 0xb8, 0x6c, 0xa5, 0xfe, 0x0f, 0xef, 0x3f, 0x02, 0x23, 0x11, 0x69, 0x04, 0x7e, 0xc3, 0xf5, + 0x48, 0x73, 0x5a, 0xba, 0xd3, 0x0f, 0x92, 0xe3, 0xc2, 0x76, 0xcd, 0xd8, 0xa0, 0x81, 0x53, 0x14, + 0xd1, 0x67, 0x2c, 0x18, 0x53, 0x19, 0x9e, 0xf4, 0x83, 0x10, 0xe1, 0xbe, 0x5d, 0x28, 0x28, 0x9f, + 0x94, 0xd1, 0xac, 0xa3, 0x3b, 0xbb, 0x13, 0x63, 0xe9, 0x36, 0x9c, 0xe1, 0x8b, 0x5e, 0x06, 0x08, + 0xd6, 0x78, 0x08, 0xcc, 0x74, 0x22, 0x7c, 0xb9, 0x07, 0x79, 0xd5, 0x31, 0x9e, 0xec, 0x26, 0x29, + 0x60, 0x83, 0x1a, 0xba, 0x0a, 0xc0, 0x97, 0xcd, 0xea, 0x4e, 0x28, 0xb7, 0x05, 0x32, 0x49, 0x09, + 0x56, 0x14, 0xe4, 0xee, 0xee, 0x44, 0xb7, 0x6f, 0x8d, 0x85, 0x19, 0x18, 0x8f, 0xa3, 0x9f, 0x80, + 0xa1, 0xb8, 0xd3, 0x6e, 0x3b, 0xca, 0xd3, 0x5b, 0x60, 0xfa, 0x1c, 0xa7, 0x6b, 0x88, 0x22, 0xde, + 0x80, 0x25, 0x47, 0x74, 0x8b, 0x0a, 0xd5, 0x58, 0x38, 0xfd, 0xd8, 0x2a, 0xe2, 0x36, 0xc1, 0x30, + 0x7b, 0xa7, 0xf7, 0xc8, 0x88, 0x1e, 0x9c, 0x83, 0x73, 0x77, 0x77, 0xe2, 0xa1, 0x74, 0xfb, 0x42, + 0x20, 0x12, 0xda, 0x72, 0x69, 0xa2, 0x2b, 0xb2, 0x4e, 0x0a, 0x7d, 0x6d, 0x99, 0xbe, 0xff, 0x94, + 0xae, 0x93, 0xc2, 0x9a, 0x7b, 0x8f, 0x99, 0xf9, 0x30, 0x5a, 0x84, 0xd3, 0x8d, 0xc0, 0x4f, 0xa2, + 0xc0, 0xf3, 0x78, 0x9d, 0x20, 0xbe, 0x43, 0xe3, 0x9e, 0xe0, 0xb7, 0x8b, 0x6e, 0x9f, 0x9e, 0xe9, + 0x46, 0xc1, 0x79, 0xcf, 0xd9, 0x7e, 0x3a, 0x36, 0x50, 0x0c, 0xce, 0x73, 0x30, 0x42, 0xb6, 0x13, + 0x12, 0xf9, 0x8e, 0x77, 0x1d, 0x2f, 0x48, 0x1f, 0x28, 0x5b, 0x03, 0x17, 0x8d, 0x76, 0x9c, 0xc2, + 0x42, 0xb6, 0x72, 0x4b, 0x18, 0x49, 0x9a, 0xdc, 0x2d, 0x21, 0x9d, 0x10, 0xf6, 0xff, 0x29, 0xa5, + 0x0c, 0xb2, 0xd5, 0x88, 0x10, 0x14, 0x40, 0xc5, 0x0f, 0x9a, 0x4a, 0xf6, 0x5f, 0x29, 0x46, 0xf6, + 0x5f, 0x0b, 0x9a, 0x46, 0x31, 0x15, 0xfa, 0x2f, 0xc6, 0x9c, 0x0f, 0xab, 0x36, 0x21, 0xcb, 0x72, + 0x30, 0x80, 0xd8, 0x68, 0x14, 0xc9, 0x59, 0x55, 0x9b, 0x58, 0x32, 0x19, 0xe1, 0x34, 0x5f, 0xb4, + 0x09, 0x95, 0x8d, 0x20, 0x4e, 0xe4, 0xf6, 0xe3, 0x88, 0x3b, 0x9d, 0xcb, 0x41, 0x9c, 0x30, 0x2b, + 0x42, 0xbd, 0x36, 0x6d, 0x89, 0x31, 0xe7, 0x61, 0xff, 0x57, 0x2b, 0xe5, 0xf1, 0xbe, 0xc9, 0xe2, + 0x64, 0xb7, 0x88, 0x4f, 0x97, 0xb5, 0x19, 0x18, 0xf4, 0xc3, 0x99, 0xac, 0xc3, 0x77, 0xf4, 0x2a, + 0x83, 0x75, 0x9b, 0x52, 0x98, 0x64, 0x24, 0x8c, 0x18, 0xa2, 0x4f, 0x58, 0xe9, 0xfc, 0xcf, 0x52, + 0x11, 0x1b, 0x0c, 0x33, 0x07, 0x7a, 0xdf, 0x54, 0x52, 0xfb, 0x4b, 0x16, 0x0c, 0xd5, 0x9d, 0xc6, + 0x66, 0xb0, 0xbe, 0x8e, 0x9e, 0x86, 0x6a, 0xb3, 0x13, 0x99, 0xa9, 0xa8, 0x6a, 0x9b, 0x3f, 0x2b, + 0xda, 0xb1, 0xc2, 0xa0, 0x73, 0x78, 0xdd, 0x69, 0xc8, 0x4c, 0xe8, 0x32, 0x9f, 0xc3, 0x97, 0x58, + 0x0b, 0x16, 0x10, 0xf4, 0x3c, 0x0c, 0xb7, 0x9d, 0x6d, 0xf9, 0x70, 0xd6, 0xdd, 0xbe, 0xa8, 0x41, + 0xd8, 0xc4, 0xb3, 0xff, 0x95, 0x05, 0xe3, 0x75, 0x27, 0x76, 0x1b, 0xd3, 0x9d, 0x64, 0xa3, 0xee, + 0x26, 0x6b, 0x9d, 0xc6, 0x26, 0x49, 0x78, 0xfa, 0x3b, 0xed, 0x65, 0x27, 0xa6, 0x4b, 0x49, 0xed, + 0xeb, 0x54, 0x2f, 0xaf, 0x8b, 0x76, 0xac, 0x30, 0xd0, 0xeb, 0x30, 0x1c, 0x3a, 0x71, 0x7c, 0x3b, + 0x88, 0x9a, 0x98, 0xac, 0x17, 0x53, 0x7c, 0x62, 0x85, 0x34, 0x22, 0x92, 0x60, 0xb2, 0x2e, 0x8e, + 0x84, 0x35, 0x7d, 0x6c, 0x32, 0xb3, 0xbf, 0x60, 0xc1, 0x23, 0x75, 0xe2, 0x44, 0x24, 0x62, 0xb5, + 0x2a, 0xd4, 0x8b, 0xcc, 0x78, 0x41, 0xa7, 0x89, 0x5e, 0x83, 0x6a, 0x42, 0x9b, 0x69, 0xb7, 0xac, + 0x62, 0xbb, 0xc5, 0x4e, 0x74, 0x57, 0x05, 0x71, 0xac, 0xd8, 0xd8, 0x7f, 0xcb, 0x82, 0x11, 0x76, + 0x38, 0x36, 0x4b, 0x12, 0xc7, 0xf5, 0xba, 0x4a, 0x3a, 0x59, 0x7d, 0x96, 0x74, 0x3a, 0x0f, 0x03, + 0x1b, 0x41, 0x9b, 0x64, 0x0f, 0x76, 0x2f, 0x07, 0x74, 0x5b, 0x4d, 0x21, 0xe8, 0x59, 0xfa, 0xe1, + 0x5d, 0x3f, 0x71, 0xe8, 0x12, 0x90, 0xce, 0xd7, 0x13, 0xfc, 0xa3, 0xab, 0x66, 0x6c, 0xe2, 0xd8, + 0xbf, 0x55, 0x83, 0x21, 0x71, 0xfa, 0xdf, 0x77, 0x09, 0x04, 0xb9, 0xbf, 0x2f, 0xf5, 0xdc, 0xdf, + 0xc7, 0x30, 0xd8, 0x60, 0xb5, 0xe5, 0x84, 0x19, 0x79, 0xb5, 0x90, 0x70, 0x11, 0x5e, 0xae, 0x4e, + 0x77, 0x8b, 0xff, 0xc7, 0x82, 0x15, 0xfa, 0xa2, 0x05, 0x27, 0x1a, 0x81, 0xef, 0x93, 0x86, 0xb6, + 0x71, 0x06, 0x8a, 0x88, 0x0a, 0x98, 0x49, 0x13, 0xd5, 0x27, 0x33, 0x19, 0x00, 0xce, 0xb2, 0x47, + 0x2f, 0xc2, 0x28, 0x1f, 0xb3, 0x1b, 0x29, 0x8f, 0xb1, 0xae, 0xf4, 0x63, 0x02, 0x71, 0x1a, 0x17, + 0x4d, 0x72, 0xcf, 0xbb, 0xa8, 0xa9, 0x33, 0xa8, 0x1d, 0x6b, 0x46, 0x35, 0x1d, 0x03, 0x03, 0x45, + 0x80, 0x22, 0xb2, 0x1e, 0x91, 0x78, 0x43, 0x44, 0x47, 0x30, 0xfb, 0x6a, 0xe8, 0x70, 0xe9, 0xd2, + 0xb8, 0x8b, 0x12, 0xce, 0xa1, 0x8e, 0x36, 0xc5, 0x06, 0xb3, 0x5a, 0x84, 0x0c, 0x15, 0x9f, 0xb9, + 0xe7, 0x3e, 0x73, 0x02, 0x2a, 0xf1, 0x86, 0x13, 0x35, 0x99, 0x5d, 0x57, 0xe6, 0x29, 0x3a, 0x2b, + 0xb4, 0x01, 0xf3, 0x76, 0x34, 0x0b, 0x27, 0x33, 0x75, 0x8a, 0x62, 0xe1, 0xd9, 0x55, 0xe9, 0x18, + 0x99, 0x0a, 0x47, 0x31, 0xee, 0x7a, 0xc2, 0x74, 0x3e, 0x0c, 0xef, 0xe3, 0x7c, 0xd8, 0x51, 0x31, + 0x78, 0xdc, 0xe7, 0xfa, 0x52, 0x21, 0x03, 0xd0, 0x57, 0xc0, 0xdd, 0xe7, 0x33, 0x01, 0x77, 0xa3, + 0xac, 0x03, 0x37, 0x8a, 0xe9, 0xc0, 0xc1, 0xa3, 0xeb, 0xee, 0x67, 0xb4, 0xdc, 0x9f, 0x5b, 0x20, + 0xbf, 0xeb, 0x8c, 0xd3, 0xd8, 0x20, 0x74, 0xca, 0xa0, 0xf7, 0xc1, 0x98, 0xda, 0x42, 0xcf, 0x04, + 0x1d, 0x9f, 0x07, 0xca, 0x95, 0xf5, 0x11, 0x2e, 0x4e, 0x41, 0x71, 0x06, 0x1b, 0x4d, 0x41, 0x8d, + 0x8e, 0x13, 0x7f, 0x94, 0xeb, 0x5a, 0xb5, 0x4d, 0x9f, 0x5e, 0x9e, 0x17, 0x4f, 0x69, 0x1c, 0x14, + 0xc0, 0x29, 0xcf, 0x89, 0x13, 0xd6, 0x03, 0xba, 0xa3, 0x3e, 0x64, 0xb1, 0x02, 0x16, 0xf3, 0xbf, + 0x90, 0x25, 0x84, 0xbb, 0x69, 0xdb, 0xdf, 0x1e, 0x80, 0xd1, 0x94, 0x64, 0x3c, 0xa0, 0x92, 0x7e, + 0x1a, 0xaa, 0x52, 0x6f, 0x66, 0xcb, 0xaa, 0x28, 0xe5, 0xaa, 0x30, 0xa8, 0xd2, 0x5a, 0xd3, 0x5a, + 0x35, 0x6b, 0x54, 0x18, 0x0a, 0x17, 0x9b, 0x78, 0x4c, 0x28, 0x27, 0x5e, 0x3c, 0xe3, 0xb9, 0xc4, + 0x4f, 0x78, 0x37, 0x8b, 0x11, 0xca, 0xab, 0x0b, 0x2b, 0x26, 0x51, 0x2d, 0x94, 0x33, 0x00, 0x9c, + 0x65, 0x8f, 0x3e, 0x6d, 0xc1, 0xa8, 0x73, 0x3b, 0xd6, 0x05, 0x50, 0x45, 0x68, 0xdd, 0x11, 0x95, + 0x54, 0xaa, 0xa6, 0x2a, 0x77, 0xf9, 0xa6, 0x9a, 0x70, 0x9a, 0x29, 0x7a, 0xd3, 0x02, 0x44, 0xb6, + 0x49, 0x43, 0x06, 0xff, 0x89, 0xbe, 0x0c, 0x16, 0xb1, 0xd3, 0xbc, 0xd8, 0x45, 0x97, 0x4b, 0xf5, + 0xee, 0x76, 0x9c, 0xd3, 0x07, 0xfb, 0x9f, 0x97, 0xd5, 0x82, 0xd2, 0xf1, 0xa6, 0x8e, 0x11, 0xf7, + 0x66, 0x1d, 0x3e, 0xee, 0x4d, 0xc7, 0x0f, 0x74, 0xe7, 0x40, 0xa6, 0x52, 0xa6, 0x4a, 0xf7, 0x29, + 0x65, 0xea, 0xa7, 0xac, 0x54, 0x01, 0xa1, 0xe1, 0x0b, 0x2f, 0x17, 0x1b, 0xeb, 0x3a, 0xc9, 0x63, + 0x1b, 0x32, 0xd2, 0x3d, 0x1d, 0xd2, 0x42, 0xa5, 0xa9, 0x81, 0x76, 0x20, 0x69, 0xf8, 0x1f, 0xca, + 0x30, 0x6c, 0x68, 0xd2, 0x5c, 0xb3, 0xc8, 0x7a, 0xc0, 0xcc, 0xa2, 0xd2, 0x01, 0xcc, 0xa2, 0x9f, + 0x84, 0x5a, 0x43, 0x4a, 0xf9, 0x62, 0x4a, 0xe8, 0x66, 0x75, 0x87, 0x16, 0xf4, 0xaa, 0x09, 0x6b, + 0x9e, 0x68, 0x2e, 0x95, 0x68, 0x23, 0x34, 0xc4, 0x00, 0xd3, 0x10, 0x79, 0x99, 0x30, 0x42, 0x53, + 0x74, 0x3f, 0xc3, 0xea, 0x4c, 0x85, 0xae, 0x78, 0x2f, 0x19, 0x91, 0xce, 0xeb, 0x4c, 0x2d, 0xcf, + 0xcb, 0x66, 0x6c, 0xe2, 0xd8, 0xdf, 0xb6, 0xd4, 0xc7, 0xbd, 0x07, 0x15, 0x15, 0x6e, 0xa5, 0x2b, + 0x2a, 0x5c, 0x2c, 0x64, 0x98, 0x7b, 0x94, 0x52, 0xb8, 0x06, 0x43, 0x33, 0x41, 0xbb, 0xed, 0xf8, + 0x4d, 0xf4, 0x83, 0x30, 0xd4, 0xe0, 0x3f, 0x85, 0x63, 0x87, 0x1d, 0x0f, 0x0a, 0x28, 0x96, 0x30, + 0xf4, 0x28, 0x0c, 0x38, 0x51, 0x4b, 0x3a, 0x73, 0x58, 0x28, 0xcc, 0x74, 0xd4, 0x8a, 0x31, 0x6b, + 0xb5, 0xff, 0xf1, 0x00, 0xb0, 0x13, 0x68, 0x27, 0x22, 0xcd, 0xd5, 0x80, 0x95, 0xf0, 0x3b, 0xd6, + 0x43, 0x35, 0xbd, 0x59, 0x7a, 0x90, 0x0f, 0xd6, 0x8c, 0xc3, 0x95, 0xf2, 0x3d, 0x3e, 0x5c, 0xe9, + 0x71, 0x5e, 0x36, 0xf0, 0x00, 0x9d, 0x97, 0xd9, 0x9f, 0xb3, 0x00, 0xa9, 0xb0, 0x05, 0x7d, 0xa0, + 0x3d, 0x05, 0x35, 0x15, 0xc0, 0x20, 0x0c, 0x2b, 0x2d, 0x22, 0x24, 0x00, 0x6b, 0x9c, 0x3e, 0x76, + 0xc8, 0x4f, 0x48, 0xf9, 0x5d, 0x4e, 0x47, 0xd1, 0x32, 0xa9, 0x2f, 0xc4, 0xb9, 0xfd, 0xdb, 0x25, + 0x78, 0x88, 0xab, 0xe4, 0x45, 0xc7, 0x77, 0x5a, 0xa4, 0x4d, 0x7b, 0xd5, 0x6f, 0x88, 0x42, 0x83, + 0x6e, 0xcd, 0x5c, 0x19, 0x15, 0x7b, 0xd4, 0xb5, 0xcb, 0xd7, 0x1c, 0x5f, 0x65, 0xf3, 0xbe, 0x9b, + 0x60, 0x46, 0x1c, 0xc5, 0x50, 0x95, 0xf5, 0xe5, 0x85, 0x2c, 0x2e, 0x88, 0x91, 0x12, 0x4b, 0x42, + 0x6f, 0x12, 0xac, 0x18, 0x51, 0xc3, 0xd5, 0x0b, 0x1a, 0x9b, 0x98, 0x84, 0x01, 0x93, 0xbb, 0x46, + 0x50, 0xe2, 0x82, 0x68, 0xc7, 0x0a, 0xc3, 0xfe, 0x6d, 0x0b, 0xb2, 0x1a, 0xc9, 0xa8, 0x95, 0x66, + 0xed, 0x59, 0x2b, 0xed, 0x00, 0xc5, 0xca, 0x7e, 0x1c, 0x86, 0x9d, 0x84, 0x1a, 0x11, 0x7c, 0xdb, + 0x5d, 0x3e, 0xdc, 0xb1, 0xc6, 0x62, 0xd0, 0x74, 0xd7, 0x5d, 0xb6, 0xdd, 0x36, 0xc9, 0xd9, 0xff, + 0x73, 0x00, 0x4e, 0x75, 0xe5, 0x6e, 0xa0, 0x17, 0x60, 0xa4, 0x21, 0xa6, 0x47, 0x28, 0x1d, 0x5a, + 0x35, 0x33, 0x88, 0x4d, 0xc3, 0x70, 0x0a, 0xb3, 0x8f, 0x09, 0x3a, 0x0f, 0xa7, 0x23, 0xba, 0xd1, + 0xef, 0x90, 0xe9, 0xf5, 0x84, 0x44, 0x2b, 0xa4, 0x11, 0xf8, 0x4d, 0x5e, 0xd1, 0xaf, 0x5c, 0x7f, + 0xf8, 0xce, 0xee, 0xc4, 0x69, 0xdc, 0x0d, 0xc6, 0x79, 0xcf, 0xa0, 0x10, 0x46, 0x3d, 0xd3, 0x06, + 0x14, 0x1b, 0x80, 0x43, 0x99, 0x8f, 0xca, 0x46, 0x48, 0x35, 0xe3, 0x34, 0x83, 0xb4, 0x21, 0x59, + 0xb9, 0x4f, 0x86, 0xe4, 0xa7, 0xb4, 0x21, 0xc9, 0xcf, 0xdf, 0x3f, 0x54, 0x70, 0xee, 0xce, 0x71, + 0x5b, 0x92, 0x2f, 0x41, 0x55, 0xc6, 0x26, 0xf5, 0x15, 0xd3, 0x63, 0xd2, 0xe9, 0x21, 0xd1, 0xee, + 0x96, 0x20, 0x67, 0x13, 0x42, 0xd7, 0x99, 0xd6, 0xf8, 0xa9, 0x75, 0x76, 0x30, 0xad, 0x8f, 0xb6, + 0x79, 0x5c, 0x16, 0xd7, 0x6d, 0x1f, 0x2c, 0x7a, 0x13, 0xa5, 0x43, 0xb5, 0x54, 0x4a, 0x83, 0x0a, + 0xd7, 0xba, 0x00, 0xa0, 0x0d, 0x35, 0x11, 0xb0, 0xae, 0x8e, 0x7d, 0xb5, 0x3d, 0x87, 0x0d, 0x2c, + 0xba, 0xa7, 0x76, 0xfd, 0x38, 0x71, 0x3c, 0xef, 0xb2, 0xeb, 0x27, 0xc2, 0x39, 0xa8, 0x94, 0xf8, + 0xbc, 0x06, 0x61, 0x13, 0xef, 0xdc, 0x7b, 0x8c, 0xef, 0x72, 0x90, 0xef, 0xb9, 0x01, 0x8f, 0xcc, + 0xb9, 0x89, 0x4a, 0xb3, 0x50, 0xf3, 0x88, 0xda, 0x61, 0x2a, 0x6d, 0xc8, 0xea, 0x99, 0x36, 0x64, + 0xa4, 0x39, 0x94, 0xd2, 0x59, 0x19, 0xd9, 0x34, 0x07, 0xfb, 0x05, 0x38, 0x33, 0xe7, 0x26, 0x97, + 0x5c, 0x8f, 0x1c, 0x90, 0x89, 0xfd, 0x9b, 0x83, 0x30, 0x62, 0x26, 0xea, 0x1d, 0x24, 0xf3, 0xe9, + 0x0b, 0xd4, 0xd4, 0x12, 0x6f, 0xe7, 0xaa, 0x43, 0xb3, 0x9b, 0x47, 0xce, 0x1a, 0xcc, 0x1f, 0x31, + 0xc3, 0xda, 0xd2, 0x3c, 0xb1, 0xd9, 0x01, 0x74, 0x1b, 0x2a, 0xeb, 0x2c, 0x0c, 0xbf, 0x5c, 0x44, + 0x64, 0x41, 0xde, 0x88, 0xea, 0x65, 0xc6, 0x03, 0xf9, 0x39, 0x3f, 0xaa, 0x21, 0xa3, 0x74, 0x6e, + 0x97, 0x11, 0x3a, 0x2a, 0xb2, 0xba, 0x14, 0x46, 0x2f, 0x51, 0x5f, 0x39, 0x84, 0xa8, 0x4f, 0x09, + 0xde, 0xc1, 0xfb, 0x24, 0x78, 0x59, 0x4a, 0x45, 0xb2, 0xc1, 0xec, 0x37, 0x11, 0xeb, 0x3e, 0xc4, + 0x06, 0xc1, 0x48, 0xa9, 0x48, 0x81, 0x71, 0x16, 0x1f, 0x7d, 0x5c, 0x89, 0xee, 0x6a, 0x11, 0x7e, + 0x55, 0x73, 0x46, 0x1f, 0xb7, 0xd4, 0xfe, 0x5c, 0x09, 0xc6, 0xe6, 0xfc, 0xce, 0xf2, 0xdc, 0x72, + 0x67, 0xcd, 0x73, 0x1b, 0x57, 0xc9, 0x0e, 0x15, 0xcd, 0x9b, 0x64, 0x67, 0x7e, 0x56, 0xac, 0x20, + 0x35, 0x67, 0xae, 0xd2, 0x46, 0xcc, 0x61, 0x54, 0x18, 0xad, 0xbb, 0x7e, 0x8b, 0x44, 0x61, 0xe4, + 0x0a, 0x97, 0xa7, 0x21, 0x8c, 0x2e, 0x69, 0x10, 0x36, 0xf1, 0x28, 0xed, 0xe0, 0xb6, 0x4f, 0xa2, + 0xac, 0x21, 0xbb, 0x44, 0x1b, 0x31, 0x87, 0x51, 0xa4, 0x24, 0xea, 0xc4, 0x89, 0x98, 0x8c, 0x0a, + 0x69, 0x95, 0x36, 0x62, 0x0e, 0xa3, 0x2b, 0x3d, 0xee, 0xac, 0xb1, 0xc0, 0x8d, 0x4c, 0x60, 0xfd, + 0x0a, 0x6f, 0xc6, 0x12, 0x4e, 0x51, 0x37, 0xc9, 0xce, 0x2c, 0xdd, 0xf5, 0x66, 0xf2, 0x6b, 0xae, + 0xf2, 0x66, 0x2c, 0xe1, 0xac, 0x14, 0x61, 0x7a, 0x38, 0xbe, 0xe7, 0x4a, 0x11, 0xa6, 0xbb, 0xdf, + 0x63, 0xff, 0xfc, 0x4b, 0x16, 0x8c, 0x98, 0xe1, 0x56, 0xa8, 0x95, 0xb1, 0x71, 0x97, 0xba, 0x2a, + 0xd9, 0xfe, 0x68, 0xde, 0x35, 0x60, 0x2d, 0x37, 0x09, 0xc2, 0xf8, 0x19, 0xe2, 0xb7, 0x5c, 0x9f, + 0xb0, 0x53, 0x74, 0x1e, 0xa6, 0x95, 0x8a, 0xe5, 0x9a, 0x09, 0x9a, 0xe4, 0x10, 0x46, 0xb2, 0x7d, + 0x13, 0x4e, 0x75, 0x25, 0x55, 0xf5, 0x61, 0x5a, 0xec, 0x9b, 0xd2, 0x6a, 0x63, 0x18, 0xa6, 0x84, + 0x65, 0x39, 0x9c, 0x19, 0x38, 0xc5, 0x17, 0x12, 0xe5, 0xb4, 0xd2, 0xd8, 0x20, 0x6d, 0x95, 0x28, + 0xc7, 0xfc, 0xeb, 0x37, 0xb2, 0x40, 0xdc, 0x8d, 0x6f, 0x7f, 0xde, 0x82, 0xd1, 0x54, 0x9e, 0x5b, + 0x41, 0x46, 0x10, 0x5b, 0x69, 0x01, 0x8b, 0xfe, 0x63, 0x21, 0xd0, 0x65, 0xa6, 0x4c, 0xf5, 0x4a, + 0xd3, 0x20, 0x6c, 0xe2, 0xd9, 0x5f, 0x2a, 0x41, 0x55, 0x46, 0x50, 0xf4, 0xd1, 0x95, 0xcf, 0x5a, + 0x30, 0xaa, 0xce, 0x34, 0x98, 0xb3, 0xac, 0x54, 0x44, 0x52, 0x02, 0xed, 0x81, 0xda, 0x6e, 0xfb, + 0xeb, 0x81, 0xb6, 0xc8, 0xb1, 0xc9, 0x0c, 0xa7, 0x79, 0xa3, 0x1b, 0x00, 0xf1, 0x4e, 0x9c, 0x90, + 0xb6, 0xe1, 0xb6, 0xb3, 0x8d, 0x15, 0x37, 0xd9, 0x08, 0x22, 0x42, 0xd7, 0xd7, 0xb5, 0xa0, 0x49, + 0x56, 0x14, 0xa6, 0x36, 0xa1, 0x74, 0x1b, 0x36, 0x28, 0xd9, 0xff, 0xb0, 0x04, 0x27, 0xb3, 0x5d, + 0x42, 0x1f, 0x82, 0x11, 0xc9, 0xdd, 0xb8, 0xd1, 0x4c, 0x86, 0x8d, 0x8c, 0x60, 0x03, 0x76, 0x77, + 0x77, 0x62, 0xa2, 0xfb, 0x4a, 0xb9, 0x49, 0x13, 0x05, 0xa7, 0x88, 0xf1, 0x83, 0x25, 0x71, 0x02, + 0x5a, 0xdf, 0x99, 0x0e, 0x43, 0x71, 0x3a, 0x64, 0x1c, 0x2c, 0x99, 0x50, 0x9c, 0xc1, 0x46, 0xcb, + 0x70, 0xc6, 0x68, 0xb9, 0x46, 0xdc, 0xd6, 0xc6, 0x5a, 0x10, 0xc9, 0x9d, 0xd5, 0xa3, 0x3a, 0xb0, + 0xab, 0x1b, 0x07, 0xe7, 0x3e, 0x49, 0xb5, 0x7d, 0xc3, 0x09, 0x9d, 0x86, 0x9b, 0xec, 0x08, 0x3f, + 0xa4, 0x92, 0x4d, 0x33, 0xa2, 0x1d, 0x2b, 0x0c, 0x7b, 0x11, 0x06, 0xfa, 0x9c, 0x41, 0x7d, 0x59, + 0xf4, 0x2f, 0x41, 0x95, 0x92, 0x93, 0xe6, 0x5d, 0x11, 0x24, 0x03, 0xa8, 0xca, 0x9b, 0x46, 0x90, + 0x0d, 0x65, 0xd7, 0x91, 0x67, 0x77, 0xea, 0xb5, 0xe6, 0xe3, 0xb8, 0xc3, 0x36, 0xc9, 0x14, 0x88, + 0x9e, 0x80, 0x32, 0xd9, 0x0e, 0xb3, 0x87, 0x74, 0x17, 0xb7, 0x43, 0x37, 0x22, 0x31, 0x45, 0x22, + 0xdb, 0x21, 0x3a, 0x07, 0x25, 0xb7, 0x29, 0x94, 0x14, 0x08, 0x9c, 0xd2, 0xfc, 0x2c, 0x2e, 0xb9, + 0x4d, 0x7b, 0x1b, 0x6a, 0xea, 0x6a, 0x13, 0xb4, 0x29, 0x65, 0xb7, 0x55, 0x44, 0xc8, 0x93, 0xa4, + 0xdb, 0x43, 0x6a, 0x77, 0x00, 0x74, 0xc2, 0x5f, 0x51, 0xf2, 0xe5, 0x3c, 0x0c, 0x34, 0x02, 0x91, + 0x8c, 0x5c, 0xd5, 0x64, 0x98, 0xd0, 0x66, 0x10, 0xfb, 0x26, 0x8c, 0x5d, 0xf5, 0x83, 0xdb, 0xac, + 0x2e, 0x3b, 0x2b, 0x43, 0x46, 0x09, 0xaf, 0xd3, 0x1f, 0x59, 0x13, 0x81, 0x41, 0x31, 0x87, 0xa9, + 0xfa, 0x4c, 0xa5, 0x5e, 0xf5, 0x99, 0xec, 0x4f, 0x58, 0x30, 0xa2, 0x32, 0x87, 0xe6, 0xb6, 0x36, + 0x29, 0xdd, 0x56, 0x14, 0x74, 0xc2, 0x2c, 0x5d, 0x76, 0xf9, 0x10, 0xe6, 0x30, 0x33, 0xa5, 0xae, + 0xb4, 0x4f, 0x4a, 0xdd, 0x79, 0x18, 0xd8, 0x74, 0xfd, 0x66, 0xf6, 0x36, 0x8d, 0xab, 0xae, 0xdf, + 0xc4, 0x0c, 0x42, 0xbb, 0x70, 0x52, 0x75, 0x41, 0x2a, 0x84, 0x17, 0x60, 0x64, 0xad, 0xe3, 0x7a, + 0x4d, 0x59, 0x5f, 0x2d, 0xe3, 0x29, 0xa9, 0x1b, 0x30, 0x9c, 0xc2, 0xa4, 0xfb, 0xba, 0x35, 0xd7, + 0x77, 0xa2, 0x9d, 0x65, 0xad, 0x81, 0x94, 0x50, 0xaa, 0x2b, 0x08, 0x36, 0xb0, 0xec, 0x37, 0xca, + 0x30, 0x96, 0xce, 0x9f, 0xea, 0x63, 0x7b, 0xf5, 0x04, 0x54, 0x58, 0x4a, 0x55, 0xf6, 0xd3, 0xf2, + 0x92, 0x64, 0x1c, 0x86, 0x62, 0x18, 0xe4, 0xc5, 0x18, 0x8a, 0xb9, 0x89, 0x46, 0x75, 0x52, 0xf9, + 0x57, 0x58, 0x3c, 0x99, 0xa8, 0xff, 0x20, 0x58, 0xa1, 0x4f, 0x5b, 0x30, 0x14, 0x84, 0x66, 0x5d, + 0x9f, 0x0f, 0x16, 0x99, 0x5b, 0x26, 0x92, 0x65, 0x84, 0x45, 0xac, 0x3e, 0xbd, 0xfc, 0x1c, 0x92, + 0xf5, 0xb9, 0xf7, 0xc2, 0x88, 0x89, 0xb9, 0x9f, 0x51, 0x5c, 0x35, 0x8d, 0xe2, 0xcf, 0x9a, 0x93, + 0x42, 0x64, 0xcf, 0xf5, 0xb1, 0xdc, 0xae, 0x43, 0xa5, 0xa1, 0x02, 0x00, 0x0e, 0x55, 0x95, 0x53, + 0x55, 0x47, 0x60, 0x87, 0x40, 0x9c, 0x9a, 0xfd, 0x6d, 0xcb, 0x98, 0x1f, 0x98, 0xc4, 0xf3, 0x4d, + 0x14, 0x41, 0xb9, 0xb5, 0xb5, 0x29, 0x4c, 0xd1, 0x2b, 0x05, 0x0d, 0xef, 0xdc, 0xd6, 0xa6, 0x9e, + 0xe3, 0x66, 0x2b, 0xa6, 0xcc, 0xfa, 0x70, 0x02, 0xa6, 0x92, 0x2c, 0xcb, 0xfb, 0x27, 0x59, 0xda, + 0x6f, 0x96, 0xe0, 0x54, 0xd7, 0xa4, 0x42, 0xaf, 0x43, 0x25, 0xa2, 0x6f, 0x29, 0x5e, 0x6f, 0xa1, + 0xb0, 0xb4, 0xc8, 0x78, 0xbe, 0xa9, 0xf5, 0x6e, 0xba, 0x1d, 0x73, 0x96, 0xe8, 0x0a, 0x20, 0x1d, + 0xa6, 0xa2, 0x3c, 0x90, 0xfc, 0x95, 0xcf, 0x89, 0x47, 0xd1, 0x74, 0x17, 0x06, 0xce, 0x79, 0x0a, + 0xbd, 0x98, 0x75, 0x64, 0x96, 0xd3, 0xe7, 0x96, 0x7b, 0xf9, 0x24, 0xed, 0x7f, 0x51, 0x82, 0xd1, + 0x54, 0x99, 0x25, 0xe4, 0x41, 0x95, 0x78, 0xcc, 0xa9, 0x2f, 0x95, 0xcd, 0x51, 0xab, 0x16, 0x2b, + 0x05, 0x79, 0x51, 0xd0, 0xc5, 0x8a, 0xc3, 0x83, 0x71, 0xb8, 0xfe, 0x02, 0x8c, 0xc8, 0x0e, 0x7d, + 0xd0, 0x69, 0x7b, 0x62, 0x00, 0xd5, 0x1c, 0xbd, 0x68, 0xc0, 0x70, 0x0a, 0xd3, 0xfe, 0x9d, 0x32, + 0x8c, 0xf3, 0x53, 0x90, 0xa6, 0x9a, 0x79, 0x8b, 0x72, 0xbf, 0xf5, 0xd7, 0x74, 0x31, 0x34, 0x3e, + 0x90, 0x6b, 0x47, 0xbd, 0x24, 0x20, 0x9f, 0x51, 0x5f, 0x91, 0x59, 0x5f, 0xcd, 0x44, 0x66, 0x71, + 0xb3, 0xbb, 0x75, 0x4c, 0x3d, 0xfa, 0xde, 0x0a, 0xd5, 0xfa, 0x95, 0x12, 0x9c, 0xc8, 0xdc, 0xc0, + 0x80, 0xde, 0x48, 0x17, 0xed, 0xb5, 0x8a, 0xf0, 0x95, 0xef, 0x59, 0x94, 0xff, 0x60, 0xa5, 0x7b, + 0xef, 0xd3, 0x52, 0xb1, 0xff, 0xa0, 0x04, 0x63, 0xe9, 0xab, 0x23, 0x1e, 0xc0, 0x91, 0x7a, 0x17, + 0xd4, 0x58, 0x75, 0x74, 0x76, 0x25, 0x26, 0x77, 0xc9, 0xf3, 0x42, 0xd4, 0xb2, 0x11, 0x6b, 0xf8, + 0x03, 0x51, 0x11, 0xd9, 0xfe, 0xfb, 0x16, 0x9c, 0xe5, 0x6f, 0x99, 0x9d, 0x87, 0x7f, 0x3d, 0x6f, + 0x74, 0x5f, 0x29, 0xb6, 0x83, 0x99, 0x22, 0x7e, 0xfb, 0x8d, 0x2f, 0xbb, 0x8a, 0x4f, 0xf4, 0x36, + 0x3d, 0x15, 0x1e, 0xc0, 0xce, 0x1e, 0x68, 0x32, 0xd8, 0x7f, 0x50, 0x06, 0x7d, 0xfb, 0x20, 0x72, + 0x45, 0x8e, 0x63, 0x21, 0xc5, 0x0c, 0x57, 0x76, 0xfc, 0x86, 0xbe, 0xe7, 0xb0, 0x9a, 0x49, 0x71, + 0xfc, 0x59, 0x0b, 0x86, 0x5d, 0xdf, 0x4d, 0x5c, 0x87, 0x6d, 0xa3, 0x8b, 0xb9, 0x19, 0x4d, 0xb1, + 0x9b, 0xe7, 0x94, 0x83, 0xc8, 0x3c, 0xc7, 0x51, 0xcc, 0xb0, 0xc9, 0x19, 0x7d, 0x44, 0x04, 0x4f, + 0x97, 0x0b, 0xcb, 0xce, 0xad, 0x66, 0x22, 0xa6, 0x43, 0x6a, 0x78, 0x25, 0x51, 0x41, 0x49, 0xed, + 0x98, 0x92, 0x52, 0x75, 0x71, 0xf5, 0x3d, 0xd0, 0xb4, 0x19, 0x73, 0x46, 0x76, 0x0c, 0xa8, 0x7b, + 0x2c, 0x0e, 0x18, 0x98, 0x3a, 0x05, 0x35, 0xa7, 0x93, 0x04, 0x6d, 0x3a, 0x4c, 0xe2, 0xa8, 0x49, + 0x87, 0xde, 0x4a, 0x00, 0xd6, 0x38, 0xf6, 0x1b, 0x15, 0xc8, 0x24, 0x1d, 0xa2, 0x6d, 0xf3, 0xe6, + 0x4c, 0xab, 0xd8, 0x9b, 0x33, 0x55, 0x67, 0xf2, 0x6e, 0xcf, 0x44, 0x2d, 0xa8, 0x84, 0x1b, 0x4e, + 0x2c, 0xcd, 0xea, 0x97, 0xd4, 0x3e, 0x8e, 0x36, 0xde, 0xdd, 0x9d, 0xf8, 0xb1, 0xfe, 0xbc, 0xae, + 0x74, 0xae, 0x4e, 0xf1, 0x62, 0x23, 0x9a, 0x35, 0xa3, 0x81, 0x39, 0xfd, 0x83, 0xdc, 0x0d, 0xf7, + 0x49, 0x51, 0x06, 0x1e, 0x93, 0xb8, 0xe3, 0x25, 0x62, 0x36, 0xbc, 0x54, 0xe0, 0x2a, 0xe3, 0x84, + 0x75, 0xba, 0x3c, 0xff, 0x8f, 0x0d, 0xa6, 0xe8, 0x43, 0x50, 0x8b, 0x13, 0x27, 0x4a, 0x0e, 0x99, + 0xe0, 0xaa, 0x06, 0x7d, 0x45, 0x12, 0xc1, 0x9a, 0x1e, 0x7a, 0x99, 0xd5, 0x76, 0x75, 0xe3, 0x8d, + 0x43, 0xe6, 0x3c, 0xc8, 0x3a, 0xb0, 0x82, 0x02, 0x36, 0xa8, 0xa1, 0x0b, 0x00, 0x6c, 0x6e, 0xf3, + 0x40, 0xbf, 0x2a, 0xf3, 0x32, 0x29, 0x51, 0x88, 0x15, 0x04, 0x1b, 0x58, 0xf6, 0x0f, 0x41, 0xba, + 0xde, 0x03, 0x9a, 0x90, 0xe5, 0x25, 0xb8, 0x17, 0x9a, 0xe5, 0x2e, 0xa4, 0x2a, 0x41, 0xfc, 0xba, + 0x05, 0x66, 0x51, 0x0a, 0xf4, 0x1a, 0xaf, 0x7e, 0x61, 0x15, 0x71, 0x72, 0x68, 0xd0, 0x9d, 0x5c, + 0x74, 0xc2, 0xcc, 0x11, 0xb6, 0x2c, 0x81, 0x71, 0xee, 0x3d, 0x50, 0x95, 0xd0, 0x03, 0x19, 0x75, + 0x1f, 0x87, 0xd3, 0xd9, 0x7b, 0xc5, 0xc5, 0xa9, 0xd3, 0xfe, 0xae, 0x1f, 0xe9, 0xcf, 0x29, 0xf5, + 0xf2, 0xe7, 0xf4, 0x71, 0x7f, 0xea, 0x6f, 0x58, 0x70, 0x7e, 0xbf, 0xeb, 0xcf, 0xd1, 0xa3, 0x30, + 0x70, 0xdb, 0x89, 0x64, 0xd1, 0x6d, 0x26, 0x28, 0x6f, 0x3a, 0x91, 0x8f, 0x59, 0x2b, 0xda, 0x81, + 0x41, 0x1e, 0x0d, 0x26, 0xac, 0xf5, 0x97, 0x8a, 0xbd, 0x8c, 0xfd, 0x2a, 0x31, 0xb6, 0x0b, 0x3c, + 0x12, 0x0d, 0x0b, 0x86, 0xf6, 0x77, 0x2c, 0x40, 0x4b, 0x5b, 0x24, 0x8a, 0xdc, 0xa6, 0x11, 0xbf, + 0xc6, 0xae, 0x53, 0x31, 0xae, 0x4d, 0x31, 0x53, 0x5c, 0x33, 0xd7, 0xa9, 0x18, 0xff, 0xf2, 0xaf, + 0x53, 0x29, 0x1d, 0xec, 0x3a, 0x15, 0xb4, 0x04, 0x67, 0xdb, 0x7c, 0xbb, 0xc1, 0xaf, 0x28, 0xe0, + 0x7b, 0x0f, 0x95, 0x50, 0xf6, 0xc8, 0x9d, 0xdd, 0x89, 0xb3, 0x8b, 0x79, 0x08, 0x38, 0xff, 0x39, + 0xfb, 0x3d, 0x80, 0x78, 0xd8, 0xda, 0x4c, 0x5e, 0x0c, 0x52, 0x4f, 0xf7, 0x8b, 0xfd, 0x95, 0x0a, + 0x9c, 0xc8, 0x94, 0x64, 0xa5, 0x5b, 0xbd, 0xee, 0xa0, 0xa7, 0x23, 0xeb, 0xef, 0xee, 0xee, 0xf5, + 0x15, 0x46, 0xe5, 0x43, 0xc5, 0xf5, 0xc3, 0x4e, 0x52, 0x4c, 0x0e, 0x29, 0xef, 0xc4, 0x3c, 0x25, + 0x68, 0xb8, 0x8b, 0xe9, 0x5f, 0xcc, 0xd9, 0x14, 0x19, 0x94, 0x95, 0x32, 0xc6, 0x07, 0xee, 0x93, + 0x3b, 0xe0, 0x93, 0x3a, 0x44, 0xaa, 0x52, 0x84, 0x63, 0x31, 0x33, 0x59, 0x8e, 0xfb, 0xa8, 0xfd, + 0xd7, 0x4a, 0x30, 0x6c, 0x7c, 0x34, 0xf4, 0x8b, 0xe9, 0x92, 0x4d, 0x56, 0x71, 0xaf, 0xc4, 0xe8, + 0x4f, 0xea, 0xa2, 0x4c, 0xfc, 0x95, 0x9e, 0xec, 0xae, 0xd6, 0x74, 0x77, 0x77, 0xe2, 0x64, 0xa6, + 0x1e, 0x53, 0xaa, 0x82, 0xd3, 0xb9, 0x8f, 0xc1, 0x89, 0x0c, 0x99, 0x9c, 0x57, 0x5e, 0x4d, 0x5f, + 0x1b, 0x7f, 0x44, 0xb7, 0x94, 0x39, 0x64, 0xdf, 0xa0, 0x43, 0x26, 0xd2, 0xe8, 0x02, 0x8f, 0xf4, + 0xe1, 0x83, 0xcd, 0x64, 0xcb, 0x96, 0xfa, 0xcc, 0x96, 0x7d, 0x0a, 0xaa, 0x61, 0xe0, 0xb9, 0x0d, + 0x57, 0x55, 0x21, 0x64, 0xf9, 0xb9, 0xcb, 0xa2, 0x0d, 0x2b, 0x28, 0xba, 0x0d, 0x35, 0x75, 0xc3, + 0xbe, 0xf0, 0x6f, 0x17, 0x75, 0xe8, 0xa3, 0x8c, 0x16, 0x7d, 0x73, 0xbe, 0xe6, 0x85, 0x6c, 0x18, + 0x64, 0x4a, 0x50, 0x86, 0xfe, 0x33, 0xdf, 0x3b, 0xd3, 0x8e, 0x31, 0x16, 0x10, 0xfb, 0xeb, 0x35, + 0x38, 0x93, 0x57, 0x17, 0x1b, 0x7d, 0x14, 0x06, 0x79, 0x1f, 0x8b, 0xb9, 0x7a, 0x21, 0x8f, 0xc7, + 0x1c, 0x23, 0x28, 0xba, 0xc5, 0x7e, 0x63, 0xc1, 0x53, 0x70, 0xf7, 0x9c, 0x35, 0x31, 0x43, 0x8e, + 0x87, 0xfb, 0x82, 0xa3, 0xb9, 0x2f, 0x38, 0x9c, 0xbb, 0xe7, 0xac, 0xa1, 0x6d, 0xa8, 0xb4, 0xdc, + 0x84, 0x38, 0xc2, 0x89, 0x70, 0xf3, 0x58, 0x98, 0x13, 0x87, 0x5b, 0x69, 0xec, 0x27, 0xe6, 0x0c, + 0xd1, 0xd7, 0x2c, 0x38, 0xb1, 0x96, 0x4e, 0x8d, 0x17, 0xc2, 0xd3, 0x39, 0x86, 0xda, 0xe7, 0x69, + 0x46, 0xfc, 0x3e, 0xa1, 0x4c, 0x23, 0xce, 0x76, 0x07, 0x7d, 0xca, 0x82, 0xa1, 0x75, 0xd7, 0x33, + 0xca, 0xe0, 0x1e, 0xc3, 0xc7, 0xb9, 0xc4, 0x18, 0xe8, 0x1d, 0x07, 0xff, 0x1f, 0x63, 0xc9, 0xb9, + 0x97, 0xa6, 0x1a, 0x3c, 0xaa, 0xa6, 0x1a, 0xba, 0x4f, 0x9a, 0xea, 0x33, 0x16, 0xd4, 0xd4, 0x48, + 0x8b, 0x74, 0xe7, 0x0f, 0x1d, 0xe3, 0x27, 0xe7, 0x9e, 0x13, 0xf5, 0x17, 0x6b, 0xe6, 0xe8, 0x8b, + 0x16, 0x0c, 0x3b, 0xaf, 0x77, 0x22, 0xd2, 0x24, 0x5b, 0x41, 0x18, 0x8b, 0xcb, 0x08, 0x5f, 0x29, + 0xbe, 0x33, 0xd3, 0x94, 0xc9, 0x2c, 0xd9, 0x5a, 0x0a, 0x63, 0x91, 0x96, 0xa4, 0x1b, 0xb0, 0xd9, + 0x05, 0x7b, 0xb7, 0x04, 0x13, 0xfb, 0x50, 0x40, 0x2f, 0xc0, 0x48, 0x10, 0xb5, 0x1c, 0xdf, 0x7d, + 0xdd, 0xac, 0x75, 0xa1, 0xac, 0xac, 0x25, 0x03, 0x86, 0x53, 0x98, 0x66, 0x42, 0x76, 0x69, 0x9f, + 0x84, 0xec, 0xf3, 0x30, 0x10, 0x91, 0x30, 0xc8, 0x6e, 0x16, 0x58, 0x4a, 0x00, 0x83, 0xa0, 0xc7, + 0xa0, 0xec, 0x84, 0xae, 0x08, 0x44, 0x53, 0x7b, 0xa0, 0xe9, 0xe5, 0x79, 0x4c, 0xdb, 0x53, 0xf5, + 0x21, 0x2a, 0xf7, 0xa4, 0x3e, 0x04, 0x55, 0x03, 0xe2, 0xec, 0x62, 0x50, 0xab, 0x81, 0xf4, 0x99, + 0x82, 0xfd, 0x66, 0x19, 0x1e, 0xdb, 0x73, 0xbe, 0xe8, 0x38, 0x3c, 0x6b, 0x8f, 0x38, 0x3c, 0x39, + 0x3c, 0xa5, 0xfd, 0x86, 0xa7, 0xdc, 0x63, 0x78, 0x3e, 0x45, 0x97, 0x81, 0xac, 0x11, 0x52, 0xcc, + 0x75, 0x72, 0xbd, 0x4a, 0x8e, 0x88, 0x15, 0x20, 0xa1, 0x58, 0xf3, 0xa5, 0x7b, 0x80, 0x54, 0x32, + 0x72, 0xa5, 0x08, 0x35, 0xd0, 0xb3, 0x66, 0x08, 0x9f, 0xfb, 0xbd, 0x32, 0x9c, 0xed, 0x9f, 0x2b, + 0xc1, 0x13, 0x7d, 0x48, 0x6f, 0x73, 0x16, 0x5b, 0x7d, 0xce, 0xe2, 0xef, 0xed, 0xcf, 0x64, 0xff, + 0x0d, 0x0b, 0xce, 0xf5, 0x56, 0x1e, 0xe8, 0x59, 0x18, 0x5e, 0x8b, 0x1c, 0xbf, 0xb1, 0xc1, 0xae, + 0xc8, 0x94, 0x83, 0xc2, 0xc6, 0x5a, 0x37, 0x63, 0x13, 0x87, 0x6e, 0x6f, 0x79, 0x4c, 0x82, 0x81, + 0x21, 0x93, 0x47, 0xe9, 0xf6, 0x76, 0x35, 0x0b, 0xc4, 0xdd, 0xf8, 0xf6, 0x9f, 0x95, 0xf2, 0xbb, + 0xc5, 0x8d, 0x8c, 0x83, 0x7c, 0x27, 0xf1, 0x15, 0x4a, 0x7d, 0xc8, 0x92, 0xf2, 0xbd, 0x96, 0x25, + 0x03, 0xbd, 0x64, 0x09, 0x9a, 0x85, 0x93, 0xc6, 0x15, 0x2a, 0x3c, 0x21, 0x98, 0x07, 0xdc, 0xaa, + 0x2a, 0x19, 0xcb, 0x19, 0x38, 0xee, 0x7a, 0x02, 0x3d, 0x0d, 0x55, 0xd7, 0x8f, 0x49, 0xa3, 0x13, + 0xf1, 0x40, 0x6f, 0x23, 0x09, 0x6b, 0x5e, 0xb4, 0x63, 0x85, 0x61, 0xff, 0x52, 0x09, 0x1e, 0xe9, + 0x69, 0x67, 0xdd, 0x23, 0xd9, 0x65, 0x7e, 0x8e, 0x81, 0x7b, 0xf3, 0x39, 0xcc, 0x41, 0xaa, 0xec, + 0x3b, 0x48, 0x7f, 0xd8, 0x7b, 0x62, 0x52, 0x9b, 0xfb, 0xfb, 0x76, 0x94, 0x5e, 0x84, 0x51, 0x27, + 0x0c, 0x39, 0x1e, 0x8b, 0xd7, 0xcc, 0x54, 0xc9, 0x99, 0x36, 0x81, 0x38, 0x8d, 0xdb, 0x97, 0xf6, + 0xfc, 0x63, 0x0b, 0x6a, 0x98, 0xac, 0x73, 0xe9, 0x80, 0x6e, 0x89, 0x21, 0xb2, 0x8a, 0xa8, 0xa7, + 0x49, 0x07, 0x36, 0x76, 0x59, 0x9d, 0xc9, 0xbc, 0xc1, 0xee, 0xbe, 0x6a, 0xa7, 0x74, 0xa0, 0xab, + 0x76, 0xd4, 0x65, 0x2b, 0xe5, 0xde, 0x97, 0xad, 0xd8, 0xdf, 0x18, 0xa2, 0xaf, 0x17, 0x06, 0x33, + 0x11, 0x69, 0xc6, 0xf4, 0xfb, 0x76, 0x22, 0x4f, 0x4c, 0x12, 0xf5, 0x7d, 0xaf, 0xe3, 0x05, 0x4c, + 0xdb, 0x53, 0x47, 0x31, 0xa5, 0x03, 0xd5, 0x08, 0x29, 0xef, 0x5b, 0x23, 0xe4, 0x45, 0x18, 0x8d, + 0xe3, 0x8d, 0xe5, 0xc8, 0xdd, 0x72, 0x12, 0x72, 0x95, 0xec, 0x08, 0x2b, 0x4b, 0xe7, 0xf5, 0xaf, + 0x5c, 0xd6, 0x40, 0x9c, 0xc6, 0x45, 0x73, 0x70, 0x4a, 0x57, 0xea, 0x20, 0x51, 0xc2, 0xa2, 0xfb, + 0xf9, 0x4c, 0x50, 0x49, 0xbc, 0xba, 0xb6, 0x87, 0x40, 0xc0, 0xdd, 0xcf, 0x50, 0xf9, 0x96, 0x6a, + 0xa4, 0x1d, 0x19, 0x4c, 0xcb, 0xb7, 0x14, 0x1d, 0xda, 0x97, 0xae, 0x27, 0xd0, 0x22, 0x9c, 0xe6, + 0x13, 0x63, 0x3a, 0x0c, 0x8d, 0x37, 0x1a, 0x4a, 0xd7, 0x31, 0x9c, 0xeb, 0x46, 0xc1, 0x79, 0xcf, + 0xa1, 0xe7, 0x61, 0x58, 0x35, 0xcf, 0xcf, 0x8a, 0x53, 0x04, 0xe5, 0xc5, 0x50, 0x64, 0xe6, 0x9b, + 0xd8, 0xc4, 0x43, 0x1f, 0x84, 0x87, 0xf5, 0x5f, 0x9e, 0x02, 0xc6, 0x8f, 0xd6, 0x66, 0x45, 0x11, + 0x24, 0x75, 0xb5, 0xc7, 0x5c, 0x2e, 0x5a, 0x13, 0xf7, 0x7a, 0x1e, 0xad, 0xc1, 0x39, 0x05, 0xba, + 0xe8, 0x27, 0x2c, 0x9f, 0x23, 0x26, 0x75, 0x27, 0x26, 0xd7, 0x23, 0x4f, 0xdc, 0x8d, 0xaa, 0x6e, + 0x5d, 0x9c, 0x73, 0x93, 0xcb, 0x79, 0x98, 0x78, 0x01, 0xef, 0x41, 0x05, 0x4d, 0x41, 0x8d, 0xf8, + 0xce, 0x9a, 0x47, 0x96, 0x66, 0xe6, 0x59, 0x31, 0x25, 0xe3, 0x24, 0xef, 0xa2, 0x04, 0x60, 0x8d, + 0xa3, 0x22, 0x4c, 0x47, 0x7a, 0xde, 0x00, 0xba, 0x0c, 0x67, 0x5a, 0x8d, 0x90, 0xda, 0x1e, 0x6e, + 0x83, 0x4c, 0x37, 0x58, 0x40, 0x1d, 0xfd, 0x30, 0xbc, 0xc0, 0xa4, 0x0a, 0x9f, 0x9e, 0x9b, 0x59, + 0xee, 0xc2, 0xc1, 0xb9, 0x4f, 0xb2, 0xc0, 0xcb, 0x28, 0xd8, 0xde, 0x19, 0x3f, 0x9d, 0x09, 0xbc, + 0xa4, 0x8d, 0x98, 0xc3, 0xd0, 0x15, 0x40, 0x2c, 0x16, 0xff, 0x72, 0x92, 0x84, 0xca, 0xd8, 0x19, + 0x3f, 0xc3, 0x5e, 0x49, 0x85, 0x91, 0x5d, 0xea, 0xc2, 0xc0, 0x39, 0x4f, 0xd9, 0xff, 0xd1, 0x82, + 0x51, 0xb5, 0x5e, 0xef, 0x41, 0x36, 0x8a, 0x97, 0xce, 0x46, 0x99, 0x3b, 0xba, 0xc4, 0x63, 0x3d, + 0xef, 0x11, 0xd2, 0xfc, 0xd3, 0xc3, 0x00, 0x5a, 0x2a, 0x2a, 0x85, 0x64, 0xf5, 0x54, 0x48, 0x0f, + 0xac, 0x44, 0xca, 0xab, 0x9c, 0x52, 0xb9, 0xbf, 0x95, 0x53, 0x56, 0xe0, 0xac, 0x34, 0x17, 0xf8, + 0x59, 0xd1, 0xe5, 0x20, 0x56, 0x02, 0xae, 0x5a, 0x7f, 0x4c, 0x10, 0x3a, 0x3b, 0x9f, 0x87, 0x84, + 0xf3, 0x9f, 0x4d, 0x59, 0x29, 0x43, 0xfb, 0x59, 0x29, 0x7a, 0x4d, 0x2f, 0xac, 0xcb, 0x3b, 0x3c, + 0x32, 0x6b, 0x7a, 0xe1, 0xd2, 0x0a, 0xd6, 0x38, 0xf9, 0x82, 0xbd, 0x56, 0x90, 0x60, 0x87, 0x03, + 0x0b, 0x76, 0x29, 0x62, 0x86, 0x7b, 0x8a, 0x18, 0xe9, 0x93, 0x1e, 0xe9, 0xe9, 0x93, 0x7e, 0x1f, + 0x8c, 0xb9, 0xfe, 0x06, 0x89, 0xdc, 0x84, 0x34, 0xd9, 0x5a, 0x60, 0xe2, 0xa7, 0xaa, 0xd5, 0xfa, + 0x7c, 0x0a, 0x8a, 0x33, 0xd8, 0x69, 0xb9, 0x38, 0xd6, 0x87, 0x5c, 0xec, 0xa1, 0x8d, 0x4e, 0x14, + 0xa3, 0x8d, 0x4e, 0x1e, 0x5d, 0x1b, 0x9d, 0x3a, 0x56, 0x6d, 0x84, 0x0a, 0xd1, 0x46, 0x7d, 0x09, + 0x7a, 0x63, 0xfb, 0x77, 0x66, 0x9f, 0xed, 0x5f, 0x2f, 0x55, 0x74, 0xf6, 0xd0, 0xaa, 0x28, 0x5f, + 0xcb, 0x3c, 0x74, 0x28, 0x2d, 0xf3, 0x99, 0x12, 0x9c, 0xd5, 0x72, 0x98, 0xce, 0x7e, 0x77, 0x9d, + 0x4a, 0x22, 0x76, 0x0d, 0x14, 0x3f, 0xb7, 0x31, 0x92, 0xa3, 0x74, 0x9e, 0x95, 0x82, 0x60, 0x03, + 0x8b, 0xe5, 0x18, 0x91, 0x88, 0x95, 0xd1, 0xcd, 0x0a, 0xe9, 0x19, 0xd1, 0x8e, 0x15, 0x06, 0x9d, + 0x5f, 0xf4, 0xb7, 0xc8, 0xdb, 0xcc, 0x16, 0x8b, 0x9b, 0xd1, 0x20, 0x6c, 0xe2, 0xa1, 0xa7, 0x38, + 0x13, 0x26, 0x20, 0xa8, 0xa0, 0x1e, 0x11, 0xf7, 0xc2, 0x4a, 0x99, 0xa0, 0xa0, 0xb2, 0x3b, 0x2c, + 0x99, 0xac, 0xd2, 0xdd, 0x1d, 0x16, 0x02, 0xa5, 0x30, 0xec, 0xff, 0x65, 0xc1, 0x23, 0xb9, 0x43, + 0x71, 0x0f, 0x94, 0xef, 0x76, 0x5a, 0xf9, 0xae, 0x14, 0xb5, 0xdd, 0x30, 0xde, 0xa2, 0x87, 0x22, + 0xfe, 0xf7, 0x16, 0x8c, 0x69, 0xfc, 0x7b, 0xf0, 0xaa, 0x6e, 0xfa, 0x55, 0x8b, 0xdb, 0x59, 0xd5, + 0xba, 0xde, 0xed, 0x77, 0x4a, 0xa0, 0x0a, 0x38, 0x4e, 0x37, 0x64, 0x79, 0xdc, 0x7d, 0x4e, 0x12, + 0x77, 0x60, 0x90, 0x1d, 0x84, 0xc6, 0xc5, 0x04, 0x79, 0xa4, 0xf9, 0xb3, 0x43, 0x55, 0x7d, 0xc8, + 0xcc, 0xfe, 0xc6, 0x58, 0x30, 0x64, 0x45, 0x9e, 0xdd, 0x98, 0x4a, 0xf3, 0xa6, 0x48, 0xcb, 0xd2, + 0x45, 0x9e, 0x45, 0x3b, 0x56, 0x18, 0x54, 0x3d, 0xb8, 0x8d, 0xc0, 0x9f, 0xf1, 0x9c, 0x58, 0xde, + 0x7d, 0xa8, 0xd4, 0xc3, 0xbc, 0x04, 0x60, 0x8d, 0xc3, 0xce, 0x48, 0xdd, 0x38, 0xf4, 0x9c, 0x1d, + 0x63, 0xff, 0x6c, 0xd4, 0x27, 0x50, 0x20, 0x6c, 0xe2, 0xd9, 0x6d, 0x18, 0x4f, 0xbf, 0xc4, 0x2c, + 0x59, 0x67, 0x01, 0x8a, 0x7d, 0x0d, 0xe7, 0x14, 0xd4, 0x1c, 0xf6, 0xd4, 0x42, 0xc7, 0xc9, 0x5e, + 0x59, 0x3e, 0x2d, 0x01, 0x58, 0xe3, 0xd8, 0xbf, 0x6a, 0xc1, 0xe9, 0x9c, 0x41, 0x2b, 0x30, 0xed, + 0x2d, 0xd1, 0xd2, 0x26, 0x4f, 0xb1, 0xbf, 0x13, 0x86, 0x9a, 0x64, 0xdd, 0x91, 0x21, 0x70, 0x86, + 0x6c, 0x9f, 0xe5, 0xcd, 0x58, 0xc2, 0xed, 0xff, 0x61, 0xc1, 0x89, 0x74, 0x5f, 0x63, 0x96, 0x4a, + 0xc2, 0x87, 0xc9, 0x8d, 0x1b, 0xc1, 0x16, 0x89, 0x76, 0xe8, 0x9b, 0x5b, 0x99, 0x54, 0x92, 0x2e, + 0x0c, 0x9c, 0xf3, 0x14, 0x2b, 0xdf, 0xda, 0x54, 0xa3, 0x2d, 0x67, 0xe4, 0x8d, 0x22, 0x67, 0xa4, + 0xfe, 0x98, 0xe6, 0x71, 0xb9, 0x62, 0x89, 0x4d, 0xfe, 0xf6, 0x77, 0x06, 0x40, 0xe5, 0xc5, 0xb2, + 0xf8, 0xa3, 0x82, 0xa2, 0xb7, 0x0e, 0x9a, 0x41, 0xa4, 0x26, 0xc3, 0xc0, 0x5e, 0x01, 0x01, 0xdc, + 0x4b, 0x62, 0xba, 0x2e, 0xd5, 0x1b, 0xae, 0x6a, 0x10, 0x36, 0xf1, 0x68, 0x4f, 0x3c, 0x77, 0x8b, + 0xf0, 0x87, 0x06, 0xd3, 0x3d, 0x59, 0x90, 0x00, 0xac, 0x71, 0x68, 0x4f, 0x9a, 0xee, 0xfa, 0xba, + 0xd8, 0xf2, 0xab, 0x9e, 0xd0, 0xd1, 0xc1, 0x0c, 0xc2, 0x2b, 0x72, 0x07, 0x9b, 0xc2, 0x0a, 0x36, + 0x2a, 0x72, 0x07, 0x9b, 0x98, 0x41, 0xa8, 0xdd, 0xe6, 0x07, 0x51, 0x9b, 0x5d, 0x29, 0xdf, 0x54, + 0x5c, 0x84, 0xf5, 0xab, 0xec, 0xb6, 0x6b, 0xdd, 0x28, 0x38, 0xef, 0x39, 0x3a, 0x03, 0xc3, 0x88, + 0x34, 0xdd, 0x46, 0x62, 0x52, 0x83, 0xf4, 0x0c, 0x5c, 0xee, 0xc2, 0xc0, 0x39, 0x4f, 0xa1, 0x69, + 0x38, 0x21, 0xf3, 0x9a, 0x65, 0xd5, 0x9a, 0xe1, 0x74, 0x95, 0x0c, 0x9c, 0x06, 0xe3, 0x2c, 0x3e, + 0x95, 0x6a, 0x6d, 0x51, 0xb0, 0x8a, 0x19, 0xcb, 0x86, 0x54, 0x93, 0x85, 0xac, 0xb0, 0xc2, 0xb0, + 0x3f, 0x59, 0xa6, 0x5a, 0xb8, 0x47, 0xa1, 0xb6, 0x7b, 0x16, 0x2d, 0x98, 0x9e, 0x91, 0x03, 0x7d, + 0xcc, 0xc8, 0xe7, 0x60, 0xe4, 0x56, 0x1c, 0xf8, 0x2a, 0x12, 0xaf, 0xd2, 0x33, 0x12, 0xcf, 0xc0, + 0xca, 0x8f, 0xc4, 0x1b, 0x2c, 0x2a, 0x12, 0x6f, 0xe8, 0x90, 0x91, 0x78, 0xdf, 0xaa, 0x80, 0xba, + 0x1a, 0xe4, 0x1a, 0x49, 0x6e, 0x07, 0xd1, 0xa6, 0xeb, 0xb7, 0x58, 0x3e, 0xf8, 0xd7, 0x2c, 0x18, + 0xe1, 0xeb, 0x65, 0xc1, 0xcc, 0xa4, 0x5a, 0x2f, 0xe8, 0xce, 0x89, 0x14, 0xb3, 0xc9, 0x55, 0x83, + 0x51, 0xe6, 0xea, 0x4d, 0x13, 0x84, 0x53, 0x3d, 0x42, 0x1f, 0x03, 0x90, 0xfe, 0xd1, 0x75, 0x29, + 0x32, 0xe7, 0x8b, 0xe9, 0x1f, 0x26, 0xeb, 0xda, 0x06, 0x5e, 0x55, 0x4c, 0xb0, 0xc1, 0x10, 0x7d, + 0x46, 0x67, 0x99, 0xf1, 0x90, 0xfd, 0x8f, 0x1c, 0xcb, 0xd8, 0xf4, 0x93, 0x63, 0x86, 0x61, 0xc8, + 0xf5, 0x5b, 0x74, 0x9e, 0x88, 0x88, 0xa5, 0x77, 0xe4, 0xd5, 0x52, 0x58, 0x08, 0x9c, 0x66, 0xdd, + 0xf1, 0x1c, 0xbf, 0x41, 0xa2, 0x79, 0x8e, 0x6e, 0x5e, 0x38, 0xcd, 0x1a, 0xb0, 0x24, 0xd4, 0x75, + 0xa9, 0x4a, 0xa5, 0x9f, 0x4b, 0x55, 0xce, 0xbd, 0x1f, 0x4e, 0x75, 0x7d, 0xcc, 0x03, 0xa5, 0x94, + 0x1d, 0x3e, 0x1b, 0xcd, 0xfe, 0x97, 0x83, 0x5a, 0x69, 0x5d, 0x0b, 0x9a, 0xfc, 0x6a, 0x8f, 0x48, + 0x7f, 0x51, 0x61, 0xe3, 0x16, 0x38, 0x45, 0x8c, 0x4b, 0xab, 0x55, 0x23, 0x36, 0x59, 0xd2, 0x39, + 0x1a, 0x3a, 0x11, 0xf1, 0x8f, 0x7b, 0x8e, 0x2e, 0x2b, 0x26, 0xd8, 0x60, 0x88, 0x36, 0x52, 0x39, + 0x25, 0x97, 0x8e, 0x9e, 0x53, 0xc2, 0xaa, 0x4c, 0xe5, 0x55, 0xe3, 0xff, 0xa2, 0x05, 0x63, 0x7e, + 0x6a, 0xe6, 0x16, 0x13, 0x46, 0x9a, 0xbf, 0x2a, 0xf8, 0xcd, 0x52, 0xe9, 0x36, 0x9c, 0xe1, 0x9f, + 0xa7, 0xd2, 0x2a, 0x07, 0x54, 0x69, 0xfa, 0x8e, 0xa0, 0xc1, 0x5e, 0x77, 0x04, 0x21, 0x5f, 0x5d, + 0x92, 0x36, 0x54, 0xf8, 0x25, 0x69, 0x90, 0x73, 0x41, 0xda, 0x4d, 0xa8, 0x35, 0x22, 0xe2, 0x24, + 0x87, 0xbc, 0x2f, 0x8b, 0x1d, 0xd0, 0xcf, 0x48, 0x02, 0x58, 0xd3, 0xb2, 0xff, 0xef, 0x00, 0x9c, + 0x94, 0x23, 0x22, 0x43, 0xd0, 0xa9, 0x7e, 0xe4, 0x7c, 0xb5, 0x71, 0xab, 0xf4, 0xe3, 0x65, 0x09, + 0xc0, 0x1a, 0x87, 0xda, 0x63, 0x9d, 0x98, 0x2c, 0x85, 0xc4, 0x5f, 0x70, 0xd7, 0x62, 0x71, 0xce, + 0xa9, 0x16, 0xca, 0x75, 0x0d, 0xc2, 0x26, 0x1e, 0x35, 0xc6, 0xb9, 0x5d, 0x1c, 0x67, 0xd3, 0x57, + 0x84, 0xbd, 0x8d, 0x25, 0x1c, 0xfd, 0x7c, 0x6e, 0xe5, 0xd8, 0x62, 0x12, 0xb7, 0xba, 0x22, 0xef, + 0x0f, 0x78, 0xc5, 0xe2, 0xdf, 0xb5, 0xe0, 0x2c, 0x6f, 0x95, 0x23, 0x79, 0x3d, 0x6c, 0x3a, 0x09, + 0x89, 0x8b, 0xa9, 0xe4, 0x9e, 0xd3, 0x3f, 0xed, 0xe4, 0xcd, 0x63, 0x8b, 0xf3, 0x7b, 0x83, 0xde, + 0xb0, 0xe0, 0xc4, 0x66, 0xaa, 0xe6, 0x87, 0x54, 0x1d, 0x47, 0x4d, 0xc7, 0x4f, 0x11, 0xd5, 0x4b, + 0x2d, 0xdd, 0x1e, 0xe3, 0x2c, 0x77, 0xfb, 0xcf, 0x2c, 0x30, 0xc5, 0xe8, 0xbd, 0x2f, 0x15, 0x72, + 0x70, 0x53, 0x50, 0x5a, 0x97, 0x95, 0x9e, 0xd6, 0xe5, 0x63, 0x50, 0xee, 0xb8, 0x4d, 0xb1, 0xbf, + 0xd0, 0xa7, 0xaf, 0xf3, 0xb3, 0x98, 0xb6, 0xdb, 0xff, 0xac, 0xa2, 0xfd, 0x16, 0x22, 0x2f, 0xea, + 0xfb, 0xe2, 0xb5, 0xd7, 0x55, 0xb1, 0x31, 0xfe, 0xe6, 0xd7, 0xba, 0x8a, 0x8d, 0xfd, 0xc8, 0xc1, + 0xd3, 0xde, 0xf8, 0x00, 0xf5, 0xaa, 0x35, 0x36, 0xb4, 0x4f, 0xce, 0xdb, 0x2d, 0xa8, 0xd2, 0x2d, + 0x18, 0x73, 0x40, 0x56, 0x53, 0x9d, 0xaa, 0x5e, 0x16, 0xed, 0x77, 0x77, 0x27, 0xde, 0x7b, 0xf0, + 0x6e, 0xc9, 0xa7, 0xb1, 0xa2, 0x8f, 0x62, 0xa8, 0xd1, 0xdf, 0x2c, 0x3d, 0x4f, 0x6c, 0xee, 0xae, + 0x2b, 0x99, 0x29, 0x01, 0x85, 0xe4, 0xfe, 0x69, 0x3e, 0xc8, 0x87, 0x1a, 0xbb, 0x8d, 0x96, 0x31, + 0xe5, 0x7b, 0xc0, 0x65, 0x95, 0x24, 0x27, 0x01, 0x77, 0x77, 0x27, 0x5e, 0x3c, 0x38, 0x53, 0xf5, + 0x38, 0xd6, 0x2c, 0xec, 0x2f, 0x0d, 0xe8, 0xb9, 0x2b, 0x6a, 0xcc, 0x7d, 0x5f, 0xcc, 0xdd, 0x17, + 0x32, 0x73, 0xf7, 0x7c, 0xd7, 0xdc, 0x1d, 0xd3, 0xb7, 0xa6, 0xa6, 0x66, 0xe3, 0xbd, 0x36, 0x04, + 0xf6, 0xf7, 0x37, 0x30, 0x0b, 0xe8, 0xb5, 0x8e, 0x1b, 0x91, 0x78, 0x39, 0xea, 0xf8, 0xae, 0xdf, + 0x62, 0xd3, 0xb1, 0x6a, 0x5a, 0x40, 0x29, 0x30, 0xce, 0xe2, 0xd3, 0x4d, 0x3d, 0xfd, 0xe6, 0x37, + 0x9d, 0x2d, 0x3e, 0xab, 0x8c, 0xb2, 0x5b, 0x2b, 0xa2, 0x1d, 0x2b, 0x0c, 0xfb, 0x1b, 0xec, 0x2c, + 0xdb, 0xc8, 0x0b, 0xa6, 0x73, 0xc2, 0x63, 0xd7, 0xff, 0xf2, 0x9a, 0x5d, 0x6a, 0x4e, 0xf0, 0x3b, + 0x7f, 0x39, 0x0c, 0xdd, 0x86, 0xa1, 0x35, 0x7e, 0xff, 0x5d, 0x31, 0xf5, 0xc9, 0xc5, 0x65, 0x7a, + 0xec, 0x96, 0x13, 0x79, 0xb3, 0xde, 0x5d, 0xfd, 0x13, 0x4b, 0x6e, 0xf6, 0xef, 0x57, 0xe0, 0x44, + 0xe6, 0x82, 0xd8, 0x54, 0xb5, 0xd4, 0xd2, 0xbe, 0xd5, 0x52, 0x3f, 0x0c, 0xd0, 0x24, 0xa1, 0x17, + 0xec, 0x30, 0x73, 0x6c, 0xe0, 0xc0, 0xe6, 0x98, 0xb2, 0xe0, 0x67, 0x15, 0x15, 0x6c, 0x50, 0x14, + 0x85, 0xca, 0x78, 0xf1, 0xd5, 0x4c, 0xa1, 0x32, 0xe3, 0x16, 0x83, 0xc1, 0x7b, 0x7b, 0x8b, 0x81, + 0x0b, 0x27, 0x78, 0x17, 0x55, 0xf6, 0xed, 0x21, 0x92, 0x6c, 0x59, 0xfe, 0xc2, 0x6c, 0x9a, 0x0c, + 0xce, 0xd2, 0xbd, 0x9f, 0xf7, 0x3f, 0xa3, 0x77, 0x41, 0x4d, 0x7e, 0xe7, 0x78, 0xbc, 0xa6, 0x2b, + 0x18, 0xc8, 0x69, 0xc0, 0xee, 0x65, 0x16, 0x3f, 0xbb, 0x0a, 0x09, 0xc0, 0xfd, 0x2a, 0x24, 0x60, + 0x7f, 0xa1, 0x44, 0xed, 0x78, 0xde, 0x2f, 0x55, 0x13, 0xe7, 0x49, 0x18, 0x74, 0x3a, 0xc9, 0x46, + 0xd0, 0x75, 0x9b, 0xdf, 0x34, 0x6b, 0xc5, 0x02, 0x8a, 0x16, 0x60, 0xa0, 0xa9, 0xeb, 0x9c, 0x1c, + 0xe4, 0x7b, 0x6a, 0x97, 0xa8, 0x93, 0x10, 0xcc, 0xa8, 0xa0, 0x47, 0x61, 0x20, 0x71, 0x5a, 0x32, + 0xe5, 0x8a, 0xa5, 0xd9, 0xae, 0x3a, 0xad, 0x18, 0xb3, 0x56, 0x53, 0x7d, 0x0f, 0xec, 0xa3, 0xbe, + 0x5f, 0x84, 0xd1, 0xd8, 0x6d, 0xf9, 0x4e, 0xd2, 0x89, 0x88, 0x71, 0xcc, 0xa7, 0x23, 0x37, 0x4c, + 0x20, 0x4e, 0xe3, 0xda, 0xbf, 0x39, 0x02, 0x67, 0x56, 0x66, 0x16, 0x65, 0xf5, 0xee, 0x63, 0xcb, + 0x9a, 0xca, 0xe3, 0x71, 0xef, 0xb2, 0xa6, 0x7a, 0x70, 0xf7, 0x8c, 0xac, 0x29, 0xcf, 0xc8, 0x9a, + 0x4a, 0xa7, 0xb0, 0x94, 0x8b, 0x48, 0x61, 0xc9, 0xeb, 0x41, 0x3f, 0x29, 0x2c, 0xc7, 0x96, 0x46, + 0xb5, 0x67, 0x87, 0x0e, 0x94, 0x46, 0xa5, 0x72, 0xcc, 0x0a, 0x49, 0x2e, 0xe8, 0xf1, 0xa9, 0x72, + 0x73, 0xcc, 0x54, 0x7e, 0x0f, 0x4f, 0x9c, 0x11, 0xa2, 0xfe, 0x95, 0xe2, 0x3b, 0xd0, 0x47, 0x7e, + 0x8f, 0xc8, 0xdd, 0x31, 0x73, 0xca, 0x86, 0x8a, 0xc8, 0x29, 0xcb, 0xeb, 0xce, 0xbe, 0x39, 0x65, + 0x2f, 0xc2, 0x68, 0xc3, 0x0b, 0x7c, 0xb2, 0x1c, 0x05, 0x49, 0xd0, 0x08, 0x3c, 0x61, 0xd6, 0x2b, + 0x91, 0x30, 0x63, 0x02, 0x71, 0x1a, 0xb7, 0x57, 0x42, 0x5a, 0xed, 0xa8, 0x09, 0x69, 0x70, 0x9f, + 0x12, 0xd2, 0x7e, 0x46, 0xa7, 0x4e, 0x0f, 0xb3, 0x2f, 0xf2, 0xe1, 0xe2, 0xbf, 0x48, 0x3f, 0xf9, + 0xd3, 0xe8, 0x4d, 0x7e, 0x9d, 0x1e, 0x35, 0x8c, 0x67, 0x82, 0x36, 0x35, 0xfc, 0x46, 0xd8, 0x90, + 0xbc, 0x7a, 0x0c, 0x13, 0xf6, 0xe6, 0x8a, 0x66, 0xa3, 0xae, 0xd8, 0xd3, 0x4d, 0x38, 0xdd, 0x91, + 0xa3, 0xa4, 0x76, 0x7f, 0xa5, 0x04, 0x3f, 0xb0, 0x6f, 0x17, 0xd0, 0x6d, 0x80, 0xc4, 0x69, 0x89, + 0x89, 0x2a, 0x0e, 0x4c, 0x8e, 0x18, 0x5e, 0xb9, 0x2a, 0xe9, 0xf1, 0x9a, 0x24, 0xea, 0x2f, 0x3b, + 0x8a, 0x90, 0xbf, 0x59, 0x54, 0x65, 0xe0, 0x75, 0x95, 0x6e, 0xc4, 0x81, 0x47, 0x30, 0x83, 0x50, + 0xf5, 0x1f, 0x91, 0x96, 0xbe, 0xff, 0x59, 0x7d, 0x3e, 0xcc, 0x5a, 0xb1, 0x80, 0xa2, 0xe7, 0x61, + 0xd8, 0xf1, 0x3c, 0x9e, 0x1f, 0x43, 0x62, 0x71, 0x9f, 0x8e, 0xae, 0x21, 0xa7, 0x41, 0xd8, 0xc4, + 0xb3, 0xff, 0xb4, 0x04, 0x13, 0xfb, 0xc8, 0x94, 0xae, 0x8c, 0xbf, 0x4a, 0xdf, 0x19, 0x7f, 0x22, + 0x47, 0x61, 0xb0, 0x47, 0x8e, 0xc2, 0xf3, 0x30, 0x9c, 0x10, 0xa7, 0x2d, 0x02, 0xb2, 0x84, 0x27, + 0x40, 0x9f, 0x00, 0x6b, 0x10, 0x36, 0xf1, 0xa8, 0x14, 0x1b, 0x73, 0x1a, 0x0d, 0x12, 0xc7, 0x32, + 0x09, 0x41, 0x78, 0x53, 0x0b, 0xcb, 0x70, 0x60, 0x4e, 0xea, 0xe9, 0x14, 0x0b, 0x9c, 0x61, 0x99, + 0x1d, 0xf0, 0x5a, 0x9f, 0x03, 0xfe, 0xf5, 0x12, 0x3c, 0xb6, 0xa7, 0x76, 0xeb, 0x3b, 0x3f, 0xa4, + 0x13, 0x93, 0x28, 0x3b, 0x71, 0xae, 0xc7, 0x24, 0xc2, 0x0c, 0xc2, 0x47, 0x29, 0x0c, 0x8d, 0xfb, + 0xb5, 0x8b, 0x4e, 0x5e, 0xe2, 0xa3, 0x94, 0x62, 0x81, 0x33, 0x2c, 0x0f, 0x3b, 0x2d, 0xff, 0x41, + 0x09, 0x9e, 0xe8, 0xc3, 0x06, 0x28, 0x30, 0xc9, 0x2b, 0x9d, 0x6a, 0x57, 0xbe, 0x4f, 0x19, 0x91, + 0x87, 0x1c, 0xae, 0x6f, 0x94, 0xe0, 0x5c, 0x6f, 0x55, 0x8c, 0x7e, 0x14, 0x4e, 0x44, 0x2a, 0x0a, + 0xcb, 0xcc, 0xd2, 0x3b, 0xcd, 0x3d, 0x09, 0x29, 0x10, 0xce, 0xe2, 0xa2, 0x49, 0x80, 0xd0, 0x49, + 0x36, 0xe2, 0x8b, 0xdb, 0x6e, 0x9c, 0x88, 0x2a, 0x34, 0x63, 0xfc, 0xec, 0x4a, 0xb6, 0x62, 0x03, + 0x83, 0xb2, 0x63, 0xff, 0x66, 0x83, 0x6b, 0x41, 0xc2, 0x1f, 0xe2, 0xdb, 0x88, 0xd3, 0xf2, 0xce, + 0x0e, 0x03, 0x84, 0xb3, 0xb8, 0x94, 0x1d, 0x3b, 0x1d, 0xe5, 0x1d, 0xe5, 0xfb, 0x0b, 0xc6, 0x6e, + 0x41, 0xb5, 0x62, 0x03, 0x23, 0x9b, 0x7f, 0x58, 0xd9, 0x3f, 0xff, 0xd0, 0xfe, 0xa7, 0x25, 0x78, + 0xa4, 0xa7, 0x29, 0xd7, 0xdf, 0x02, 0x7c, 0xf0, 0x72, 0x06, 0x0f, 0x37, 0x77, 0x0e, 0x98, 0xdb, + 0xf6, 0xc7, 0x3d, 0x66, 0x9a, 0xc8, 0x6d, 0x3b, 0x7c, 0x72, 0xf8, 0x83, 0x37, 0x9e, 0x5d, 0xe9, + 0x6c, 0x03, 0x07, 0x48, 0x67, 0xcb, 0x7c, 0x8c, 0x4a, 0x9f, 0x0b, 0xf9, 0xcf, 0xcb, 0x3d, 0x87, + 0x97, 0x6e, 0xfd, 0xfa, 0xf2, 0xd3, 0xce, 0xc2, 0x49, 0xd7, 0x67, 0xf7, 0x37, 0xad, 0x74, 0xd6, + 0x44, 0x61, 0x92, 0x52, 0xfa, 0xf6, 0xf4, 0xf9, 0x0c, 0x1c, 0x77, 0x3d, 0xf1, 0x00, 0xa6, 0x17, + 0x1e, 0x6e, 0x48, 0x0f, 0x96, 0xe0, 0x8a, 0x96, 0xe0, 0xac, 0x1c, 0x8a, 0x0d, 0x27, 0x22, 0x4d, + 0xa1, 0x46, 0x62, 0x91, 0x50, 0xf1, 0x08, 0x4f, 0xca, 0xc8, 0x41, 0xc0, 0xf9, 0xcf, 0xb1, 0x2b, + 0x73, 0x82, 0xd0, 0x6d, 0x88, 0x4d, 0x8e, 0xbe, 0x32, 0x87, 0x36, 0x62, 0x0e, 0xb3, 0x3f, 0x0c, + 0x35, 0xf5, 0xfe, 0x3c, 0xac, 0x5b, 0x4d, 0xba, 0xae, 0xb0, 0x6e, 0x35, 0xe3, 0x0c, 0x2c, 0xfa, + 0xb5, 0xa8, 0x49, 0x9c, 0x59, 0x3d, 0x57, 0xc9, 0x0e, 0xb3, 0x8f, 0xed, 0x77, 0xc3, 0x88, 0xf2, + 0xb3, 0xf4, 0x7b, 0x91, 0x90, 0xfd, 0xa5, 0x41, 0x18, 0x4d, 0x15, 0x07, 0x4c, 0x39, 0x58, 0xad, + 0x7d, 0x1d, 0xac, 0x2c, 0x4c, 0xbf, 0xe3, 0xcb, 0x5b, 0xc6, 0x8c, 0x30, 0xfd, 0x8e, 0x4f, 0x30, + 0x87, 0x51, 0xf3, 0xb6, 0x19, 0xed, 0xe0, 0x8e, 0x2f, 0xc2, 0x69, 0x95, 0x79, 0x3b, 0xcb, 0x5a, + 0xb1, 0x80, 0xa2, 0x4f, 0x58, 0x30, 0x12, 0x33, 0xef, 0x3d, 0x77, 0x4f, 0x8b, 0x49, 0x77, 0xe5, + 0xe8, 0xb5, 0x0f, 0x55, 0x21, 0x4c, 0x16, 0x21, 0x63, 0xb6, 0xe0, 0x14, 0x47, 0xf4, 0x69, 0x0b, + 0x6a, 0xea, 0x32, 0x14, 0x71, 0x15, 0xe0, 0x4a, 0xb1, 0xb5, 0x17, 0xb9, 0x5f, 0x53, 0x1d, 0x84, + 0xa8, 0x22, 0x78, 0x58, 0x33, 0x46, 0xb1, 0xf2, 0x1d, 0x0f, 0x1d, 0x8f, 0xef, 0x18, 0x72, 0xfc, + 0xc6, 0xef, 0x82, 0x5a, 0xdb, 0xf1, 0xdd, 0x75, 0x12, 0x27, 0xdc, 0x9d, 0x2b, 0x4b, 0xc2, 0xca, + 0x46, 0xac, 0xe1, 0x54, 0x21, 0xc7, 0xec, 0xc5, 0x12, 0xc3, 0xff, 0xca, 0x14, 0xf2, 0x8a, 0x6e, + 0xc6, 0x26, 0x8e, 0xe9, 0x2c, 0x86, 0xfb, 0xea, 0x2c, 0x1e, 0xde, 0xdb, 0x59, 0x6c, 0xff, 0x23, + 0x0b, 0xce, 0xe6, 0x7e, 0xb5, 0x07, 0x37, 0xf0, 0xd1, 0xfe, 0x72, 0x05, 0x4e, 0xe7, 0x54, 0xf9, + 0x44, 0x3b, 0xe6, 0x7c, 0xb6, 0x8a, 0x88, 0x21, 0x48, 0x1f, 0x89, 0xcb, 0x61, 0xcc, 0x99, 0xc4, + 0x07, 0x3b, 0xaa, 0xd1, 0xc7, 0x25, 0xe5, 0x7b, 0x7b, 0x5c, 0x62, 0x4c, 0xcb, 0x81, 0xfb, 0x3a, + 0x2d, 0x2b, 0xfb, 0x9c, 0x61, 0xfc, 0x9a, 0x05, 0xe3, 0xed, 0x1e, 0xa5, 0xe5, 0x85, 0xe3, 0xf1, + 0xc6, 0xf1, 0x14, 0xae, 0xaf, 0x3f, 0x7a, 0x67, 0x77, 0xa2, 0x67, 0x45, 0x7f, 0xdc, 0xb3, 0x57, + 0xf6, 0x77, 0xca, 0xc0, 0x4a, 0xcc, 0xb2, 0x4a, 0x6e, 0x3b, 0xe8, 0xe3, 0x66, 0xb1, 0x60, 0xab, + 0xa8, 0xc2, 0xb6, 0x9c, 0xb8, 0x2a, 0x36, 0xcc, 0x47, 0x30, 0xaf, 0xf6, 0x70, 0x56, 0x68, 0x95, + 0xfa, 0x10, 0x5a, 0x9e, 0xac, 0xca, 0x5c, 0x2e, 0xbe, 0x2a, 0x73, 0x2d, 0x5b, 0x91, 0x79, 0xef, + 0x4f, 0x3c, 0xf0, 0x40, 0x7e, 0xe2, 0x5f, 0xb0, 0xb8, 0xe0, 0xc9, 0x7c, 0x05, 0x6d, 0x19, 0x58, + 0x7b, 0x58, 0x06, 0x4f, 0x43, 0x35, 0x26, 0xde, 0xfa, 0x65, 0xe2, 0x78, 0xc2, 0x82, 0xd0, 0xe7, + 0xd7, 0xa2, 0x1d, 0x2b, 0x0c, 0x76, 0x6d, 0xab, 0xe7, 0x05, 0xb7, 0x2f, 0xb6, 0xc3, 0x64, 0x47, + 0xd8, 0x12, 0xfa, 0xda, 0x56, 0x05, 0xc1, 0x06, 0x96, 0xfd, 0x77, 0x4a, 0x7c, 0x06, 0x8a, 0x20, + 0x88, 0x17, 0x32, 0x17, 0xed, 0xf5, 0x1f, 0x3f, 0xf0, 0x51, 0x80, 0x86, 0xba, 0xa2, 0x5e, 0x9c, + 0x09, 0x5d, 0x3e, 0xf2, 0xfd, 0xd9, 0x82, 0x9e, 0x7e, 0x0d, 0xdd, 0x86, 0x0d, 0x7e, 0x29, 0x59, + 0x5a, 0xde, 0x57, 0x96, 0xa6, 0xc4, 0xca, 0xc0, 0x3e, 0xda, 0xee, 0x4f, 0x2d, 0x48, 0x59, 0x44, + 0x28, 0x84, 0x0a, 0xed, 0xee, 0x4e, 0x31, 0xb7, 0xef, 0x9b, 0xa4, 0xa9, 0x68, 0x14, 0xd3, 0x9e, + 0xfd, 0xc4, 0x9c, 0x11, 0xf2, 0x44, 0xac, 0x04, 0x1f, 0xd5, 0x6b, 0xc5, 0x31, 0xbc, 0x1c, 0x04, + 0x9b, 0xfc, 0x60, 0x53, 0xc7, 0x5d, 0xd8, 0x2f, 0xc0, 0xa9, 0xae, 0x4e, 0xb1, 0x3b, 0xb5, 0x02, + 0xaa, 0x7d, 0x32, 0xd3, 0x95, 0x25, 0x70, 0x62, 0x0e, 0xb3, 0xbf, 0x61, 0xc1, 0xc9, 0x2c, 0x79, + 0xf4, 0xa6, 0x05, 0xa7, 0xe2, 0x2c, 0xbd, 0xe3, 0x1a, 0x3b, 0x15, 0xef, 0xd8, 0x05, 0xc2, 0xdd, + 0x9d, 0xb0, 0xff, 0x9f, 0x98, 0xfc, 0x37, 0x5d, 0xbf, 0x19, 0xdc, 0x56, 0x86, 0x89, 0xd5, 0xd3, + 0x30, 0xa1, 0xeb, 0xb1, 0xb1, 0x41, 0x9a, 0x1d, 0xaf, 0x2b, 0x73, 0x74, 0x45, 0xb4, 0x63, 0x85, + 0xc1, 0x12, 0xe5, 0x3a, 0xa2, 0x6c, 0x7b, 0x66, 0x52, 0xce, 0x8a, 0x76, 0xac, 0x30, 0xd0, 0x73, + 0x30, 0x62, 0xbc, 0xa4, 0x9c, 0x97, 0xcc, 0x20, 0x37, 0x54, 0x66, 0x8c, 0x53, 0x58, 0x68, 0x12, + 0x40, 0x19, 0x39, 0x52, 0x45, 0x32, 0x47, 0x91, 0x92, 0x44, 0x31, 0x36, 0x30, 0x58, 0x5a, 0xaa, + 0xd7, 0x89, 0x99, 0x8f, 0x7f, 0x50, 0x97, 0x12, 0x9d, 0x11, 0x6d, 0x58, 0x41, 0xa9, 0x34, 0x69, + 0x3b, 0x7e, 0xc7, 0xf1, 0xe8, 0x08, 0x89, 0xad, 0x9f, 0x5a, 0x86, 0x8b, 0x0a, 0x82, 0x0d, 0x2c, + 0xfa, 0xc6, 0x89, 0xdb, 0x26, 0x2f, 0x07, 0xbe, 0x8c, 0x53, 0xd3, 0xc7, 0x3e, 0xa2, 0x1d, 0x2b, + 0x0c, 0xfb, 0xbf, 0x59, 0x70, 0x42, 0x27, 0xb9, 0xf3, 0xdb, 0xb3, 0xcd, 0x9d, 0xaa, 0xb5, 0xef, + 0x4e, 0x35, 0x9d, 0xfd, 0x5b, 0xea, 0x2b, 0xfb, 0xd7, 0x4c, 0xcc, 0x2d, 0xef, 0x99, 0x98, 0xfb, + 0x83, 0xfa, 0x66, 0x56, 0x9e, 0xc1, 0x3b, 0x9c, 0x77, 0x2b, 0x2b, 0xb2, 0x61, 0xb0, 0xe1, 0xa8, + 0x0a, 0x2f, 0x23, 0x7c, 0xef, 0x30, 0x33, 0xcd, 0x90, 0x04, 0xc4, 0x5e, 0x82, 0x9a, 0x3a, 0xfd, + 0x90, 0x1b, 0x55, 0x2b, 0x7f, 0xa3, 0xda, 0x57, 0x82, 0x60, 0x7d, 0xed, 0x9b, 0xdf, 0x7d, 0xfc, + 0x6d, 0xbf, 0xf7, 0xdd, 0xc7, 0xdf, 0xf6, 0x47, 0xdf, 0x7d, 0xfc, 0x6d, 0x9f, 0xb8, 0xf3, 0xb8, + 0xf5, 0xcd, 0x3b, 0x8f, 0x5b, 0xbf, 0x77, 0xe7, 0x71, 0xeb, 0x8f, 0xee, 0x3c, 0x6e, 0x7d, 0xe7, + 0xce, 0xe3, 0xd6, 0x17, 0xff, 0xf3, 0xe3, 0x6f, 0x7b, 0x39, 0x37, 0x50, 0x91, 0xfe, 0x78, 0xa6, + 0xd1, 0x9c, 0xda, 0xba, 0xc0, 0x62, 0xe5, 0xe8, 0xf2, 0x9a, 0x32, 0xe6, 0xd4, 0x94, 0x5c, 0x5e, + 0xff, 0x3f, 0x00, 0x00, 0xff, 0xff, 0xe2, 0x8b, 0xe4, 0x9e, 0x5b, 0xe1, 0x00, 0x00, } func (m *AWSAuthConfig) Marshal() (dAtA []byte, err error) { @@ -5156,6 +5159,11 @@ func (m *AWSAuthConfig) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + i -= len(m.Profile) + copy(dAtA[i:], m.Profile) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Profile))) + i-- + dAtA[i] = 0x1a i -= len(m.RoleARN) copy(dAtA[i:], m.RoleARN) i = encodeVarintGenerated(dAtA, i, uint64(len(m.RoleARN))) @@ -6425,6 +6433,13 @@ func (m *ApplicationSetSpec) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.TemplatePatch != nil { + i -= len(*m.TemplatePatch) + copy(dAtA[i:], *m.TemplatePatch) + i = encodeVarintGenerated(dAtA, i, uint64(len(*m.TemplatePatch))) + i-- + dAtA[i] = 0x52 + } if len(m.IgnoreApplicationDifferences) > 0 { for iNdEx := len(m.IgnoreApplicationDifferences) - 1; iNdEx >= 0; iNdEx-- { { @@ -7246,6 +7261,15 @@ func (m *ApplicationSourceKustomize) MarshalToSizedBuffer(dAtA []byte) (int, err _ = i var l int _ = l + if len(m.Components) > 0 { + for iNdEx := len(m.Components) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Components[iNdEx]) + copy(dAtA[i:], m.Components[iNdEx]) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.Components[iNdEx]))) + i-- + dAtA[i] = 0x6a + } + } if len(m.Patches) > 0 { for iNdEx := len(m.Patches) - 1; iNdEx >= 0; iNdEx-- { { @@ -12776,6 +12800,16 @@ func (m *RevisionHistory) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + { + size, err := m.InitiatedBy.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x52 if len(m.Revisions) > 0 { for iNdEx := len(m.Revisions) - 1; iNdEx >= 0; iNdEx-- { i -= len(m.Revisions[iNdEx]) @@ -14329,6 +14363,8 @@ func (m *AWSAuthConfig) Size() (n int) { n += 1 + l + sovGenerated(uint64(l)) l = len(m.RoleARN) n += 1 + l + sovGenerated(uint64(l)) + l = len(m.Profile) + n += 1 + l + sovGenerated(uint64(l)) return n } @@ -14835,6 +14871,10 @@ func (m *ApplicationSetSpec) Size() (n int) { n += 1 + l + sovGenerated(uint64(l)) } } + if m.TemplatePatch != nil { + l = len(*m.TemplatePatch) + n += 1 + l + sovGenerated(uint64(l)) + } return n } @@ -15146,6 +15186,12 @@ func (m *ApplicationSourceKustomize) Size() (n int) { n += 1 + l + sovGenerated(uint64(l)) } } + if len(m.Components) > 0 { + for _, s := range m.Components { + l = len(s) + n += 1 + l + sovGenerated(uint64(l)) + } + } return n } @@ -17198,6 +17244,8 @@ func (m *RevisionHistory) Size() (n int) { n += 1 + l + sovGenerated(uint64(l)) } } + l = m.InitiatedBy.Size() + n += 1 + l + sovGenerated(uint64(l)) return n } @@ -17766,6 +17814,7 @@ func (this *AWSAuthConfig) String() string { s := strings.Join([]string{`&AWSAuthConfig{`, `ClusterName:` + fmt.Sprintf("%v", this.ClusterName) + `,`, `RoleARN:` + fmt.Sprintf("%v", this.RoleARN) + `,`, + `Profile:` + fmt.Sprintf("%v", this.Profile) + `,`, `}`, }, "") return s @@ -18117,6 +18166,7 @@ func (this *ApplicationSetSpec) String() string { `GoTemplateOptions:` + fmt.Sprintf("%v", this.GoTemplateOptions) + `,`, `ApplyNestedSelectors:` + fmt.Sprintf("%v", this.ApplyNestedSelectors) + `,`, `IgnoreApplicationDifferences:` + repeatedStringForIgnoreApplicationDifferences + `,`, + `TemplatePatch:` + valueToStringGenerated(this.TemplatePatch) + `,`, `}`, }, "") return s @@ -18355,6 +18405,7 @@ func (this *ApplicationSourceKustomize) String() string { `CommonAnnotationsEnvsubst:` + fmt.Sprintf("%v", this.CommonAnnotationsEnvsubst) + `,`, `Replicas:` + repeatedStringForReplicas + `,`, `Patches:` + repeatedStringForPatches + `,`, + `Components:` + fmt.Sprintf("%v", this.Components) + `,`, `}`, }, "") return s @@ -19942,6 +19993,7 @@ func (this *RevisionHistory) String() string { `DeployStartedAt:` + strings.Replace(fmt.Sprintf("%v", this.DeployStartedAt), "Time", "v1.Time", 1) + `,`, `Sources:` + repeatedStringForSources + `,`, `Revisions:` + fmt.Sprintf("%v", this.Revisions) + `,`, + `InitiatedBy:` + strings.Replace(strings.Replace(this.InitiatedBy.String(), "OperationInitiator", "OperationInitiator", 1), `&`, ``, 1) + `,`, `}`, }, "") return s @@ -20413,6 +20465,38 @@ func (m *AWSAuthConfig) Unmarshal(dAtA []byte) error { } m.RoleARN = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Profile", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Profile = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) @@ -24385,6 +24469,39 @@ func (m *ApplicationSetSpec) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TemplatePatch", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + s := string(dAtA[iNdEx:postIndex]) + m.TemplatePatch = &s + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) @@ -27183,6 +27300,38 @@ func (m *ApplicationSourceKustomize) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 13: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Components", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Components = append(m.Components, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) @@ -45671,6 +45820,39 @@ func (m *RevisionHistory) Unmarshal(dAtA []byte) error { } m.Revisions = append(m.Revisions, string(dAtA[iNdEx:postIndex])) iNdEx = postIndex + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field InitiatedBy", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.InitiatedBy.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) diff --git a/pkg/apis/application/v1alpha1/generated.proto b/pkg/apis/application/v1alpha1/generated.proto index a0e6782be69f9..8a6fa85d9ad1b 100644 --- a/pkg/apis/application/v1alpha1/generated.proto +++ b/pkg/apis/application/v1alpha1/generated.proto @@ -22,6 +22,9 @@ message AWSAuthConfig { // RoleARN contains optional role ARN. If set then AWS IAM Authenticator assume a role to perform cluster operations instead of the default AWS credential provider chain. optional string roleARN = 2; + + // Profile contains optional role ARN. If set then AWS IAM Authenticator uses the profile to perform cluster operations instead of the default AWS credential provider chain. + optional string profile = 3; } // AppProject provides a logical grouping of applications, providing controls for: @@ -316,6 +319,8 @@ message ApplicationSetSpec { optional bool applyNestedSelectors = 8; repeated ApplicationSetResourceIgnoreDifferences ignoreApplicationDifferences = 9; + + optional string templatePatch = 10; } // ApplicationSetStatus defines the observed state of ApplicationSet @@ -521,6 +526,9 @@ message ApplicationSourceKustomize { // Patches is a list of Kustomize patches repeated KustomizePatch patches = 12; + + // Components specifies a list of kustomize components to add to the kustomization before building + repeated string components = 13; } // ApplicationSourcePlugin holds options specific to config management plugins @@ -1890,6 +1898,9 @@ message RevisionHistory { // Revisions holds the revision of each source in sources field the sync was performed against repeated string revisions = 9; + + // InitiatedBy contains information about who initiated the operations + optional OperationInitiator initiatedBy = 10; } // RevisionMetadata contains metadata for a specific revision in a Git repository diff --git a/pkg/apis/application/v1alpha1/openapi_generated.go b/pkg/apis/application/v1alpha1/openapi_generated.go index 561b361d13d43..ae07404f60f2c 100644 --- a/pkg/apis/application/v1alpha1/openapi_generated.go +++ b/pkg/apis/application/v1alpha1/openapi_generated.go @@ -191,6 +191,13 @@ func schema_pkg_apis_application_v1alpha1_AWSAuthConfig(ref common.ReferenceCall Format: "", }, }, + "profile": { + SchemaProps: spec.SchemaProps{ + Description: "Profile contains optional role ARN. If set then AWS IAM Authenticator uses the profile to perform cluster operations instead of the default AWS credential provider chain.", + Type: []string{"string"}, + Format: "", + }, + }, }, }, }, @@ -1281,6 +1288,12 @@ func schema_pkg_apis_application_v1alpha1_ApplicationSetSpec(ref common.Referenc }, }, }, + "templatePatch": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, }, Required: []string{"generators", "template"}, }, @@ -1957,6 +1970,21 @@ func schema_pkg_apis_application_v1alpha1_ApplicationSourceKustomize(ref common. }, }, }, + "components": { + SchemaProps: spec.SchemaProps{ + Description: "Components specifies a list of kustomize components to add to the kustomization before building", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, }, }, }, @@ -6641,12 +6669,19 @@ func schema_pkg_apis_application_v1alpha1_RevisionHistory(ref common.ReferenceCa }, }, }, + "initiatedBy": { + SchemaProps: spec.SchemaProps{ + Description: "InitiatedBy contains information about who initiated the operations", + Default: map[string]interface{}{}, + Ref: ref("github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.OperationInitiator"), + }, + }, }, Required: []string{"deployedAt", "id"}, }, }, Dependencies: []string{ - "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSource", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.ApplicationSource", "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1.OperationInitiator", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, } } diff --git a/pkg/apis/application/v1alpha1/repository_types.go b/pkg/apis/application/v1alpha1/repository_types.go index 31e8c47971414..3a557813d87c6 100644 --- a/pkg/apis/application/v1alpha1/repository_types.go +++ b/pkg/apis/application/v1alpha1/repository_types.go @@ -196,7 +196,7 @@ func (repo *Repository) GetGitCreds(store git.CredsStore) git.Creds { return git.NewHTTPSCreds(repo.Username, repo.Password, repo.TLSClientCertData, repo.TLSClientCertKey, repo.IsInsecure(), repo.Proxy, store, repo.ForceHttpBasicAuth) } if repo.SSHPrivateKey != "" { - return git.NewSSHCreds(repo.SSHPrivateKey, getCAPath(repo.Repo), repo.IsInsecure(), store) + return git.NewSSHCreds(repo.SSHPrivateKey, getCAPath(repo.Repo), repo.IsInsecure(), store, repo.Proxy) } if repo.GithubAppPrivateKey != "" && repo.GithubAppId != 0 && repo.GithubAppInstallationId != 0 { return git.NewGitHubAppCreds(repo.GithubAppId, repo.GithubAppInstallationId, repo.GithubAppPrivateKey, repo.GitHubAppEnterpriseBaseURL, repo.Repo, repo.TLSClientCertData, repo.TLSClientCertKey, repo.IsInsecure(), repo.Proxy, store) diff --git a/pkg/apis/application/v1alpha1/types.go b/pkg/apis/application/v1alpha1/types.go index 8d02fa5bfb624..18829dbcf940d 100644 --- a/pkg/apis/application/v1alpha1/types.go +++ b/pkg/apis/application/v1alpha1/types.go @@ -35,11 +35,11 @@ import ( "k8s.io/client-go/tools/clientcmd/api" "sigs.k8s.io/yaml" - "github.com/argoproj/argo-cd/v2/util/env" - "github.com/argoproj/argo-cd/v2/common" "github.com/argoproj/argo-cd/v2/util/collections" + "github.com/argoproj/argo-cd/v2/util/env" "github.com/argoproj/argo-cd/v2/util/helm" + utilhttp "github.com/argoproj/argo-cd/v2/util/http" "github.com/argoproj/argo-cd/v2/util/security" ) @@ -467,6 +467,8 @@ type ApplicationSourceKustomize struct { Replicas KustomizeReplicas `json:"replicas,omitempty" protobuf:"bytes,11,opt,name=replicas"` // Patches is a list of Kustomize patches Patches KustomizePatches `json:"patches,omitempty" protobuf:"bytes,12,opt,name=patches"` + // Components specifies a list of kustomize components to add to the kustomization before building + Components []string `json:"components,omitempty" protobuf:"bytes,13,rep,name=components"` } type KustomizeReplica struct { @@ -556,7 +558,8 @@ func (k *ApplicationSourceKustomize) AllowsConcurrentProcessing() bool { k.NamePrefix == "" && k.Namespace == "" && k.NameSuffix == "" && - len(k.Patches) == 0 + len(k.Patches) == 0 && + len(k.Components) == 0 } // IsZero returns true when the Kustomize options are considered empty @@ -570,7 +573,8 @@ func (k *ApplicationSourceKustomize) IsZero() bool { len(k.Replicas) == 0 && len(k.CommonLabels) == 0 && len(k.CommonAnnotations) == 0 && - len(k.Patches) == 0 + len(k.Patches) == 0 && + len(k.Components) == 0 } // MergeImage merges a new Kustomize image identifier in to a list of images @@ -951,6 +955,35 @@ type ApplicationStatus struct { ControllerNamespace string `json:"controllerNamespace,omitempty" protobuf:"bytes,13,opt,name=controllerNamespace"` } +// GetRevisions will return the current revision associated with the Application. +// If app has multisources, it will return all corresponding revisions preserving +// order from the app.spec.sources. If app has only one source, it will return a +// single revision in the list. +func (a *ApplicationStatus) GetRevisions() []string { + revisions := []string{} + if len(a.Sync.Revisions) > 0 { + revisions = a.Sync.Revisions + } else if a.Sync.Revision != "" { + revisions = append(revisions, a.Sync.Revision) + } + return revisions +} + +// BuildComparedToStatus will build a ComparedTo object based on the current +// Application state. +func (app *Application) BuildComparedToStatus() ComparedTo { + ct := ComparedTo{ + Destination: app.Spec.Destination, + IgnoreDifferences: app.Spec.IgnoreDifferences, + } + if app.Spec.HasMultipleSources() { + ct.Sources = app.Spec.Sources + } else { + ct.Source = app.Spec.GetSource() + } + return ct +} + // JWTTokens represents a list of JWT tokens type JWTTokens struct { Items []JWTToken `json:"items,omitempty" protobuf:"bytes,1,opt,name=items"` @@ -1135,11 +1168,12 @@ type SyncPolicy struct { Retry *RetryStrategy `json:"retry,omitempty" protobuf:"bytes,3,opt,name=retry"` // ManagedNamespaceMetadata controls metadata in the given namespace (if CreateNamespace=true) ManagedNamespaceMetadata *ManagedNamespaceMetadata `json:"managedNamespaceMetadata,omitempty" protobuf:"bytes,4,opt,name=managedNamespaceMetadata"` + // If you add a field here, be sure to update IsZero. } // IsZero returns true if the sync policy is empty func (p *SyncPolicy) IsZero() bool { - return p == nil || (p.Automated == nil && len(p.SyncOptions) == 0 && p.Retry == nil) + return p == nil || (p.Automated == nil && len(p.SyncOptions) == 0 && p.Retry == nil && p.ManagedNamespaceMetadata == nil) } // RetryStrategy contains information about the strategy to apply when a sync failed @@ -1367,6 +1401,8 @@ type RevisionHistory struct { Sources ApplicationSources `json:"sources,omitempty" protobuf:"bytes,8,opt,name=sources"` // Revisions holds the revision of each source in sources field the sync was performed against Revisions []string `json:"revisions,omitempty" protobuf:"bytes,9,opt,name=revisions"` + // InitiatedBy contains information about who initiated the operations + InitiatedBy OperationInitiator `json:"initiatedBy,omitempty" protobuf:"bytes,10,opt,name=initiatedBy"` } // ApplicationWatchEvent contains information about application change. @@ -1820,6 +1856,9 @@ type AWSAuthConfig struct { // RoleARN contains optional role ARN. If set then AWS IAM Authenticator assume a role to perform cluster operations instead of the default AWS credential provider chain. RoleARN string `json:"roleARN,omitempty" protobuf:"bytes,2,opt,name=roleARN"` + + // Profile contains optional role ARN. If set then AWS IAM Authenticator uses the profile to perform cluster operations instead of the default AWS credential provider chain. + Profile string `json:"profile,omitempty" protobuf:"bytes,3,opt,name=profile"` } // ExecProviderConfig is config used to call an external command to perform cluster authentication @@ -2617,6 +2656,18 @@ func (app *Application) IsRefreshRequested() (RefreshType, bool) { return refreshType, true } +func (app *Application) HasPostDeleteFinalizer(stage ...string) bool { + return getFinalizerIndex(app.ObjectMeta, strings.Join(append([]string{PostDeleteFinalizerName}, stage...), "/")) > -1 +} + +func (app *Application) SetPostDeleteFinalizer(stage ...string) { + setFinalizer(&app.ObjectMeta, strings.Join(append([]string{PostDeleteFinalizerName}, stage...), "/"), true) +} + +func (app *Application) UnSetPostDeleteFinalizer(stage ...string) { + setFinalizer(&app.ObjectMeta, strings.Join(append([]string{PostDeleteFinalizerName}, stage...), "/"), false) +} + // SetCascadedDeletion will enable cascaded deletion by setting the propagation policy finalizer func (app *Application) SetCascadedDeletion(finalizer string) { setFinalizer(&app.ObjectMeta, finalizer, true) @@ -2891,6 +2942,12 @@ func SetK8SConfigDefaults(config *rest.Config) error { config.Timeout = K8sServerSideTimeout config.Transport = tr + maxRetries := env.ParseInt64FromEnv(utilhttp.EnvRetryMax, 0, 1, math.MaxInt64) + if maxRetries > 0 { + backoffDurationMS := env.ParseInt64FromEnv(utilhttp.EnvRetryBaseBackoff, 100, 1, math.MaxInt64) + backoffDuration := time.Duration(backoffDurationMS) * time.Millisecond + config.WrapTransport = utilhttp.WithRetry(maxRetries, backoffDuration) + } return nil } @@ -2933,6 +2990,9 @@ func (c *Cluster) RawRestConfig() *rest.Config { if c.Config.AWSAuthConfig.RoleARN != "" { args = append(args, "--role-arn", c.Config.AWSAuthConfig.RoleARN) } + if c.Config.AWSAuthConfig.Profile != "" { + args = append(args, "--profile", c.Config.AWSAuthConfig.Profile) + } config = &rest.Config{ Host: c.Server, TLSClientConfig: tlsClientConfig, diff --git a/pkg/apis/application/v1alpha1/types_test.go b/pkg/apis/application/v1alpha1/types_test.go index 35b49f8e91c70..2374f5fb503e6 100644 --- a/pkg/apis/application/v1alpha1/types_test.go +++ b/pkg/apis/application/v1alpha1/types_test.go @@ -370,7 +370,7 @@ func TestAppProject_IsDestinationPermitted_PermitOnlyProjectScopedClusters(t *te projDest: []ApplicationDestination{{ Server: "https://my-cluster.123.com", Namespace: "default", }}, - appDest: ApplicationDestination{Server: "https://some-other-cluster.com", Namespace: "default"}, + appDest: ApplicationDestination{Server: "https://some-other-cluster.example.com", Namespace: "default"}, clusters: []*Cluster{{ Server: "https://my-cluster.123.com", }}, @@ -646,7 +646,7 @@ func TestAppProject_ValidateDestinations(t *testing.T) { err = p.ValidateProject() assert.NoError(t, err) - //no duplicates allowed + // no duplicates allowed p.Spec.Destinations = []ApplicationDestination{validDestination, validDestination} err = p.ValidateProject() assert.Error(t, err) @@ -2966,7 +2966,7 @@ func TestRetryStrategy_NextRetryAtCustomBackoff(t *testing.T) { retry := RetryStrategy{ Backoff: &Backoff{ Duration: "2s", - Factor: pointer.Int64Ptr(3), + Factor: pointer.Int64(3), MaxDuration: "1m", }, } @@ -3075,10 +3075,10 @@ func TestOrphanedResourcesMonitorSettings_IsWarn(t *testing.T) { settings := OrphanedResourcesMonitorSettings{} assert.False(t, settings.IsWarn()) - settings.Warn = pointer.BoolPtr(false) + settings.Warn = pointer.Bool(false) assert.False(t, settings.IsWarn()) - settings.Warn = pointer.BoolPtr(true) + settings.Warn = pointer.Bool(true) assert.True(t, settings.IsWarn()) } diff --git a/pkg/apis/application/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/application/v1alpha1/zz_generated.deepcopy.go index 8732d2f484996..8c851067a6be3 100644 --- a/pkg/apis/application/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/application/v1alpha1/zz_generated.deepcopy.go @@ -733,6 +733,11 @@ func (in *ApplicationSetSpec) DeepCopyInto(out *ApplicationSetSpec) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.TemplatePatch != nil { + in, out := &in.TemplatePatch, &out.TemplatePatch + *out = new(string) + **out = **in + } return } @@ -1103,6 +1108,11 @@ func (in *ApplicationSourceKustomize) DeepCopyInto(out *ApplicationSourceKustomi (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.Components != nil { + in, out := &in.Components, &out.Components + *out = make([]string, len(*in)) + copy(*out, *in) + } return } @@ -3679,6 +3689,7 @@ func (in *RevisionHistory) DeepCopyInto(out *RevisionHistory) { *out = make([]string, len(*in)) copy(*out, *in) } + out.InitiatedBy = in.InitiatedBy return } diff --git a/pkg/client/clientset/versioned/clientset.go b/pkg/client/clientset/versioned/clientset.go index 0c0911e0387c5..869b10d0f82d6 100644 --- a/pkg/client/clientset/versioned/clientset.go +++ b/pkg/client/clientset/versioned/clientset.go @@ -17,8 +17,7 @@ type Interface interface { ArgoprojV1alpha1() argoprojv1alpha1.ArgoprojV1alpha1Interface } -// Clientset contains the clients for groups. Each group has exactly one -// version included in a Clientset. +// Clientset contains the clients for groups. type Clientset struct { *discovery.DiscoveryClient argoprojV1alpha1 *argoprojv1alpha1.ArgoprojV1alpha1Client diff --git a/pkg/client/informers/externalversions/factory.go b/pkg/client/informers/externalversions/factory.go index 57bd66c672490..7d04eeb35ed52 100644 --- a/pkg/client/informers/externalversions/factory.go +++ b/pkg/client/informers/externalversions/factory.go @@ -31,6 +31,11 @@ type sharedInformerFactory struct { // startedInformers is used for tracking which informers have been started. // This allows Start() to be called multiple times safely. startedInformers map[reflect.Type]bool + // wg tracks how many goroutines were started. + wg sync.WaitGroup + // shuttingDown is true when Shutdown has been called. It may still be running + // because it needs to wait for goroutines. + shuttingDown bool } // WithCustomResyncConfig sets a custom resync period for the specified informer types. @@ -91,20 +96,39 @@ func NewSharedInformerFactoryWithOptions(client versioned.Interface, defaultResy return factory } -// Start initializes all requested informers. func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) { f.lock.Lock() defer f.lock.Unlock() + if f.shuttingDown { + return + } + for informerType, informer := range f.informers { if !f.startedInformers[informerType] { - go informer.Run(stopCh) + f.wg.Add(1) + // We need a new variable in each loop iteration, + // otherwise the goroutine would use the loop variable + // and that keeps changing. + informer := informer + go func() { + defer f.wg.Done() + informer.Run(stopCh) + }() f.startedInformers[informerType] = true } } } -// WaitForCacheSync waits for all started informers' cache were synced. +func (f *sharedInformerFactory) Shutdown() { + f.lock.Lock() + f.shuttingDown = true + f.lock.Unlock() + + // Will return immediately if there is nothing to wait for. + f.wg.Wait() +} + func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool { informers := func() map[reflect.Type]cache.SharedIndexInformer { f.lock.Lock() @@ -151,11 +175,58 @@ func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internal // SharedInformerFactory provides shared informers for resources in all known // API group versions. +// +// It is typically used like this: +// +// ctx, cancel := context.Background() +// defer cancel() +// factory := NewSharedInformerFactory(client, resyncPeriod) +// defer factory.WaitForStop() // Returns immediately if nothing was started. +// genericInformer := factory.ForResource(resource) +// typedInformer := factory.SomeAPIGroup().V1().SomeType() +// factory.Start(ctx.Done()) // Start processing these informers. +// synced := factory.WaitForCacheSync(ctx.Done()) +// for v, ok := range synced { +// if !ok { +// fmt.Fprintf(os.Stderr, "caches failed to sync: %v", v) +// return +// } +// } +// +// // Creating informers can also be created after Start, but then +// // Start must be called again: +// anotherGenericInformer := factory.ForResource(resource) +// factory.Start(ctx.Done()) type SharedInformerFactory interface { internalinterfaces.SharedInformerFactory - ForResource(resource schema.GroupVersionResource) (GenericInformer, error) + + // Start initializes all requested informers. They are handled in goroutines + // which run until the stop channel gets closed. + Start(stopCh <-chan struct{}) + + // Shutdown marks a factory as shutting down. At that point no new + // informers can be started anymore and Start will return without + // doing anything. + // + // In addition, Shutdown blocks until all goroutines have terminated. For that + // to happen, the close channel(s) that they were started with must be closed, + // either before Shutdown gets called or while it is waiting. + // + // Shutdown may be called multiple times, even concurrently. All such calls will + // block until all goroutines have terminated. + Shutdown() + + // WaitForCacheSync blocks until all started informers' caches were synced + // or the stop channel gets closed. WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool + // ForResource gives generic access to a shared informer of the matching type. + ForResource(resource schema.GroupVersionResource) (GenericInformer, error) + + // InternalInformerFor returns the SharedIndexInformer for obj using an internal + // client. + InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer + Argoproj() application.Interface } diff --git a/pkg/ratelimiter/ratelimiter.go b/pkg/ratelimiter/ratelimiter.go new file mode 100644 index 0000000000000..32507d883e8ae --- /dev/null +++ b/pkg/ratelimiter/ratelimiter.go @@ -0,0 +1,123 @@ +package ratelimiter + +import ( + "math" + "sync" + "time" + + "golang.org/x/time/rate" + "k8s.io/client-go/util/workqueue" +) + +type AppControllerRateLimiterConfig struct { + BucketSize int64 + BucketQPS int64 + FailureCoolDown time.Duration + BaseDelay time.Duration + MaxDelay time.Duration + BackoffFactor float64 +} + +func GetDefaultAppRateLimiterConfig() *AppControllerRateLimiterConfig { + return &AppControllerRateLimiterConfig{ + // global queue rate limit config + 500, + 50, + // individual item rate limit config + // when WORKQUEUE_FAILURE_COOLDOWN is 0 per item rate limiting is disabled(default) + 0, + time.Millisecond, + time.Second, + 1.5, + } +} + +// NewCustomAppControllerRateLimiter is a constructor for the rate limiter for a workqueue used by app controller. It has +// both overall and per-item rate limiting. The overall is a token bucket and the per-item is exponential(with auto resets) +func NewCustomAppControllerRateLimiter(cfg *AppControllerRateLimiterConfig) workqueue.RateLimiter { + return workqueue.NewMaxOfRateLimiter( + NewItemExponentialRateLimiterWithAutoReset(cfg.BaseDelay, cfg.MaxDelay, cfg.FailureCoolDown, cfg.BackoffFactor), + &workqueue.BucketRateLimiter{Limiter: rate.NewLimiter(rate.Limit(cfg.BucketQPS), int(cfg.BucketSize))}, + ) +} + +type failureData struct { + failures int + lastFailure time.Time +} + +// ItemExponentialRateLimiterWithAutoReset does a simple baseDelay*2^ limit +// dealing with max failures and expiration/resets are up dependent on the cooldown period +type ItemExponentialRateLimiterWithAutoReset struct { + failuresLock sync.Mutex + failures map[interface{}]failureData + + baseDelay time.Duration + maxDelay time.Duration + coolDown time.Duration + backoffFactor float64 +} + +var _ workqueue.RateLimiter = &ItemExponentialRateLimiterWithAutoReset{} + +func NewItemExponentialRateLimiterWithAutoReset(baseDelay, maxDelay, failureCoolDown time.Duration, backoffFactor float64) workqueue.RateLimiter { + return &ItemExponentialRateLimiterWithAutoReset{ + failures: map[interface{}]failureData{}, + baseDelay: baseDelay, + maxDelay: maxDelay, + coolDown: failureCoolDown, + backoffFactor: backoffFactor, + } +} + +func (r *ItemExponentialRateLimiterWithAutoReset) When(item interface{}) time.Duration { + r.failuresLock.Lock() + defer r.failuresLock.Unlock() + + if _, ok := r.failures[item]; !ok { + r.failures[item] = failureData{ + failures: 0, + lastFailure: time.Now(), + } + } + + exp := r.failures[item] + + // if coolDown period is reached reset failures for item + if time.Since(exp.lastFailure) >= r.coolDown { + delete(r.failures, item) + return r.baseDelay + } + + r.failures[item] = failureData{ + failures: exp.failures + 1, + lastFailure: time.Now(), + } + + // The backoff is capped such that 'calculated' value never overflows. + backoff := float64(r.baseDelay.Nanoseconds()) * math.Pow(r.backoffFactor, float64(exp.failures)) + if backoff > math.MaxInt64 { + return r.maxDelay + } + + calculated := time.Duration(backoff) + if calculated > r.maxDelay { + return r.maxDelay + } + + return calculated +} + +func (r *ItemExponentialRateLimiterWithAutoReset) NumRequeues(item interface{}) int { + r.failuresLock.Lock() + defer r.failuresLock.Unlock() + + return r.failures[item].failures +} + +func (r *ItemExponentialRateLimiterWithAutoReset) Forget(item interface{}) { + r.failuresLock.Lock() + defer r.failuresLock.Unlock() + + delete(r.failures, item) +} diff --git a/reposerver/apiclient/repository.pb.go b/reposerver/apiclient/repository.pb.go index 4c05248b87e16..914a967db3dfc 100644 --- a/reposerver/apiclient/repository.pb.go +++ b/reposerver/apiclient/repository.pb.go @@ -1910,6 +1910,7 @@ type GitFilesRequest struct { Revision string `protobuf:"bytes,3,opt,name=revision,proto3" json:"revision,omitempty"` Path string `protobuf:"bytes,4,opt,name=path,proto3" json:"path,omitempty"` NewGitFileGlobbingEnabled bool `protobuf:"varint,5,opt,name=NewGitFileGlobbingEnabled,proto3" json:"NewGitFileGlobbingEnabled,omitempty"` + NoRevisionCache bool `protobuf:"varint,6,opt,name=noRevisionCache,proto3" json:"noRevisionCache,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -1983,6 +1984,13 @@ func (m *GitFilesRequest) GetNewGitFileGlobbingEnabled() bool { return false } +func (m *GitFilesRequest) GetNoRevisionCache() bool { + if m != nil { + return m.NoRevisionCache + } + return false +} + type GitFilesResponse struct { // Map consisting of path of the path to its contents in bytes Map map[string][]byte `protobuf:"bytes,1,rep,name=map,proto3" json:"map,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` @@ -2035,6 +2043,7 @@ type GitDirectoriesRequest struct { Repo *v1alpha1.Repository `protobuf:"bytes,1,opt,name=repo,proto3" json:"repo,omitempty"` SubmoduleEnabled bool `protobuf:"varint,2,opt,name=submoduleEnabled,proto3" json:"submoduleEnabled,omitempty"` Revision string `protobuf:"bytes,3,opt,name=revision,proto3" json:"revision,omitempty"` + NoRevisionCache bool `protobuf:"varint,4,opt,name=noRevisionCache,proto3" json:"noRevisionCache,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -2094,6 +2103,13 @@ func (m *GitDirectoriesRequest) GetRevision() string { return "" } +func (m *GitDirectoriesRequest) GetNoRevisionCache() bool { + if m != nil { + return m.NoRevisionCache + } + return false +} + type GitDirectoriesResponse struct { // A set of directory paths Paths []string `protobuf:"bytes,1,rep,name=paths,proto3" json:"paths,omitempty"` @@ -2189,140 +2205,140 @@ func init() { } var fileDescriptor_dd8723cfcc820480 = []byte{ - // 2114 bytes of a gzipped FileDescriptorProto + // 2127 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x5a, 0x5b, 0x6f, 0x1b, 0xc7, - 0x15, 0xe6, 0x92, 0xba, 0x90, 0x47, 0xb2, 0x44, 0x8d, 0x75, 0x59, 0x31, 0x8e, 0xa0, 0x6c, 0x6b, - 0x43, 0xb5, 0x13, 0x12, 0x92, 0x91, 0xb8, 0x70, 0xd2, 0x14, 0x8a, 0x62, 0x4b, 0x8e, 0x2d, 0x5b, - 0x5d, 0xbb, 0x2d, 0xd2, 0xba, 0x2d, 0x86, 0xcb, 0x21, 0xb9, 0xe1, 0x5e, 0xc6, 0xbb, 0xb3, 0x0a, - 0x64, 0xa0, 0x0f, 0x45, 0x8b, 0x02, 0xfd, 0x03, 0x7d, 0xe8, 0xff, 0x28, 0xfa, 0x54, 0xf4, 0xa9, - 0x97, 0xc7, 0xa0, 0x7f, 0xa0, 0x85, 0x1f, 0xfb, 0x2b, 0x8a, 0xb9, 0xec, 0x95, 0x2b, 0xd9, 0x29, - 0x65, 0x19, 0xcd, 0x8b, 0xbd, 0x73, 0xe6, 0xcc, 0x39, 0x67, 0xce, 0x9c, 0xcb, 0x37, 0x43, 0xc1, - 0xb5, 0x80, 0x50, 0x3f, 0x24, 0xc1, 0x31, 0x09, 0x3a, 0xe2, 0xd3, 0x66, 0x7e, 0x70, 0x92, 0xf9, - 0x6c, 0xd3, 0xc0, 0x67, 0x3e, 0x82, 0x94, 0xd2, 0x7a, 0x30, 0xb0, 0xd9, 0x30, 0xea, 0xb6, 0x2d, - 0xdf, 0xed, 0xe0, 0x60, 0xe0, 0xd3, 0xc0, 0xff, 0x42, 0x7c, 0xbc, 0x67, 0xf5, 0x3a, 0xc7, 0x3b, - 0x1d, 0x3a, 0x1a, 0x74, 0x30, 0xb5, 0xc3, 0x0e, 0xa6, 0xd4, 0xb1, 0x2d, 0xcc, 0x6c, 0xdf, 0xeb, - 0x1c, 0x6f, 0x63, 0x87, 0x0e, 0xf1, 0x76, 0x67, 0x40, 0x3c, 0x12, 0x60, 0x46, 0x7a, 0x52, 0x72, - 0xeb, 0xad, 0x81, 0xef, 0x0f, 0x1c, 0xd2, 0x11, 0xa3, 0x6e, 0xd4, 0xef, 0x10, 0x97, 0x32, 0xa5, - 0xd6, 0xf8, 0xcf, 0x3c, 0x2c, 0x1e, 0x62, 0xcf, 0xee, 0x93, 0x90, 0x99, 0xe4, 0x59, 0x44, 0x42, - 0x86, 0x9e, 0xc2, 0x14, 0x37, 0x46, 0xd7, 0x36, 0xb5, 0xad, 0xb9, 0x9d, 0x83, 0x76, 0x6a, 0x4d, - 0x3b, 0xb6, 0x46, 0x7c, 0xfc, 0xc2, 0xea, 0xb5, 0x8f, 0x77, 0xda, 0x74, 0x34, 0x68, 0x73, 0x6b, - 0xda, 0x19, 0x6b, 0xda, 0xb1, 0x35, 0x6d, 0x33, 0xd9, 0x96, 0x29, 0xa4, 0xa2, 0x16, 0xd4, 0x03, - 0x72, 0x6c, 0x87, 0xb6, 0xef, 0xe9, 0xd5, 0x4d, 0x6d, 0xab, 0x61, 0x26, 0x63, 0xa4, 0xc3, 0xac, - 0xe7, 0xef, 0x61, 0x6b, 0x48, 0xf4, 0xda, 0xa6, 0xb6, 0x55, 0x37, 0xe3, 0x21, 0xda, 0x84, 0x39, - 0x4c, 0xe9, 0x03, 0xdc, 0x25, 0xce, 0x7d, 0x72, 0xa2, 0x4f, 0x89, 0x85, 0x59, 0x12, 0x5f, 0x8b, - 0x29, 0x7d, 0x88, 0x5d, 0xa2, 0x4f, 0x8b, 0xd9, 0x78, 0x88, 0xae, 0x40, 0xc3, 0xc3, 0x2e, 0x09, - 0x29, 0xb6, 0x88, 0x5e, 0x17, 0x73, 0x29, 0x01, 0xfd, 0x12, 0x96, 0x32, 0x86, 0x3f, 0xf6, 0xa3, - 0xc0, 0x22, 0x3a, 0x88, 0xad, 0x3f, 0x9a, 0x6c, 0xeb, 0xbb, 0x45, 0xb1, 0xe6, 0xb8, 0x26, 0xf4, - 0x73, 0x98, 0x16, 0x27, 0xaf, 0xcf, 0x6d, 0xd6, 0xce, 0xd5, 0xdb, 0x52, 0x2c, 0xf2, 0x60, 0x96, - 0x3a, 0xd1, 0xc0, 0xf6, 0x42, 0x7d, 0x5e, 0x68, 0x78, 0x32, 0x99, 0x86, 0x3d, 0xdf, 0xeb, 0xdb, - 0x83, 0x43, 0xec, 0xe1, 0x01, 0x71, 0x89, 0xc7, 0x8e, 0x84, 0x70, 0x33, 0x56, 0x82, 0x9e, 0x43, - 0x73, 0x14, 0x85, 0xcc, 0x77, 0xed, 0xe7, 0xe4, 0x11, 0xe5, 0x6b, 0x43, 0xfd, 0x92, 0xf0, 0xe6, - 0xc3, 0xc9, 0x14, 0xdf, 0x2f, 0x48, 0x35, 0xc7, 0xf4, 0xf0, 0x20, 0x19, 0x45, 0x5d, 0xf2, 0x23, - 0x12, 0x88, 0xe8, 0x5a, 0x90, 0x41, 0x92, 0x21, 0xc9, 0x30, 0xb2, 0xd5, 0x28, 0xd4, 0x17, 0x37, - 0x6b, 0x32, 0x8c, 0x12, 0x12, 0xda, 0x82, 0xc5, 0x63, 0x12, 0xd8, 0xfd, 0x93, 0xc7, 0xf6, 0xc0, - 0xc3, 0x2c, 0x0a, 0x88, 0xde, 0x14, 0xa1, 0x58, 0x24, 0x23, 0x17, 0x2e, 0x0d, 0x89, 0xe3, 0x72, - 0x97, 0xef, 0x05, 0xa4, 0x17, 0xea, 0x4b, 0xc2, 0xbf, 0xfb, 0x93, 0x9f, 0xa0, 0x10, 0x67, 0xe6, - 0xa5, 0x73, 0xc3, 0x3c, 0xdf, 0x54, 0x99, 0x22, 0x73, 0x04, 0x49, 0xc3, 0x0a, 0x64, 0x74, 0x0d, - 0x16, 0x58, 0x80, 0xad, 0x91, 0xed, 0x0d, 0x0e, 0x09, 0x1b, 0xfa, 0x3d, 0xfd, 0xb2, 0xf0, 0x44, - 0x81, 0x8a, 0x2c, 0x40, 0xc4, 0xc3, 0x5d, 0x87, 0xf4, 0x64, 0x2c, 0x3e, 0x39, 0xa1, 0x24, 0xd4, - 0x97, 0xc5, 0x2e, 0x6e, 0xb6, 0x33, 0x15, 0xaa, 0x50, 0x20, 0xda, 0x77, 0xc6, 0x56, 0xdd, 0xf1, - 0x58, 0x70, 0x62, 0x96, 0x88, 0x43, 0x23, 0x98, 0xe3, 0xfb, 0x88, 0x43, 0x61, 0x45, 0x84, 0xc2, - 0xbd, 0xc9, 0x7c, 0x74, 0x90, 0x0a, 0x34, 0xb3, 0xd2, 0x51, 0x1b, 0xd0, 0x10, 0x87, 0x87, 0x91, - 0xc3, 0x6c, 0xea, 0x10, 0x69, 0x46, 0xa8, 0xaf, 0x0a, 0x37, 0x95, 0xcc, 0xa0, 0xfb, 0x00, 0x01, - 0xe9, 0xc7, 0x7c, 0x6b, 0x62, 0xe7, 0x37, 0xce, 0xda, 0xb9, 0x99, 0x70, 0xcb, 0x1d, 0x67, 0x96, - 0x73, 0xe5, 0x7c, 0x1b, 0xc4, 0x62, 0x2a, 0xdb, 0x45, 0x5a, 0xeb, 0x22, 0xc4, 0x4a, 0x66, 0x78, - 0x2c, 0x2a, 0xaa, 0x28, 0x5a, 0xeb, 0x32, 0x5a, 0x33, 0xa4, 0xd6, 0x1d, 0x58, 0x3b, 0xc5, 0xd5, - 0xa8, 0x09, 0xb5, 0x11, 0x39, 0x11, 0x25, 0xba, 0x61, 0xf2, 0x4f, 0xb4, 0x0c, 0xd3, 0xc7, 0xd8, - 0x89, 0x88, 0x28, 0xaa, 0x75, 0x53, 0x0e, 0x6e, 0x57, 0xbf, 0xab, 0xb5, 0x7e, 0xab, 0xc1, 0x62, - 0xc1, 0xf0, 0x92, 0xf5, 0x3f, 0xcb, 0xae, 0x3f, 0x87, 0x30, 0xee, 0x3f, 0xc1, 0xc1, 0x80, 0xb0, - 0x8c, 0x21, 0xc6, 0x3f, 0x35, 0xd0, 0x0b, 0x1e, 0xfd, 0xb1, 0xcd, 0x86, 0x77, 0x6d, 0x87, 0x84, - 0xe8, 0x16, 0xcc, 0x06, 0x92, 0xa6, 0x1a, 0xcf, 0x5b, 0x67, 0x1c, 0xc4, 0x41, 0xc5, 0x8c, 0xb9, - 0xd1, 0xc7, 0x50, 0x77, 0x09, 0xc3, 0x3d, 0xcc, 0xb0, 0xb2, 0x7d, 0xb3, 0x6c, 0x25, 0xd7, 0x72, - 0xa8, 0xf8, 0x0e, 0x2a, 0x66, 0xb2, 0x06, 0xbd, 0x0f, 0xd3, 0xd6, 0x30, 0xf2, 0x46, 0xa2, 0xe5, - 0xcc, 0xed, 0xbc, 0x7d, 0xda, 0xe2, 0x3d, 0xce, 0x74, 0x50, 0x31, 0x25, 0xf7, 0x27, 0x33, 0x30, - 0x45, 0x71, 0xc0, 0x8c, 0xbb, 0xb0, 0x5c, 0xa6, 0x82, 0xf7, 0x39, 0x6b, 0x48, 0xac, 0x51, 0x18, - 0xb9, 0xca, 0xcd, 0xc9, 0x18, 0x21, 0x98, 0x0a, 0xed, 0xe7, 0xd2, 0xd5, 0x35, 0x53, 0x7c, 0x1b, - 0xdf, 0x81, 0xa5, 0x31, 0x6d, 0xfc, 0x50, 0xa5, 0x6d, 0x5c, 0xc2, 0xbc, 0x52, 0x6d, 0x44, 0xb0, - 0xf2, 0x44, 0xf8, 0x22, 0x29, 0xf6, 0x17, 0xd1, 0xb9, 0x8d, 0x03, 0x58, 0x2d, 0xaa, 0x0d, 0xa9, - 0xef, 0x85, 0x84, 0x87, 0xbe, 0xa8, 0x8e, 0x36, 0xe9, 0xa5, 0xb3, 0xc2, 0x8a, 0xba, 0x59, 0x32, - 0x63, 0xfc, 0xaa, 0x0a, 0xab, 0x26, 0x09, 0x7d, 0xe7, 0x98, 0xc4, 0xa5, 0xeb, 0x62, 0xc0, 0xc7, - 0x4f, 0xa1, 0x86, 0x29, 0x55, 0x61, 0x72, 0xef, 0xdc, 0xda, 0xbb, 0xc9, 0xa5, 0xa2, 0x77, 0x61, - 0x09, 0xbb, 0x5d, 0x7b, 0x10, 0xf9, 0x51, 0x18, 0x6f, 0x4b, 0x04, 0x55, 0xc3, 0x1c, 0x9f, 0x30, - 0x2c, 0x58, 0x1b, 0x73, 0x81, 0x72, 0x67, 0x16, 0x22, 0x69, 0x05, 0x88, 0x54, 0xaa, 0xa4, 0x7a, - 0x9a, 0x92, 0xbf, 0x69, 0xd0, 0x4c, 0x53, 0x47, 0x89, 0xbf, 0x02, 0x0d, 0x57, 0xd1, 0x42, 0x5d, - 0x13, 0xf5, 0x29, 0x25, 0xe4, 0xd1, 0x52, 0xb5, 0x88, 0x96, 0x56, 0x61, 0x46, 0x82, 0x59, 0xb5, - 0x31, 0x35, 0xca, 0x99, 0x3c, 0x55, 0x30, 0x79, 0x03, 0x20, 0x4c, 0xea, 0x97, 0x3e, 0x23, 0x66, - 0x33, 0x14, 0x64, 0xc0, 0xbc, 0xec, 0xad, 0x26, 0x09, 0x23, 0x87, 0xe9, 0xb3, 0x82, 0x23, 0x47, - 0x33, 0x7c, 0x58, 0x7c, 0x60, 0xf3, 0x3d, 0xf4, 0xc3, 0x8b, 0x09, 0xf6, 0x0f, 0x60, 0x8a, 0x2b, - 0xe3, 0x1b, 0xeb, 0x06, 0xd8, 0xb3, 0x86, 0x24, 0xf6, 0x55, 0x32, 0xe6, 0x69, 0xcc, 0xf0, 0x20, - 0xd4, 0xab, 0x82, 0x2e, 0xbe, 0x8d, 0x3f, 0x55, 0xa5, 0xa5, 0xbb, 0x94, 0x86, 0x6f, 0x1e, 0x50, - 0x97, 0xb7, 0xf8, 0xda, 0x78, 0x8b, 0x2f, 0x98, 0xfc, 0x75, 0x5a, 0xfc, 0x39, 0xb5, 0x29, 0x23, - 0x82, 0xd9, 0x5d, 0x4a, 0xb9, 0x21, 0x68, 0x1b, 0xa6, 0x30, 0xa5, 0xd2, 0xe1, 0x85, 0x8a, 0xac, - 0x58, 0xf8, 0xff, 0xca, 0x24, 0xc1, 0xda, 0xba, 0x05, 0x8d, 0x84, 0xf4, 0x32, 0xb5, 0x8d, 0xac, - 0xda, 0x4d, 0x00, 0x89, 0x61, 0xef, 0x79, 0x7d, 0x9f, 0x1f, 0x29, 0x0f, 0x76, 0xb5, 0x54, 0x7c, - 0x1b, 0xb7, 0x63, 0x0e, 0x61, 0xdb, 0xbb, 0x30, 0x6d, 0x33, 0xe2, 0xc6, 0xc6, 0xad, 0x66, 0x8d, - 0x4b, 0x05, 0x99, 0x92, 0xc9, 0xf8, 0x7b, 0x1d, 0xd6, 0xf9, 0x89, 0x3d, 0x16, 0x69, 0xb2, 0x4b, - 0xe9, 0xa7, 0x84, 0x61, 0xdb, 0x09, 0x7f, 0x10, 0x91, 0xe0, 0xe4, 0x35, 0x07, 0xc6, 0x00, 0x66, - 0x64, 0x96, 0xa9, 0x7a, 0x77, 0xee, 0xd7, 0x19, 0x25, 0x3e, 0xbd, 0xc3, 0xd4, 0x5e, 0xcf, 0x1d, - 0xa6, 0xec, 0x4e, 0x31, 0x75, 0x41, 0x77, 0x8a, 0xd3, 0xaf, 0x95, 0x99, 0xcb, 0xea, 0x4c, 0xfe, - 0xb2, 0x5a, 0x02, 0xd5, 0x67, 0x5f, 0x15, 0xaa, 0xd7, 0x4b, 0xa1, 0xba, 0x5b, 0x9a, 0xc7, 0x0d, - 0xe1, 0xee, 0xef, 0x65, 0x23, 0xf0, 0xd4, 0x58, 0x9b, 0x04, 0xb4, 0xc3, 0x6b, 0x05, 0xed, 0x3f, - 0xcc, 0x81, 0x70, 0x79, 0x0d, 0x7e, 0xff, 0xd5, 0xf6, 0x74, 0x06, 0x1c, 0xff, 0xc6, 0x81, 0xe7, - 0xdf, 0x08, 0xcc, 0x44, 0xfd, 0xd4, 0x07, 0x49, 0x43, 0xe7, 0x7d, 0x88, 0xb7, 0x56, 0x55, 0xb4, - 0xf8, 0x37, 0xba, 0x01, 0x53, 0xdc, 0xc9, 0x0a, 0xd4, 0xae, 0x65, 0xfd, 0xc9, 0x4f, 0x62, 0x97, - 0xd2, 0xc7, 0x94, 0x58, 0xa6, 0x60, 0x42, 0xb7, 0xa1, 0x91, 0x04, 0xbe, 0xca, 0xac, 0x2b, 0xd9, - 0x15, 0x49, 0x9e, 0xc4, 0xcb, 0x52, 0x76, 0xbe, 0xb6, 0x67, 0x07, 0xc4, 0x12, 0x90, 0x6f, 0x7a, - 0x7c, 0xed, 0xa7, 0xf1, 0x64, 0xb2, 0x36, 0x61, 0x47, 0xdb, 0x30, 0x23, 0xdf, 0x0d, 0x44, 0x06, - 0xcd, 0xed, 0xac, 0x8f, 0x17, 0xd3, 0x78, 0x95, 0x62, 0x34, 0xfe, 0xaa, 0xc1, 0x3b, 0x69, 0x40, - 0xc4, 0xd9, 0x14, 0xa3, 0xee, 0x37, 0xdf, 0x71, 0xaf, 0xc1, 0x82, 0x80, 0xf9, 0xe9, 0xf3, 0x81, - 0x7c, 0xc9, 0x2a, 0x50, 0x8d, 0x3f, 0x6a, 0x70, 0x75, 0x7c, 0x1f, 0x7b, 0x43, 0x1c, 0xb0, 0xe4, - 0x78, 0x2f, 0x62, 0x2f, 0x71, 0xc3, 0xab, 0xa6, 0x0d, 0x2f, 0xb7, 0xbf, 0x5a, 0x7e, 0x7f, 0xc6, - 0x5f, 0xaa, 0x30, 0x97, 0x09, 0xa0, 0xb2, 0x86, 0xc9, 0x01, 0x9f, 0x88, 0x5b, 0x71, 0xb1, 0x13, - 0x4d, 0xa1, 0x61, 0x66, 0x28, 0x68, 0x04, 0x40, 0x71, 0x80, 0x5d, 0xc2, 0x48, 0xc0, 0x2b, 0x39, - 0xcf, 0xf8, 0xfb, 0x93, 0x57, 0x97, 0xa3, 0x58, 0xa6, 0x99, 0x11, 0xcf, 0x11, 0xab, 0x50, 0x1d, - 0xaa, 0xfa, 0xad, 0x46, 0xe8, 0x4b, 0x58, 0xe8, 0xdb, 0x0e, 0x39, 0x4a, 0x0d, 0x99, 0x11, 0x86, - 0x3c, 0x9a, 0xdc, 0x90, 0xbb, 0x59, 0xb9, 0x66, 0x41, 0x8d, 0x71, 0x1d, 0x9a, 0xc5, 0x7c, 0xe2, - 0x46, 0xda, 0x2e, 0x1e, 0x24, 0xde, 0x52, 0x23, 0x03, 0x41, 0xb3, 0x98, 0x3f, 0xc6, 0xbf, 0xaa, - 0xb0, 0x92, 0x88, 0xdb, 0xf5, 0x3c, 0x3f, 0xf2, 0x2c, 0xf1, 0x14, 0x57, 0x7a, 0x16, 0xcb, 0x30, - 0xcd, 0x6c, 0xe6, 0x24, 0xc0, 0x47, 0x0c, 0x78, 0xef, 0x62, 0xbe, 0xef, 0x30, 0x9b, 0xaa, 0x03, - 0x8e, 0x87, 0xf2, 0xec, 0x9f, 0x45, 0x76, 0x40, 0x7a, 0xa2, 0x12, 0xd4, 0xcd, 0x64, 0xcc, 0xe7, - 0x38, 0xaa, 0x11, 0x30, 0x5e, 0x3a, 0x33, 0x19, 0x8b, 0xb8, 0xf7, 0x1d, 0x87, 0x58, 0xdc, 0x1d, - 0x19, 0xa0, 0x5f, 0xa0, 0x8a, 0x0b, 0x04, 0x0b, 0x6c, 0x6f, 0xa0, 0x60, 0xbe, 0x1a, 0x71, 0x3b, - 0x71, 0x10, 0xe0, 0x13, 0xbd, 0x2e, 0x1c, 0x20, 0x07, 0xe8, 0x23, 0xa8, 0xb9, 0x98, 0xaa, 0x46, - 0x77, 0x3d, 0x57, 0x1d, 0xca, 0x3c, 0xd0, 0x3e, 0xc4, 0x54, 0x76, 0x02, 0xbe, 0xac, 0xf5, 0x01, - 0xd4, 0x63, 0xc2, 0xd7, 0x82, 0x84, 0x5f, 0xc0, 0xa5, 0x5c, 0xf1, 0x41, 0x9f, 0xc3, 0x6a, 0x1a, - 0x51, 0x59, 0x85, 0x0a, 0x04, 0xbe, 0xf3, 0x52, 0xcb, 0xcc, 0x53, 0x04, 0x18, 0xcf, 0x60, 0x89, - 0x87, 0x8c, 0x48, 0xfc, 0x0b, 0xba, 0xda, 0x7c, 0x08, 0x8d, 0x44, 0x65, 0x69, 0xcc, 0xb4, 0xa0, - 0x7e, 0x1c, 0x3f, 0x91, 0xca, 0xbb, 0x4d, 0x32, 0x36, 0x76, 0x01, 0x65, 0xed, 0x55, 0x1d, 0xe8, - 0x46, 0x1e, 0x14, 0xaf, 0x14, 0xdb, 0x8d, 0x60, 0x8f, 0x31, 0xf1, 0xef, 0xaa, 0xb0, 0xb8, 0x6f, - 0x8b, 0x57, 0x8e, 0x0b, 0x2a, 0x72, 0xd7, 0xa1, 0x19, 0x46, 0x5d, 0xd7, 0xef, 0x45, 0x0e, 0x51, - 0xa0, 0x40, 0x75, 0xfa, 0x31, 0xfa, 0x59, 0xc5, 0x8f, 0x3b, 0x8b, 0x62, 0x36, 0x54, 0x37, 0x5c, - 0xf1, 0x8d, 0x3e, 0x82, 0xf5, 0x87, 0xe4, 0x4b, 0xb5, 0x9f, 0x7d, 0xc7, 0xef, 0x76, 0x6d, 0x6f, - 0x10, 0x2b, 0x99, 0x16, 0x4a, 0x4e, 0x67, 0x30, 0x7e, 0xad, 0x41, 0x33, 0xf5, 0x85, 0xf2, 0xe6, - 0x2d, 0x19, 0xf5, 0xd2, 0x97, 0x57, 0xb3, 0xbe, 0x2c, 0xb2, 0xfe, 0xef, 0x01, 0x3f, 0x9f, 0x0d, - 0xf8, 0x3f, 0x6b, 0xb0, 0xb2, 0x6f, 0xb3, 0xb8, 0xd4, 0xd8, 0xff, 0x67, 0xe7, 0x62, 0xb4, 0x61, - 0xb5, 0x68, 0xbe, 0x72, 0xe5, 0x32, 0x4c, 0xf3, 0x53, 0x8a, 0xef, 0xee, 0x72, 0xb0, 0xf3, 0x55, - 0x03, 0x96, 0xd2, 0xe6, 0xcb, 0xff, 0xb5, 0x2d, 0x82, 0x1e, 0x41, 0x73, 0x5f, 0xfd, 0x76, 0x16, - 0xbf, 0x99, 0xa0, 0xb3, 0x1e, 0x21, 0x5b, 0x57, 0xca, 0x27, 0xa5, 0x6a, 0xa3, 0x82, 0x2c, 0x58, - 0x2f, 0x0a, 0x4c, 0xdf, 0x3b, 0xbf, 0x7d, 0x86, 0xe4, 0x84, 0xeb, 0x65, 0x2a, 0xb6, 0x34, 0xf4, - 0x39, 0x2c, 0xe4, 0x5f, 0xe5, 0x50, 0xae, 0x1a, 0x95, 0x3e, 0x14, 0xb6, 0x8c, 0xb3, 0x58, 0x12, - 0xfb, 0x9f, 0x72, 0xe8, 0x9b, 0x7b, 0xa2, 0x42, 0x46, 0x1e, 0x98, 0x97, 0x3d, 0xe1, 0xb5, 0xbe, - 0x75, 0x26, 0x4f, 0x22, 0xfd, 0x43, 0xa8, 0xc7, 0x4f, 0x3a, 0x79, 0x37, 0x17, 0x1e, 0x7a, 0x5a, - 0xcd, 0xbc, 0xbc, 0x7e, 0x68, 0x54, 0xd0, 0xc7, 0x72, 0x31, 0xbf, 0xf2, 0x8f, 0x2f, 0xce, 0x3c, - 0x64, 0xb4, 0x2e, 0x97, 0x3c, 0x1e, 0x18, 0x15, 0xf4, 0x7d, 0x98, 0xe3, 0x5f, 0x47, 0xea, 0x57, - 0xab, 0xd5, 0xb6, 0xfc, 0x91, 0xb4, 0x1d, 0xff, 0x48, 0xda, 0xbe, 0xe3, 0x52, 0x76, 0xd2, 0x2a, - 0xb9, 0xdd, 0x2b, 0x01, 0x4f, 0xe1, 0xd2, 0x3e, 0x61, 0x29, 0x18, 0x47, 0x57, 0x5f, 0xe9, 0xca, - 0xd2, 0x32, 0x8a, 0x6c, 0xe3, 0x78, 0xde, 0xa8, 0xa0, 0xdf, 0x6b, 0x70, 0x79, 0x9f, 0xb0, 0x22, - 0xbc, 0x45, 0xef, 0x95, 0x2b, 0x39, 0x05, 0x06, 0xb7, 0x1e, 0x4e, 0x9a, 0xaf, 0x79, 0xb1, 0x46, - 0x05, 0xfd, 0x41, 0x83, 0xb5, 0x8c, 0x61, 0x59, 0xbc, 0x8a, 0xb6, 0xcf, 0x36, 0xae, 0x04, 0xdb, - 0xb6, 0x3e, 0x9b, 0xf0, 0xc7, 0xc8, 0x8c, 0x48, 0xa3, 0x82, 0x8e, 0xc4, 0x99, 0xa4, 0xed, 0x09, - 0xbd, 0x5d, 0xda, 0x87, 0x12, 0xed, 0x1b, 0xa7, 0x4d, 0x27, 0xe7, 0xf0, 0x19, 0xcc, 0xed, 0x13, - 0x16, 0x57, 0xdd, 0x7c, 0xa4, 0x15, 0x5a, 0x58, 0x3e, 0x55, 0x8b, 0x85, 0x5a, 0x44, 0xcc, 0x92, - 0x94, 0x95, 0xa9, 0x53, 0xf9, 0x5c, 0x2d, 0x2d, 0xc1, 0xf9, 0x88, 0x29, 0x2f, 0x73, 0x46, 0xe5, - 0x93, 0xdd, 0x7f, 0xbc, 0xd8, 0xd0, 0xbe, 0x7a, 0xb1, 0xa1, 0xfd, 0xfb, 0xc5, 0x86, 0xf6, 0x93, - 0x9b, 0x2f, 0xf9, 0x0b, 0x82, 0xcc, 0x1f, 0x25, 0x60, 0x6a, 0x5b, 0x8e, 0x4d, 0x3c, 0xd6, 0x9d, - 0x11, 0xc1, 0x7f, 0xf3, 0xbf, 0x01, 0x00, 0x00, 0xff, 0xff, 0xf8, 0x86, 0xe4, 0x0d, 0xb3, 0x20, - 0x00, 0x00, + 0xf5, 0xe7, 0x92, 0x94, 0x44, 0x1e, 0xd9, 0x12, 0x35, 0xd6, 0x65, 0xc5, 0x38, 0x82, 0xb2, 0xff, + 0xbf, 0x0d, 0xd5, 0x4e, 0x48, 0x48, 0x46, 0xe2, 0xc2, 0x49, 0x53, 0x28, 0x8a, 0x2d, 0x39, 0xb6, + 0x6c, 0x75, 0xed, 0xb6, 0x48, 0xeb, 0xb6, 0x18, 0x2e, 0x87, 0xe4, 0x86, 0x7b, 0x19, 0xef, 0xce, + 0x2a, 0x90, 0x81, 0x3e, 0x14, 0x2d, 0xfa, 0x11, 0xfa, 0xd0, 0xaf, 0x51, 0x14, 0x7d, 0xec, 0x53, + 0x2f, 0x8f, 0x41, 0xbf, 0x40, 0x0b, 0xbf, 0x14, 0xe8, 0xa7, 0x28, 0xe6, 0xb2, 0x57, 0xae, 0x64, + 0xa7, 0x94, 0x15, 0xb4, 0x2f, 0xf6, 0xce, 0x99, 0x33, 0xe7, 0x9c, 0x39, 0x73, 0x2e, 0xbf, 0x19, + 0x0a, 0xae, 0x07, 0x84, 0xfa, 0x21, 0x09, 0x8e, 0x49, 0xd0, 0x15, 0x9f, 0x36, 0xf3, 0x83, 0x93, + 0xcc, 0x67, 0x87, 0x06, 0x3e, 0xf3, 0x11, 0xa4, 0x94, 0xf6, 0xc3, 0xa1, 0xcd, 0x46, 0x51, 0xaf, + 0x63, 0xf9, 0x6e, 0x17, 0x07, 0x43, 0x9f, 0x06, 0xfe, 0x17, 0xe2, 0xe3, 0x3d, 0xab, 0xdf, 0x3d, + 0xde, 0xe9, 0xd2, 0xf1, 0xb0, 0x8b, 0xa9, 0x1d, 0x76, 0x31, 0xa5, 0x8e, 0x6d, 0x61, 0x66, 0xfb, + 0x5e, 0xf7, 0x78, 0x1b, 0x3b, 0x74, 0x84, 0xb7, 0xbb, 0x43, 0xe2, 0x91, 0x00, 0x33, 0xd2, 0x97, + 0x92, 0xdb, 0x6f, 0x0d, 0x7d, 0x7f, 0xe8, 0x90, 0xae, 0x18, 0xf5, 0xa2, 0x41, 0x97, 0xb8, 0x94, + 0x29, 0xb5, 0xc6, 0xbf, 0x2e, 0xc1, 0xe2, 0x21, 0xf6, 0xec, 0x01, 0x09, 0x99, 0x49, 0x9e, 0x47, + 0x24, 0x64, 0xe8, 0x19, 0xd4, 0xb9, 0x31, 0xba, 0xb6, 0xa9, 0x6d, 0xcd, 0xef, 0x1c, 0x74, 0x52, + 0x6b, 0x3a, 0xb1, 0x35, 0xe2, 0xe3, 0x67, 0x56, 0xbf, 0x73, 0xbc, 0xd3, 0xa1, 0xe3, 0x61, 0x87, + 0x5b, 0xd3, 0xc9, 0x58, 0xd3, 0x89, 0xad, 0xe9, 0x98, 0xc9, 0xb6, 0x4c, 0x21, 0x15, 0xb5, 0xa1, + 0x11, 0x90, 0x63, 0x3b, 0xb4, 0x7d, 0x4f, 0xaf, 0x6e, 0x6a, 0x5b, 0x4d, 0x33, 0x19, 0x23, 0x1d, + 0xe6, 0x3c, 0x7f, 0x0f, 0x5b, 0x23, 0xa2, 0xd7, 0x36, 0xb5, 0xad, 0x86, 0x19, 0x0f, 0xd1, 0x26, + 0xcc, 0x63, 0x4a, 0x1f, 0xe2, 0x1e, 0x71, 0x1e, 0x90, 0x13, 0xbd, 0x2e, 0x16, 0x66, 0x49, 0x7c, + 0x2d, 0xa6, 0xf4, 0x11, 0x76, 0x89, 0x3e, 0x23, 0x66, 0xe3, 0x21, 0xba, 0x0a, 0x4d, 0x0f, 0xbb, + 0x24, 0xa4, 0xd8, 0x22, 0x7a, 0x43, 0xcc, 0xa5, 0x04, 0xf4, 0x73, 0x58, 0xca, 0x18, 0xfe, 0xc4, + 0x8f, 0x02, 0x8b, 0xe8, 0x20, 0xb6, 0xfe, 0x78, 0xba, 0xad, 0xef, 0x16, 0xc5, 0x9a, 0x93, 0x9a, + 0xd0, 0x4f, 0x61, 0x46, 0x9c, 0xbc, 0x3e, 0xbf, 0x59, 0x3b, 0x57, 0x6f, 0x4b, 0xb1, 0xc8, 0x83, + 0x39, 0xea, 0x44, 0x43, 0xdb, 0x0b, 0xf5, 0x4b, 0x42, 0xc3, 0xd3, 0xe9, 0x34, 0xec, 0xf9, 0xde, + 0xc0, 0x1e, 0x1e, 0x62, 0x0f, 0x0f, 0x89, 0x4b, 0x3c, 0x76, 0x24, 0x84, 0x9b, 0xb1, 0x12, 0xf4, + 0x02, 0x5a, 0xe3, 0x28, 0x64, 0xbe, 0x6b, 0xbf, 0x20, 0x8f, 0x29, 0x5f, 0x1b, 0xea, 0x97, 0x85, + 0x37, 0x1f, 0x4d, 0xa7, 0xf8, 0x41, 0x41, 0xaa, 0x39, 0xa1, 0x87, 0x07, 0xc9, 0x38, 0xea, 0x91, + 0x1f, 0x90, 0x40, 0x44, 0xd7, 0x82, 0x0c, 0x92, 0x0c, 0x49, 0x86, 0x91, 0xad, 0x46, 0xa1, 0xbe, + 0xb8, 0x59, 0x93, 0x61, 0x94, 0x90, 0xd0, 0x16, 0x2c, 0x1e, 0x93, 0xc0, 0x1e, 0x9c, 0x3c, 0xb1, + 0x87, 0x1e, 0x66, 0x51, 0x40, 0xf4, 0x96, 0x08, 0xc5, 0x22, 0x19, 0xb9, 0x70, 0x79, 0x44, 0x1c, + 0x97, 0xbb, 0x7c, 0x2f, 0x20, 0xfd, 0x50, 0x5f, 0x12, 0xfe, 0xdd, 0x9f, 0xfe, 0x04, 0x85, 0x38, + 0x33, 0x2f, 0x9d, 0x1b, 0xe6, 0xf9, 0xa6, 0xca, 0x14, 0x99, 0x23, 0x48, 0x1a, 0x56, 0x20, 0xa3, + 0xeb, 0xb0, 0xc0, 0x02, 0x6c, 0x8d, 0x6d, 0x6f, 0x78, 0x48, 0xd8, 0xc8, 0xef, 0xeb, 0x57, 0x84, + 0x27, 0x0a, 0x54, 0x64, 0x01, 0x22, 0x1e, 0xee, 0x39, 0xa4, 0x2f, 0x63, 0xf1, 0xe9, 0x09, 0x25, + 0xa1, 0xbe, 0x2c, 0x76, 0x71, 0xab, 0x93, 0xa9, 0x50, 0x85, 0x02, 0xd1, 0xb9, 0x3b, 0xb1, 0xea, + 0xae, 0xc7, 0x82, 0x13, 0xb3, 0x44, 0x1c, 0x1a, 0xc3, 0x3c, 0xdf, 0x47, 0x1c, 0x0a, 0x2b, 0x22, + 0x14, 0xee, 0x4f, 0xe7, 0xa3, 0x83, 0x54, 0xa0, 0x99, 0x95, 0x8e, 0x3a, 0x80, 0x46, 0x38, 0x3c, + 0x8c, 0x1c, 0x66, 0x53, 0x87, 0x48, 0x33, 0x42, 0x7d, 0x55, 0xb8, 0xa9, 0x64, 0x06, 0x3d, 0x00, + 0x08, 0xc8, 0x20, 0xe6, 0x5b, 0x13, 0x3b, 0xbf, 0x79, 0xd6, 0xce, 0xcd, 0x84, 0x5b, 0xee, 0x38, + 0xb3, 0x9c, 0x2b, 0xe7, 0xdb, 0x20, 0x16, 0x53, 0xd9, 0x2e, 0xd2, 0x5a, 0x17, 0x21, 0x56, 0x32, + 0xc3, 0x63, 0x51, 0x51, 0x45, 0xd1, 0x5a, 0x97, 0xd1, 0x9a, 0x21, 0xb5, 0xef, 0xc2, 0xda, 0x29, + 0xae, 0x46, 0x2d, 0xa8, 0x8d, 0xc9, 0x89, 0x28, 0xd1, 0x4d, 0x93, 0x7f, 0xa2, 0x65, 0x98, 0x39, + 0xc6, 0x4e, 0x44, 0x44, 0x51, 0x6d, 0x98, 0x72, 0x70, 0xa7, 0xfa, 0x6d, 0xad, 0xfd, 0x6b, 0x0d, + 0x16, 0x0b, 0x86, 0x97, 0xac, 0xff, 0x49, 0x76, 0xfd, 0x39, 0x84, 0xf1, 0xe0, 0x29, 0x0e, 0x86, + 0x84, 0x65, 0x0c, 0x31, 0xfe, 0xa6, 0x81, 0x5e, 0xf0, 0xe8, 0x0f, 0x6d, 0x36, 0xba, 0x67, 0x3b, + 0x24, 0x44, 0xb7, 0x61, 0x2e, 0x90, 0x34, 0xd5, 0x78, 0xde, 0x3a, 0xe3, 0x20, 0x0e, 0x2a, 0x66, + 0xcc, 0x8d, 0x3e, 0x86, 0x86, 0x4b, 0x18, 0xee, 0x63, 0x86, 0x95, 0xed, 0x9b, 0x65, 0x2b, 0xb9, + 0x96, 0x43, 0xc5, 0x77, 0x50, 0x31, 0x93, 0x35, 0xe8, 0x7d, 0x98, 0xb1, 0x46, 0x91, 0x37, 0x16, + 0x2d, 0x67, 0x7e, 0xe7, 0xed, 0xd3, 0x16, 0xef, 0x71, 0xa6, 0x83, 0x8a, 0x29, 0xb9, 0x3f, 0x99, + 0x85, 0x3a, 0xc5, 0x01, 0x33, 0xee, 0xc1, 0x72, 0x99, 0x0a, 0xde, 0xe7, 0xac, 0x11, 0xb1, 0xc6, + 0x61, 0xe4, 0x2a, 0x37, 0x27, 0x63, 0x84, 0xa0, 0x1e, 0xda, 0x2f, 0xa4, 0xab, 0x6b, 0xa6, 0xf8, + 0x36, 0xbe, 0x05, 0x4b, 0x13, 0xda, 0xf8, 0xa1, 0x4a, 0xdb, 0xb8, 0x84, 0x4b, 0x4a, 0xb5, 0x11, + 0xc1, 0xca, 0x53, 0xe1, 0x8b, 0xa4, 0xd8, 0x5f, 0x44, 0xe7, 0x36, 0x0e, 0x60, 0xb5, 0xa8, 0x36, + 0xa4, 0xbe, 0x17, 0x12, 0x1e, 0xfa, 0xa2, 0x3a, 0xda, 0xa4, 0x9f, 0xce, 0x0a, 0x2b, 0x1a, 0x66, + 0xc9, 0x8c, 0xf1, 0x8b, 0x2a, 0xac, 0x9a, 0x24, 0xf4, 0x9d, 0x63, 0x12, 0x97, 0xae, 0x8b, 0x01, + 0x1f, 0x3f, 0x86, 0x1a, 0xa6, 0x54, 0x85, 0xc9, 0xfd, 0x73, 0x6b, 0xef, 0x26, 0x97, 0x8a, 0xde, + 0x85, 0x25, 0xec, 0xf6, 0xec, 0x61, 0xe4, 0x47, 0x61, 0xbc, 0x2d, 0x11, 0x54, 0x4d, 0x73, 0x72, + 0xc2, 0xb0, 0x60, 0x6d, 0xc2, 0x05, 0xca, 0x9d, 0x59, 0x88, 0xa4, 0x15, 0x20, 0x52, 0xa9, 0x92, + 0xea, 0x69, 0x4a, 0xfe, 0xac, 0x41, 0x2b, 0x4d, 0x1d, 0x25, 0xfe, 0x2a, 0x34, 0x5d, 0x45, 0x0b, + 0x75, 0x4d, 0xd4, 0xa7, 0x94, 0x90, 0x47, 0x4b, 0xd5, 0x22, 0x5a, 0x5a, 0x85, 0x59, 0x09, 0x66, + 0xd5, 0xc6, 0xd4, 0x28, 0x67, 0x72, 0xbd, 0x60, 0xf2, 0x06, 0x40, 0x98, 0xd4, 0x2f, 0x7d, 0x56, + 0xcc, 0x66, 0x28, 0xc8, 0x80, 0x4b, 0xb2, 0xb7, 0x9a, 0x24, 0x8c, 0x1c, 0xa6, 0xcf, 0x09, 0x8e, + 0x1c, 0xcd, 0xf0, 0x61, 0xf1, 0xa1, 0xcd, 0xf7, 0x30, 0x08, 0x2f, 0x26, 0xd8, 0x3f, 0x80, 0x3a, + 0x57, 0xc6, 0x37, 0xd6, 0x0b, 0xb0, 0x67, 0x8d, 0x48, 0xec, 0xab, 0x64, 0xcc, 0xd3, 0x98, 0xe1, + 0x61, 0xa8, 0x57, 0x05, 0x5d, 0x7c, 0x1b, 0x7f, 0xa8, 0x4a, 0x4b, 0x77, 0x29, 0x0d, 0xbf, 0x79, + 0x40, 0x5d, 0xde, 0xe2, 0x6b, 0x93, 0x2d, 0xbe, 0x60, 0xf2, 0xd7, 0x69, 0xf1, 0xe7, 0xd4, 0xa6, + 0x8c, 0x08, 0xe6, 0x76, 0x29, 0xe5, 0x86, 0xa0, 0x6d, 0xa8, 0x63, 0x4a, 0xa5, 0xc3, 0x0b, 0x15, + 0x59, 0xb1, 0xf0, 0xff, 0x95, 0x49, 0x82, 0xb5, 0x7d, 0x1b, 0x9a, 0x09, 0xe9, 0x55, 0x6a, 0x9b, + 0x59, 0xb5, 0x9b, 0x00, 0x12, 0xc3, 0xde, 0xf7, 0x06, 0x3e, 0x3f, 0x52, 0x1e, 0xec, 0x6a, 0xa9, + 0xf8, 0x36, 0xee, 0xc4, 0x1c, 0xc2, 0xb6, 0x77, 0x61, 0xc6, 0x66, 0xc4, 0x8d, 0x8d, 0x5b, 0xcd, + 0x1a, 0x97, 0x0a, 0x32, 0x25, 0x93, 0xf1, 0x97, 0x06, 0xac, 0xf3, 0x13, 0x7b, 0x22, 0xd2, 0x64, + 0x97, 0xd2, 0x4f, 0x09, 0xc3, 0xb6, 0x13, 0x7e, 0x2f, 0x22, 0xc1, 0xc9, 0x1b, 0x0e, 0x8c, 0x21, + 0xcc, 0xca, 0x2c, 0x53, 0xf5, 0xee, 0xdc, 0xaf, 0x33, 0x4a, 0x7c, 0x7a, 0x87, 0xa9, 0xbd, 0x99, + 0x3b, 0x4c, 0xd9, 0x9d, 0xa2, 0x7e, 0x41, 0x77, 0x8a, 0xd3, 0xaf, 0x95, 0x99, 0xcb, 0xea, 0x6c, + 0xfe, 0xb2, 0x5a, 0x02, 0xd5, 0xe7, 0x5e, 0x17, 0xaa, 0x37, 0x4a, 0xa1, 0xba, 0x5b, 0x9a, 0xc7, + 0x4d, 0xe1, 0xee, 0xef, 0x64, 0x23, 0xf0, 0xd4, 0x58, 0x9b, 0x06, 0xb4, 0xc3, 0x1b, 0x05, 0xed, + 0xdf, 0xcf, 0x81, 0x70, 0x79, 0x0d, 0x7e, 0xff, 0xf5, 0xf6, 0x74, 0x06, 0x1c, 0xff, 0x9f, 0x03, + 0xcf, 0xbf, 0x12, 0x98, 0x89, 0xfa, 0xa9, 0x0f, 0x92, 0x86, 0xce, 0xfb, 0x10, 0x6f, 0xad, 0xaa, + 0x68, 0xf1, 0x6f, 0x74, 0x13, 0xea, 0xdc, 0xc9, 0x0a, 0xd4, 0xae, 0x65, 0xfd, 0xc9, 0x4f, 0x62, + 0x97, 0xd2, 0x27, 0x94, 0x58, 0xa6, 0x60, 0x42, 0x77, 0xa0, 0x99, 0x04, 0xbe, 0xca, 0xac, 0xab, + 0xd9, 0x15, 0x49, 0x9e, 0xc4, 0xcb, 0x52, 0x76, 0xbe, 0xb6, 0x6f, 0x07, 0xc4, 0x12, 0x90, 0x6f, + 0x66, 0x72, 0xed, 0xa7, 0xf1, 0x64, 0xb2, 0x36, 0x61, 0x47, 0xdb, 0x30, 0x2b, 0xdf, 0x0d, 0x44, + 0x06, 0xcd, 0xef, 0xac, 0x4f, 0x16, 0xd3, 0x78, 0x95, 0x62, 0x34, 0xfe, 0xa4, 0xc1, 0x3b, 0x69, + 0x40, 0xc4, 0xd9, 0x14, 0xa3, 0xee, 0x6f, 0xbe, 0xe3, 0x5e, 0x87, 0x05, 0x01, 0xf3, 0xd3, 0xe7, + 0x03, 0xf9, 0x92, 0x55, 0xa0, 0x1a, 0xbf, 0xd7, 0xe0, 0xda, 0xe4, 0x3e, 0xf6, 0x46, 0x38, 0x60, + 0xc9, 0xf1, 0x5e, 0xc4, 0x5e, 0xe2, 0x86, 0x57, 0x4d, 0x1b, 0x5e, 0x6e, 0x7f, 0xb5, 0xfc, 0xfe, + 0x8c, 0x3f, 0x56, 0x61, 0x3e, 0x13, 0x40, 0x65, 0x0d, 0x93, 0x03, 0x3e, 0x11, 0xb7, 0xe2, 0x62, + 0x27, 0x9a, 0x42, 0xd3, 0xcc, 0x50, 0xd0, 0x18, 0x80, 0xe2, 0x00, 0xbb, 0x84, 0x91, 0x80, 0x57, + 0x72, 0x9e, 0xf1, 0x0f, 0xa6, 0xaf, 0x2e, 0x47, 0xb1, 0x4c, 0x33, 0x23, 0x9e, 0x23, 0x56, 0xa1, + 0x3a, 0x54, 0xf5, 0x5b, 0x8d, 0xd0, 0x97, 0xb0, 0x30, 0xb0, 0x1d, 0x72, 0x94, 0x1a, 0x32, 0x2b, + 0x0c, 0x79, 0x3c, 0xbd, 0x21, 0xf7, 0xb2, 0x72, 0xcd, 0x82, 0x1a, 0xe3, 0x06, 0xb4, 0x8a, 0xf9, + 0xc4, 0x8d, 0xb4, 0x5d, 0x3c, 0x4c, 0xbc, 0xa5, 0x46, 0x06, 0x82, 0x56, 0x31, 0x7f, 0x8c, 0xbf, + 0x57, 0x61, 0x25, 0x11, 0xb7, 0xeb, 0x79, 0x7e, 0xe4, 0x59, 0xe2, 0x29, 0xae, 0xf4, 0x2c, 0x96, + 0x61, 0x86, 0xd9, 0xcc, 0x49, 0x80, 0x8f, 0x18, 0xf0, 0xde, 0xc5, 0x7c, 0xdf, 0x61, 0x36, 0x55, + 0x07, 0x1c, 0x0f, 0xe5, 0xd9, 0x3f, 0x8f, 0xec, 0x80, 0xf4, 0x45, 0x25, 0x68, 0x98, 0xc9, 0x98, + 0xcf, 0x71, 0x54, 0x23, 0x60, 0xbc, 0x74, 0x66, 0x32, 0x16, 0x71, 0xef, 0x3b, 0x0e, 0xb1, 0xb8, + 0x3b, 0x32, 0x40, 0xbf, 0x40, 0x15, 0x17, 0x08, 0x16, 0xd8, 0xde, 0x50, 0xc1, 0x7c, 0x35, 0xe2, + 0x76, 0xe2, 0x20, 0xc0, 0x27, 0x7a, 0x43, 0x38, 0x40, 0x0e, 0xd0, 0x47, 0x50, 0x73, 0x31, 0x55, + 0x8d, 0xee, 0x46, 0xae, 0x3a, 0x94, 0x79, 0xa0, 0x73, 0x88, 0xa9, 0xec, 0x04, 0x7c, 0x59, 0xfb, + 0x03, 0x68, 0xc4, 0x84, 0xaf, 0x05, 0x09, 0xbf, 0x80, 0xcb, 0xb9, 0xe2, 0x83, 0x3e, 0x87, 0xd5, + 0x34, 0xa2, 0xb2, 0x0a, 0x15, 0x08, 0x7c, 0xe7, 0x95, 0x96, 0x99, 0xa7, 0x08, 0x30, 0x9e, 0xc3, + 0x12, 0x0f, 0x19, 0x91, 0xf8, 0x17, 0x74, 0xb5, 0xf9, 0x10, 0x9a, 0x89, 0xca, 0xd2, 0x98, 0x69, + 0x43, 0xe3, 0x38, 0x7e, 0x22, 0x95, 0x77, 0x9b, 0x64, 0x6c, 0xec, 0x02, 0xca, 0xda, 0xab, 0x3a, + 0xd0, 0xcd, 0x3c, 0x28, 0x5e, 0x29, 0xb6, 0x1b, 0xc1, 0x1e, 0x63, 0xe2, 0xdf, 0x55, 0x61, 0x71, + 0xdf, 0x16, 0xaf, 0x1c, 0x17, 0x54, 0xe4, 0x6e, 0x40, 0x2b, 0x8c, 0x7a, 0xae, 0xdf, 0x8f, 0x1c, + 0xa2, 0x40, 0x81, 0xea, 0xf4, 0x13, 0xf4, 0xb3, 0x8a, 0x1f, 0x77, 0x16, 0xc5, 0x6c, 0xa4, 0x6e, + 0xb8, 0xe2, 0x1b, 0x7d, 0x04, 0xeb, 0x8f, 0xc8, 0x97, 0x6a, 0x3f, 0xfb, 0x8e, 0xdf, 0xeb, 0xd9, + 0xde, 0x30, 0x56, 0x32, 0x23, 0x94, 0x9c, 0xce, 0x50, 0x06, 0x15, 0x67, 0x4b, 0xa1, 0xa2, 0xf1, + 0x4b, 0x0d, 0x5a, 0xa9, 0xd7, 0x94, 0xdf, 0x6f, 0xcb, 0xfc, 0x90, 0x5e, 0xbf, 0x96, 0xf5, 0x7a, + 0x91, 0xf5, 0x3f, 0x4f, 0x8d, 0x4b, 0xd9, 0xd4, 0xf8, 0xa7, 0x06, 0x2b, 0xfb, 0x36, 0x8b, 0x8b, + 0x92, 0xfd, 0xdf, 0x76, 0x82, 0x25, 0xfe, 0xae, 0x97, 0xfb, 0xbb, 0x03, 0xab, 0xc5, 0x8d, 0x2a, + 0xa7, 0x2f, 0xc3, 0x0c, 0x3f, 0xf9, 0xf8, 0x3d, 0x40, 0x0e, 0x76, 0xbe, 0x6a, 0xc2, 0x52, 0xda, + 0xd0, 0xf9, 0xbf, 0xb6, 0x45, 0xd0, 0x63, 0x68, 0xed, 0xab, 0xdf, 0xe3, 0xe2, 0x77, 0x18, 0x74, + 0xd6, 0xc3, 0x66, 0xfb, 0x6a, 0xf9, 0xa4, 0x54, 0x6d, 0x54, 0x90, 0x05, 0xeb, 0x45, 0x81, 0xe9, + 0x1b, 0xea, 0xff, 0x9f, 0x21, 0x39, 0xe1, 0x7a, 0x95, 0x8a, 0x2d, 0x0d, 0x7d, 0x0e, 0x0b, 0xf9, + 0x97, 0x3e, 0x94, 0xab, 0x70, 0xa5, 0x8f, 0x8f, 0x6d, 0xe3, 0x2c, 0x96, 0xc4, 0xfe, 0x67, 0x1c, + 0x4e, 0xe7, 0x9e, 0xbd, 0x90, 0x91, 0x07, 0xfb, 0x65, 0xcf, 0x82, 0xed, 0xff, 0x3b, 0x93, 0x27, + 0x91, 0xfe, 0x21, 0x34, 0xe2, 0x67, 0xa2, 0xbc, 0x9b, 0x0b, 0x8f, 0x47, 0xed, 0x56, 0x5e, 0xde, + 0x20, 0x34, 0x2a, 0xe8, 0x63, 0xb9, 0x78, 0x97, 0xd2, 0x92, 0xc5, 0x99, 0xc7, 0x91, 0xf6, 0x95, + 0x92, 0x07, 0x09, 0xa3, 0x82, 0xbe, 0x0b, 0xf3, 0xfc, 0xeb, 0x48, 0xfd, 0x12, 0xb6, 0xda, 0x91, + 0x3f, 0xbc, 0x76, 0xe2, 0x1f, 0x5e, 0x3b, 0x77, 0x5d, 0xca, 0x4e, 0xda, 0x25, 0x2f, 0x06, 0x4a, + 0xc0, 0x33, 0xb8, 0xbc, 0x4f, 0x58, 0x0a, 0xf0, 0xd1, 0xb5, 0xd7, 0xba, 0x06, 0xb5, 0x8d, 0x22, + 0xdb, 0xe4, 0x1d, 0xc1, 0xa8, 0xa0, 0xdf, 0x68, 0x70, 0x65, 0x9f, 0xb0, 0x22, 0x64, 0x46, 0xef, + 0x95, 0x2b, 0x39, 0x05, 0x5a, 0xb7, 0x1f, 0x4d, 0x9b, 0xd9, 0x79, 0xb1, 0x46, 0x05, 0xfd, 0x56, + 0x83, 0xb5, 0x8c, 0x61, 0x59, 0x0c, 0x8c, 0xb6, 0xcf, 0x36, 0xae, 0x04, 0x2f, 0xb7, 0x3f, 0x9b, + 0xf2, 0x07, 0xce, 0x8c, 0x48, 0xa3, 0x82, 0x8e, 0xc4, 0x99, 0xa4, 0x2d, 0x0f, 0xbd, 0x5d, 0xda, + 0xdb, 0x12, 0xed, 0x1b, 0xa7, 0x4d, 0x27, 0xe7, 0xf0, 0x19, 0xcc, 0xef, 0x13, 0x16, 0xd7, 0xe7, + 0x7c, 0xa4, 0x15, 0xda, 0x62, 0x3e, 0x55, 0x8b, 0x25, 0x5d, 0x44, 0xcc, 0x92, 0x94, 0x95, 0xa9, + 0x53, 0xf9, 0x5c, 0x2d, 0x2d, 0xd6, 0xf9, 0x88, 0x29, 0x2f, 0x73, 0x46, 0xe5, 0x93, 0xdd, 0xbf, + 0xbe, 0xdc, 0xd0, 0xbe, 0x7a, 0xb9, 0xa1, 0xfd, 0xe3, 0xe5, 0x86, 0xf6, 0xa3, 0x5b, 0xaf, 0xf8, + 0xab, 0x84, 0xcc, 0x1f, 0x3a, 0x60, 0x6a, 0x5b, 0x8e, 0x4d, 0x3c, 0xd6, 0x9b, 0x15, 0xc1, 0x7f, + 0xeb, 0xdf, 0x01, 0x00, 0x00, 0xff, 0xff, 0xf2, 0x91, 0xe2, 0xd9, 0x07, 0x21, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -4679,6 +4695,16 @@ func (m *GitFilesRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if m.NoRevisionCache { + i-- + if m.NoRevisionCache { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x30 + } if m.NewGitFileGlobbingEnabled { i-- if m.NewGitFileGlobbingEnabled { @@ -4800,6 +4826,16 @@ func (m *GitDirectoriesRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if m.NoRevisionCache { + i-- + if m.NoRevisionCache { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x20 + } if len(m.Revision) > 0 { i -= len(m.Revision) copy(dAtA[i:], m.Revision) @@ -5686,6 +5722,9 @@ func (m *GitFilesRequest) Size() (n int) { if m.NewGitFileGlobbingEnabled { n += 2 } + if m.NoRevisionCache { + n += 2 + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -5733,6 +5772,9 @@ func (m *GitDirectoriesRequest) Size() (n int) { if l > 0 { n += 1 + l + sovRepository(uint64(l)) } + if m.NoRevisionCache { + n += 2 + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -10874,6 +10916,26 @@ func (m *GitFilesRequest) Unmarshal(dAtA []byte) error { } } m.NewGitFileGlobbingEnabled = bool(v != 0) + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field NoRevisionCache", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRepository + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.NoRevisionCache = bool(v != 0) default: iNdEx = preIndex skippy, err := skipRepository(dAtA[iNdEx:]) @@ -11192,6 +11254,26 @@ func (m *GitDirectoriesRequest) Unmarshal(dAtA []byte) error { } m.Revision = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field NoRevisionCache", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRepository + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.NoRevisionCache = bool(v != 0) default: iNdEx = preIndex skippy, err := skipRepository(dAtA[iNdEx:]) diff --git a/reposerver/cache/cache.go b/reposerver/cache/cache.go index 79d3a02b62750..4437bd3ac0dd7 100644 --- a/reposerver/cache/cache.go +++ b/reposerver/cache/cache.go @@ -12,7 +12,6 @@ import ( "github.com/argoproj/gitops-engine/pkg/utils/text" "github.com/go-git/go-git/v5/plumbing" - "github.com/redis/go-redis/v9" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -44,7 +43,7 @@ func NewCache(cache *cacheutil.Cache, repoCacheExpiration time.Duration, revisio return &Cache{cache, repoCacheExpiration, revisionCacheExpiration} } -func AddCacheFlagsToCmd(cmd *cobra.Command, opts ...func(client *redis.Client)) func() (*Cache, error) { +func AddCacheFlagsToCmd(cmd *cobra.Command, opts ...cacheutil.Options) func() (*Cache, error) { var repoCacheExpiration time.Duration var revisionCacheExpiration time.Duration @@ -225,6 +224,12 @@ func LogDebugManifestCacheKeyFields(message string, reason string, revision stri } } +func (c *Cache) SetNewRevisionManifests(newRevision string, revision string, appSrc *appv1.ApplicationSource, srcRefs appv1.RefTargetRevisionMapping, clusterInfo ClusterRuntimeInfo, namespace string, trackingMethod string, appLabelKey string, appName string, refSourceCommitSHAs ResolvedRevisions) error { + oldKey := manifestCacheKey(revision, appSrc, srcRefs, namespace, trackingMethod, appLabelKey, appName, clusterInfo, refSourceCommitSHAs) + newKey := manifestCacheKey(newRevision, appSrc, srcRefs, namespace, trackingMethod, appLabelKey, appName, clusterInfo, refSourceCommitSHAs) + return c.cache.RenameItem(oldKey, newKey, c.repoCacheExpiration) +} + func (c *Cache) GetManifests(revision string, appSrc *appv1.ApplicationSource, srcRefs appv1.RefTargetRevisionMapping, clusterInfo ClusterRuntimeInfo, namespace string, trackingMethod string, appLabelKey string, appName string, res *CachedManifestResponse, refSourceCommitSHAs ResolvedRevisions) error { err := c.cache.GetItem(manifestCacheKey(revision, appSrc, srcRefs, namespace, trackingMethod, appLabelKey, appName, clusterInfo, refSourceCommitSHAs), res) diff --git a/reposerver/cache/mocks/reposervercache.go b/reposerver/cache/mocks/reposervercache.go new file mode 100644 index 0000000000000..0e49b5816178e --- /dev/null +++ b/reposerver/cache/mocks/reposervercache.go @@ -0,0 +1,71 @@ +package mocks + +import ( + "testing" + "time" + + "github.com/alicebob/miniredis/v2" + cacheutil "github.com/argoproj/argo-cd/v2/util/cache" + cacheutilmocks "github.com/argoproj/argo-cd/v2/util/cache/mocks" + "github.com/redis/go-redis/v9" + "github.com/stretchr/testify/mock" +) + +type MockCacheType int + +const ( + MockCacheTypeRedis MockCacheType = iota + MockCacheTypeInMem +) + +type MockRepoCache struct { + mock.Mock + RedisClient *cacheutilmocks.MockCacheClient + StopRedisCallback func() +} + +type MockCacheOptions struct { + RepoCacheExpiration time.Duration + RevisionCacheExpiration time.Duration + ReadDelay time.Duration + WriteDelay time.Duration +} + +type CacheCallCounts struct { + ExternalSets int + ExternalGets int + ExternalDeletes int +} + +// Checks that the cache was called the expected number of times +func (mockCache *MockRepoCache) AssertCacheCalledTimes(t *testing.T, calls *CacheCallCounts) { + mockCache.RedisClient.AssertNumberOfCalls(t, "Get", calls.ExternalGets) + mockCache.RedisClient.AssertNumberOfCalls(t, "Set", calls.ExternalSets) + mockCache.RedisClient.AssertNumberOfCalls(t, "Delete", calls.ExternalDeletes) +} + +func (mockCache *MockRepoCache) ConfigureDefaultCallbacks() { + mockCache.RedisClient.On("Get", mock.Anything, mock.Anything).Return(nil) + mockCache.RedisClient.On("Set", mock.Anything).Return(nil) + mockCache.RedisClient.On("Delete", mock.Anything).Return(nil) +} + +func NewInMemoryRedis() (*redis.Client, func()) { + cacheutil.NewInMemoryCache(5 * time.Second) + mr, err := miniredis.Run() + if err != nil { + panic(err) + } + return redis.NewClient(&redis.Options{Addr: mr.Addr()}), mr.Close +} + +func NewMockRepoCache(cacheOpts *MockCacheOptions) *MockRepoCache { + redisClient, stopRedis := NewInMemoryRedis() + redisCacheClient := &cacheutilmocks.MockCacheClient{ + ReadDelay: cacheOpts.ReadDelay, + WriteDelay: cacheOpts.WriteDelay, + BaseCache: cacheutil.NewRedisCache(redisClient, cacheOpts.RepoCacheExpiration, cacheutil.RedisCompressionNone)} + newMockCache := &MockRepoCache{RedisClient: redisCacheClient, StopRedisCallback: stopRedis} + newMockCache.ConfigureDefaultCallbacks() + return newMockCache +} diff --git a/reposerver/gpgwatcher.go b/reposerver/gpgwatcher.go index 9c2c9be790813..5b43d6a24ac76 100644 --- a/reposerver/gpgwatcher.go +++ b/reposerver/gpgwatcher.go @@ -19,7 +19,7 @@ func StartGPGWatcher(sourcePath string) error { forceSync := false watcher, err := fsnotify.NewWatcher() if err != nil { - return err + return fmt.Errorf("failed to create fsnotify Watcher: %w", err) } defer func(watcher *fsnotify.Watcher) { if err = watcher.Close(); err != nil { @@ -83,7 +83,7 @@ func StartGPGWatcher(sourcePath string) error { err = watcher.Add(sourcePath) if err != nil { - return err + return fmt.Errorf("failed to add a new source to the watcher: %w", err) } <-done return fmt.Errorf("Abnormal termination of GPG watcher, refusing to continue.") diff --git a/reposerver/metrics/githandlers.go b/reposerver/metrics/githandlers.go index cce632cf56813..09a0591002c52 100644 --- a/reposerver/metrics/githandlers.go +++ b/reposerver/metrics/githandlers.go @@ -1,11 +1,27 @@ package metrics import ( + "context" + "math" "time" + "golang.org/x/sync/semaphore" + + "github.com/argoproj/argo-cd/v2/util/env" "github.com/argoproj/argo-cd/v2/util/git" ) +var ( + lsRemoteParallelismLimit = env.ParseInt64FromEnv("ARGOCD_GIT_LS_REMOTE_PARALLELISM_LIMIT", 0, 0, math.MaxInt64) + lsRemoteParallelismLimitSemaphore *semaphore.Weighted +) + +func init() { + if lsRemoteParallelismLimit > 0 { + lsRemoteParallelismLimitSemaphore = semaphore.NewWeighted(lsRemoteParallelismLimit) + } +} + // NewGitClientEventHandlers creates event handlers that update Git related metrics func NewGitClientEventHandlers(metricsServer *MetricsServer) git.EventHandlers { return git.EventHandlers{ @@ -19,7 +35,15 @@ func NewGitClientEventHandlers(metricsServer *MetricsServer) git.EventHandlers { OnLsRemote: func(repo string) func() { startTime := time.Now() metricsServer.IncGitRequest(repo, GitRequestTypeLsRemote) + if lsRemoteParallelismLimitSemaphore != nil { + // The `Acquire` method returns either `nil` or error of the provided context. The + // context.Background() is never canceled, so it is safe to ignore the error. + _ = lsRemoteParallelismLimitSemaphore.Acquire(context.Background(), 1) + } return func() { + if lsRemoteParallelismLimitSemaphore != nil { + lsRemoteParallelismLimitSemaphore.Release(1) + } metricsServer.ObserveGitRequestDuration(repo, GitRequestTypeLsRemote, time.Since(startTime)) } }, diff --git a/reposerver/metrics/githandlers_test.go b/reposerver/metrics/githandlers_test.go new file mode 100644 index 0000000000000..6eaeeca82cc36 --- /dev/null +++ b/reposerver/metrics/githandlers_test.go @@ -0,0 +1,122 @@ +package metrics + +import ( + "os" + "testing" + + "github.com/stretchr/testify/assert" + "golang.org/x/sync/semaphore" +) + +func TestMain(m *testing.M) { + os.Exit(m.Run()) +} + +func TestEdgeCasesAndErrorHandling(t *testing.T) { + tests := []struct { + name string + setup func() + teardown func() + testFunc func(t *testing.T) + }{ + { + name: "lsRemoteParallelismLimitSemaphore is nil", + testFunc: func(t *testing.T) { + lsRemoteParallelismLimitSemaphore = nil + assert.NotPanics(t, func() { + NewGitClientEventHandlers(&MetricsServer{}) + }) + }, + }, + { + name: "lsRemoteParallelismLimitSemaphore is not nil", + setup: func() { + lsRemoteParallelismLimitSemaphore = semaphore.NewWeighted(1) + }, + teardown: func() { + lsRemoteParallelismLimitSemaphore = nil + }, + testFunc: func(t *testing.T) { + assert.NotPanics(t, func() { + NewGitClientEventHandlers(&MetricsServer{}) + }) + }, + }, + { + name: "lsRemoteParallelismLimitSemaphore is not nil and Acquire returns error", + setup: func() { + lsRemoteParallelismLimitSemaphore = semaphore.NewWeighted(1) + }, + teardown: func() { + lsRemoteParallelismLimitSemaphore = nil + }, + testFunc: func(t *testing.T) { + assert.NotPanics(t, func() { + NewGitClientEventHandlers(&MetricsServer{}) + }) + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.setup != nil { + tt.setup() + } + if tt.teardown != nil { + defer tt.teardown() + } + tt.testFunc(t) + }) + } +} + +func TestSemaphoreFunctionality(t *testing.T) { + os.Setenv("ARGOCD_GIT_LSREMOTE_PARALLELISM_LIMIT", "1") + + tests := []struct { + name string + setup func() + teardown func() + testFunc func(t *testing.T) + }{ + { + name: "lsRemoteParallelismLimitSemaphore is not nil", + setup: func() { + lsRemoteParallelismLimitSemaphore = semaphore.NewWeighted(1) + }, + teardown: func() { + lsRemoteParallelismLimitSemaphore = nil + }, + testFunc: func(t *testing.T) { + assert.NotPanics(t, func() { + NewGitClientEventHandlers(&MetricsServer{}) + }) + }, + }, + { + name: "lsRemoteParallelismLimitSemaphore is not nil and Acquire returns error", + setup: func() { + lsRemoteParallelismLimitSemaphore = semaphore.NewWeighted(1) + }, + teardown: func() { + lsRemoteParallelismLimitSemaphore = nil + }, + testFunc: func(t *testing.T) { + assert.NotPanics(t, func() { + NewGitClientEventHandlers(&MetricsServer{}) + }) + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.setup != nil { + tt.setup() + } + if tt.teardown != nil { + defer tt.teardown() + } + tt.testFunc(t) + }) + } +} diff --git a/reposerver/repository/repository.go b/reposerver/repository/repository.go index 1498dd81d4f6e..5d11a6438272d 100644 --- a/reposerver/repository/repository.go +++ b/reposerver/repository/repository.go @@ -300,6 +300,7 @@ func (s *Service) runRepoOperation( var gitClient git.Client var helmClient helm.Client var err error + gitClientOpts := git.WithCache(s.cache, !settings.noRevisionCache && !settings.noCache) revision = textutils.FirstNonEmpty(revision, source.TargetRevision) unresolvedRevision := revision if source.IsHelm() { @@ -308,13 +309,13 @@ func (s *Service) runRepoOperation( return err } } else { - gitClient, revision, err = s.newClientResolveRevision(repo, revision, git.WithCache(s.cache, !settings.noRevisionCache && !settings.noCache)) + gitClient, revision, err = s.newClientResolveRevision(repo, revision, gitClientOpts) if err != nil { return err } } - repoRefs, err := resolveReferencedSources(hasMultipleSources, source.Helm, refSources, s.newClientResolveRevision) + repoRefs, err := resolveReferencedSources(hasMultipleSources, source.Helm, refSources, s.newClientResolveRevision, gitClientOpts) if err != nil { return err } @@ -463,7 +464,7 @@ type gitClientGetter func(repo *v1alpha1.Repository, revision string, opts ...gi // // Much of this logic is duplicated in runManifestGenAsync. If making changes here, check whether runManifestGenAsync // should be updated. -func resolveReferencedSources(hasMultipleSources bool, source *v1alpha1.ApplicationSourceHelm, refSources map[string]*v1alpha1.RefTarget, newClientResolveRevision gitClientGetter) (map[string]string, error) { +func resolveReferencedSources(hasMultipleSources bool, source *v1alpha1.ApplicationSourceHelm, refSources map[string]*v1alpha1.RefTarget, newClientResolveRevision gitClientGetter, gitClientOpts git.ClientOpts) (map[string]string, error) { repoRefs := make(map[string]string) if !hasMultipleSources || source == nil { return repoRefs, nil @@ -490,7 +491,7 @@ func resolveReferencedSources(hasMultipleSources bool, source *v1alpha1.Applicat normalizedRepoURL := git.NormalizeGitURL(refSourceMapping.Repo.Repo) _, ok = repoRefs[normalizedRepoURL] if !ok { - _, referencedCommitSHA, err := newClientResolveRevision(&refSourceMapping.Repo, refSourceMapping.TargetRevision) + _, referencedCommitSHA, err := newClientResolveRevision(&refSourceMapping.Repo, refSourceMapping.TargetRevision, gitClientOpts) if err != nil { log.Errorf("Failed to get git client for repo %s: %v", refSourceMapping.Repo.Repo, err) return nil, fmt.Errorf("failed to get git client for repo %s", refSourceMapping.Repo.Repo) @@ -506,6 +507,17 @@ func resolveReferencedSources(hasMultipleSources bool, source *v1alpha1.Applicat func (s *Service) GenerateManifest(ctx context.Context, q *apiclient.ManifestRequest) (*apiclient.ManifestResponse, error) { var res *apiclient.ManifestResponse var err error + + // Skip this path for ref only sources + if q.HasMultipleSources && q.ApplicationSource.Path == "" && q.ApplicationSource.Chart == "" && q.ApplicationSource.Ref != "" { + log.Debugf("Skipping manifest generation for ref only source for application: %s and ref %s", q.AppName, q.ApplicationSource.Ref) + _, revision, err := s.newClientResolveRevision(q.Repo, q.Revision, git.WithCache(s.cache, !q.NoRevisionCache && !q.NoCache)) + res = &apiclient.ManifestResponse{ + Revision: revision, + } + return res, err + } + cacheFn := func(cacheKey string, refSourceCommitSHAs cache.ResolvedRevisions, firstInvocation bool) (bool, error) { ok, resp, err := s.getManifestCacheEntry(cacheKey, q, refSourceCommitSHAs, firstInvocation) res = resp @@ -728,7 +740,7 @@ func (s *Service) runManifestGenAsync(ctx context.Context, repoRoot, commitSHA, return } } else { - gitClient, referencedCommitSHA, err := s.newClientResolveRevision(&refSourceMapping.Repo, refSourceMapping.TargetRevision) + gitClient, referencedCommitSHA, err := s.newClientResolveRevision(&refSourceMapping.Repo, refSourceMapping.TargetRevision, git.WithCache(s.cache, !q.NoRevisionCache && !q.NoCache)) if err != nil { log.Errorf("Failed to get git client for repo %s: %v", refSourceMapping.Repo.Repo, err) ch.errCh <- fmt.Errorf("failed to get git client for repo %s", refSourceMapping.Repo.Repo) @@ -1021,6 +1033,10 @@ func getHelmDependencyRepos(appPath string) ([]*v1alpha1.Repository, error) { repos = append(repos, &v1alpha1.Repository{ Name: r.Repository[1:], }) + } else if strings.HasPrefix(r.Repository, "alias:") { + repos = append(repos, &v1alpha1.Repository{ + Name: strings.TrimPrefix(r.Repository, "alias:"), + }) } else if u, err := url.Parse(r.Repository); err == nil && (u.Scheme == "https" || u.Scheme == "oci") { repo := &v1alpha1.Repository{ // trimming oci:// prefix since it is currently not supported by Argo CD (OCI repos just have no scheme) @@ -1373,7 +1389,7 @@ func GenerateManifests(ctx context.Context, appPath, repoRoot, revision string, if q.KustomizeOptions != nil { kustomizeBinary = q.KustomizeOptions.BinaryPath } - k := kustomize.NewKustomizeApp(appPath, q.Repo.GetGitCreds(gitCredsStore), repoURL, kustomizeBinary) + k := kustomize.NewKustomizeApp(repoRoot, appPath, q.Repo.GetGitCreds(gitCredsStore), repoURL, kustomizeBinary) targetObjs, _, err = k.Build(q.ApplicationSource.Kustomize, q.KustomizeOptions, env) case v1alpha1.ApplicationSourceTypePlugin: pluginName := "" @@ -1960,7 +1976,7 @@ func (s *Service) GetAppDetails(ctx context.Context, q *apiclient.RepoServerAppD return err } case v1alpha1.ApplicationSourceTypeKustomize: - if err := populateKustomizeAppDetails(res, q, opContext.appPath, commitSHA, s.gitCredsStore); err != nil { + if err := populateKustomizeAppDetails(res, q, repoRoot, opContext.appPath, commitSHA, s.gitCredsStore); err != nil { return err } case v1alpha1.ApplicationSourceTypePlugin: @@ -1997,12 +2013,13 @@ func (s *Service) createGetAppDetailsCacheHandler(res *apiclient.RepoAppDetailsR func populateHelmAppDetails(res *apiclient.RepoAppDetailsResponse, appPath string, repoRoot string, q *apiclient.RepoServerAppDetailsQuery, gitRepoPaths io.TempPaths) error { var selectedValueFiles []string + var availableValueFiles []string if q.Source.Helm != nil { selectedValueFiles = q.Source.Helm.ValueFiles } - availableValueFiles, err := findHelmValueFilesInPath(appPath) + err := filepath.Walk(appPath, walkHelmValueFilesInPath(appPath, &availableValueFiles)) if err != nil { return err } @@ -2079,35 +2096,34 @@ func loadFileIntoIfExists(path pathutil.ResolvedFilePath, destination *string) e return nil } -func findHelmValueFilesInPath(path string) ([]string, error) { - var result []string +func walkHelmValueFilesInPath(root string, valueFiles *[]string) filepath.WalkFunc { + return func(path string, info os.FileInfo, err error) error { - files, err := os.ReadDir(path) - if err != nil { - return result, fmt.Errorf("error reading helm values file from %s: %w", path, err) - } - - for _, f := range files { - if f.IsDir() { - continue + if err != nil { + return fmt.Errorf("error reading helm values file from %s: %w", path, err) } - filename := f.Name() - fileNameExt := strings.ToLower(filepath.Ext(filename)) + + filename := info.Name() + fileNameExt := strings.ToLower(filepath.Ext(path)) if strings.Contains(filename, "values") && (fileNameExt == ".yaml" || fileNameExt == ".yml") { - result = append(result, filename) + relPath, err := filepath.Rel(root, path) + if err != nil { + return fmt.Errorf("error traversing path from %s to %s: %w", root, path, err) + } + *valueFiles = append(*valueFiles, relPath) } - } - return result, nil + return nil + } } -func populateKustomizeAppDetails(res *apiclient.RepoAppDetailsResponse, q *apiclient.RepoServerAppDetailsQuery, appPath string, reversion string, credsStore git.CredsStore) error { +func populateKustomizeAppDetails(res *apiclient.RepoAppDetailsResponse, q *apiclient.RepoServerAppDetailsQuery, repoRoot string, appPath string, reversion string, credsStore git.CredsStore) error { res.Kustomize = &apiclient.KustomizeAppSpec{} kustomizeBinary := "" if q.KustomizeOptions != nil { kustomizeBinary = q.KustomizeOptions.BinaryPath } - k := kustomize.NewKustomizeApp(appPath, q.Repo.GetGitCreds(credsStore), q.Repo.Repo, kustomizeBinary) + k := kustomize.NewKustomizeApp(repoRoot, appPath, q.Repo.GetGitCreds(credsStore), q.Repo.Repo, kustomizeBinary) fakeManifestRequest := apiclient.ManifestRequest{ AppName: q.AppName, Namespace: "", // FIXME: omit it for now @@ -2505,6 +2521,7 @@ func (s *Service) GetGitFiles(_ context.Context, request *apiclient.GitFilesRequ repo := request.GetRepo() revision := request.GetRevision() gitPath := request.GetPath() + noRevisionCache := request.GetNoRevisionCache() enableNewGitFileGlobbing := request.GetNewGitFileGlobbingEnabled() if gitPath == "" { gitPath = "." @@ -2514,7 +2531,7 @@ func (s *Service) GetGitFiles(_ context.Context, request *apiclient.GitFilesRequ return nil, status.Error(codes.InvalidArgument, "must pass a valid repo") } - gitClient, revision, err := s.newClientResolveRevision(repo, revision, git.WithCache(s.cache, true)) + gitClient, revision, err := s.newClientResolveRevision(repo, revision, git.WithCache(s.cache, !noRevisionCache)) if err != nil { return nil, status.Errorf(codes.Internal, "unable to resolve git revision %s: %v", revision, err) } @@ -2567,12 +2584,12 @@ func (s *Service) GetGitFiles(_ context.Context, request *apiclient.GitFilesRequ func (s *Service) GetGitDirectories(_ context.Context, request *apiclient.GitDirectoriesRequest) (*apiclient.GitDirectoriesResponse, error) { repo := request.GetRepo() revision := request.GetRevision() - + noRevisionCache := request.GetNoRevisionCache() if repo == nil { return nil, status.Error(codes.InvalidArgument, "must pass a valid repo") } - gitClient, revision, err := s.newClientResolveRevision(repo, revision, git.WithCache(s.cache, true)) + gitClient, revision, err := s.newClientResolveRevision(repo, revision, git.WithCache(s.cache, !noRevisionCache)) if err != nil { return nil, status.Errorf(codes.Internal, "unable to resolve git revision %s: %v", revision, err) } diff --git a/reposerver/repository/repository.proto b/reposerver/repository/repository.proto index 8e4b69000f7e1..de061122e2586 100644 --- a/reposerver/repository/repository.proto +++ b/reposerver/repository/repository.proto @@ -236,6 +236,7 @@ message GitFilesRequest { string revision = 3; string path = 4; bool NewGitFileGlobbingEnabled = 5; + bool noRevisionCache = 6; } message GitFilesResponse { @@ -247,6 +248,7 @@ message GitDirectoriesRequest { github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.Repository repo = 1; bool submoduleEnabled = 2; string revision = 3; + bool noRevisionCache = 4; } message GitDirectoriesResponse { diff --git a/reposerver/repository/repository_test.go b/reposerver/repository/repository_test.go index c2ac086d85346..3f2f74c4e5ae0 100644 --- a/reposerver/repository/repository_test.go +++ b/reposerver/repository/repository_test.go @@ -1,6 +1,7 @@ package repository import ( + "bytes" "context" "encoding/json" "errors" @@ -17,6 +18,7 @@ import ( "testing" "time" + cacheutil "github.com/argoproj/argo-cd/v2/util/cache" log "github.com/sirupsen/logrus" "k8s.io/apimachinery/pkg/api/resource" @@ -28,13 +30,14 @@ import ( "k8s.io/apimachinery/pkg/runtime" "sigs.k8s.io/yaml" + "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" argoappv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" "github.com/argoproj/argo-cd/v2/reposerver/apiclient" "github.com/argoproj/argo-cd/v2/reposerver/cache" + repositorymocks "github.com/argoproj/argo-cd/v2/reposerver/cache/mocks" "github.com/argoproj/argo-cd/v2/reposerver/metrics" fileutil "github.com/argoproj/argo-cd/v2/test/fixture/path" "github.com/argoproj/argo-cd/v2/util/argo" - cacheutil "github.com/argoproj/argo-cd/v2/util/cache" dbmocks "github.com/argoproj/argo-cd/v2/util/db/mocks" "github.com/argoproj/argo-cd/v2/util/git" gitmocks "github.com/argoproj/argo-cd/v2/util/git/mocks" @@ -51,12 +54,49 @@ gpg: Good signature from "GitHub (web-flow commit signing) " type clientFunc func(*gitmocks.Client, *helmmocks.Client, *iomocks.TempPaths) -func newServiceWithMocks(root string, signed bool) (*Service, *gitmocks.Client) { +type repoCacheMocks struct { + mock.Mock + cacheutilCache *cacheutil.Cache + cache *cache.Cache + mockCache *repositorymocks.MockRepoCache +} + +type newGitRepoHelmChartOptions struct { + chartName string + chartVersion string + // valuesFiles is a map of the values file name to the key/value pairs to be written to the file + valuesFiles map[string]map[string]string +} + +type newGitRepoOptions struct { + path string + createPath bool + remote string + addEmptyCommit bool + helmChartOptions newGitRepoHelmChartOptions +} + +func newCacheMocks() *repoCacheMocks { + mockRepoCache := repositorymocks.NewMockRepoCache(&repositorymocks.MockCacheOptions{ + RepoCacheExpiration: 1 * time.Minute, + RevisionCacheExpiration: 1 * time.Minute, + ReadDelay: 0, + WriteDelay: 0, + }) + cacheutilCache := cacheutil.NewCache(mockRepoCache.RedisClient) + return &repoCacheMocks{ + cacheutilCache: cacheutilCache, + cache: cache.NewCache(cacheutilCache, 1*time.Minute, 1*time.Minute), + mockCache: mockRepoCache, + } +} + +func newServiceWithMocks(t *testing.T, root string, signed bool) (*Service, *gitmocks.Client, *repoCacheMocks) { root, err := filepath.Abs(root) if err != nil { panic(err) } - return newServiceWithOpt(func(gitClient *gitmocks.Client, helmClient *helmmocks.Client, paths *iomocks.TempPaths) { + return newServiceWithOpt(t, func(gitClient *gitmocks.Client, helmClient *helmmocks.Client, paths *iomocks.TempPaths) { gitClient.On("Init").Return(nil) gitClient.On("Fetch", mock.Anything).Return(nil) gitClient.On("Checkout", mock.Anything, mock.Anything).Return(nil) @@ -73,7 +113,7 @@ func newServiceWithMocks(root string, signed bool) (*Service, *gitmocks.Client) chart := "my-chart" oobChart := "out-of-bounds-chart" version := "1.1.0" - helmClient.On("GetIndex", true).Return(&helm.Index{Entries: map[string]helm.Entries{ + helmClient.On("GetIndex", mock.AnythingOfType("bool")).Return(&helm.Index{Entries: map[string]helm.Entries{ chart: {{Version: "1.0.0"}, {Version: version}}, oobChart: {{Version: "1.0.0"}, {Version: version}}, }}, nil) @@ -89,18 +129,16 @@ func newServiceWithMocks(root string, signed bool) (*Service, *gitmocks.Client) }, root) } -func newServiceWithOpt(cf clientFunc, root string) (*Service, *gitmocks.Client) { +func newServiceWithOpt(t *testing.T, cf clientFunc, root string) (*Service, *gitmocks.Client, *repoCacheMocks) { helmClient := &helmmocks.Client{} gitClient := &gitmocks.Client{} paths := &iomocks.TempPaths{} cf(gitClient, helmClient, paths) - service := NewService(metrics.NewMetricsServer(), cache.NewCache( - cacheutil.NewCache(cacheutil.NewInMemoryCache(1*time.Minute)), - 1*time.Minute, - 1*time.Minute, - ), RepoServerInitConstants{ParallelismLimit: 1}, argo.NewResourceTracking(), &git.NoopCredsStore{}, root) + cacheMocks := newCacheMocks() + t.Cleanup(cacheMocks.mockCache.StopRedisCallback) + service := NewService(metrics.NewMetricsServer(), cacheMocks.cache, RepoServerInitConstants{ParallelismLimit: 1}, argo.NewResourceTracking(), &git.NoopCredsStore{}, root) - service.newGitClient = func(rawRepoURL string, root string, creds git.Creds, insecure bool, enableLfs bool, prosy string, opts ...git.ClientOpts) (client git.Client, e error) { + service.newGitClient = func(rawRepoURL string, root string, creds git.Creds, insecure bool, enableLfs bool, proxy string, opts ...git.ClientOpts) (client git.Client, e error) { return gitClient, nil } service.newHelmClient = func(repoURL string, creds helm.Creds, enableOci bool, proxy string, opts ...helm.ClientOpts) helm.Client { @@ -110,20 +148,20 @@ func newServiceWithOpt(cf clientFunc, root string) (*Service, *gitmocks.Client) return io.NopCloser } service.gitRepoPaths = paths - return service, gitClient + return service, gitClient, cacheMocks } -func newService(root string) *Service { - service, _ := newServiceWithMocks(root, false) +func newService(t *testing.T, root string) *Service { + service, _, _ := newServiceWithMocks(t, root, false) return service } -func newServiceWithSignature(root string) *Service { - service, _ := newServiceWithMocks(root, true) +func newServiceWithSignature(t *testing.T, root string) *Service { + service, _, _ := newServiceWithMocks(t, root, true) return service } -func newServiceWithCommitSHA(root, revision string) *Service { +func newServiceWithCommitSHA(t *testing.T, root, revision string) *Service { var revisionErr error commitSHARegex := regexp.MustCompile("^[0-9A-Fa-f]{40}$") @@ -131,7 +169,7 @@ func newServiceWithCommitSHA(root, revision string) *Service { revisionErr = errors.New("not a commit SHA") } - service, gitClient := newServiceWithOpt(func(gitClient *gitmocks.Client, helmClient *helmmocks.Client, paths *iomocks.TempPaths) { + service, gitClient, _ := newServiceWithOpt(t, func(gitClient *gitmocks.Client, helmClient *helmmocks.Client, paths *iomocks.TempPaths) { gitClient.On("Init").Return(nil) gitClient.On("Fetch", mock.Anything).Return(nil) gitClient.On("Checkout", mock.Anything, mock.Anything).Return(nil) @@ -150,7 +188,7 @@ func newServiceWithCommitSHA(root, revision string) *Service { } func TestGenerateYamlManifestInDir(t *testing.T) { - service := newService("../../manifests/base") + service := newService(t, "../../manifests/base") src := argoappv1.ApplicationSource{Path: "."} q := apiclient.ManifestRequest{ @@ -247,7 +285,7 @@ func TestGenerateManifests_MissingSymlinkDestination(t *testing.T) { } func TestGenerateManifests_K8SAPIResetCache(t *testing.T) { - service := newService("../../manifests/base") + service := newService(t, "../../manifests/base") src := argoappv1.ApplicationSource{Path: "."} q := apiclient.ManifestRequest{ @@ -275,7 +313,7 @@ func TestGenerateManifests_K8SAPIResetCache(t *testing.T) { } func TestGenerateManifests_EmptyCache(t *testing.T) { - service := newService("../../manifests/base") + service, gitMocks, mockCache := newServiceWithMocks(t, "../../manifests/base", false) src := argoappv1.ApplicationSource{Path: "."} q := apiclient.ManifestRequest{ @@ -291,11 +329,141 @@ func TestGenerateManifests_EmptyCache(t *testing.T) { res, err := service.GenerateManifest(context.Background(), &q) assert.NoError(t, err) assert.True(t, len(res.Manifests) > 0) + mockCache.mockCache.AssertCacheCalledTimes(t, &repositorymocks.CacheCallCounts{ + ExternalSets: 2, + ExternalGets: 2, + ExternalDeletes: 1}) + gitMocks.AssertCalled(t, "LsRemote", mock.Anything) + gitMocks.AssertCalled(t, "Fetch", mock.Anything) +} + +// Test that when Generate manifest is called with a source that is ref only it does not try to generate manifests or hit the manifest cache +// but it does resolve and cache the revision +func TestGenerateManifest_RefOnlyShortCircuit(t *testing.T) { + lsremoteCalled := false + dir := t.TempDir() + repopath := fmt.Sprintf("%s/tmprepo", dir) + repoRemote := fmt.Sprintf("file://%s", repopath) + cacheMocks := newCacheMocks() + t.Cleanup(cacheMocks.mockCache.StopRedisCallback) + service := NewService(metrics.NewMetricsServer(), cacheMocks.cache, RepoServerInitConstants{ParallelismLimit: 1}, argo.NewResourceTracking(), &git.NoopCredsStore{}, repopath) + service.newGitClient = func(rawRepoURL string, root string, creds git.Creds, insecure bool, enableLfs bool, proxy string, opts ...git.ClientOpts) (client git.Client, e error) { + opts = append(opts, git.WithEventHandlers(git.EventHandlers{ + // Primary check, we want to make sure ls-remote is not called when the item is in cache + OnLsRemote: func(repo string) func() { + return func() { + lsremoteCalled = true + } + }, + OnFetch: func(repo string) func() { + return func() { + assert.Fail(t, "Fetch should not be called from GenerateManifest when the source is ref only") + } + }, + })) + gitClient, err := git.NewClientExt(rawRepoURL, root, creds, insecure, enableLfs, proxy, opts...) + return gitClient, err + } + revision := initGitRepo(t, newGitRepoOptions{ + path: repopath, + createPath: true, + remote: repoRemote, + addEmptyCommit: true, + }) + src := argoappv1.ApplicationSource{RepoURL: repoRemote, TargetRevision: "HEAD", Ref: "test-ref"} + repo := &argoappv1.Repository{ + Repo: repoRemote, + } + q := apiclient.ManifestRequest{ + Repo: repo, + Revision: "HEAD", + HasMultipleSources: true, + ApplicationSource: &src, + ProjectName: "default", + ProjectSourceRepos: []string{"*"}, + } + _, err := service.GenerateManifest(context.Background(), &q) + assert.NoError(t, err) + cacheMocks.mockCache.AssertCacheCalledTimes(t, &repositorymocks.CacheCallCounts{ + ExternalSets: 1, + ExternalGets: 1}) + assert.True(t, lsremoteCalled, "ls-remote should be called when the source is ref only") + var revisions [][2]string + assert.NoError(t, cacheMocks.cacheutilCache.GetItem(fmt.Sprintf("git-refs|%s", repoRemote), &revisions)) + assert.ElementsMatch(t, [][2]string{{"refs/heads/main", revision}, {"HEAD", "ref: refs/heads/main"}}, revisions) +} + +// Test that calling manifest generation on source helm reference helm files that when the revision is cached it does not call ls-remote +func TestGenerateManifestsHelmWithRefs_CachedNoLsRemote(t *testing.T) { + dir := t.TempDir() + repopath := fmt.Sprintf("%s/tmprepo", dir) + cacheMocks := newCacheMocks() + t.Cleanup(func() { + cacheMocks.mockCache.StopRedisCallback() + err := filepath.WalkDir(dir, + func(path string, di fs.DirEntry, err error) error { + if err == nil { + return os.Chmod(path, 0777) + } + return err + }) + if err != nil { + t.Fatal(err) + } + }) + service := NewService(metrics.NewMetricsServer(), cacheMocks.cache, RepoServerInitConstants{ParallelismLimit: 1}, argo.NewResourceTracking(), &git.NoopCredsStore{}, repopath) + var gitClient git.Client + var err error + service.newGitClient = func(rawRepoURL string, root string, creds git.Creds, insecure bool, enableLfs bool, proxy string, opts ...git.ClientOpts) (client git.Client, e error) { + opts = append(opts, git.WithEventHandlers(git.EventHandlers{ + // Primary check, we want to make sure ls-remote is not called when the item is in cache + OnLsRemote: func(repo string) func() { + return func() { + assert.Fail(t, "LsRemote should not be called when the item is in cache") + } + }, + })) + gitClient, err = git.NewClientExt(rawRepoURL, root, creds, insecure, enableLfs, proxy, opts...) + return gitClient, err + } + repoRemote := fmt.Sprintf("file://%s", repopath) + revision := initGitRepo(t, newGitRepoOptions{ + path: repopath, + createPath: true, + remote: repoRemote, + helmChartOptions: newGitRepoHelmChartOptions{ + chartName: "my-chart", + chartVersion: "v1.0.0", + valuesFiles: map[string]map[string]string{"test.yaml": {"testval": "test"}}}, + }) + src := argoappv1.ApplicationSource{RepoURL: repoRemote, Path: ".", TargetRevision: "HEAD", Helm: &argoappv1.ApplicationSourceHelm{ + ValueFiles: []string{"$ref/test.yaml"}, + }} + repo := &argoappv1.Repository{ + Repo: repoRemote, + } + q := apiclient.ManifestRequest{ + Repo: repo, + Revision: "HEAD", + HasMultipleSources: true, + ApplicationSource: &src, + ProjectName: "default", + ProjectSourceRepos: []string{"*"}, + RefSources: map[string]*argoappv1.RefTarget{"$ref": {TargetRevision: "HEAD", Repo: *repo}}, + } + err = cacheMocks.cacheutilCache.SetItem(fmt.Sprintf("git-refs|%s", repoRemote), [][2]string{{"HEAD", revision}}, 30*time.Second, false) + assert.NoError(t, err) + _, err = service.GenerateManifest(context.Background(), &q) + assert.NoError(t, err) + cacheMocks.mockCache.AssertCacheCalledTimes(t, &repositorymocks.CacheCallCounts{ + ExternalSets: 2, + ExternalGets: 5}) } // ensure we can use a semver constraint range (>= 1.0.0) and get back the correct chart (1.0.0) func TestHelmManifestFromChartRepo(t *testing.T) { - service := newService(".") + root := t.TempDir() + service, gitMocks, mockCache := newServiceWithMocks(t, root, false) source := &argoappv1.ApplicationSource{Chart: "my-chart", TargetRevision: ">= 1.0.0"} request := &apiclient.ManifestRequest{Repo: &argoappv1.Repository{}, ApplicationSource: source, NoCache: true, ProjectName: "something", ProjectSourceRepos: []string{"*"}} @@ -309,10 +477,14 @@ func TestHelmManifestFromChartRepo(t *testing.T) { Revision: "1.1.0", SourceType: "Helm", }, response) + mockCache.mockCache.AssertCacheCalledTimes(t, &repositorymocks.CacheCallCounts{ + ExternalSets: 1, + ExternalGets: 0}) + gitMocks.AssertNotCalled(t, "LsRemote", mock.Anything) } func TestHelmChartReferencingExternalValues(t *testing.T) { - service := newService(".") + service := newService(t, ".") spec := argoappv1.ApplicationSpec{ Sources: []argoappv1.ApplicationSource{ {RepoURL: "https://helm.example.com", Chart: "my-chart", TargetRevision: ">= 1.0.0", Helm: &argoappv1.ApplicationSourceHelm{ @@ -342,7 +514,7 @@ func TestHelmChartReferencingExternalValues(t *testing.T) { } func TestHelmChartReferencingExternalValues_OutOfBounds_Symlink(t *testing.T) { - service := newService(".") + service := newService(t, ".") err := os.Mkdir("testdata/oob-symlink", 0755) require.NoError(t, err) t.Cleanup(func() { @@ -376,7 +548,7 @@ func TestHelmChartReferencingExternalValues_OutOfBounds_Symlink(t *testing.T) { } func TestGenerateManifestsUseExactRevision(t *testing.T) { - service, gitClient := newServiceWithMocks(".", false) + service, gitClient, _ := newServiceWithMocks(t, ".", false) src := argoappv1.ApplicationSource{Path: "./testdata/recurse", Directory: &argoappv1.ApplicationSourceDirectory{Recurse: true}} @@ -390,7 +562,7 @@ func TestGenerateManifestsUseExactRevision(t *testing.T) { } func TestRecurseManifestsInDir(t *testing.T) { - service := newService(".") + service := newService(t, ".") src := argoappv1.ApplicationSource{Path: "./testdata/recurse", Directory: &argoappv1.ApplicationSourceDirectory{Recurse: true}} @@ -403,7 +575,7 @@ func TestRecurseManifestsInDir(t *testing.T) { } func TestInvalidManifestsInDir(t *testing.T) { - service := newService(".") + service := newService(t, ".") src := argoappv1.ApplicationSource{Path: "./testdata/invalid-manifests", Directory: &argoappv1.ApplicationSourceDirectory{Recurse: true}} @@ -414,7 +586,7 @@ func TestInvalidManifestsInDir(t *testing.T) { } func TestInvalidMetadata(t *testing.T) { - service := newService(".") + service := newService(t, ".") src := argoappv1.ApplicationSource{Path: "./testdata/invalid-metadata", Directory: &argoappv1.ApplicationSourceDirectory{Recurse: true}} q := apiclient.ManifestRequest{Repo: &argoappv1.Repository{}, ApplicationSource: &src, AppLabelKey: "test", AppName: "invalid-metadata", TrackingMethod: "annotation+label"} @@ -424,7 +596,7 @@ func TestInvalidMetadata(t *testing.T) { } func TestNilMetadataAccessors(t *testing.T) { - service := newService(".") + service := newService(t, ".") expected := "{\"apiVersion\":\"v1\",\"kind\":\"ConfigMap\",\"metadata\":{\"annotations\":{\"argocd.argoproj.io/tracking-id\":\"nil-metadata-accessors:/ConfigMap:/my-map\"},\"labels\":{\"test\":\"nil-metadata-accessors\"},\"name\":\"my-map\"},\"stringData\":{\"foo\":\"bar\"}}" src := argoappv1.ApplicationSource{Path: "./testdata/nil-metadata-accessors", Directory: &argoappv1.ApplicationSourceDirectory{Recurse: true}} @@ -436,7 +608,7 @@ func TestNilMetadataAccessors(t *testing.T) { } func TestGenerateJsonnetManifestInDir(t *testing.T) { - service := newService(".") + service := newService(t, ".") q := apiclient.ManifestRequest{ Repo: &argoappv1.Repository{}, @@ -459,7 +631,7 @@ func TestGenerateJsonnetManifestInDir(t *testing.T) { } func TestGenerateJsonnetManifestInRootDir(t *testing.T) { - service := newService("testdata/jsonnet-1") + service := newService(t, "testdata/jsonnet-1") q := apiclient.ManifestRequest{ Repo: &argoappv1.Repository{}, @@ -482,7 +654,7 @@ func TestGenerateJsonnetManifestInRootDir(t *testing.T) { } func TestGenerateJsonnetLibOutside(t *testing.T) { - service := newService(".") + service := newService(t, ".") q := apiclient.ManifestRequest{ Repo: &argoappv1.Repository{}, @@ -553,7 +725,7 @@ func TestManifestGenErrorCacheByNumRequests(t *testing.T) { for _, tt := range tests { testName := fmt.Sprintf("gen-attempts-%d-pause-%d-total-%d", tt.PauseGenerationAfterFailedGenerationAttempts, tt.PauseGenerationOnFailureForRequests, tt.TotalCacheInvocations) t.Run(testName, func(t *testing.T) { - service := newService(".") + service := newService(t, ".") service.initConstants = RepoServerInitConstants{ ParallelismLimit: 1, @@ -631,7 +803,7 @@ func TestManifestGenErrorCacheFileContentsChange(t *testing.T) { tmpDir := t.TempDir() - service := newService(tmpDir) + service := newService(t, tmpDir) service.initConstants = RepoServerInitConstants{ ParallelismLimit: 1, @@ -701,7 +873,7 @@ func TestManifestGenErrorCacheByMinutesElapsed(t *testing.T) { for _, tt := range tests { testName := fmt.Sprintf("pause-time-%d", tt.PauseGenerationOnFailureForMinutes) t.Run(testName, func(t *testing.T) { - service := newService(".") + service := newService(t, ".") // Here we simulate the passage of time by overriding the now() function of Service currentTime := time.Now() @@ -771,7 +943,7 @@ func TestManifestGenErrorCacheByMinutesElapsed(t *testing.T) { func TestManifestGenErrorCacheRespectsNoCache(t *testing.T) { - service := newService(".") + service := newService(t, ".") service.initConstants = RepoServerInitConstants{ ParallelismLimit: 1, @@ -828,7 +1000,7 @@ func TestManifestGenErrorCacheRespectsNoCache(t *testing.T) { } func TestGenerateHelmWithValues(t *testing.T) { - service := newService("../../util/helm/testdata/redis") + service := newService(t, "../../util/helm/testdata/redis") res, err := service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{ Repo: &argoappv1.Repository{}, @@ -865,7 +1037,7 @@ func TestGenerateHelmWithValues(t *testing.T) { } func TestHelmWithMissingValueFiles(t *testing.T) { - service := newService("../../util/helm/testdata/redis") + service := newService(t, "../../util/helm/testdata/redis") missingValuesFile := "values-prod-overrides.yaml" req := &apiclient.ManifestRequest{ @@ -893,7 +1065,7 @@ func TestHelmWithMissingValueFiles(t *testing.T) { } func TestGenerateHelmWithEnvVars(t *testing.T) { - service := newService("../../util/helm/testdata/redis") + service := newService(t, "../../util/helm/testdata/redis") res, err := service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{ Repo: &argoappv1.Repository{}, @@ -930,7 +1102,7 @@ func TestGenerateHelmWithEnvVars(t *testing.T) { // The requested value file (`../minio/values.yaml`) is outside the app path (`./util/helm/testdata/redis`), however // since the requested value is still under the repo directory (`~/go/src/github.com/argoproj/argo-cd`), it is allowed func TestGenerateHelmWithValuesDirectoryTraversal(t *testing.T) { - service := newService("../../util/helm/testdata") + service := newService(t, "../../util/helm/testdata") _, err := service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{ Repo: &argoappv1.Repository{}, AppName: "test", @@ -947,7 +1119,7 @@ func TestGenerateHelmWithValuesDirectoryTraversal(t *testing.T) { assert.NoError(t, err) // Test the case where the path is "." - service = newService("./testdata") + service = newService(t, "./testdata") _, err = service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{ Repo: &argoappv1.Repository{}, AppName: "test", @@ -961,7 +1133,7 @@ func TestGenerateHelmWithValuesDirectoryTraversal(t *testing.T) { } func TestChartRepoWithOutOfBoundsSymlink(t *testing.T) { - service := newService(".") + service := newService(t, ".") source := &argoappv1.ApplicationSource{Chart: "out-of-bounds-chart", TargetRevision: ">= 1.0.0"} request := &apiclient.ManifestRequest{Repo: &argoappv1.Repository{}, ApplicationSource: source, NoCache: true} _, err := service.GenerateManifest(context.Background(), request) @@ -971,7 +1143,7 @@ func TestChartRepoWithOutOfBoundsSymlink(t *testing.T) { // This is a Helm first-class app with a values file inside the repo directory // (`~/go/src/github.com/argoproj/argo-cd/reposerver/repository`), so it is allowed func TestHelmManifestFromChartRepoWithValueFile(t *testing.T) { - service := newService(".") + service := newService(t, ".") source := &argoappv1.ApplicationSource{ Chart: "my-chart", TargetRevision: ">= 1.0.0", @@ -1000,7 +1172,7 @@ func TestHelmManifestFromChartRepoWithValueFile(t *testing.T) { // This is a Helm first-class app with a values file outside the repo directory // (`~/go/src/github.com/argoproj/argo-cd/reposerver/repository`), so it is not allowed func TestHelmManifestFromChartRepoWithValueFileOutsideRepo(t *testing.T) { - service := newService(".") + service := newService(t, ".") source := &argoappv1.ApplicationSource{ Chart: "my-chart", TargetRevision: ">= 1.0.0", @@ -1015,7 +1187,7 @@ func TestHelmManifestFromChartRepoWithValueFileOutsideRepo(t *testing.T) { func TestHelmManifestFromChartRepoWithValueFileLinks(t *testing.T) { t.Run("Valid symlink", func(t *testing.T) { - service := newService(".") + service := newService(t, ".") source := &argoappv1.ApplicationSource{ Chart: "my-chart", TargetRevision: ">= 1.0.0", @@ -1031,7 +1203,7 @@ func TestHelmManifestFromChartRepoWithValueFileLinks(t *testing.T) { } func TestGenerateHelmWithURL(t *testing.T) { - service := newService("../../util/helm/testdata/redis") + service := newService(t, "../../util/helm/testdata/redis") _, err := service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{ Repo: &argoappv1.Repository{}, @@ -1054,7 +1226,7 @@ func TestGenerateHelmWithURL(t *testing.T) { // (`~/go/src/github.com/argoproj/argo-cd/util/helm/testdata/redis`), so it is blocked func TestGenerateHelmWithValuesDirectoryTraversalOutsideRepo(t *testing.T) { t.Run("Values file with relative path pointing outside repo root", func(t *testing.T) { - service := newService("../../util/helm/testdata/redis") + service := newService(t, "../../util/helm/testdata/redis") _, err := service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{ Repo: &argoappv1.Repository{}, AppName: "test", @@ -1073,7 +1245,7 @@ func TestGenerateHelmWithValuesDirectoryTraversalOutsideRepo(t *testing.T) { }) t.Run("Values file with relative path pointing inside repo root", func(t *testing.T) { - service := newService("./testdata") + service := newService(t, "./testdata") _, err := service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{ Repo: &argoappv1.Repository{}, AppName: "test", @@ -1091,7 +1263,7 @@ func TestGenerateHelmWithValuesDirectoryTraversalOutsideRepo(t *testing.T) { }) t.Run("Values file with absolute path stays within repo root", func(t *testing.T) { - service := newService("./testdata") + service := newService(t, "./testdata") _, err := service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{ Repo: &argoappv1.Repository{}, AppName: "test", @@ -1109,7 +1281,7 @@ func TestGenerateHelmWithValuesDirectoryTraversalOutsideRepo(t *testing.T) { }) t.Run("Values file with absolute path using back-references outside repo root", func(t *testing.T) { - service := newService("./testdata") + service := newService(t, "./testdata") _, err := service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{ Repo: &argoappv1.Repository{}, AppName: "test", @@ -1128,7 +1300,7 @@ func TestGenerateHelmWithValuesDirectoryTraversalOutsideRepo(t *testing.T) { }) t.Run("Remote values file from forbidden protocol", func(t *testing.T) { - service := newService("./testdata") + service := newService(t, "./testdata") _, err := service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{ Repo: &argoappv1.Repository{}, AppName: "test", @@ -1147,7 +1319,7 @@ func TestGenerateHelmWithValuesDirectoryTraversalOutsideRepo(t *testing.T) { }) t.Run("Remote values file from custom allowed protocol", func(t *testing.T) { - service := newService("./testdata") + service := newService(t, "./testdata") _, err := service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{ Repo: &argoappv1.Repository{}, AppName: "test", @@ -1168,7 +1340,7 @@ func TestGenerateHelmWithValuesDirectoryTraversalOutsideRepo(t *testing.T) { // File parameter should not allow traversal outside of the repository root func TestGenerateHelmWithAbsoluteFileParameter(t *testing.T) { - service := newService("../..") + service := newService(t, "../..") file, err := os.CreateTemp("", "external-secret.txt") assert.NoError(t, err) @@ -1209,7 +1381,7 @@ func TestGenerateHelmWithAbsoluteFileParameter(t *testing.T) { // directory (`~/go/src/github.com/argoproj/argo-cd`), it is allowed. It is used as a means of // providing direct content to a helm chart via a specific key. func TestGenerateHelmWithFileParameter(t *testing.T) { - service := newService("../../util/helm/testdata") + service := newService(t, "../../util/helm/testdata") res, err := service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{ Repo: &argoappv1.Repository{}, @@ -1234,7 +1406,7 @@ func TestGenerateHelmWithFileParameter(t *testing.T) { } func TestGenerateNullList(t *testing.T) { - service := newService(".") + service := newService(t, ".") t.Run("null list", func(t *testing.T) { res1, err := service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{ @@ -1302,7 +1474,7 @@ func TestGenerateFromUTF16(t *testing.T) { } func TestListApps(t *testing.T) { - service := newService("./testdata") + service := newService(t, "./testdata") res, err := service.ListApps(context.Background(), &apiclient.ListAppsRequest{Repo: &argoappv1.Repository{}}) assert.NoError(t, err) @@ -1324,12 +1496,30 @@ func TestListApps(t *testing.T) { "out-of-bounds-values-file-link": "Helm", "values-files": "Helm", "helm-with-dependencies": "Helm", + "helm-with-dependencies-alias": "Helm", } assert.Equal(t, expectedApps, res.Apps) } func TestGetAppDetailsHelm(t *testing.T) { - service := newService("../../util/helm/testdata/dependency") + service := newService(t, "../../util/helm/testdata/dependency") + + res, err := service.GetAppDetails(context.Background(), &apiclient.RepoServerAppDetailsQuery{ + Repo: &argoappv1.Repository{}, + Source: &argoappv1.ApplicationSource{ + Path: ".", + }, + }) + + assert.NoError(t, err) + assert.NotNil(t, res.Helm) + + assert.Equal(t, "Helm", res.Type) + assert.EqualValues(t, []string{"values-production.yaml", "values.yaml"}, res.Helm.ValueFiles) +} + +func TestGetAppDetailsHelmUsesCache(t *testing.T) { + service := newService(t, "../../util/helm/testdata/dependency") res, err := service.GetAppDetails(context.Background(), &apiclient.RepoServerAppDetailsQuery{ Repo: &argoappv1.Repository{}, @@ -1344,8 +1534,9 @@ func TestGetAppDetailsHelm(t *testing.T) { assert.Equal(t, "Helm", res.Type) assert.EqualValues(t, []string{"values-production.yaml", "values.yaml"}, res.Helm.ValueFiles) } + func TestGetAppDetailsHelm_WithNoValuesFile(t *testing.T) { - service := newService("../../util/helm/testdata/api-versions") + service := newService(t, "../../util/helm/testdata/api-versions") res, err := service.GetAppDetails(context.Background(), &apiclient.RepoServerAppDetailsQuery{ Repo: &argoappv1.Repository{}, @@ -1363,7 +1554,7 @@ func TestGetAppDetailsHelm_WithNoValuesFile(t *testing.T) { } func TestGetAppDetailsKustomize(t *testing.T) { - service := newService("../../util/kustomize/testdata/kustomization_yaml") + service := newService(t, "../../util/kustomize/testdata/kustomization_yaml") res, err := service.GetAppDetails(context.Background(), &apiclient.RepoServerAppDetailsQuery{ Repo: &argoappv1.Repository{}, @@ -1380,7 +1571,7 @@ func TestGetAppDetailsKustomize(t *testing.T) { } func TestGetHelmCharts(t *testing.T) { - service := newService("../..") + service := newService(t, "../..") res, err := service.GetHelmCharts(context.Background(), &apiclient.HelmChartsRequest{Repo: &argoappv1.Repository{}}) // fix flakiness @@ -1401,7 +1592,7 @@ func TestGetHelmCharts(t *testing.T) { } func TestGetRevisionMetadata(t *testing.T) { - service, gitClient := newServiceWithMocks("../..", false) + service, gitClient, _ := newServiceWithMocks(t, "../..", false) now := time.Now() gitClient.On("RevisionMetadata", mock.Anything).Return(&git.RevisionMetadata{ @@ -1469,7 +1660,7 @@ func TestGetRevisionMetadata(t *testing.T) { func TestGetSignatureVerificationResult(t *testing.T) { // Commit with signature and verification requested { - service := newServiceWithSignature("../../manifests/base") + service := newServiceWithSignature(t, "../../manifests/base") src := argoappv1.ApplicationSource{Path: "."} q := apiclient.ManifestRequest{ @@ -1486,7 +1677,7 @@ func TestGetSignatureVerificationResult(t *testing.T) { } // Commit with signature and verification not requested { - service := newServiceWithSignature("../../manifests/base") + service := newServiceWithSignature(t, "../../manifests/base") src := argoappv1.ApplicationSource{Path: "."} q := apiclient.ManifestRequest{Repo: &argoappv1.Repository{}, ApplicationSource: &src, ProjectName: "something", @@ -1498,7 +1689,7 @@ func TestGetSignatureVerificationResult(t *testing.T) { } // Commit without signature and verification requested { - service := newService("../../manifests/base") + service := newService(t, "../../manifests/base") src := argoappv1.ApplicationSource{Path: "."} q := apiclient.ManifestRequest{Repo: &argoappv1.Repository{}, ApplicationSource: &src, VerifySignature: true, ProjectName: "something", @@ -1510,7 +1701,7 @@ func TestGetSignatureVerificationResult(t *testing.T) { } // Commit without signature and verification not requested { - service := newService("../../manifests/base") + service := newService(t, "../../manifests/base") src := argoappv1.ApplicationSource{Path: "."} q := apiclient.ManifestRequest{Repo: &argoappv1.Repository{}, ApplicationSource: &src, VerifySignature: true, ProjectName: "something", @@ -1543,7 +1734,7 @@ func Test_newEnv(t *testing.T) { } func TestService_newHelmClientResolveRevision(t *testing.T) { - service := newService(".") + service := newService(t, ".") t.Run("EmptyRevision", func(t *testing.T) { _, _, err := service.newHelmClientResolveRevision(&argoappv1.Repository{}, "", "", true) @@ -1557,7 +1748,7 @@ func TestService_newHelmClientResolveRevision(t *testing.T) { func TestGetAppDetailsWithAppParameterFile(t *testing.T) { t.Run("No app name set and app specific file exists", func(t *testing.T) { - service := newService(".") + service := newService(t, ".") runWithTempTestdata(t, "multi", func(t *testing.T, path string) { details, err := service.GetAppDetails(context.Background(), &apiclient.RepoServerAppDetailsQuery{ Repo: &argoappv1.Repository{}, @@ -1570,7 +1761,7 @@ func TestGetAppDetailsWithAppParameterFile(t *testing.T) { }) }) t.Run("No app specific override", func(t *testing.T) { - service := newService(".") + service := newService(t, ".") runWithTempTestdata(t, "single-global", func(t *testing.T, path string) { details, err := service.GetAppDetails(context.Background(), &apiclient.RepoServerAppDetailsQuery{ Repo: &argoappv1.Repository{}, @@ -1584,7 +1775,7 @@ func TestGetAppDetailsWithAppParameterFile(t *testing.T) { }) }) t.Run("Only app specific override", func(t *testing.T) { - service := newService(".") + service := newService(t, ".") runWithTempTestdata(t, "single-app-only", func(t *testing.T, path string) { details, err := service.GetAppDetails(context.Background(), &apiclient.RepoServerAppDetailsQuery{ Repo: &argoappv1.Repository{}, @@ -1598,7 +1789,7 @@ func TestGetAppDetailsWithAppParameterFile(t *testing.T) { }) }) t.Run("App specific override", func(t *testing.T) { - service := newService(".") + service := newService(t, ".") runWithTempTestdata(t, "multi", func(t *testing.T, path string) { details, err := service.GetAppDetails(context.Background(), &apiclient.RepoServerAppDetailsQuery{ Repo: &argoappv1.Repository{}, @@ -1612,7 +1803,7 @@ func TestGetAppDetailsWithAppParameterFile(t *testing.T) { }) }) t.Run("App specific overrides containing non-mergeable field", func(t *testing.T) { - service := newService(".") + service := newService(t, ".") runWithTempTestdata(t, "multi", func(t *testing.T, path string) { details, err := service.GetAppDetails(context.Background(), &apiclient.RepoServerAppDetailsQuery{ Repo: &argoappv1.Repository{}, @@ -1626,7 +1817,7 @@ func TestGetAppDetailsWithAppParameterFile(t *testing.T) { }) }) t.Run("Broken app-specific overrides", func(t *testing.T) { - service := newService(".") + service := newService(t, ".") runWithTempTestdata(t, "multi", func(t *testing.T, path string) { _, err := service.GetAppDetails(context.Background(), &apiclient.RepoServerAppDetailsQuery{ Repo: &argoappv1.Repository{}, @@ -1668,7 +1859,7 @@ func runWithTempTestdata(t *testing.T, path string, runner func(t *testing.T, pa func TestGenerateManifestsWithAppParameterFile(t *testing.T) { t.Run("Single global override", func(t *testing.T) { runWithTempTestdata(t, "single-global", func(t *testing.T, path string) { - service := newService(".") + service := newService(t, ".") manifests, err := service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{ Repo: &argoappv1.Repository{}, ApplicationSource: &argoappv1.ApplicationSource{ @@ -1699,7 +1890,7 @@ func TestGenerateManifestsWithAppParameterFile(t *testing.T) { t.Run("Single global override Helm", func(t *testing.T) { runWithTempTestdata(t, "single-global-helm", func(t *testing.T, path string) { - service := newService(".") + service := newService(t, ".") manifests, err := service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{ Repo: &argoappv1.Repository{}, ApplicationSource: &argoappv1.ApplicationSource{ @@ -1729,7 +1920,7 @@ func TestGenerateManifestsWithAppParameterFile(t *testing.T) { }) t.Run("Application specific override", func(t *testing.T) { - service := newService(".") + service := newService(t, ".") runWithTempTestdata(t, "single-app-only", func(t *testing.T, path string) { manifests, err := service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{ Repo: &argoappv1.Repository{}, @@ -1760,8 +1951,29 @@ func TestGenerateManifestsWithAppParameterFile(t *testing.T) { }) }) + t.Run("Multi-source with source as ref only does not generate manifests", func(t *testing.T) { + service := newService(t, ".") + runWithTempTestdata(t, "single-app-only", func(t *testing.T, path string) { + manifests, err := service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{ + Repo: &argoappv1.Repository{}, + ApplicationSource: &argoappv1.ApplicationSource{ + Path: "", + Chart: "", + Ref: "test", + }, + AppName: "testapp-multi-ref-only", + ProjectName: "something", + ProjectSourceRepos: []string{"*"}, + HasMultipleSources: true, + }) + assert.NoError(t, err) + assert.Empty(t, manifests.Manifests) + assert.NotEmpty(t, manifests.Revision) + }) + }) + t.Run("Application specific override for other app", func(t *testing.T) { - service := newService(".") + service := newService(t, ".") runWithTempTestdata(t, "single-app-only", func(t *testing.T, path string) { manifests, err := service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{ Repo: &argoappv1.Repository{}, @@ -1793,7 +2005,7 @@ func TestGenerateManifestsWithAppParameterFile(t *testing.T) { }) t.Run("Override info does not appear in cache key", func(t *testing.T) { - service := newService(".") + service := newService(t, ".") runWithTempTestdata(t, "single-global", func(t *testing.T, path string) { source := &argoappv1.ApplicationSource{ Path: path, @@ -1843,7 +2055,7 @@ func TestGenerateManifestWithAnnotatedAndRegularGitTagHashes(t *testing.T) { ProjectSourceRepos: []string{"*"}, }, wantError: false, - service: newServiceWithCommitSHA(".", regularGitTagHash), + service: newServiceWithCommitSHA(t, ".", regularGitTagHash), }, { @@ -1859,7 +2071,7 @@ func TestGenerateManifestWithAnnotatedAndRegularGitTagHashes(t *testing.T) { ProjectSourceRepos: []string{"*"}, }, wantError: false, - service: newServiceWithCommitSHA(".", annotatedGitTaghash), + service: newServiceWithCommitSHA(t, ".", annotatedGitTaghash), }, { @@ -1875,7 +2087,7 @@ func TestGenerateManifestWithAnnotatedAndRegularGitTagHashes(t *testing.T) { ProjectSourceRepos: []string{"*"}, }, wantError: true, - service: newServiceWithCommitSHA(".", invalidGitTaghash), + service: newServiceWithCommitSHA(t, ".", invalidGitTaghash), }, } for _, tt := range tests { @@ -1900,7 +2112,7 @@ func TestGenerateManifestWithAnnotatedAndRegularGitTagHashes(t *testing.T) { func TestGenerateManifestWithAnnotatedTagsAndMultiSourceApp(t *testing.T) { annotatedGitTaghash := "95249be61b028d566c29d47b19e65c5603388a41" - service := newServiceWithCommitSHA(".", annotatedGitTaghash) + service := newServiceWithCommitSHA(t, ".", annotatedGitTaghash) refSources := map[string]*argoappv1.RefTarget{} @@ -2485,7 +2697,7 @@ func Test_findManifests(t *testing.T) { } func TestTestRepoOCI(t *testing.T) { - service := newService(".") + service := newService(t, ".") _, err := service.TestRepository(context.Background(), &apiclient.TestRepositoryRequest{ Repo: &argoappv1.Repository{ Repo: "https://demo.goharbor.io", @@ -2510,7 +2722,7 @@ func Test_getHelmDependencyRepos(t *testing.T) { func TestResolveRevision(t *testing.T) { - service := newService(".") + service := newService(t, ".") repo := &argoappv1.Repository{Repo: "https://github.com/argoproj/argo-cd"} app := &argoappv1.Application{Spec: argoappv1.ApplicationSpec{Source: &argoappv1.ApplicationSource{}}} resolveRevisionResponse, err := service.ResolveRevision(context.Background(), &apiclient.ResolveRevisionRequest{ @@ -2532,7 +2744,7 @@ func TestResolveRevision(t *testing.T) { func TestResolveRevisionNegativeScenarios(t *testing.T) { - service := newService(".") + service := newService(t, ".") repo := &argoappv1.Repository{Repo: "https://github.com/argoproj/argo-cd"} app := &argoappv1.Application{Spec: argoappv1.ApplicationSpec{Source: &argoappv1.ApplicationSource{}}} resolveRevisionResponse, err := service.ResolveRevision(context.Background(), &apiclient.ResolveRevisionRequest{ @@ -2579,19 +2791,57 @@ func TestDirectoryPermissionInitializer(t *testing.T) { require.Error(t, err) } -func initGitRepo(repoPath string, remote string) error { - if err := os.Mkdir(repoPath, 0755); err != nil { - return err +func addHelmToGitRepo(t *testing.T, options newGitRepoOptions) { + err := os.WriteFile(filepath.Join(options.path, "Chart.yaml"), []byte("name: test\nversion: v1.0.0"), 0777) + assert.NoError(t, err) + for valuesFileName, values := range options.helmChartOptions.valuesFiles { + valuesFileContents, err := yaml.Marshal(values) + assert.NoError(t, err) + err = os.WriteFile(filepath.Join(options.path, valuesFileName), valuesFileContents, 0777) + assert.NoError(t, err) + } + assert.NoError(t, err) + cmd := exec.Command("git", "add", "-A") + cmd.Dir = options.path + assert.NoError(t, cmd.Run()) + cmd = exec.Command("git", "commit", "-m", "Initial commit") + cmd.Dir = options.path + assert.NoError(t, cmd.Run()) +} + +func initGitRepo(t *testing.T, options newGitRepoOptions) (revision string) { + if options.createPath { + assert.NoError(t, os.Mkdir(options.path, 0755)) + } + + cmd := exec.Command("git", "init", "-b", "main", options.path) + cmd.Dir = options.path + assert.NoError(t, cmd.Run()) + + if options.remote != "" { + cmd = exec.Command("git", "remote", "add", "origin", options.path) + cmd.Dir = options.path + assert.NoError(t, cmd.Run()) } - cmd := exec.Command("git", "init", repoPath) - cmd.Dir = repoPath - if err := cmd.Run(); err != nil { - return err + commitAdded := options.addEmptyCommit || options.helmChartOptions.chartName != "" + if options.addEmptyCommit { + cmd = exec.Command("git", "commit", "-m", "Initial commit", "--allow-empty") + cmd.Dir = options.path + assert.NoError(t, cmd.Run()) + } else if options.helmChartOptions.chartName != "" { + addHelmToGitRepo(t, options) } - cmd = exec.Command("git", "remote", "add", "origin", remote) - cmd.Dir = repoPath - return cmd.Run() + + if commitAdded { + var revB bytes.Buffer + cmd = exec.Command("git", "rev-parse", "HEAD", options.path) + cmd.Dir = options.path + cmd.Stdout = &revB + assert.NoError(t, cmd.Run()) + revision = strings.Split(revB.String(), "\n")[0] + } + return revision } func TestInit(t *testing.T) { @@ -2604,16 +2854,16 @@ func TestInit(t *testing.T) { }) repoPath := path.Join(dir, "repo1") - require.NoError(t, initGitRepo(repoPath, "https://github.com/argo-cd/test-repo1")) + initGitRepo(t, newGitRepoOptions{path: repoPath, remote: "https://github.com/argo-cd/test-repo1", createPath: true, addEmptyCommit: false}) - service := newService(".") + service := newService(t, ".") service.rootDir = dir require.NoError(t, service.Init()) _, err := os.ReadDir(dir) require.Error(t, err) - require.NoError(t, initGitRepo(path.Join(dir, "repo2"), "https://github.com/argo-cd/test-repo2")) + initGitRepo(t, newGitRepoOptions{path: path.Join(dir, "repo2"), remote: "https://github.com/argo-cd/test-repo2", createPath: true, addEmptyCommit: false}) } // TestCheckoutRevisionCanGetNonstandardRefs shows that we can fetch a revision that points to a non-standard ref. In @@ -2663,16 +2913,27 @@ func runGit(t *testing.T, workDir string, args ...string) string { return stringOut } -func Test_findHelmValueFilesInPath(t *testing.T) { +func Test_walkHelmValueFilesInPath(t *testing.T) { t.Run("does not exist", func(t *testing.T) { - files, err := findHelmValueFilesInPath("/obviously/does/not/exist") + var files []string + root := "/obviously/does/not/exist" + err := filepath.Walk(root, walkHelmValueFilesInPath(root, &files)) assert.Error(t, err) assert.Empty(t, files) }) t.Run("values files", func(t *testing.T) { - files, err := findHelmValueFilesInPath("./testdata/values-files") + var files []string + root := "./testdata/values-files" + err := filepath.Walk(root, walkHelmValueFilesInPath(root, &files)) assert.NoError(t, err) - assert.Len(t, files, 4) + assert.Len(t, files, 5) + }) + t.Run("unrelated root", func(t *testing.T) { + var files []string + root := "./testdata/values-files" + unrelated_root := "/different/root/path" + err := filepath.Walk(root, walkHelmValueFilesInPath(unrelated_root, &files)) + assert.Error(t, err) }) } @@ -2690,7 +2951,7 @@ func Test_populateHelmAppDetails(t *testing.T) { err = populateHelmAppDetails(&res, appPath, appPath, &q, emptyTempPaths) require.NoError(t, err) assert.Len(t, res.Helm.Parameters, 3) - assert.Len(t, res.Helm.ValueFiles, 4) + assert.Len(t, res.Helm.ValueFiles, 5) } func Test_populateHelmAppDetails_values_symlinks(t *testing.T) { @@ -2745,6 +3006,22 @@ func TestGetHelmRepo_NamedRepos(t *testing.T) { assert.Equal(t, helmRepos[0].Repo, "https://example.com") } +func TestGetHelmRepo_NamedReposAlias(t *testing.T) { + src := argoappv1.ApplicationSource{Path: "."} + q := apiclient.ManifestRequest{Repo: &argoappv1.Repository{}, ApplicationSource: &src, Repos: []*argoappv1.Repository{{ + Name: "custom-repo-alias", + Repo: "https://example.com", + Username: "test-alias", + }}} + + helmRepos, err := getHelmRepos("./testdata/helm-with-dependencies-alias", q.Repos, q.HelmRepoCreds) + assert.Nil(t, err) + + assert.Equal(t, len(helmRepos), 1) + assert.Equal(t, helmRepos[0].Username, "test-alias") + assert.Equal(t, helmRepos[0].Repo, "https://example.com") +} + func Test_getResolvedValueFiles(t *testing.T) { tempDir := t.TempDir() paths := io.NewRandomizedTempPaths(tempDir) @@ -2915,7 +3192,7 @@ func TestErrorGetGitDirectories(t *testing.T) { want *apiclient.GitDirectoriesResponse wantErr assert.ErrorAssertionFunc }{ - {name: "InvalidRepo", fields: fields{service: newService(".")}, args: args{ + {name: "InvalidRepo", fields: fields{service: newService(t, ".")}, args: args{ ctx: context.TODO(), request: &apiclient.GitDirectoriesRequest{ Repo: nil, @@ -2924,7 +3201,7 @@ func TestErrorGetGitDirectories(t *testing.T) { }, }, want: nil, wantErr: assert.Error}, {name: "InvalidResolveRevision", fields: fields{service: func() *Service { - s, _ := newServiceWithOpt(func(gitClient *gitmocks.Client, helmClient *helmmocks.Client, paths *iomocks.TempPaths) { + s, _, _ := newServiceWithOpt(t, func(gitClient *gitmocks.Client, helmClient *helmmocks.Client, paths *iomocks.TempPaths) { gitClient.On("Checkout", mock.Anything, mock.Anything).Return(nil) gitClient.On("LsRemote", mock.Anything).Return("", fmt.Errorf("ah error")) paths.On("GetPath", mock.Anything).Return(".", nil) @@ -2955,7 +3232,7 @@ func TestErrorGetGitDirectories(t *testing.T) { func TestGetGitDirectories(t *testing.T) { // test not using the cache root := "./testdata/git-files-dirs" - s, _ := newServiceWithOpt(func(gitClient *gitmocks.Client, helmClient *helmmocks.Client, paths *iomocks.TempPaths) { + s, _, cacheMocks := newServiceWithOpt(t, func(gitClient *gitmocks.Client, helmClient *helmmocks.Client, paths *iomocks.TempPaths) { gitClient.On("Init").Return(nil) gitClient.On("Fetch", mock.Anything).Return(nil) gitClient.On("Checkout", mock.Anything, mock.Anything).Once().Return(nil) @@ -2978,6 +3255,10 @@ func TestGetGitDirectories(t *testing.T) { directories, err = s.GetGitDirectories(context.TODO(), dirRequest) assert.Nil(t, err) assert.ElementsMatch(t, []string{"app", "app/bar", "app/foo/bar", "somedir", "app/foo"}, directories.GetPaths()) + cacheMocks.mockCache.AssertCacheCalledTimes(t, &repositorymocks.CacheCallCounts{ + ExternalSets: 1, + ExternalGets: 2, + }) } func TestErrorGetGitFiles(t *testing.T) { @@ -2995,7 +3276,7 @@ func TestErrorGetGitFiles(t *testing.T) { want *apiclient.GitFilesResponse wantErr assert.ErrorAssertionFunc }{ - {name: "InvalidRepo", fields: fields{service: newService(".")}, args: args{ + {name: "InvalidRepo", fields: fields{service: newService(t, ".")}, args: args{ ctx: context.TODO(), request: &apiclient.GitFilesRequest{ Repo: nil, @@ -3004,7 +3285,7 @@ func TestErrorGetGitFiles(t *testing.T) { }, }, want: nil, wantErr: assert.Error}, {name: "InvalidResolveRevision", fields: fields{service: func() *Service { - s, _ := newServiceWithOpt(func(gitClient *gitmocks.Client, helmClient *helmmocks.Client, paths *iomocks.TempPaths) { + s, _, _ := newServiceWithOpt(t, func(gitClient *gitmocks.Client, helmClient *helmmocks.Client, paths *iomocks.TempPaths) { gitClient.On("Checkout", mock.Anything, mock.Anything).Return(nil) gitClient.On("LsRemote", mock.Anything).Return("", fmt.Errorf("ah error")) paths.On("GetPath", mock.Anything).Return(".", nil) @@ -3037,7 +3318,7 @@ func TestGetGitFiles(t *testing.T) { files := []string{"./testdata/git-files-dirs/somedir/config.yaml", "./testdata/git-files-dirs/config.yaml", "./testdata/git-files-dirs/config.yaml", "./testdata/git-files-dirs/app/foo/bar/config.yaml"} root := "" - s, _ := newServiceWithOpt(func(gitClient *gitmocks.Client, helmClient *helmmocks.Client, paths *iomocks.TempPaths) { + s, _, cacheMocks := newServiceWithOpt(t, func(gitClient *gitmocks.Client, helmClient *helmmocks.Client, paths *iomocks.TempPaths) { gitClient.On("Init").Return(nil) gitClient.On("Fetch", mock.Anything).Return(nil) gitClient.On("Checkout", mock.Anything, mock.Anything).Once().Return(nil) @@ -3070,6 +3351,10 @@ func TestGetGitFiles(t *testing.T) { fileResponse, err = s.GetGitFiles(context.TODO(), filesRequest) assert.Nil(t, err) assert.Equal(t, expected, fileResponse.GetMap()) + cacheMocks.mockCache.AssertCacheCalledTimes(t, &repositorymocks.CacheCallCounts{ + ExternalSets: 1, + ExternalGets: 2, + }) } func Test_getRepoSanitizerRegex(t *testing.T) { @@ -3079,3 +3364,45 @@ func Test_getRepoSanitizerRegex(t *testing.T) { msg = r.ReplaceAllString("error message containing /tmp/_argocd-repo/SENSITIVE/with/trailing/path and other stuff", "") assert.Equal(t, "error message containing /with/trailing/path and other stuff", msg) } + +func TestGetRevisionChartDetails(t *testing.T) { + t.Run("Test revision semvar", func(t *testing.T) { + root := t.TempDir() + service := newService(t, root) + _, err := service.GetRevisionChartDetails(context.Background(), &apiclient.RepoServerRevisionChartDetailsRequest{ + Repo: &v1alpha1.Repository{ + Repo: fmt.Sprintf("file://%s", root), + Name: "test-repo-name", + Type: "helm", + }, + Name: "test-name", + Revision: "test-revision", + }) + assert.ErrorContains(t, err, "invalid revision") + }) + + t.Run("Test GetRevisionChartDetails", func(t *testing.T) { + root := t.TempDir() + service := newService(t, root) + repoUrl := fmt.Sprintf("file://%s", root) + err := service.cache.SetRevisionChartDetails(repoUrl, "my-chart", "1.1.0", &argoappv1.ChartDetails{ + Description: "test-description", + Home: "test-home", + Maintainers: []string{"test-maintainer"}, + }) + assert.NoError(t, err) + chartDetails, err := service.GetRevisionChartDetails(context.Background(), &apiclient.RepoServerRevisionChartDetailsRequest{ + Repo: &v1alpha1.Repository{ + Repo: fmt.Sprintf("file://%s", root), + Name: "test-repo-name", + Type: "helm", + }, + Name: "my-chart", + Revision: "1.1.0", + }) + assert.NoError(t, err) + assert.Equal(t, "test-description", chartDetails.Description) + assert.Equal(t, "test-home", chartDetails.Home) + assert.Equal(t, []string{"test-maintainer"}, chartDetails.Maintainers) + }) +} diff --git a/reposerver/repository/testdata/helm-with-dependencies-alias/Chart.yaml b/reposerver/repository/testdata/helm-with-dependencies-alias/Chart.yaml new file mode 100644 index 0000000000000..8a38d551070c7 --- /dev/null +++ b/reposerver/repository/testdata/helm-with-dependencies-alias/Chart.yaml @@ -0,0 +1,7 @@ +apiVersion: v2 +name: helm-with-dependencies-alias +version: v1.0.0 +dependencies: + - name: helm + repository: "alias:custom-repo-alias" + version: v1.0.0 diff --git a/reposerver/repository/testdata/values-files/dir/values.yaml b/reposerver/repository/testdata/values-files/dir/values.yaml new file mode 100644 index 0000000000000..55262d50ff71c --- /dev/null +++ b/reposerver/repository/testdata/values-files/dir/values.yaml @@ -0,0 +1 @@ +values: yaml diff --git a/reposerver/server.go b/reposerver/server.go index 9576604751dfc..e1d611801c3ec 100644 --- a/reposerver/server.go +++ b/reposerver/server.go @@ -90,7 +90,7 @@ func NewServer(metricsServer *metrics.MetricsServer, cache *reposervercache.Cach grpc.MaxSendMsgSize(apiclient.MaxGRPCMessageSize), grpc.KeepaliveEnforcementPolicy( keepalive.EnforcementPolicy{ - MinTime: common.GRPCKeepAliveEnforcementMinimum, + MinTime: common.GetGRPCKeepAliveEnforcementMinimum(), }, ), } @@ -102,7 +102,7 @@ func NewServer(metricsServer *metrics.MetricsServer, cache *reposervercache.Cach } repoService := repository.NewService(metricsServer, cache, initConstants, argo.NewResourceTracking(), gitCredsStore, filepath.Join(os.TempDir(), "_argocd-repo")) if err := repoService.Init(); err != nil { - return nil, err + return nil, fmt.Errorf("failed to initialize the repo service: %w", err) } return &ArgoCDRepoServer{ diff --git a/resource_customizations/apps.kruise.io/AdvancedCronJob/health.lua b/resource_customizations/apps.kruise.io/AdvancedCronJob/health.lua new file mode 100644 index 0000000000000..1e68d862722e1 --- /dev/null +++ b/resource_customizations/apps.kruise.io/AdvancedCronJob/health.lua @@ -0,0 +1,36 @@ +hs = { status = "Progressing", message = "AdvancedCronJobs has active jobs" } +-- Extract lastScheduleTime and convert to time objects +lastScheduleTime = nil + +if obj.status.lastScheduleTime ~= nil then + local year, month, day, hour, min, sec = string.match(obj.status.lastScheduleTime, "(%d+)-(%d+)-(%d+)T(%d+):(%d+):(%d+)Z") + lastScheduleTime = os.time({year=year, month=month, day=day, hour=hour, min=min, sec=sec}) +end + + +if lastScheduleTime == nil and obj.spec.paused == true then + hs.status = "Suspended" + hs.message = "AdvancedCronJob is Paused" + return hs +end + +-- AdvancedCronJobs are progressing if they have any object in the "active" state +if obj.status.active ~= nil and #obj.status.active > 0 then + hs.status = "Progressing" + hs.message = "AdvancedCronJobs has active jobs" + return hs +end +-- AdvancedCronJobs are Degraded if they don't have lastScheduleTime +if lastScheduleTime == nil then + hs.status = "Degraded" + hs.message = "AdvancedCronJobs has not run successfully" + return hs +end +-- AdvancedCronJobs are healthy if they have lastScheduleTime +if lastScheduleTime ~= nil then + hs.status = "Healthy" + hs.message = "AdvancedCronJobs has run successfully" + return hs +end + +return hs diff --git a/resource_customizations/apps.kruise.io/AdvancedCronJob/health_test.yaml b/resource_customizations/apps.kruise.io/AdvancedCronJob/health_test.yaml new file mode 100644 index 0000000000000..939c701955abb --- /dev/null +++ b/resource_customizations/apps.kruise.io/AdvancedCronJob/health_test.yaml @@ -0,0 +1,17 @@ +tests: + - healthStatus: + status: Healthy + message: AdvancedCronJobs has run successfully + inputPath: testdata/lastScheduleTime.yaml + - healthStatus: + status: Degraded + message: AdvancedCronJobs has not run successfully + inputPath: testdata/notScheduled.yaml + - healthStatus: + status: Progressing + message: AdvancedCronJobs has active jobs + inputPath: testdata/activeJobs.yaml + - healthStatus: + status: Suspended + message: AdvancedCronJob is Paused + inputPath: testdata/suspended.yaml diff --git a/resource_customizations/apps.kruise.io/AdvancedCronJob/testdata/activeJobs.yaml b/resource_customizations/apps.kruise.io/AdvancedCronJob/testdata/activeJobs.yaml new file mode 100644 index 0000000000000..5748143874d5e --- /dev/null +++ b/resource_customizations/apps.kruise.io/AdvancedCronJob/testdata/activeJobs.yaml @@ -0,0 +1,30 @@ +apiVersion: apps.kruise.io/v1alpha1 +kind: AdvancedCronJob +metadata: + name: acj-test +spec: + schedule: "*/1 * * * *" + template: + broadcastJobTemplate: + spec: + template: + spec: + containers: + - name: pi + image: perl + command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"] + restartPolicy: Never + completionPolicy: + type: Always + ttlSecondsAfterFinished: 30 + +status: + active: + - apiVersion: apps.kruise.io/v1alpha1 + kind: BroadcastJob + name: acj-test-1694882400 + namespace: default + resourceVersion: '4012' + uid: 2b08a429-a43b-4382-8e5d-3db0c72b5b13 + lastScheduleTime: '2023-09-16T16:40:00Z' + type: BroadcastJob diff --git a/resource_customizations/apps.kruise.io/AdvancedCronJob/testdata/lastScheduleTime.yaml b/resource_customizations/apps.kruise.io/AdvancedCronJob/testdata/lastScheduleTime.yaml new file mode 100644 index 0000000000000..bf48bdba777dc --- /dev/null +++ b/resource_customizations/apps.kruise.io/AdvancedCronJob/testdata/lastScheduleTime.yaml @@ -0,0 +1,23 @@ +apiVersion: apps.kruise.io/v1alpha1 +kind: AdvancedCronJob +metadata: + name: acj-test +spec: + schedule: "*/1 * * * *" + template: + broadcastJobTemplate: + spec: + template: + spec: + containers: + - name: pi + image: perl + command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"] + restartPolicy: Never + completionPolicy: + type: Always + ttlSecondsAfterFinished: 30 + +status: + lastScheduleTime: "2023-09-16T16:29:00Z" + type: BroadcastJob diff --git a/resource_customizations/apps.kruise.io/AdvancedCronJob/testdata/notScheduled.yaml b/resource_customizations/apps.kruise.io/AdvancedCronJob/testdata/notScheduled.yaml new file mode 100644 index 0000000000000..cc8a9dd436d80 --- /dev/null +++ b/resource_customizations/apps.kruise.io/AdvancedCronJob/testdata/notScheduled.yaml @@ -0,0 +1,22 @@ +apiVersion: apps.kruise.io/v1alpha1 +kind: AdvancedCronJob +metadata: + name: acj-test +spec: + schedule: "*/1 * * * *" + template: + broadcastJobTemplate: + spec: + template: + spec: + containers: + - name: pi + image: perl + command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"] + restartPolicy: Never + completionPolicy: + type: Always + ttlSecondsAfterFinished: 30 + +status: + lastScheduleTime: null diff --git a/resource_customizations/apps.kruise.io/AdvancedCronJob/testdata/suspended.yaml b/resource_customizations/apps.kruise.io/AdvancedCronJob/testdata/suspended.yaml new file mode 100644 index 0000000000000..dc79f1b41218b --- /dev/null +++ b/resource_customizations/apps.kruise.io/AdvancedCronJob/testdata/suspended.yaml @@ -0,0 +1,23 @@ +apiVersion: apps.kruise.io/v1alpha1 +kind: AdvancedCronJob +metadata: + name: acj-test +spec: + schedule: "*/1 * * * *" + template: + broadcastJobTemplate: + spec: + template: + spec: + containers: + - name: pi + image: perl + command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"] + restartPolicy: Never + completionPolicy: + type: Always + ttlSecondsAfterFinished: 30 + paused: true + +status: + type: BroadcastJob diff --git a/resource_customizations/apps.kruise.io/BroadcastJob/health.lua b/resource_customizations/apps.kruise.io/BroadcastJob/health.lua new file mode 100644 index 0000000000000..3b20ca8849975 --- /dev/null +++ b/resource_customizations/apps.kruise.io/BroadcastJob/health.lua @@ -0,0 +1,32 @@ +hs={ status= "Progressing", message= "BroadcastJob is still running" } + +if obj.status ~= nil then + +-- BroadcastJob are healthy if desired number and succeeded number is equal + if obj.status.desired == obj.status.succeeded and obj.status.phase == "completed" then + hs.status = "Healthy" + hs.message = "BroadcastJob is completed successfully" + return hs + end +-- BroadcastJob are progressing if active is not equal to 0 + if obj.status.active ~= 0 and obj.status.phase == "running" then + hs.status = "Progressing" + hs.message = "BroadcastJob is still running" + return hs + end +-- BroadcastJob are progressing if failed is not equal to 0 + if obj.status.failed ~= 0 and obj.status.phase == "failed" then + hs.status = "Degraded" + hs.message = "BroadcastJob failed" + return hs + end + + if obj.status.phase == "paused" and obj.spec.paused == true then + hs.status = "Suspended" + hs.message = "BroadcastJob is Paused" + return hs + end + +end + +return hs diff --git a/resource_customizations/apps.kruise.io/BroadcastJob/health_test.yaml b/resource_customizations/apps.kruise.io/BroadcastJob/health_test.yaml new file mode 100644 index 0000000000000..e3e16e22bfeef --- /dev/null +++ b/resource_customizations/apps.kruise.io/BroadcastJob/health_test.yaml @@ -0,0 +1,17 @@ +tests: + - healthStatus: + status: Healthy + message: "BroadcastJob is completed successfully" + inputPath: testdata/succeeded.yaml + - healthStatus: + status: Degraded + message: "BroadcastJob failed" + inputPath: testdata/failed.yaml + - healthStatus: + status: Progressing + message: "BroadcastJob is still running" + inputPath: testdata/running.yaml + - healthStatus: + status: Suspended + message: "BroadcastJob is Paused" + inputPath: testdata/suspended.yaml diff --git a/resource_customizations/apps.kruise.io/BroadcastJob/testdata/failed.yaml b/resource_customizations/apps.kruise.io/BroadcastJob/testdata/failed.yaml new file mode 100644 index 0000000000000..88b85cae28189 --- /dev/null +++ b/resource_customizations/apps.kruise.io/BroadcastJob/testdata/failed.yaml @@ -0,0 +1,31 @@ +apiVersion: apps.kruise.io/v1alpha1 +kind: BroadcastJob +metadata: + name: failed-job +spec: + template: + spec: + containers: + - name: guestbook + image: openkruise/guestbook:v3 + command: ["exit", "1"] # a dummy command to fail + restartPolicy: Never + completionPolicy: + type: Always + ttlSecondsAfterFinished: 60 # the job will be deleted after 60 seconds + +status: + active: 0 + completionTime: '2023-09-17T14:31:38Z' + conditions: + - lastProbeTime: '2023-09-17T14:31:38Z' + lastTransitionTime: '2023-09-17T14:31:38Z' + message: failure policy is FailurePolicyTypeFailFast and failed pod is found + reason: Failed + status: 'True' + type: Failed + desired: 1 + failed: 1 + phase: failed + startTime: '2023-09-17T14:31:32Z' + succeeded: 0 diff --git a/resource_customizations/apps.kruise.io/BroadcastJob/testdata/running.yaml b/resource_customizations/apps.kruise.io/BroadcastJob/testdata/running.yaml new file mode 100644 index 0000000000000..f679fa3ee0d50 --- /dev/null +++ b/resource_customizations/apps.kruise.io/BroadcastJob/testdata/running.yaml @@ -0,0 +1,22 @@ +apiVersion: apps.kruise.io/v1alpha1 +kind: BroadcastJob +metadata: + name: download-image +spec: + template: + spec: + containers: + - name: guestbook + image: openkruise/guestbook:v3 + command: ["echo", "started"] # a dummy command to do nothing + restartPolicy: Never + completionPolicy: + type: Always + ttlSecondsAfterFinished: 60 # the job will be deleted after 60 seconds +status: + active: 1 + desired: 1 + failed: 0 + phase: running + startTime: '2023-09-17T14:43:30Z' + succeeded: 0 diff --git a/resource_customizations/apps.kruise.io/BroadcastJob/testdata/succeeded.yaml b/resource_customizations/apps.kruise.io/BroadcastJob/testdata/succeeded.yaml new file mode 100644 index 0000000000000..61746b20cd907 --- /dev/null +++ b/resource_customizations/apps.kruise.io/BroadcastJob/testdata/succeeded.yaml @@ -0,0 +1,31 @@ +apiVersion: apps.kruise.io/v1alpha1 +kind: BroadcastJob +metadata: + name: download-image +spec: + template: + spec: + containers: + - name: guestbook + image: openkruise/guestbook:v3 + command: ["echo", "started"] # a dummy command to do nothing + restartPolicy: Never + completionPolicy: + type: Always + ttlSecondsAfterFinished: 60 # the job will be deleted after 60 seconds +status: + active: 0 + completionTime: '2023-09-17T14:35:14Z' + conditions: + - lastProbeTime: '2023-09-17T14:35:14Z' + lastTransitionTime: '2023-09-17T14:35:14Z' + message: Job completed, 1 pods succeeded, 0 pods failed + reason: Complete + status: 'True' + type: Complete + desired: 1 + failed: 0 + phase: completed + startTime: '2023-09-17T14:35:07Z' + succeeded: 1 + diff --git a/resource_customizations/apps.kruise.io/BroadcastJob/testdata/suspended.yaml b/resource_customizations/apps.kruise.io/BroadcastJob/testdata/suspended.yaml new file mode 100644 index 0000000000000..60a9b587b8ec0 --- /dev/null +++ b/resource_customizations/apps.kruise.io/BroadcastJob/testdata/suspended.yaml @@ -0,0 +1,31 @@ +apiVersion: apps.kruise.io/v1alpha1 +kind: BroadcastJob +metadata: + name: download-image +spec: + template: + spec: + containers: + - name: guestbook + image: openkruise/guestbook:v3 + command: ["echo", "started"] # a dummy command to do nothing + restartPolicy: Never + paused: true + completionPolicy: + type: Always + ttlSecondsAfterFinished: 60 # the job will be deleted after 60 seconds +status: + active: 0 + completionTime: '2023-09-17T14:35:14Z' + conditions: + - lastProbeTime: '2023-09-17T14:35:14Z' + lastTransitionTime: '2023-09-17T14:35:14Z' + message: Job completed, 1 pods succeeded, 0 pods failed + reason: Complete + status: 'True' + type: Complete + desired: 1 + failed: 0 + phase: paused + startTime: '2023-09-17T14:35:07Z' + succeeded: 0 diff --git a/resource_customizations/apps.kruise.io/CloneSet/health.lua b/resource_customizations/apps.kruise.io/CloneSet/health.lua new file mode 100644 index 0000000000000..197ab7573dfe8 --- /dev/null +++ b/resource_customizations/apps.kruise.io/CloneSet/health.lua @@ -0,0 +1,33 @@ +hs={ status = "Progressing", message = "Waiting for initialization" } + +if obj.status ~= nil then + + if obj.metadata.generation == obj.status.observedGeneration then + + if obj.spec.updateStrategy.paused == true or not obj.status.updatedAvailableReplicas then + hs.status = "Suspended" + hs.message = "Cloneset is paused" + return hs + elseif obj.spec.updateStrategy.partition ~= 0 and obj.metadata.generation > 1 then + if obj.status.updatedReplicas >= obj.status.expectedUpdatedReplicas then + hs.status = "Suspended" + hs.message = "Cloneset needs manual intervention" + return hs + end + + elseif obj.status.updatedAvailableReplicas == obj.status.replicas then + hs.status = "Healthy" + hs.message = "All Cloneset workloads are ready and updated" + return hs + + else + if obj.status.updatedAvailableReplicas ~= obj.status.replicas then + hs.status = "Degraded" + hs.message = "Some replicas are not ready or available" + return hs + end + end + end +end + +return hs diff --git a/resource_customizations/apps.kruise.io/CloneSet/health_test.yaml b/resource_customizations/apps.kruise.io/CloneSet/health_test.yaml new file mode 100644 index 0000000000000..e740eca850778 --- /dev/null +++ b/resource_customizations/apps.kruise.io/CloneSet/health_test.yaml @@ -0,0 +1,21 @@ +tests: + - healthStatus: + status: Healthy + message: "All Cloneset workloads are ready and updated" + inputPath: testdata/healthy.yaml + - healthStatus: + status: Degraded + message: "Some replicas are not ready or available" + inputPath: testdata/degraded.yaml + - healthStatus: + status: Progressing + message: "Waiting for initialization" + inputPath: testdata/unknown.yaml + - healthStatus: + status: Suspended + message: "Cloneset is paused" + inputpath: testdata/suspended.yaml + - healthStatus: + status: Suspended + message: "Cloneset needs manual intervention" + inputpath: testdata/partition_suspended.yaml diff --git a/resource_customizations/apps.kruise.io/CloneSet/testdata/degraded.yaml b/resource_customizations/apps.kruise.io/CloneSet/testdata/degraded.yaml new file mode 100644 index 0000000000000..36e9a0d537c85 --- /dev/null +++ b/resource_customizations/apps.kruise.io/CloneSet/testdata/degraded.yaml @@ -0,0 +1,35 @@ +apiVersion: apps.kruise.io/v1alpha1 +kind: CloneSet +metadata: + name: cloneset-test + namespace: kruise + generation: 1 + labels: + app: sample +spec: + replicas: 2 + selector: + matchLabels: + app: sample + template: + metadata: + labels: + app: sample + spec: + containers: + - name: nginx + image: nginx:alpine + updateStrategy: + paused: false + +status: + observedGeneration: 1 + replicas: 2 + updatedReadyReplicas: 1 + updatedAvailableReplicas: 1 + conditions: + - lastTransitionTime: "2021-09-21T22:35:31Z" + message: Deployment has minimum availability. + reason: MinimumReplicasAvailable + status: 'True' + type: FailedScale diff --git a/resource_customizations/apps.kruise.io/CloneSet/testdata/healthy.yaml b/resource_customizations/apps.kruise.io/CloneSet/testdata/healthy.yaml new file mode 100644 index 0000000000000..8a1935381e04e --- /dev/null +++ b/resource_customizations/apps.kruise.io/CloneSet/testdata/healthy.yaml @@ -0,0 +1,36 @@ +apiVersion: apps.kruise.io/v1alpha1 +kind: CloneSet +metadata: + name: cloneset-test + namespace: kruise + generation: 1 + labels: + app: sample +spec: + replicas: 1 + selector: + matchLabels: + app: sample + template: + metadata: + labels: + app: sample + spec: + containers: + - name: nginx + image: nginx:alpine + updateStrategy: + paused: false + + +status: + observedGeneration: 1 + replicas: 2 + updatedReadyReplicas: 2 + updatedAvailableReplicas: 2 + conditions: + - lastTransitionTime: "2021-09-21T22:35:31Z" + message: Deployment has minimum availability. + reason: MinimumReplicasAvailable + status: 'True' + type: FailedScale diff --git a/resource_customizations/apps.kruise.io/CloneSet/testdata/partition_suspended.yaml b/resource_customizations/apps.kruise.io/CloneSet/testdata/partition_suspended.yaml new file mode 100644 index 0000000000000..674c5226b3072 --- /dev/null +++ b/resource_customizations/apps.kruise.io/CloneSet/testdata/partition_suspended.yaml @@ -0,0 +1,31 @@ +apiVersion: apps.kruise.io/v1alpha1 +kind: CloneSet +metadata: + name: cloneset-test + namespace: kruise + generation: 2 + labels: + app: sample +spec: + replicas: 5 + selector: + matchLabels: + app: sample + template: + metadata: + labels: + app: sample + spec: + containers: + - name: nginx + image: nginx:alpine + updateStrategy: + partition: 3 + +status: + observedGeneration: 2 + replicas: 5 + expectedUpdatedReplicas: 2 + updatedReadyReplicas: 1 + updatedAvailableReplicas: 1 + updatedReplicas: 3 diff --git a/resource_customizations/apps.kruise.io/CloneSet/testdata/suspended.yaml b/resource_customizations/apps.kruise.io/CloneSet/testdata/suspended.yaml new file mode 100644 index 0000000000000..9edfaca6a5149 --- /dev/null +++ b/resource_customizations/apps.kruise.io/CloneSet/testdata/suspended.yaml @@ -0,0 +1,35 @@ +apiVersion: apps.kruise.io/v1alpha1 +kind: CloneSet +metadata: + name: cloneset-test + namespace: kruise + generation: 2 + labels: + app: sample +spec: + replicas: 1 + selector: + matchLabels: + app: sample + template: + metadata: + labels: + app: sample + spec: + containers: + - name: nginx + image: nginx:alpine + updateStrategy: + paused: true + +status: + observedGeneration: 2 + replicas: 2 + updatedReadyReplicas: 2 + updatedAvailableReplicas: 2 + conditions: + - lastTransitionTime: "2021-09-21T22:35:31Z" + message: Deployment has minimum availability. + reason: MinimumReplicasAvailable + status: 'True' + type: FailedScale diff --git a/resource_customizations/apps.kruise.io/CloneSet/testdata/unknown.yaml b/resource_customizations/apps.kruise.io/CloneSet/testdata/unknown.yaml new file mode 100644 index 0000000000000..c1ccdb22fc76e --- /dev/null +++ b/resource_customizations/apps.kruise.io/CloneSet/testdata/unknown.yaml @@ -0,0 +1,5 @@ +apiVersion: apps.kruise.io/v1alpha1 +kind: CloneSet +metadata: + name: cloneset-test + namespace: kruise diff --git a/resource_customizations/apps.kruise.io/DaemonSet/health.lua b/resource_customizations/apps.kruise.io/DaemonSet/health.lua new file mode 100644 index 0000000000000..7705bcc3325e5 --- /dev/null +++ b/resource_customizations/apps.kruise.io/DaemonSet/health.lua @@ -0,0 +1,35 @@ +hs={ status = "Progressing", message = "Waiting for initialization" } + +if obj.status ~= nil then + + if obj.metadata.generation == obj.status.observedGeneration then + + if obj.spec.updateStrategy.rollingUpdate.paused == true or not obj.status.updatedNumberScheduled then + hs.status = "Suspended" + hs.message = "Daemonset is paused" + return hs + elseif obj.spec.updateStrategy.rollingUpdate.partition ~= 0 and obj.metadata.generation > 1 then + if obj.status.updatedNumberScheduled > (obj.status.desiredNumberScheduled - obj.spec.updateStrategy.rollingUpdate.partition) then + hs.status = "Suspended" + hs.message = "Daemonset needs manual intervention" + return hs + end + + elseif (obj.status.updatedNumberScheduled == obj.status.desiredNumberScheduled) and (obj.status.numberAvailable == obj.status.desiredNumberScheduled) then + hs.status = "Healthy" + hs.message = "All Daemonset workloads are ready and updated" + return hs + + else + if (obj.status.updatedNumberScheduled == obj.status.desiredNumberScheduled) and (obj.status.numberUnavailable == obj.status.desiredNumberScheduled) then + hs.status = "Degraded" + hs.message = "Some pods are not ready or available" + return hs + end + end + + end + +end + +return hs diff --git a/resource_customizations/apps.kruise.io/DaemonSet/health_test.yaml b/resource_customizations/apps.kruise.io/DaemonSet/health_test.yaml new file mode 100644 index 0000000000000..0a8c8292672f3 --- /dev/null +++ b/resource_customizations/apps.kruise.io/DaemonSet/health_test.yaml @@ -0,0 +1,21 @@ +tests: + - healthStatus: + status: Healthy + message: "All Daemonset workloads are ready and updated" + inputPath: testdata/healthy.yaml + - healthStatus: + status: Degraded + message: "Some pods are not ready or available" + inputPath: testdata/degraded.yaml + - healthStatus: + status: Progressing + message: "Waiting for initialization" + inputPath: testdata/unknown.yaml + - healthStatus: + status: Suspended + message: "Daemonset is paused" + inputPath: testdata/suspended.yaml + - healthStatus: + status: Suspended + message: "Daemonset needs manual intervention" + inputPath: testdata/partition_suspended.yaml diff --git a/resource_customizations/apps.kruise.io/DaemonSet/testdata/degraded.yaml b/resource_customizations/apps.kruise.io/DaemonSet/testdata/degraded.yaml new file mode 100644 index 0000000000000..ed8cbc0b4699e --- /dev/null +++ b/resource_customizations/apps.kruise.io/DaemonSet/testdata/degraded.yaml @@ -0,0 +1,34 @@ +apiVersion: apps.kruise.io/v1alpha1 +kind: DaemonSet +metadata: + name: daemonset-test + namespace: kruise + generation: 1 + labels: + app: sample +spec: + selector: + matchLabels: + app: sample + template: + metadata: + labels: + app: sample + spec: + containers: + - name: nginx + image: nginx:alpine + updateStrategy: + rollingUpdate: + partition: 0 + paused: false + +status: + currentNumberScheduled: 1 + daemonSetHash: 5dffcdfcd7 + desiredNumberScheduled: 1 + numberUnavailable: 1 + numberMisscheduled: 0 + numberReady: 0 + observedGeneration: 1 + updatedNumberScheduled: 1 diff --git a/resource_customizations/apps.kruise.io/DaemonSet/testdata/healthy.yaml b/resource_customizations/apps.kruise.io/DaemonSet/testdata/healthy.yaml new file mode 100644 index 0000000000000..6224ebf35e164 --- /dev/null +++ b/resource_customizations/apps.kruise.io/DaemonSet/testdata/healthy.yaml @@ -0,0 +1,34 @@ +apiVersion: apps.kruise.io/v1alpha1 +kind: DaemonSet +metadata: + name: daemonset-test + namespace: kruise + generation: 1 + labels: + app: sample +spec: + selector: + matchLabels: + app: sample + template: + metadata: + labels: + app: sample + spec: + containers: + - name: nginx + image: nginx:alpine + updateStrategy: + rollingUpdate: + partition: 0 + paused: false + +status: + currentNumberScheduled: 1 + daemonSetHash: 5dffcdfcd7 + desiredNumberScheduled: 1 + numberAvailable: 1 + numberMisscheduled: 0 + numberReady: 1 + observedGeneration: 1 + updatedNumberScheduled: 1 diff --git a/resource_customizations/apps.kruise.io/DaemonSet/testdata/partition_suspended.yaml b/resource_customizations/apps.kruise.io/DaemonSet/testdata/partition_suspended.yaml new file mode 100644 index 0000000000000..4c0819cdc8703 --- /dev/null +++ b/resource_customizations/apps.kruise.io/DaemonSet/testdata/partition_suspended.yaml @@ -0,0 +1,33 @@ +apiVersion: apps.kruise.io/v1alpha1 +kind: DaemonSet +metadata: + name: daemonset-test + namespace: kruise + generation: 6 + labels: + app: sample +spec: + selector: + matchLabels: + app: sample + template: + metadata: + labels: + app: sample + spec: + containers: + - name: nginx + image: nginx:alpine + updateStrategy: + rollingUpdate: + partition: 4 + +status: + currentNumberScheduled: 1 + daemonSetHash: 5f8cdcdc65 + desiredNumberScheduled: 10 + numberAvailable: 10 + numberMisscheduled: 0 + numberReady: 10 + observedGeneration: 6 + updatedNumberScheduled: 7 diff --git a/resource_customizations/apps.kruise.io/DaemonSet/testdata/suspended.yaml b/resource_customizations/apps.kruise.io/DaemonSet/testdata/suspended.yaml new file mode 100644 index 0000000000000..fb705f5578176 --- /dev/null +++ b/resource_customizations/apps.kruise.io/DaemonSet/testdata/suspended.yaml @@ -0,0 +1,33 @@ +apiVersion: apps.kruise.io/v1alpha1 +kind: DaemonSet +metadata: + name: daemonset-test + namespace: kruise + generation: 1 + labels: + app: sample +spec: + selector: + matchLabels: + app: sample + template: + metadata: + labels: + app: sample + spec: + containers: + - name: nginx + image: nginx:alpine + updateStrategy: + rollingUpdate: + paused: true + +status: + currentNumberScheduled: 1 + daemonSetHash: 5dffcdfcd7 + desiredNumberScheduled: 1 + numberAvailable: 1 + numberMisscheduled: 0 + numberReady: 1 + observedGeneration: 1 + updatedNumberScheduled: 1 diff --git a/resource_customizations/apps.kruise.io/DaemonSet/testdata/unknown.yaml b/resource_customizations/apps.kruise.io/DaemonSet/testdata/unknown.yaml new file mode 100644 index 0000000000000..aa5791c52bc6c --- /dev/null +++ b/resource_customizations/apps.kruise.io/DaemonSet/testdata/unknown.yaml @@ -0,0 +1,5 @@ +apiVersion: apps.kruise.io/v1alpha1 +kind: DaemonSet +metadata: + name: daemonset-test + namespace: kruise diff --git a/resource_customizations/apps.kruise.io/StatefulSet/health.lua b/resource_customizations/apps.kruise.io/StatefulSet/health.lua new file mode 100644 index 0000000000000..47340452db2dc --- /dev/null +++ b/resource_customizations/apps.kruise.io/StatefulSet/health.lua @@ -0,0 +1,35 @@ +hs={ status = "Progressing", message = "Waiting for initialization" } + +if obj.status ~= nil then + + if obj.metadata.generation == obj.status.observedGeneration then + + if obj.spec.updateStrategy.rollingUpdate.paused == true or not obj.status.updatedAvailableReplicas then + hs.status = "Suspended" + hs.message = "Statefulset is paused" + return hs + elseif obj.spec.updateStrategy.rollingUpdate.partition ~= 0 and obj.metadata.generation > 1 then + if obj.status.updatedReplicas > (obj.status.replicas - obj.spec.updateStrategy.rollingUpdate.partition) then + hs.status = "Suspended" + hs.message = "Statefulset needs manual intervention" + return hs + end + + elseif obj.status.updatedAvailableReplicas == obj.status.replicas then + hs.status = "Healthy" + hs.message = "All Statefulset workloads are ready and updated" + return hs + + else + if obj.status.updatedAvailableReplicas ~= obj.status.replicas then + hs.status = "Degraded" + hs.message = "Some replicas are not ready or available" + return hs + end + end + + end + +end + +return hs diff --git a/resource_customizations/apps.kruise.io/StatefulSet/health_test.yaml b/resource_customizations/apps.kruise.io/StatefulSet/health_test.yaml new file mode 100644 index 0000000000000..6672b9f46d4f4 --- /dev/null +++ b/resource_customizations/apps.kruise.io/StatefulSet/health_test.yaml @@ -0,0 +1,21 @@ +tests: + - healthStatus: + status: Healthy + message: "All Statefulset workloads are ready and updated" + inputPath: testdata/healthy.yaml + - healthStatus: + status: Degraded + message: "Some replicas are not ready or available" + inputPath: testdata/degraded.yaml + - healthStatus: + status: Progressing + message: "Waiting for initialization" + inputPath: testdata/unknown.yaml + - healthStatus: + status: Suspended + message: "Statefulset is paused" + inputPath: testdata/suspended.yaml + - healthStatus: + status: Suspended + message: "Statefulset needs manual intervention" + inputPath: testdata/partition_suspended.yaml diff --git a/resource_customizations/apps.kruise.io/StatefulSet/testdata/degraded.yaml b/resource_customizations/apps.kruise.io/StatefulSet/testdata/degraded.yaml new file mode 100644 index 0000000000000..88e58914940fc --- /dev/null +++ b/resource_customizations/apps.kruise.io/StatefulSet/testdata/degraded.yaml @@ -0,0 +1,42 @@ +apiVersion: apps.kruise.io/v1beta1 +kind: StatefulSet +metadata: + name: statefulset-test + namespace: kruise + generation: 5 + labels: + app: sample +spec: + replicas: 2 + selector: + matchLabels: + app: sample + template: + metadata: + labels: + app: sample + spec: + containers: + - name: nginx + image: nginx:alpine + updateStrategy: + rollingUpdate: + maxUnavailable: 1 + minReadySeconds: 0 + paused: false + partition: 0 + podUpdatePolicy: ReCreate + type: RollingUpdate + +status: + observedGeneration: 5 + replicas: 2 + updatedAvailableReplicas: 1 + updatedReadyReplicas: 1 + conditions: + - lastTransitionTime: "2021-09-21T22:35:31Z" + message: Deployment has minimum availability. + reason: MinimumReplicasAvailable + status: 'True' + type: FailedCreatePod + diff --git a/resource_customizations/apps.kruise.io/StatefulSet/testdata/healthy.yaml b/resource_customizations/apps.kruise.io/StatefulSet/testdata/healthy.yaml new file mode 100644 index 0000000000000..793de25d3da1c --- /dev/null +++ b/resource_customizations/apps.kruise.io/StatefulSet/testdata/healthy.yaml @@ -0,0 +1,41 @@ +apiVersion: apps.kruise.io/v1beta1 +kind: StatefulSet +metadata: + name: statefulset-test + namespace: kruise + generation: 2 + labels: + app: sample +spec: + replicas: 2 + selector: + matchLabels: + app: sample + template: + metadata: + labels: + app: sample + spec: + containers: + - name: nginx + image: nginx:alpine + updateStrategy: + rollingUpdate: + maxUnavailable: 1 + minReadySeconds: 0 + paused: false + partition: 0 + podUpdatePolicy: ReCreate + type: RollingUpdate + +status: + observedGeneration: 2 + replicas: 2 + updatedAvailableReplicas: 2 + updatedReadyReplicas: 2 + conditions: + - lastTransitionTime: "2021-09-21T22:35:31Z" + message: Deployment has minimum availability. + reason: MinimumReplicasAvailable + status: 'False' + type: FailedCreatePod diff --git a/resource_customizations/apps.kruise.io/StatefulSet/testdata/partition_suspended.yaml b/resource_customizations/apps.kruise.io/StatefulSet/testdata/partition_suspended.yaml new file mode 100644 index 0000000000000..b09a7726bf5d7 --- /dev/null +++ b/resource_customizations/apps.kruise.io/StatefulSet/testdata/partition_suspended.yaml @@ -0,0 +1,36 @@ +apiVersion: apps.kruise.io/v1beta1 +kind: StatefulSet +metadata: + name: statefulset-test + namespace: kruise + generation: 3 + labels: + app: sample +spec: + replicas: 10 + selector: + matchLabels: + app: sample + template: + metadata: + labels: + app: sample + spec: + containers: + - image: nginx:mainline + updateStrategy: + rollingUpdate: + partition: 4 + +status: + availableReplicas: 10 + currentReplicas: 4 + currentRevision: statefulset-test-d4d4fb5bd + labelSelector: app=sample + observedGeneration: 3 + readyReplicas: 10 + replicas: 10 + updateRevision: statefulset-test-56dfb978d4 + updatedAvailableReplicas: 7 + updatedReadyReplicas: 7 + updatedReplicas: 7 diff --git a/resource_customizations/apps.kruise.io/StatefulSet/testdata/suspended.yaml b/resource_customizations/apps.kruise.io/StatefulSet/testdata/suspended.yaml new file mode 100644 index 0000000000000..42dae9cf5e322 --- /dev/null +++ b/resource_customizations/apps.kruise.io/StatefulSet/testdata/suspended.yaml @@ -0,0 +1,36 @@ +apiVersion: apps.kruise.io/v1beta1 +kind: StatefulSet +metadata: + name: statefulset-test + namespace: kruise + generation: 2 + labels: + app: sample +spec: + replicas: 2 + selector: + matchLabels: + app: sample + template: + metadata: + labels: + app: sample + spec: + containers: + - name: nginx + image: nginx:alpine + updateStrategy: + rollingUpdate: + paused: true + +status: + observedGeneration: 2 + replicas: 2 + updatedAvailableReplicas: 2 + updatedReadyReplicas: 2 + conditions: + - lastTransitionTime: "2021-09-21T22:35:31Z" + message: Deployment has minimum availability. + reason: MinimumReplicasAvailable + status: 'False' + type: FailedCreatePod diff --git a/resource_customizations/apps.kruise.io/StatefulSet/testdata/unknown.yaml b/resource_customizations/apps.kruise.io/StatefulSet/testdata/unknown.yaml new file mode 100644 index 0000000000000..67d28de6dae64 --- /dev/null +++ b/resource_customizations/apps.kruise.io/StatefulSet/testdata/unknown.yaml @@ -0,0 +1,5 @@ +apiVersion: apps.kruise.io/v1beta1 +kind: StatefulSet +metadata: + name: statefulset-test + namespace: kruise diff --git a/resource_customizations/batch/CronJob/actions/create-job/action.lua b/resource_customizations/batch/CronJob/actions/create-job/action.lua index 8753144d404e7..a6f3253a5b757 100644 --- a/resource_customizations/batch/CronJob/actions/create-job/action.lua +++ b/resource_customizations/batch/CronJob/actions/create-job/action.lua @@ -38,12 +38,18 @@ if job.metadata == nil then end job.metadata.name = obj.metadata.name .. "-" ..os.date("!%Y%m%d%H%M") job.metadata.namespace = obj.metadata.namespace +if job.metadata.annotations == nil then + job.metadata.annotations = {} +end +job.metadata.annotations['cronjob.kubernetes.io/instantiate'] = "manual" local ownerRef = {} ownerRef.apiVersion = obj.apiVersion ownerRef.kind = obj.kind ownerRef.name = obj.metadata.name ownerRef.uid = obj.metadata.uid +ownerRef.blockOwnerDeletion = true +ownerRef.controller = true job.metadata.ownerReferences = {} job.metadata.ownerReferences[1] = ownerRef diff --git a/resource_customizations/batch/CronJob/actions/testdata/job.yaml b/resource_customizations/batch/CronJob/actions/testdata/job.yaml index 1ef281afdcdb4..322ab0480beb5 100644 --- a/resource_customizations/batch/CronJob/actions/testdata/job.yaml +++ b/resource_customizations/batch/CronJob/actions/testdata/job.yaml @@ -8,6 +8,7 @@ labels: my: label annotations: + cronjob.kubernetes.io/instantiate: manual my: annotation spec: ttlSecondsAfterFinished: 100 @@ -26,4 +27,4 @@ - /bin/sh - -c - date; echo Hello from the Kubernetes cluster - restartPolicy: OnFailure \ No newline at end of file + restartPolicy: OnFailure diff --git a/resource_customizations/beat.k8s.elastic.co/Beat/health.lua b/resource_customizations/beat.k8s.elastic.co/Beat/health.lua new file mode 100644 index 0000000000000..c7639dbbd94f0 --- /dev/null +++ b/resource_customizations/beat.k8s.elastic.co/Beat/health.lua @@ -0,0 +1,31 @@ +local hs = {} + +if obj.status ~= nil and (obj.status.health ~= nil or obj.status.expectedNodes ~= nil) then + if obj.status.health == "red" then + hs.status = "Degraded" + hs.message = "Elastic Beat status is Red" + return hs + elseif obj.status.health == "green" then + hs.status = "Healthy" + hs.message = "Elastic Beat status is Green" + return hs + elseif obj.status.health == "yellow" then + if obj.status.availableNodes ~= nil and obj.status.expectedNodes ~= nil then + hs.status = "Progressing" + hs.message = "Elastic Beat status is deploying, there is " .. obj.status.availableNodes .. " instance(s) on " .. obj.status.expectedNodes .. " expected" + return hs + else + hs.status = "Progressing" + hs.message = "Elastic Beat phase is progressing" + return hs + end + elseif obj.status.health == nil then + hs.status = "Progressing" + hs.message = "Elastic Beat phase is progressing" + return hs + end +end + +hs.status = "Unknown" +hs.message = "Elastic Beat status is unknown. Ensure your ArgoCD is current and then check for/file a bug report: https://github.com/argoproj/argo-cd/issues" +return hs diff --git a/resource_customizations/beat.k8s.elastic.co/Beat/health_test.yaml b/resource_customizations/beat.k8s.elastic.co/Beat/health_test.yaml new file mode 100644 index 0000000000000..fb44e998ffaf1 --- /dev/null +++ b/resource_customizations/beat.k8s.elastic.co/Beat/health_test.yaml @@ -0,0 +1,29 @@ +tests: +- healthStatus: + status: Healthy + message: "Elastic Beat status is Green" + inputPath: testdata/ready_green.yaml +- healthStatus: + status: Progressing + message: "Elastic Beat phase is progressing" + inputPath: testdata/ready_yellow_single_node.yaml +- healthStatus: + status: Progressing + message: "Elastic Beat status is deploying, there is 1 instance(s) on 2 expected" + inputPath: testdata/ready_yellow.yaml +- healthStatus: + status: Progressing + message: "Elastic Beat phase is progressing" + inputPath: testdata/progressing.yaml +- healthStatus: + status: Degraded + message: "Elastic Beat status is Red" + inputPath: testdata/ready_red.yaml +- healthStatus: + status: Unknown + message: "Elastic Beat status is unknown. Ensure your ArgoCD is current and then check for/file a bug report: https://github.com/argoproj/argo-cd/issues" + inputPath: testdata/unknown.yaml +- healthStatus: + status: Unknown + message: "Elastic Beat status is unknown. Ensure your ArgoCD is current and then check for/file a bug report: https://github.com/argoproj/argo-cd/issues" + inputPath: testdata/invalid.yaml diff --git a/resource_customizations/beat.k8s.elastic.co/Beat/testdata/invalid.yaml b/resource_customizations/beat.k8s.elastic.co/Beat/testdata/invalid.yaml new file mode 100644 index 0000000000000..3eca183165a5c --- /dev/null +++ b/resource_customizations/beat.k8s.elastic.co/Beat/testdata/invalid.yaml @@ -0,0 +1,12 @@ +apiVersion: beat.k8s.elastic.co/v1beta1 +kind: Beat +metadata: + name: quickstart +spec: + version: 8.8.8 + type: metricbeat +status: + expectedNodes: 1 + health: invalid + observedGeneration: 1 + version: 8.8.1 diff --git a/resource_customizations/beat.k8s.elastic.co/Beat/testdata/progressing.yaml b/resource_customizations/beat.k8s.elastic.co/Beat/testdata/progressing.yaml new file mode 100644 index 0000000000000..b007ad72ae3fe --- /dev/null +++ b/resource_customizations/beat.k8s.elastic.co/Beat/testdata/progressing.yaml @@ -0,0 +1,11 @@ +apiVersion: beat.k8s.elastic.co/v1beta1 +kind: Beat +metadata: + name: quickstart +spec: + version: 8.8.8 + type: metricbeat +status: + expectedNodes: 1 + observedGeneration: 1 + version: 8.8.1 diff --git a/resource_customizations/beat.k8s.elastic.co/Beat/testdata/ready_green.yaml b/resource_customizations/beat.k8s.elastic.co/Beat/testdata/ready_green.yaml new file mode 100644 index 0000000000000..3f3c1866793d8 --- /dev/null +++ b/resource_customizations/beat.k8s.elastic.co/Beat/testdata/ready_green.yaml @@ -0,0 +1,13 @@ +apiVersion: beat.k8s.elastic.co/v1beta1 +kind: Beat +metadata: + name: quickstart +spec: + version: 8.8.8 + type: metricbeat +status: + expectedNodes: 1 + availableNodes: 1 + health: green + observedGeneration: 1 + version: 8.8.1 diff --git a/resource_customizations/beat.k8s.elastic.co/Beat/testdata/ready_red.yaml b/resource_customizations/beat.k8s.elastic.co/Beat/testdata/ready_red.yaml new file mode 100644 index 0000000000000..fc2433c8076a8 --- /dev/null +++ b/resource_customizations/beat.k8s.elastic.co/Beat/testdata/ready_red.yaml @@ -0,0 +1,10 @@ +apiVersion: beat.k8s.elastic.co/v1beta1 +kind: Beat +metadata: + name: quickstart +spec: + version: 8.8.8 + type: metricbeat +status: + expectedNodes: 1 + health: red diff --git a/resource_customizations/beat.k8s.elastic.co/Beat/testdata/ready_yellow.yaml b/resource_customizations/beat.k8s.elastic.co/Beat/testdata/ready_yellow.yaml new file mode 100644 index 0000000000000..831ee281ef02d --- /dev/null +++ b/resource_customizations/beat.k8s.elastic.co/Beat/testdata/ready_yellow.yaml @@ -0,0 +1,11 @@ +apiVersion: beat.k8s.elastic.co/v1beta1 +kind: Beat +metadata: + name: quickstart +spec: + version: 8.8.8 + type: metricbeat +status: + availableNodes: 1 + expectedNodes: 2 + health: yellow diff --git a/resource_customizations/beat.k8s.elastic.co/Beat/testdata/ready_yellow_single_node.yaml b/resource_customizations/beat.k8s.elastic.co/Beat/testdata/ready_yellow_single_node.yaml new file mode 100644 index 0000000000000..d652b5a55d0ff --- /dev/null +++ b/resource_customizations/beat.k8s.elastic.co/Beat/testdata/ready_yellow_single_node.yaml @@ -0,0 +1,10 @@ +apiVersion: beat.k8s.elastic.co/v1beta1 +kind: Beat +metadata: + name: quickstart +spec: + version: 8.8.8 + type: metricbeat +status: + expectedNodes: 1 + health: yellow diff --git a/resource_customizations/beat.k8s.elastic.co/Beat/testdata/unknown.yaml b/resource_customizations/beat.k8s.elastic.co/Beat/testdata/unknown.yaml new file mode 100644 index 0000000000000..dbcca36c9e691 --- /dev/null +++ b/resource_customizations/beat.k8s.elastic.co/Beat/testdata/unknown.yaml @@ -0,0 +1,8 @@ +apiVersion: beat.k8s.elastic.co/v1beta1 +kind: Beat +metadata: + name: quickstart +spec: + version: 8.8.8 + type: metricbeat +status: {} diff --git a/resource_customizations/cert-manager.io/Certificate/health.lua b/resource_customizations/cert-manager.io/Certificate/health.lua index ddecb2631b39a..fce5bcbe3d1d0 100644 --- a/resource_customizations/cert-manager.io/Certificate/health.lua +++ b/resource_customizations/cert-manager.io/Certificate/health.lua @@ -1,12 +1,17 @@ local hs = {} if obj.status ~= nil then if obj.status.conditions ~= nil then + + -- Always Handle Issuing First to ensure consistent behaviour for i, condition in ipairs(obj.status.conditions) do if condition.type == "Issuing" and condition.status == "True" then hs.status = "Progressing" hs.message = condition.message return hs end + end + + for i, condition in ipairs(obj.status.conditions) do if condition.type == "Ready" and condition.status == "False" then hs.status = "Degraded" hs.message = condition.message diff --git a/resource_customizations/cert-manager.io/Certificate/health_test.yaml b/resource_customizations/cert-manager.io/Certificate/health_test.yaml index ebf8e75e89064..1af7b1a759a60 100644 --- a/resource_customizations/cert-manager.io/Certificate/health_test.yaml +++ b/resource_customizations/cert-manager.io/Certificate/health_test.yaml @@ -7,6 +7,10 @@ tests: status: Progressing message: Issuing certificate as Secret does not exist inputPath: testdata/progressing_issuing.yaml +- healthStatus: + status: Progressing + message: Issuing certificate as Secret does not exist + inputPath: testdata/progressing_issuing_last.yaml - healthStatus: status: Degraded message: 'Resource validation failed: spec.acme.config: Required value: no ACME diff --git a/resource_customizations/cert-manager.io/Certificate/testdata/progressing_issuing_last.yaml b/resource_customizations/cert-manager.io/Certificate/testdata/progressing_issuing_last.yaml new file mode 100644 index 0000000000000..4d21a9b3610f1 --- /dev/null +++ b/resource_customizations/cert-manager.io/Certificate/testdata/progressing_issuing_last.yaml @@ -0,0 +1,36 @@ +apiVersion: cert-manager.io/v1alpha2 +kind: Certificate +metadata: + creationTimestamp: '2018-11-07T00:06:12Z' + generation: 1 + name: test-cert + namespace: argocd + resourceVersion: '64763033' + selfLink: /apis/cert-manager.io/v1alpha2/namespaces/argocd/certificates/test-cert + uid: e6cfba50-314d-11e9-be3f-42010a800011 +spec: + acme: + config: + - domains: + - cd.apps.argoproj.io + http01: + ingress: http01 + commonName: cd.apps.argoproj.io + dnsNames: + - cd.apps.argoproj.io + issuerRef: + kind: Issuer + name: argo-cd-issuer + secretName: test-secret +status: + conditions: + - lastTransitionTime: '2021-09-15T02:10:00Z' + message: Issuing certificate as Secret does not exist + reason: DoesNotExist + status: 'False' + type: Ready + - lastTransitionTime: '2021-09-15T02:10:00Z' + message: Issuing certificate as Secret does not exist + reason: DoesNotExist + status: 'True' + type: Issuing diff --git a/resource_customizations/cert-manager.io/ClusterIssuer/testdata/degraded_acmeFailed.yaml b/resource_customizations/cert-manager.io/ClusterIssuer/testdata/degraded_acmeFailed.yaml index 75a249feb3da6..c99c1f4f84ba4 100644 --- a/resource_customizations/cert-manager.io/ClusterIssuer/testdata/degraded_acmeFailed.yaml +++ b/resource_customizations/cert-manager.io/ClusterIssuer/testdata/degraded_acmeFailed.yaml @@ -8,7 +8,7 @@ metadata: uid: 37f408e3-3157-11e9-be3f-42010a800011 spec: acme: - email: myemail@test.com + email: myemail@example.com http01: {} privateKeySecretRef: key: "" diff --git a/resource_customizations/cert-manager.io/ClusterIssuer/testdata/healthy_registered.yaml b/resource_customizations/cert-manager.io/ClusterIssuer/testdata/healthy_registered.yaml index edad50241c40b..e883b51e3a793 100644 --- a/resource_customizations/cert-manager.io/ClusterIssuer/testdata/healthy_registered.yaml +++ b/resource_customizations/cert-manager.io/ClusterIssuer/testdata/healthy_registered.yaml @@ -8,7 +8,7 @@ metadata: uid: b0045219-e219-11e8-9f93-42010a80021d spec: acme: - email: myemail@test.com + email: myemail@example.com http01: {} privateKeySecretRef: key: "" diff --git a/resource_customizations/cert-manager.io/ClusterIssuer/testdata/progressing_noStatus.yaml b/resource_customizations/cert-manager.io/ClusterIssuer/testdata/progressing_noStatus.yaml index b05c4aeb7d13f..4571d229ffed7 100644 --- a/resource_customizations/cert-manager.io/ClusterIssuer/testdata/progressing_noStatus.yaml +++ b/resource_customizations/cert-manager.io/ClusterIssuer/testdata/progressing_noStatus.yaml @@ -8,7 +8,7 @@ metadata: uid: b0045219-e219-11e8-9f93-42010a80021d spec: acme: - email: myemail@test.com + email: myemail@example.com http01: {} privateKeySecretRef: key: "" diff --git a/resource_customizations/cert-manager.io/Issuer/testdata/degraded_acmeFailed.yaml b/resource_customizations/cert-manager.io/Issuer/testdata/degraded_acmeFailed.yaml index 62226e3b3be62..a5abcf57a5ac2 100644 --- a/resource_customizations/cert-manager.io/Issuer/testdata/degraded_acmeFailed.yaml +++ b/resource_customizations/cert-manager.io/Issuer/testdata/degraded_acmeFailed.yaml @@ -10,7 +10,7 @@ metadata: uid: 37f408e3-3157-11e9-be3f-42010a800011 spec: acme: - email: myemail@test.com + email: myemail@example.com http01: {} privateKeySecretRef: key: "" diff --git a/resource_customizations/cert-manager.io/Issuer/testdata/healthy_registered.yaml b/resource_customizations/cert-manager.io/Issuer/testdata/healthy_registered.yaml index 08b96394ec823..07181567145f2 100644 --- a/resource_customizations/cert-manager.io/Issuer/testdata/healthy_registered.yaml +++ b/resource_customizations/cert-manager.io/Issuer/testdata/healthy_registered.yaml @@ -10,7 +10,7 @@ metadata: uid: b0045219-e219-11e8-9f93-42010a80021d spec: acme: - email: myemail@test.com + email: myemail@example.com http01: {} privateKeySecretRef: key: "" diff --git a/resource_customizations/cert-manager.io/Issuer/testdata/progressing_noStatus.yaml b/resource_customizations/cert-manager.io/Issuer/testdata/progressing_noStatus.yaml index 820182e3e1e6a..f2e7b80e7f0b5 100644 --- a/resource_customizations/cert-manager.io/Issuer/testdata/progressing_noStatus.yaml +++ b/resource_customizations/cert-manager.io/Issuer/testdata/progressing_noStatus.yaml @@ -10,7 +10,7 @@ metadata: uid: b0045219-e219-11e8-9f93-42010a80021d spec: acme: - email: myemail@test.com + email: myemail@example.com http01: {} privateKeySecretRef: key: "" diff --git a/resource_customizations/certmanager.k8s.io/Issuer/testdata/degraded_acmeFailed.yaml b/resource_customizations/certmanager.k8s.io/Issuer/testdata/degraded_acmeFailed.yaml index dbd819ca9f113..5f0dbec676917 100644 --- a/resource_customizations/certmanager.k8s.io/Issuer/testdata/degraded_acmeFailed.yaml +++ b/resource_customizations/certmanager.k8s.io/Issuer/testdata/degraded_acmeFailed.yaml @@ -10,7 +10,7 @@ metadata: uid: 37f408e3-3157-11e9-be3f-42010a800011 spec: acme: - email: myemail@test.com + email: myemail@example.com http01: {} privateKeySecretRef: key: "" diff --git a/resource_customizations/certmanager.k8s.io/Issuer/testdata/healthy_registered.yaml b/resource_customizations/certmanager.k8s.io/Issuer/testdata/healthy_registered.yaml index db0a81b941bab..a5f6aa14986d6 100644 --- a/resource_customizations/certmanager.k8s.io/Issuer/testdata/healthy_registered.yaml +++ b/resource_customizations/certmanager.k8s.io/Issuer/testdata/healthy_registered.yaml @@ -10,7 +10,7 @@ metadata: uid: b0045219-e219-11e8-9f93-42010a80021d spec: acme: - email: myemail@test.com + email: myemail@example.com http01: {} privateKeySecretRef: key: "" diff --git a/resource_customizations/certmanager.k8s.io/Issuer/testdata/progressing_noStatus.yaml b/resource_customizations/certmanager.k8s.io/Issuer/testdata/progressing_noStatus.yaml index 68f35fa773256..501b7aa20060f 100644 --- a/resource_customizations/certmanager.k8s.io/Issuer/testdata/progressing_noStatus.yaml +++ b/resource_customizations/certmanager.k8s.io/Issuer/testdata/progressing_noStatus.yaml @@ -10,7 +10,7 @@ metadata: uid: b0045219-e219-11e8-9f93-42010a80021d spec: acme: - email: myemail@test.com + email: myemail@example.com http01: {} privateKeySecretRef: key: "" diff --git a/resource_customizations/cloudfront.aws.crossplane.io/Distribution/health.lua b/resource_customizations/cloudfront.aws.crossplane.io/Distribution/health.lua new file mode 100644 index 0000000000000..3e07226b3cf89 --- /dev/null +++ b/resource_customizations/cloudfront.aws.crossplane.io/Distribution/health.lua @@ -0,0 +1,42 @@ +local hs = {} +if obj.status ~= nil then + if obj.status.conditions ~= nil then + local ready = false + local synced = false + local suspended = false + + for i, condition in ipairs(obj.status.conditions) do + + if condition.type == "Ready" then + ready = condition.status == "True" + ready_message = condition.reason + elseif condition.type == "Synced" then + synced = condition.status == "True" + if condition.reason == "ReconcileError" then + synced_message = condition.message + elseif condition.reason == "ReconcilePaused" then + suspended = true + suspended_message = condition.reason + end + end + end + if ready and synced then + hs.status = "Healthy" + hs.message = ready_message + elseif synced == false and suspended == true then + hs.status = "Suspended" + hs.message = suspended_message + elseif ready == false and synced == true and suspended == false then + hs.status = "Progressing" + hs.message = "Waiting for distribution to be available" + else + hs.status = "Degraded" + hs.message = synced_message + end + return hs + end +end + +hs.status = "Progressing" +hs.message = "Waiting for distribution to be created" +return hs \ No newline at end of file diff --git a/resource_customizations/cloudfront.aws.crossplane.io/Distribution/health_test.yaml b/resource_customizations/cloudfront.aws.crossplane.io/Distribution/health_test.yaml new file mode 100644 index 0000000000000..981a6000ecb88 --- /dev/null +++ b/resource_customizations/cloudfront.aws.crossplane.io/Distribution/health_test.yaml @@ -0,0 +1,37 @@ +tests: +- healthStatus: + status: Progressing + message: Waiting for distribution to be available + inputPath: testdata/progressing_creating.yaml +- healthStatus: + status: Progressing + message: Waiting for distribution to be available + inputPath: testdata/progressing_noavailable.yaml +- healthStatus: + status: Progressing + message: Waiting for distribution to be available + inputPath: testdata/progressing.yaml +- healthStatus: + status: Progressing + message: Waiting for distribution to be created + inputPath: testdata/progressing_noStatus.yaml +- healthStatus: + status: Degraded + message: > + update failed: cannot update Distribution in AWS: InvalidParameter: 2 + validation error(s) found. + + - missing required field, + UpdateDistributionInput.DistributionConfig.Origins.Items[0].DomainName. + + - missing required field, + UpdateDistributionInput.DistributionConfig.Origins.Items[0].Id. + inputPath: testdata/degraded_reconcileError.yaml +- healthStatus: + status: Suspended + message: ReconcilePaused + inputPath: testdata/suspended.yaml +- healthStatus: + status: Healthy + message: Available + inputPath: testdata/healthy.yaml diff --git a/resource_customizations/cloudfront.aws.crossplane.io/Distribution/testdata/degraded_reconcileError.yaml b/resource_customizations/cloudfront.aws.crossplane.io/Distribution/testdata/degraded_reconcileError.yaml new file mode 100644 index 0000000000000..80ea7930574ac --- /dev/null +++ b/resource_customizations/cloudfront.aws.crossplane.io/Distribution/testdata/degraded_reconcileError.yaml @@ -0,0 +1,96 @@ +apiVersion: cloudfront.aws.crossplane.io/v1alpha1 +kind: Distribution +metadata: + creationTimestamp: '2024-01-17T07:26:02Z' + generation: 2 + name: crossplane.io + resourceVersion: '261942288' + uid: 4b50c88b-165c-4176-be8e-aa28fdec0a94 +spec: + deletionPolicy: Orphan + forProvider: + distributionConfig: + comment: 'crossplane' + customErrorResponses: + items: [] + defaultCacheBehavior: + allowedMethods: + cachedMethods: + items: + - HEAD + - GET + items: + - HEAD + - GET + compress: false + defaultTTL: 600 + fieldLevelEncryptionID: '' + forwardedValues: + cookies: + forward: none + headers: + items: [] + queryString: false + queryStringCacheKeys: {} + functionAssociations: {} + lambdaFunctionAssociations: {} + maxTTL: 600 + minTTL: 0 + smoothStreaming: false + targetOriginID: crossplane.io + trustedKeyGroups: + enabled: false + trustedSigners: + enabled: false + viewerProtocolPolicy: allow-all + defaultRootObject: index.html + enabled: true + httpVersion: http2 + isIPV6Enabled: true + logging: + bucket: '' + enabled: false + includeCookies: false + prefix: '' + originGroups: {} + origins: + items: + - connectionAttempts: 3 + connectionTimeout: 10 + customOriginConfig: + httpPort: 8080 + httpSPort: 443 + originKeepaliveTimeout: 5 + originProtocolPolicy: http-only + originReadTimeout: 10 + originSSLProtocols: + items: + - TLSv1 + - TLSv1.1 + - TLSv1.2 + priceClass: PriceClass_200 + restrictions: + geoRestriction: + restrictionType: none + region: ap-northeast-2 + providerConfigRef: + name: crossplane +status: + conditions: + - lastTransitionTime: '2024-01-17T07:26:02Z' + message: > + update failed: cannot update Distribution in AWS: InvalidParameter: 2 + validation error(s) found. + + - missing required field, + UpdateDistributionInput.DistributionConfig.Origins.Items[0].DomainName. + + - missing required field, + UpdateDistributionInput.DistributionConfig.Origins.Items[0].Id. + reason: ReconcileError + status: 'False' + type: Synced + - lastTransitionTime: '2024-01-17T07:26:03Z' + reason: Available + status: 'True' + type: Ready diff --git a/resource_customizations/cloudfront.aws.crossplane.io/Distribution/testdata/healthy.yaml b/resource_customizations/cloudfront.aws.crossplane.io/Distribution/testdata/healthy.yaml new file mode 100644 index 0000000000000..23d0287445e83 --- /dev/null +++ b/resource_customizations/cloudfront.aws.crossplane.io/Distribution/testdata/healthy.yaml @@ -0,0 +1,92 @@ +apiVersion: cloudfront.aws.crossplane.io/v1alpha1 +kind: Distribution +metadata: + creationTimestamp: "2023-09-07T01:01:16Z" + generation: 121 + name: crossplane.io + resourceVersion: "254225966" + uid: 531d989c-a3d2-4ab4-841d-ab380cce0bdb +spec: + deletionPolicy: Orphan + forProvider: + distributionConfig: + comment: 'crossplane' + customErrorResponses: + items: [] + defaultCacheBehavior: + allowedMethods: + cachedMethods: + items: + - HEAD + - GET + items: + - HEAD + - GET + compress: false + defaultTTL: 600 + fieldLevelEncryptionID: '' + forwardedValues: + cookies: + forward: none + headers: + items: [] + queryString: false + queryStringCacheKeys: {} + functionAssociations: {} + lambdaFunctionAssociations: {} + maxTTL: 600 + minTTL: 0 + smoothStreaming: false + targetOriginID: crossplane.io + trustedKeyGroups: + enabled: false + trustedSigners: + enabled: false + viewerProtocolPolicy: allow-all + defaultRootObject: index.html + enabled: true + httpVersion: http2 + isIPV6Enabled: true + logging: + bucket: '' + enabled: false + includeCookies: false + prefix: '' + originGroups: {} + origins: + items: + - connectionAttempts: 3 + connectionTimeout: 10 + customHeaders: {} + customOriginConfig: + httpPort: 8080 + httpSPort: 443 + originKeepaliveTimeout: 5 + originProtocolPolicy: http-only + originReadTimeout: 10 + originSSLProtocols: + items: + - TLSv1 + - TLSv1.1 + - TLSv1.2 + domainName: crossplane.io + id: crossplane.io + originShield: + enabled: false + priceClass: PriceClass_200 + restrictions: + geoRestriction: + restrictionType: none + region: ap-northeast-2 + providerConfigRef: + name: crossplane +status: + conditions: + - lastTransitionTime: "2024-01-11T06:23:18Z" + reason: ReconcileSuccess + status: "True" + type: Synced + - lastTransitionTime: "2024-01-10T03:23:02Z" + reason: Available + status: "True" + type: Ready diff --git a/resource_customizations/cloudfront.aws.crossplane.io/Distribution/testdata/progressing.yaml b/resource_customizations/cloudfront.aws.crossplane.io/Distribution/testdata/progressing.yaml new file mode 100644 index 0000000000000..3dbde7e040867 --- /dev/null +++ b/resource_customizations/cloudfront.aws.crossplane.io/Distribution/testdata/progressing.yaml @@ -0,0 +1,92 @@ +apiVersion: cloudfront.aws.crossplane.io/v1alpha1 +kind: Distribution +metadata: + creationTimestamp: '2023-06-16T04:42:04Z' + generation: 37 + name: crossplane.io + resourceVersion: '254326453' + uid: fd357670-b762-4285-ae83-00859c40dd6b +spec: + deletionPolicy: Orphan + forProvider: + distributionConfig: + comment: 'crossplane' + customErrorResponses: + items: [] + defaultCacheBehavior: + allowedMethods: + cachedMethods: + items: + - HEAD + - GET + items: + - GET + - HEAD + compress: false + defaultTTL: 600 + fieldLevelEncryptionID: "" + forwardedValues: + cookies: + forward: none + headers: + items: [] + queryString: false + queryStringCacheKeys: {} + functionAssociations: {} + lambdaFunctionAssociations: {} + maxTTL: 600 + minTTL: 0 + smoothStreaming: false + targetOriginID: crossplane.io + trustedKeyGroups: + enabled: false + trustedSigners: + enabled: false + viewerProtocolPolicy: allow-all + defaultRootObject: index.html + enabled: true + httpVersion: http2 + isIPV6Enabled: true + logging: + bucket: "" + enabled: false + includeCookies: false + prefix: "" + originGroups: {} + origins: + items: + - connectionAttempts: 3 + connectionTimeout: 10 + customHeaders: {} + customOriginConfig: + httpPort: 8080 + httpSPort: 443 + originKeepaliveTimeout: 5 + originProtocolPolicy: http-only + originReadTimeout: 10 + originSSLProtocols: + items: + - TLSv1 + - TLSv1.1 + - TLSv1.2 + domainName: crossplane.io + id: crossplane.io + originShield: + enabled: false + priceClass: PriceClass_200 + restrictions: + geoRestriction: + restrictionType: none + region: ap-northeast-2 + providerConfigRef: + name: crossplane +status: + conditions: + - lastTransitionTime: '2024-01-11T08:11:27Z' + reason: Unavailable + status: 'False' + type: Ready + - lastTransitionTime: '2024-01-11T08:11:02Z' + reason: ReconcileSuccess + status: 'True' + type: Synced diff --git a/resource_customizations/cloudfront.aws.crossplane.io/Distribution/testdata/progressing_creating.yaml b/resource_customizations/cloudfront.aws.crossplane.io/Distribution/testdata/progressing_creating.yaml new file mode 100644 index 0000000000000..122ab330d593b --- /dev/null +++ b/resource_customizations/cloudfront.aws.crossplane.io/Distribution/testdata/progressing_creating.yaml @@ -0,0 +1,92 @@ +apiVersion: cloudfront.aws.crossplane.io/v1alpha1 +kind: Distribution +metadata: + creationTimestamp: "2023-09-07T01:01:16Z" + generation: 121 + name: crossplane.io + resourceVersion: "254225966" + uid: 531d989c-a3d2-4ab4-841d-ab380cce0bdb +spec: + deletionPolicy: Orphan + forProvider: + distributionConfig: + comment: 'crossplane' + customErrorResponses: + items: [] + defaultCacheBehavior: + allowedMethods: + cachedMethods: + items: + - HEAD + - GET + items: + - GET + - HEAD + compress: false + defaultTTL: 600 + fieldLevelEncryptionID: "" + forwardedValues: + cookies: + forward: none + headers: + items: [] + queryString: false + queryStringCacheKeys: {} + functionAssociations: {} + lambdaFunctionAssociations: {} + maxTTL: 600 + minTTL: 0 + smoothStreaming: false + targetOriginID: crossplane.io + trustedKeyGroups: + enabled: false + trustedSigners: + enabled: false + viewerProtocolPolicy: allow-all + defaultRootObject: index.html + enabled: true + httpVersion: http2 + isIPV6Enabled: true + logging: + bucket: "" + enabled: false + includeCookies: false + prefix: "" + originGroups: {} + origins: + items: + - connectionAttempts: 3 + connectionTimeout: 10 + customHeaders: {} + customOriginConfig: + httpPort: 8080 + httpSPort: 443 + originKeepaliveTimeout: 5 + originProtocolPolicy: http-only + originReadTimeout: 10 + originSSLProtocols: + items: + - TLSv1 + - TLSv1.1 + - TLSv1.2 + domainName: crossplane.io + id: crossplane.io + originShield: + enabled: false + priceClass: PriceClass_200 + restrictions: + geoRestriction: + restrictionType: none + region: ap-northeast-2 + providerConfigRef: + name: crossplane +status: + conditions: + - lastTransitionTime: "2023-11-16T04:44:27Z" + reason: Creating + status: "False" + type: Ready + - lastTransitionTime: "2023-11-16T04:44:25Z" + reason: ReconcileSuccess + status: "True" + type: Synced diff --git a/resource_customizations/cloudfront.aws.crossplane.io/Distribution/testdata/progressing_noStatus.yaml b/resource_customizations/cloudfront.aws.crossplane.io/Distribution/testdata/progressing_noStatus.yaml new file mode 100644 index 0000000000000..2985ec2dea657 --- /dev/null +++ b/resource_customizations/cloudfront.aws.crossplane.io/Distribution/testdata/progressing_noStatus.yaml @@ -0,0 +1,82 @@ +apiVersion: cloudfront.aws.crossplane.io/v1alpha1 +kind: Distribution +metadata: + creationTimestamp: "2023-09-07T01:01:16Z" + generation: 121 + name: crossplane.io + resourceVersion: "254225966" + uid: 531d989c-a3d2-4ab4-841d-ab380cce0bdb +spec: + deletionPolicy: Orphan + forProvider: + distributionConfig: + comment: 'crossplane' + customErrorResponses: + items: [] + defaultCacheBehavior: + allowedMethods: + cachedMethods: + items: + - HEAD + - GET + items: + - GET + - HEAD + compress: false + defaultTTL: 600 + fieldLevelEncryptionID: "" + forwardedValues: + cookies: + forward: none + headers: + items: [] + queryString: false + queryStringCacheKeys: {} + functionAssociations: {} + lambdaFunctionAssociations: {} + maxTTL: 600 + minTTL: 0 + smoothStreaming: false + targetOriginID: crossplane.io + trustedKeyGroups: + enabled: false + trustedSigners: + enabled: false + viewerProtocolPolicy: allow-all + defaultRootObject: index.html + enabled: true + httpVersion: http2 + isIPV6Enabled: true + logging: + bucket: "" + enabled: false + includeCookies: false + prefix: "" + originGroups: {} + origins: + items: + - connectionAttempts: 3 + connectionTimeout: 10 + customHeaders: {} + customOriginConfig: + httpPort: 8080 + httpSPort: 443 + originKeepaliveTimeout: 5 + originProtocolPolicy: http-only + originReadTimeout: 10 + originSSLProtocols: + items: + - TLSv1 + - TLSv1.1 + - TLSv1.2 + domainName: crossplane.io + id: crossplane.io + originShield: + enabled: false + priceClass: PriceClass_200 + restrictions: + geoRestriction: + restrictionType: none + region: ap-northeast-2 + providerConfigRef: + name: crossplane diff --git a/resource_customizations/cloudfront.aws.crossplane.io/Distribution/testdata/progressing_noavailable.yaml b/resource_customizations/cloudfront.aws.crossplane.io/Distribution/testdata/progressing_noavailable.yaml new file mode 100644 index 0000000000000..7a47b0f48eea7 --- /dev/null +++ b/resource_customizations/cloudfront.aws.crossplane.io/Distribution/testdata/progressing_noavailable.yaml @@ -0,0 +1,88 @@ +apiVersion: cloudfront.aws.crossplane.io/v1alpha1 +kind: Distribution +metadata: + generation: 1 + name: crossplane.io + resourceVersion: "261937039" + uid: a52c105f-b0e1-4027-aa19-7e93f269f2a6 +spec: + deletionPolicy: Orphan + forProvider: + distributionConfig: + comment: 'crossplane' + customErrorResponses: + items: [] + defaultCacheBehavior: + allowedMethods: + cachedMethods: + items: + - HEAD + - GET + items: + - GET + - HEAD + compress: false + defaultTTL: 600 + fieldLevelEncryptionID: "" + forwardedValues: + cookies: + forward: none + headers: + items: [] + queryString: false + queryStringCacheKeys: {} + functionAssociations: {} + lambdaFunctionAssociations: {} + maxTTL: 600 + minTTL: 0 + smoothStreaming: false + targetOriginID: crossplane.io + trustedKeyGroups: + enabled: false + trustedSigners: + enabled: false + viewerProtocolPolicy: allow-all + defaultRootObject: index.html + enabled: true + httpVersion: http2 + isIPV6Enabled: true + logging: + bucket: "" + enabled: false + includeCookies: false + prefix: "" + originGroups: {} + origins: + items: + - connectionAttempts: 3 + connectionTimeout: 10 + customHeaders: {} + customOriginConfig: + httpPort: 8080 + httpSPort: 443 + originKeepaliveTimeout: 5 + originProtocolPolicy: http-only + originReadTimeout: 10 + originSSLProtocols: + items: + - TLSv1 + - TLSv1.1 + - TLSv1.2 + domainName: crossplane.io + id: crossplane.io + originShield: + enabled: false + priceClass: PriceClass_200 + restrictions: + geoRestriction: + restrictionType: none + region: ap-northeast-2 + providerConfigRef: + name: crossplane +status: + atProvider: {} + conditions: + - lastTransitionTime: "2024-01-17T07:20:35Z" + reason: ReconcileSuccess + status: "True" + type: Synced diff --git a/resource_customizations/cloudfront.aws.crossplane.io/Distribution/testdata/suspended.yaml b/resource_customizations/cloudfront.aws.crossplane.io/Distribution/testdata/suspended.yaml new file mode 100644 index 0000000000000..d15713737ff72 --- /dev/null +++ b/resource_customizations/cloudfront.aws.crossplane.io/Distribution/testdata/suspended.yaml @@ -0,0 +1,94 @@ +apiVersion: cloudfront.aws.crossplane.io/v1alpha1 +kind: Distribution +metadata: + annotations: + crossplane.io/paused: "true" + creationTimestamp: "2023-06-16T04:42:04Z" + generation: 34 + name: crossplane.io + resourceVersion: "254259056" + uid: fd357670-b762-4285-ae83-00859c40dd6b +spec: + deletionPolicy: Orphan + forProvider: + distributionConfig: + comment: 'crossplane' + customErrorResponses: + items: [] + defaultCacheBehavior: + allowedMethods: + cachedMethods: + items: + - HEAD + - GET + items: + - GET + - HEAD + compress: false + defaultTTL: 600 + fieldLevelEncryptionID: "" + forwardedValues: + cookies: + forward: none + headers: + items: [] + queryString: false + queryStringCacheKeys: {} + functionAssociations: {} + lambdaFunctionAssociations: {} + maxTTL: 600 + minTTL: 0 + smoothStreaming: false + targetOriginID: crossplane.io + trustedKeyGroups: + enabled: false + trustedSigners: + enabled: false + viewerProtocolPolicy: allow-all + defaultRootObject: index.html + enabled: true + httpVersion: http2 + isIPV6Enabled: true + logging: + bucket: "" + enabled: false + includeCookies: false + prefix: "" + originGroups: {} + origins: + items: + - connectionAttempts: 3 + connectionTimeout: 10 + customHeaders: {} + customOriginConfig: + httpPort: 8080 + httpSPort: 443 + originKeepaliveTimeout: 5 + originProtocolPolicy: http-only + originReadTimeout: 10 + originSSLProtocols: + items: + - TLSv1 + - TLSv1.1 + - TLSv1.2 + domainName: crossplane.io + id: crossplane.io + originShield: + enabled: false + priceClass: PriceClass_200 + restrictions: + geoRestriction: + restrictionType: none + region: ap-northeast-2 + providerConfigRef: + name: crossplane +status: + conditions: + - lastTransitionTime: "2023-10-16T07:40:47Z" + reason: Available + status: "True" + type: Ready + - lastTransitionTime: "2024-01-11T06:59:47Z" + reason: ReconcilePaused + status: "False" + type: Synced diff --git a/resource_customizations/db.atlasgo.io/AtlasMigration/health.lua b/resource_customizations/db.atlasgo.io/AtlasMigration/health.lua new file mode 100644 index 0000000000000..332b43ec21314 --- /dev/null +++ b/resource_customizations/db.atlasgo.io/AtlasMigration/health.lua @@ -0,0 +1,37 @@ +hs = {} + +local function readyCond(obj) + if obj.status ~= nil and obj.status.conditions ~= nil then + for _, condition in ipairs(obj.status.conditions) do + if condition.type == "Ready" then + return condition + end + end + end + return nil +end + +local ready = readyCond(obj) + +if ready == nil then + hs.status = "Progressing" + hs.message = "Waiting for Atlas Operator" + return hs +end + +if ready.status == "True" then + hs.status = "Healthy" + hs.message = ready.reason + return hs +end + +if ready.reason == "Reconciling" then + hs.status = "Progressing" +else + hs.status = "Degraded" +end + +hs.message = ready.reason + +return hs + diff --git a/resource_customizations/db.atlasgo.io/AtlasMigration/health_test.yaml b/resource_customizations/db.atlasgo.io/AtlasMigration/health_test.yaml new file mode 100644 index 0000000000000..b827f89c0bdf2 --- /dev/null +++ b/resource_customizations/db.atlasgo.io/AtlasMigration/health_test.yaml @@ -0,0 +1,13 @@ +tests: +- healthStatus: + status: Progressing + message: "Reconciling" + inputPath: testdata/progressing.yaml +- healthStatus: + status: Degraded + message: "Migrating" + inputPath: testdata/degraded.yaml +- healthStatus: + status: Healthy + message: "Applied" + inputPath: testdata/healthy.yaml diff --git a/resource_customizations/db.atlasgo.io/AtlasMigration/testdata/degraded.yaml b/resource_customizations/db.atlasgo.io/AtlasMigration/testdata/degraded.yaml new file mode 100644 index 0000000000000..ee51f15e48241 --- /dev/null +++ b/resource_customizations/db.atlasgo.io/AtlasMigration/testdata/degraded.yaml @@ -0,0 +1,29 @@ +apiVersion: db.atlasgo.io/v1alpha1 +kind: AtlasMigration +metadata: + annotations: + kubectl.kubernetes.io/last-applied-configuration: | + {"apiVersion":"db.atlasgo.io/v1alpha1","kind":"AtlasMigration","metadata":{"annotations":{},"name":"atlasmigration-sample","namespace":"default"},"spec":{"dir":{"configMapRef":{"name":"migration-dir"}},"urlFrom":{"secretKeyRef":{"key":"url","name":"mysql-credentials"}}}} + creationTimestamp: "2023-11-16T08:37:23Z" + generation: 1 + name: atlasmigration-sample + namespace: default + resourceVersion: "49923" + uid: 0d5bc3d6-750e-4f5a-82a3-8b9173106ef4 +spec: + dir: + configMapRef: + name: migration-dir + urlFrom: + secretKeyRef: + key: url + name: mysql-credentials +status: + conditions: + - lastTransitionTime: "2023-11-16T08:37:23Z" + message: 'Error: checksum mismatch' + reason: Migrating + status: "False" + type: Ready + lastApplied: 0 + observed_hash: "" diff --git a/resource_customizations/db.atlasgo.io/AtlasMigration/testdata/healthy.yaml b/resource_customizations/db.atlasgo.io/AtlasMigration/testdata/healthy.yaml new file mode 100644 index 0000000000000..4a7a91324d196 --- /dev/null +++ b/resource_customizations/db.atlasgo.io/AtlasMigration/testdata/healthy.yaml @@ -0,0 +1,30 @@ +apiVersion: db.atlasgo.io/v1alpha1 +kind: AtlasMigration +metadata: + annotations: + kubectl.kubernetes.io/last-applied-configuration: | + {"apiVersion":"db.atlasgo.io/v1alpha1","kind":"AtlasMigration","metadata":{"annotations":{},"name":"atlasmigration-sample","namespace":"default"},"spec":{"dir":{"configMapRef":{"name":"migration-dir"}},"urlFrom":{"secretKeyRef":{"key":"url","name":"mysql-credentials"}}}} + creationTimestamp: "2023-11-16T08:37:23Z" + generation: 1 + name: atlasmigration-sample + namespace: default + resourceVersion: "50387" + uid: 0d5bc3d6-750e-4f5a-82a3-8b9173106ef4 +spec: + dir: + configMapRef: + name: migration-dir + urlFrom: + secretKeyRef: + key: url + name: mysql-credentials +status: + conditions: + - lastTransitionTime: "2023-11-16T08:46:27Z" + message: "" + reason: Applied + status: "True" + type: Ready + lastApplied: 1700124387 + lastAppliedVersion: "20230316085611" + observed_hash: 4969b3c84c097ff61a9f9722b595a66c1a4473bd85fdd282107b98a92db8a43b diff --git a/resource_customizations/db.atlasgo.io/AtlasMigration/testdata/progressing.yaml b/resource_customizations/db.atlasgo.io/AtlasMigration/testdata/progressing.yaml new file mode 100644 index 0000000000000..024f9f7558d78 --- /dev/null +++ b/resource_customizations/db.atlasgo.io/AtlasMigration/testdata/progressing.yaml @@ -0,0 +1,30 @@ +apiVersion: db.atlasgo.io/v1alpha1 +kind: AtlasMigration +metadata: + annotations: + kubectl.kubernetes.io/last-applied-configuration: | + {"apiVersion":"db.atlasgo.io/v1alpha1","kind":"AtlasMigration","metadata":{"annotations":{},"name":"atlasmigration-sample","namespace":"default"},"spec":{"dir":{"configMapRef":{"name":"migration-dir"}},"urlFrom":{"secretKeyRef":{"key":"url","name":"mysql-credentials"}}}} + creationTimestamp: "2023-11-16T08:37:23Z" + generation: 1 + name: atlasmigration-sample + namespace: default + resourceVersion: "50387" + uid: 0d5bc3d6-750e-4f5a-82a3-8b9173106ef4 +spec: + dir: + configMapRef: + name: migration-dir + urlFrom: + secretKeyRef: + key: url + name: mysql-credentials +status: + conditions: + - lastTransitionTime: "2023-11-16T08:46:27Z" + message: "Current migration data has changed" + reason: "Reconciling" + status: "False" + type: Ready + lastApplied: 1700124387 + lastAppliedVersion: "20230316085611" + observed_hash: 4969b3c84c097ff61a9f9722b595a66c1a4473bd85fdd282107b98a92db8a43b diff --git a/resource_customizations/db.atlasgo.io/AtlasSchema/health.lua b/resource_customizations/db.atlasgo.io/AtlasSchema/health.lua new file mode 100644 index 0000000000000..c66d66d15b5a8 --- /dev/null +++ b/resource_customizations/db.atlasgo.io/AtlasSchema/health.lua @@ -0,0 +1,37 @@ +hs = {} + +local function readyCond(obj) + if obj.status ~= nil and obj.status.conditions ~= nil then + for _, condition in ipairs(obj.status.conditions) do + if condition.type == "Ready" then + return condition + end + end + end + return nil +end + +local ready = readyCond(obj) + +if ready == nil then + hs.status = "Progressing" + hs.message = "Waiting for Atlas Operator" + return hs +end + +if ready.status == "True" then + hs.status = "Healthy" + hs.message = ready.reason + return hs +end + +if ready.message == "Reconciling" or ready.message == "GettingDevDB" then + hs.status = "Progressing" +else + hs.status = "Degraded" +end + +hs.message = ready.reason + +return hs + diff --git a/resource_customizations/db.atlasgo.io/AtlasSchema/health_test.yaml b/resource_customizations/db.atlasgo.io/AtlasSchema/health_test.yaml new file mode 100644 index 0000000000000..0fe102f299138 --- /dev/null +++ b/resource_customizations/db.atlasgo.io/AtlasSchema/health_test.yaml @@ -0,0 +1,13 @@ +tests: +- healthStatus: + status: Progressing + message: "Reconciling" + inputPath: testdata/progressing.yaml +- healthStatus: + status: Degraded + message: "ApplyingSchema" + inputPath: testdata/degraded.yaml +- healthStatus: + status: Healthy + message: "Applied" + inputPath: testdata/healthy.yaml diff --git a/resource_customizations/db.atlasgo.io/AtlasSchema/testdata/degraded.yaml b/resource_customizations/db.atlasgo.io/AtlasSchema/testdata/degraded.yaml new file mode 100644 index 0000000000000..08383988e996a --- /dev/null +++ b/resource_customizations/db.atlasgo.io/AtlasSchema/testdata/degraded.yaml @@ -0,0 +1,38 @@ +apiVersion: db.atlasgo.io/v1alpha1 +kind: AtlasSchema +metadata: + annotations: + kubectl.kubernetes.io/last-applied-configuration: | + {"apiVersion":"db.atlasgo.io/v1alpha1","kind":"AtlasSchema","metadata":{"annotations":{},"name":"atlasschema-mysql","namespace":"default"},"spec":{"schema":{"sql":"create table users (\n id int not null auto_increment,\n name varchar(255) not null,\n email varchar(255) unique not null,\n short_bio varchar(255) not null,\n primary key (id)\n);\n"},"urlFrom":{"secretKeyRef":{"key":"url","name":"mysql-credentials"}}}} + creationTimestamp: "2023-11-15T14:33:18Z" + generation: 2 + name: atlasschema-mysql + namespace: default + resourceVersion: "46659" + uid: 54a4cdfc-e4f9-4c3d-934c-e08b6122e38a +spec: + schema: + sql: | + xcreate table users ( + id int not null auto_increment, + name varchar(255) not null, + email varchar(255) unique not null, + short_bio varchar(255) not null, + primary key (id) + ); + urlFrom: + secretKeyRef: + key: url + name: mysql-credentials +status: + conditions: + - lastTransitionTime: "2023-11-15T14:38:41Z" + message: |- + Error: sql/migrate: read migration directory state: sql/migrate: execute: executing statement "xcreate table users (\n id int not null auto_increment,\n name varchar(255) not null,\n email varchar(255) unique not null,\n short_bio varchar(255) not null,\n primary key (id)\n);" from version "schema": Error 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'xcreate table users ( + id int not null auto_increment, + name varchar(255) not ' at line 1 + reason: ApplyingSchema + status: "False" + type: Ready + last_applied: 1700058814 + observed_hash: ddfe666707ddf5c2cc7625c2a0de89da51e54fc7caa6403db307146430d20d85 diff --git a/resource_customizations/db.atlasgo.io/AtlasSchema/testdata/healthy.yaml b/resource_customizations/db.atlasgo.io/AtlasSchema/testdata/healthy.yaml new file mode 100644 index 0000000000000..eca8ec497f09a --- /dev/null +++ b/resource_customizations/db.atlasgo.io/AtlasSchema/testdata/healthy.yaml @@ -0,0 +1,39 @@ +apiVersion: db.atlasgo.io/v1alpha1 +kind: AtlasSchema +metadata: + annotations: + kubectl.kubernetes.io/last-applied-configuration: | + {"apiVersion":"db.atlasgo.io/v1alpha1","kind":"AtlasSchema","metadata":{"annotations":{},"name":"atlasschema-mysql","namespace":"default"},"spec":{"schema":{"sql":"create table users (\n id int not null auto_increment,\n name varchar(255) not null,\n email varchar(255) unique not null,\n short_bio varchar(255) not null,\n primary key (id)\n);\n"},"urlFrom":{"secretKeyRef":{"key":"url","name":"mysql-credentials"}}}} + creationTimestamp: "2023-11-15T14:33:18Z" + generation: 1 + name: atlasschema-mysql + namespace: default + resourceVersion: "46390" + uid: 54a4cdfc-e4f9-4c3d-934c-e08b6122e38a +spec: + schema: + sql: | + create table users ( + id int not null auto_increment, + name varchar(255) not null, + email varchar(255) unique not null, + short_bio varchar(255) not null, + primary key (id) + ); + urlFrom: + secretKeyRef: + key: url + name: mysql-credentials +status: + conditions: + - lastTransitionTime: "2023-11-15T14:33:34Z" + message: 'The schema has been applied successfully. Apply response: {"Driver":"mysql","URL":{"Scheme":"mysql","Opaque":"","User":{},"Host":"mysql.default:3306","Path":"/myapp","RawPath":"","OmitHost":false,"ForceQuery":false,"RawQuery":"parseTime=true","Fragment":"","RawFragment":"","Schema":"myapp"},"Changes":{"Applied":["CREATE + TABLE `users` (\n `id` int NOT NULL AUTO_INCREMENT,\n `name` varchar(255) + NOT NULL,\n `email` varchar(255) NOT NULL,\n `short_bio` varchar(255) NOT + NULL,\n PRIMARY KEY (`id`),\n UNIQUE INDEX `email` (`email`)\n) CHARSET utf8mb4 + COLLATE utf8mb4_0900_ai_ci"]}}' + reason: Applied + status: "True" + type: Ready + last_applied: 1700058814 + observed_hash: ddfe666707ddf5c2cc7625c2a0de89da51e54fc7caa6403db307146430d20d85 diff --git a/resource_customizations/db.atlasgo.io/AtlasSchema/testdata/progressing.yaml b/resource_customizations/db.atlasgo.io/AtlasSchema/testdata/progressing.yaml new file mode 100644 index 0000000000000..79d59ca768141 --- /dev/null +++ b/resource_customizations/db.atlasgo.io/AtlasSchema/testdata/progressing.yaml @@ -0,0 +1,35 @@ +apiVersion: db.atlasgo.io/v1alpha1 +kind: AtlasSchema +metadata: + annotations: + kubectl.kubernetes.io/last-applied-configuration: | + {"apiVersion":"db.atlasgo.io/v1alpha1","kind":"AtlasSchema","metadata":{"annotations":{},"name":"atlasschema-mysql","namespace":"default"},"spec":{"schema":{"sql":"create table users (\n id int not null auto_increment,\n name varchar(255) not null,\n email varchar(255) unique not null,\n short_bio varchar(255) not null,\n primary key (id)\n);\n"},"urlFrom":{"secretKeyRef":{"key":"url","name":"mysql-credentials"}}}} + creationTimestamp: "2023-11-15T14:33:18Z" + generation: 1 + name: atlasschema-mysql + namespace: default + resourceVersion: "46390" + uid: 54a4cdfc-e4f9-4c3d-934c-e08b6122e38a +spec: + schema: + sql: | + create table users ( + id int not null auto_increment, + name varchar(255) not null, + email varchar(255) unique not null, + short_bio varchar(255) not null, + primary key (id) + ); + urlFrom: + secretKeyRef: + key: url + name: mysql-credentials +status: + conditions: + - lastTransitionTime: "2023-11-15T14:33:34Z" + message: 'Reconciling' + reason: Reconciling + status: "False" + type: Ready + last_applied: 1700058814 + observed_hash: ddfe666707ddf5c2cc7625c2a0de89da51e54fc7caa6403db307146430d20d85 diff --git a/resource_customizations/kafka.banzaicloud.io/KafkaCluster/health.lua b/resource_customizations/kafka.banzaicloud.io/KafkaCluster/health.lua index d24afea652c2a..7422fd4104727 100644 --- a/resource_customizations/kafka.banzaicloud.io/KafkaCluster/health.lua +++ b/resource_customizations/kafka.banzaicloud.io/KafkaCluster/health.lua @@ -1,22 +1,17 @@ local health_status = {} if obj.status ~= nil then if obj.status.brokersState ~= nil then - local counter = 0 - local brokerReady = 0 - for i, broker in pairs(obj.status.brokersState) do - if (brokerReady <= tonumber(i)) then - brokerReady = tonumber(i)+1 - else - brokerReady = brokerReady - end - if broker.configurationState == "ConfigInSync" and broker.gracefulActionState.cruiseControlState == "GracefulUpscaleSucceeded" then - counter = counter + 1 - end - if broker.configurationState == "ConfigInSync" and broker.gracefulActionState.cruiseControlState == "GracefulDownscaleSucceeded" then - counter = counter + 1 + local numberBrokers = 0 + local healthyBrokers = 0 + for _, broker in pairs(obj.status.brokersState) do + numberBrokers = numberBrokers + 1 + if broker.configurationState == "ConfigInSync" then + if broker.gracefulActionState.cruiseControlState == "GracefulUpscaleSucceeded" or broker.gracefulActionState.cruiseControlState == "GracefulDownscaleSucceeded" then + healthyBrokers = healthyBrokers + 1 end + end end - if counter == brokerReady then + if numberBrokers == healthyBrokers then if obj.status.cruiseControlTopicStatus == "CruiseControlTopicReady" and obj.status.state == "ClusterRunning" then health_status.message = "Kafka Brokers, CruiseControl and cluster are in Healthy State." health_status.status = "Healthy" diff --git a/resource_customizations/kafka.banzaicloud.io/KafkaCluster/health_test.yaml b/resource_customizations/kafka.banzaicloud.io/KafkaCluster/health_test.yaml index 9446d882d941a..776cc02739326 100644 --- a/resource_customizations/kafka.banzaicloud.io/KafkaCluster/health_test.yaml +++ b/resource_customizations/kafka.banzaicloud.io/KafkaCluster/health_test.yaml @@ -14,4 +14,4 @@ tests: - healthStatus: status: Healthy message: "Kafka Brokers, CruiseControl and cluster are in Healthy State." - inputPath: testdata/healthy.yaml + inputPath: testdata/healthy.yaml \ No newline at end of file diff --git a/resource_customizations/kafka.banzaicloud.io/KafkaCluster/testdata/healthy.yaml b/resource_customizations/kafka.banzaicloud.io/KafkaCluster/testdata/healthy.yaml index 9dd791b9c39fe..44666fd6a83a5 100644 --- a/resource_customizations/kafka.banzaicloud.io/KafkaCluster/testdata/healthy.yaml +++ b/resource_customizations/kafka.banzaicloud.io/KafkaCluster/testdata/healthy.yaml @@ -20,21 +20,21 @@ spec: {} status: alertCount: 0 brokersState: - "0": + "101": configurationState: ConfigInSync gracefulActionState: cruiseControlState: GracefulUpscaleSucceeded errorMessage: CruiseControl not yet ready rackAwarenessState: | broker.rack=us-east-1,us-east-1c - "1": + "102": configurationState: ConfigInSync gracefulActionState: cruiseControlState: GracefulUpscaleSucceeded errorMessage: CruiseControl not yet ready rackAwarenessState: | broker.rack=us-east-1,us-east-1b - "2": + "103": configurationState: ConfigInSync gracefulActionState: cruiseControlState: GracefulUpscaleSucceeded diff --git a/resource_customizations/pxc.percona.com/PerconaXtraDBCluster/health.lua b/resource_customizations/pxc.percona.com/PerconaXtraDBCluster/health.lua index 9de2180197571..d614828d461f2 100644 --- a/resource_customizations/pxc.percona.com/PerconaXtraDBCluster/health.lua +++ b/resource_customizations/pxc.percona.com/PerconaXtraDBCluster/health.lua @@ -27,7 +27,7 @@ if obj.status ~= nil then if obj.status.state == "error" then hs.status = "Degraded" - hs.message = "Cluster is on error: " .. table.concat(obj.status.messages, ", ") + hs.message = "Cluster is on error: " .. table.concat(obj.status.message, ", ") return hs end diff --git a/resource_customizations/pxc.percona.com/PerconaXtraDBCluster/testdata/error.yaml b/resource_customizations/pxc.percona.com/PerconaXtraDBCluster/testdata/error.yaml index b6f1884be0819..4a373358dcd8c 100644 --- a/resource_customizations/pxc.percona.com/PerconaXtraDBCluster/testdata/error.yaml +++ b/resource_customizations/pxc.percona.com/PerconaXtraDBCluster/testdata/error.yaml @@ -12,7 +12,7 @@ status: pmm: {} proxysql: {} pxc: - image: '' + image: "" ready: 1 size: 2 status: error @@ -20,5 +20,5 @@ status: ready: 1 size: 2 state: error - messages: - - we lost node + message: + - we lost node diff --git a/resource_customizations/rollouts.kruise.io/Rollout/health.lua b/resource_customizations/rollouts.kruise.io/Rollout/health.lua new file mode 100644 index 0000000000000..5fd4ddb2a5486 --- /dev/null +++ b/resource_customizations/rollouts.kruise.io/Rollout/health.lua @@ -0,0 +1,31 @@ +hs={ status = "Progressing", message = "Rollout is still progressing" } + +if obj.metadata.generation == obj.status.observedGeneration then + + if obj.status.canaryStatus.currentStepState == "StepUpgrade" and obj.status.phase == "Progressing" then + hs.status = "Progressing" + hs.message = "Rollout is still progressing" + return hs + end + + if obj.status.canaryStatus.currentStepState == "StepPaused" and obj.status.phase == "Progressing" then + hs.status = "Suspended" + hs.message = "Rollout is Paused need manual intervention" + return hs + end + + if obj.status.canaryStatus.currentStepState == "Completed" and obj.status.phase == "Healthy" then + hs.status = "Healthy" + hs.message = "Rollout is Completed" + return hs + end + + if obj.status.canaryStatus.currentStepState == "StepPaused" and (obj.status.phase == "Terminating" or obj.status.phase == "Disabled") then + hs.status = "Degraded" + hs.message = "Rollout is Disabled or Terminating" + return hs + end + +end + +return hs diff --git a/resource_customizations/rollouts.kruise.io/Rollout/health_test.yaml b/resource_customizations/rollouts.kruise.io/Rollout/health_test.yaml new file mode 100644 index 0000000000000..c89ea3409ec77 --- /dev/null +++ b/resource_customizations/rollouts.kruise.io/Rollout/health_test.yaml @@ -0,0 +1,17 @@ +tests: + - healthStatus: + status: Healthy + message: "Rollout is Completed" + inputPath: testdata/healthy.yaml + - healthStatus: + status: Degraded + message: "Rollout is Disabled or Terminating" + inputPath: testdata/degraded.yaml + - healthStatus: + status: Progressing + message: "Rollout is still progressing" + inputPath: testdata/progressing.yaml + - healthStatus: + status: Suspended + message: "Rollout is Paused need manual intervention" + inputPath: testdata/suspended.yaml diff --git a/resource_customizations/rollouts.kruise.io/Rollout/testdata/degraded.yaml b/resource_customizations/rollouts.kruise.io/Rollout/testdata/degraded.yaml new file mode 100644 index 0000000000000..97c40f10a0c96 --- /dev/null +++ b/resource_customizations/rollouts.kruise.io/Rollout/testdata/degraded.yaml @@ -0,0 +1,50 @@ +apiVersion: rollouts.kruise.io/v1alpha1 +kind: Rollout +metadata: + name: rollouts-demo + namespace: default + annotations: + rollouts.kruise.io/rolling-style: partition + generation: 5 +spec: + objectRef: + workloadRef: + apiVersion: apps/v1 + kind: Deployment + name: workload-demo + strategy: + canary: + steps: + - replicas: 1 + pause: + duration: 0 + - replicas: 50% + pause: + duration: 0 + - replicas: 100% + +status: + canaryStatus: + canaryReadyReplicas: 1 + canaryReplicas: 1 + canaryRevision: 76fd76f75b + currentStepIndex: 1 + currentStepState: StepPaused + lastUpdateTime: '2023-09-23T11:44:39Z' + message: BatchRelease is at state Ready, rollout-id , step 1 + observedWorkloadGeneration: 7 + podTemplateHash: 76fd76f75b + rolloutHash: 77cxd69w47b7bwddwv2w7vxvb4xxdbwcx9x289vw69w788w4w6z4x8dd4vbz2zbw + stableRevision: 6bfdfb5bfb + conditions: + - lastTransitionTime: '2023-09-23T11:44:09Z' + lastUpdateTime: '2023-09-23T11:44:09Z' + message: Rollout is in Progressing + reason: InRolling + status: 'True' + type: Progressing + message: >- + Rollout is in step(1/3), and you need manually confirm to enter the next + step + observedGeneration: 5 + phase: Disabled diff --git a/resource_customizations/rollouts.kruise.io/Rollout/testdata/healthy.yaml b/resource_customizations/rollouts.kruise.io/Rollout/testdata/healthy.yaml new file mode 100644 index 0000000000000..77743b50007ad --- /dev/null +++ b/resource_customizations/rollouts.kruise.io/Rollout/testdata/healthy.yaml @@ -0,0 +1,56 @@ +apiVersion: rollouts.kruise.io/v1alpha1 +kind: Rollout +metadata: + name: rollouts-demo + namespace: default + annotations: + rollouts.kruise.io/rolling-style: partition + generation: 7 +spec: + objectRef: + workloadRef: + apiVersion: apps/v1 + kind: Deployment + name: workload-demo + strategy: + canary: + steps: + - replicas: 1 + pause: + duration: 0 + - replicas: 50% + pause: + duration: 0 + - replicas: 100% + +status: + canaryStatus: + canaryReadyReplicas: 10 + canaryReplicas: 10 + canaryRevision: 76fd76f75b + currentStepIndex: 3 + currentStepState: Completed + lastUpdateTime: '2023-09-23T11:48:58Z' + message: BatchRelease is at state Ready, rollout-id , step 3 + observedWorkloadGeneration: 22 + podTemplateHash: 76fd76f75b + rolloutHash: 77cxd69w47b7bwddwv2w7vxvb4xxdbwcx9x289vw69w788w4w6z4x8dd4vbz2zbw + stableRevision: 6bfdfb5bfb + conditions: + - lastTransitionTime: '2023-09-23T11:44:09Z' + lastUpdateTime: '2023-09-23T11:44:09Z' + message: Rollout progressing has been completed + reason: Completed + status: 'False' + type: Progressing + - lastTransitionTime: '2023-09-23T11:49:01Z' + lastUpdateTime: '2023-09-23T11:49:01Z' + message: '' + reason: '' + status: 'True' + type: Succeeded + message: Rollout progressing has been completed + observedGeneration: 7 + phase: Healthy + + diff --git a/resource_customizations/rollouts.kruise.io/Rollout/testdata/progressing.yaml b/resource_customizations/rollouts.kruise.io/Rollout/testdata/progressing.yaml new file mode 100644 index 0000000000000..f84d395867530 --- /dev/null +++ b/resource_customizations/rollouts.kruise.io/Rollout/testdata/progressing.yaml @@ -0,0 +1,48 @@ +apiVersion: rollouts.kruise.io/v1alpha1 +kind: Rollout +metadata: + name: rollouts-demo + namespace: default + annotations: + rollouts.kruise.io/rolling-style: partition + generation: 5 +spec: + objectRef: + workloadRef: + apiVersion: apps/v1 + kind: Deployment + name: workload-demo + strategy: + canary: + steps: + - replicas: 1 + pause: + duration: 0 + - replicas: 50% + pause: + duration: 0 + - replicas: 100% + +status: + canaryStatus: + canaryReadyReplicas: 0 + canaryReplicas: 1 + canaryRevision: 76fd76f75b + currentStepIndex: 1 + currentStepState: StepUpgrade + lastUpdateTime: '2023-09-23T11:44:12Z' + message: BatchRelease is at state Verifying, rollout-id , step 1 + observedWorkloadGeneration: 6 + podTemplateHash: 76fd76f75b + rolloutHash: 77cxd69w47b7bwddwv2w7vxvb4xxdbwcx9x289vw69w788w4w6z4x8dd4vbz2zbw + stableRevision: 6bfdfb5bfb + conditions: + - lastTransitionTime: '2023-09-23T11:44:09Z' + lastUpdateTime: '2023-09-23T11:44:09Z' + message: Rollout is in Progressing + reason: InRolling + status: 'True' + type: Progressing + message: Rollout is in step(1/3), and upgrade workload to new version + observedGeneration: 5 + phase: Progressing diff --git a/resource_customizations/rollouts.kruise.io/Rollout/testdata/suspended.yaml b/resource_customizations/rollouts.kruise.io/Rollout/testdata/suspended.yaml new file mode 100644 index 0000000000000..77a67129a248e --- /dev/null +++ b/resource_customizations/rollouts.kruise.io/Rollout/testdata/suspended.yaml @@ -0,0 +1,50 @@ +apiVersion: rollouts.kruise.io/v1alpha1 +kind: Rollout +metadata: + name: rollouts-demo + namespace: default + annotations: + rollouts.kruise.io/rolling-style: partition + generation: 5 +spec: + objectRef: + workloadRef: + apiVersion: apps/v1 + kind: Deployment + name: workload-demo + strategy: + canary: + steps: + - replicas: 1 + pause: + duration: 0 + - replicas: 50% + pause: + duration: 0 + - replicas: 100% + +status: + canaryStatus: + canaryReadyReplicas: 1 + canaryReplicas: 1 + canaryRevision: 76fd76f75b + currentStepIndex: 1 + currentStepState: StepPaused + lastUpdateTime: '2023-09-23T11:44:39Z' + message: BatchRelease is at state Ready, rollout-id , step 1 + observedWorkloadGeneration: 7 + podTemplateHash: 76fd76f75b + rolloutHash: 77cxd69w47b7bwddwv2w7vxvb4xxdbwcx9x289vw69w788w4w6z4x8dd4vbz2zbw + stableRevision: 6bfdfb5bfb + conditions: + - lastTransitionTime: '2023-09-23T11:44:09Z' + lastUpdateTime: '2023-09-23T11:44:09Z' + message: Rollout is in Progressing + reason: InRolling + status: 'True' + type: Progressing + message: >- + Rollout is in step(1/3), and you need manually confirm to enter the next + step + observedGeneration: 5 + phase: Progressing diff --git a/resource_customizations/route53.aws.crossplane.io/ResourceRecordSet/health_test.yaml b/resource_customizations/route53.aws.crossplane.io/ResourceRecordSet/health_test.yaml new file mode 100644 index 0000000000000..aa83951d5a2db --- /dev/null +++ b/resource_customizations/route53.aws.crossplane.io/ResourceRecordSet/health_test.yaml @@ -0,0 +1,25 @@ +tests: +- healthStatus: + status: Progressing + message: Waiting for resourcrecordset to be available + inputPath: testdata/progressing_creating.yaml +- healthStatus: + status: Progressing + message: Waiting for resourcrecordset to be created + inputPath: testdata/progressing_noStatus.yaml +- healthStatus: + status: Degraded + message: >- + create failed: failed to create the ResourceRecordSet resource: + InvalidChangeBatch: [RRSet of type CNAME with DNS name + www.crossplane.io. is not permitted as it conflicts with other + records with the same DNS name in zone crossplane.io.] + inputPath: testdata/degraded_reconcileError.yaml +- healthStatus: + status: Suspended + message: ReconcilePaused + inputPath: testdata/suspended_reconcilePaused.yaml +- healthStatus: + status: Healthy + message: Available + inputPath: testdata/healthy.yaml diff --git a/resource_customizations/route53.aws.crossplane.io/ResourceRecordSet/heatlh.lua b/resource_customizations/route53.aws.crossplane.io/ResourceRecordSet/heatlh.lua new file mode 100644 index 0000000000000..0cf5253e910ff --- /dev/null +++ b/resource_customizations/route53.aws.crossplane.io/ResourceRecordSet/heatlh.lua @@ -0,0 +1,41 @@ +local hs = {} +if obj.status ~= nil then + if obj.status.conditions ~= nil then + local ready = false + local synced = false + local suspended = false + for i, condition in ipairs(obj.status.conditions) do + + if condition.type == "Ready" then + ready = condition.status == "True" + ready_message = condition.reason + elseif condition.type == "Synced" then + synced = condition.status == "True" + if condition.reason == "ReconcileError" then + synced_message = condition.message + elseif condition.reason == "ReconcilePaused" then + suspended = true + suspended_message = condition.reason + end + end + end + if ready and synced then + hs.status = "Healthy" + hs.message = ready_message + elseif synced == false and suspended == true then + hs.status = "Suspended" + hs.message = suspended_message + elseif ready == false and synced == true and suspended == false then + hs.status = "Progressing" + hs.message = "Waiting for resourcrecordset to be available" + else + hs.status = "Degraded" + hs.message = synced_message + end + return hs + end +end + +hs.status = "Progressing" +hs.message = "Waiting for resourcrecordset to be created" +return hs diff --git a/resource_customizations/route53.aws.crossplane.io/ResourceRecordSet/testdata/degraded_reconcileError.yaml b/resource_customizations/route53.aws.crossplane.io/ResourceRecordSet/testdata/degraded_reconcileError.yaml new file mode 100644 index 0000000000000..31bc5123c7bfd --- /dev/null +++ b/resource_customizations/route53.aws.crossplane.io/ResourceRecordSet/testdata/degraded_reconcileError.yaml @@ -0,0 +1,35 @@ +apiVersion: route53.aws.crossplane.io/v1alpha1 +kind: ResourceRecordSet +metadata: + creationTimestamp: '2024-01-11T03:48:32Z' + generation: 1 + name: www-domain + resourceVersion: '187731157' + selfLink: /apis/route53.aws.crossplane.io/v1alpha1/resourcerecordsets/www-domain + uid: c9c85395-0830-4549-b255-e9e426663547 +spec: + providerConfigRef: + name: crossplane + forProvider: + resourceRecords: + - value: www.crossplane.io + setIdentifier: www + ttl: 60 + type: CNAME + weight: 0 + zoneId: ABCDEFGAB07CD +status: + conditions: + - lastTransitionTime: '2024-01-11T03:48:57Z' + message: >- + create failed: failed to create the ResourceRecordSet resource: + InvalidChangeBatch: [RRSet of type CNAME with DNS name + www.crossplane.io. is not permitted as it conflicts with other + records with the same DNS name in zone crossplane.io.] + reason: ReconcileError + status: 'False' + type: Synced + - lastTransitionTime: '2024-01-11T03:48:34Z' + reason: Creating + status: 'False' + type: Ready diff --git a/resource_customizations/route53.aws.crossplane.io/ResourceRecordSet/testdata/healthy.yaml b/resource_customizations/route53.aws.crossplane.io/ResourceRecordSet/testdata/healthy.yaml new file mode 100644 index 0000000000000..f808e46cc8c92 --- /dev/null +++ b/resource_customizations/route53.aws.crossplane.io/ResourceRecordSet/testdata/healthy.yaml @@ -0,0 +1,29 @@ +apiVersion: route53.aws.crossplane.io/v1alpha1 +kind: ResourceRecordSet +metadata: + creationTimestamp: "2023-11-16T04:44:19Z" + generation: 4 + name: www-domain + resourceVersion: "140397563" + selfLink: /apis/route53.aws.crossplane.io/v1alpha1/resourcerecordsets/www-domain + uid: 11f0d48d-134f-471b-9340-b6d45d953fcb +spec: + providerConfigRef: + name: crossplane + forProvider: + zoneId: A1B2C3D4 + type: A + aliasTarget: + dnsName: abcdefg.cloudfront.net. + evaluateTargetHealth: false + hostedZoneId: AZBZCZDEFG +status: + conditions: + - lastTransitionTime: "2023-11-16T04:44:27Z" + reason: Available + status: "True" + type: Ready + - lastTransitionTime: "2023-11-16T04:44:25Z" + reason: ReconcileSuccess + status: "True" + type: Synced diff --git a/resource_customizations/route53.aws.crossplane.io/ResourceRecordSet/testdata/progressing_creating.yaml b/resource_customizations/route53.aws.crossplane.io/ResourceRecordSet/testdata/progressing_creating.yaml new file mode 100644 index 0000000000000..abf59775fb8e0 --- /dev/null +++ b/resource_customizations/route53.aws.crossplane.io/ResourceRecordSet/testdata/progressing_creating.yaml @@ -0,0 +1,29 @@ +apiVersion: route53.aws.crossplane.io/v1alpha1 +kind: ResourceRecordSet +metadata: + creationTimestamp: "2023-11-16T04:44:19Z" + generation: 4 + name: www-domain + resourceVersion: "140397563" + selfLink: /apis/route53.aws.crossplane.io/v1alpha1/resourcerecordsets/www-domain + uid: 11f0d48d-134f-471b-9340-b6d45d953fcb +spec: + providerConfigRef: + name: crossplane + forProvider: + zoneId: A1B2C3D4 + type: A + aliasTarget: + dnsName: abcdefg.cloudfront.net. + evaluateTargetHealth: false + hostedZoneId: AZBZCZDEFG +status: + conditions: + - lastTransitionTime: "2023-11-16T04:44:27Z" + reason: Creating + status: "False" + type: Ready + - lastTransitionTime: "2023-11-16T04:44:25Z" + reason: ReconcileSuccess + status: "True" + type: Synced diff --git a/resource_customizations/route53.aws.crossplane.io/ResourceRecordSet/testdata/progressing_noStatus.yaml b/resource_customizations/route53.aws.crossplane.io/ResourceRecordSet/testdata/progressing_noStatus.yaml new file mode 100644 index 0000000000000..28d778d055050 --- /dev/null +++ b/resource_customizations/route53.aws.crossplane.io/ResourceRecordSet/testdata/progressing_noStatus.yaml @@ -0,0 +1,19 @@ +apiVersion: route53.aws.crossplane.io/v1alpha1 +kind: ResourceRecordSet +metadata: + creationTimestamp: "2023-11-16T04:44:19Z" + generation: 4 + name: www-domain + resourceVersion: "140397563" + selfLink: /apis/route53.aws.crossplane.io/v1alpha1/resourcerecordsets/www-domain + uid: 11f0d48d-134f-471b-9340-b6d45d953fcb +spec: + providerConfigRef: + name: crossplane + forProvider: + zoneId: A1B2C3D4 + type: A + aliasTarget: + dnsName: abcdefg.cloudfront.net. + evaluateTargetHealth: false + hostedZoneId: AZBZCZDEFG diff --git a/resource_customizations/route53.aws.crossplane.io/ResourceRecordSet/testdata/suspended_reconcilePaused.yaml b/resource_customizations/route53.aws.crossplane.io/ResourceRecordSet/testdata/suspended_reconcilePaused.yaml new file mode 100644 index 0000000000000..522c0e878dcf8 --- /dev/null +++ b/resource_customizations/route53.aws.crossplane.io/ResourceRecordSet/testdata/suspended_reconcilePaused.yaml @@ -0,0 +1,27 @@ +apiVersion: route53.aws.crossplane.io/v1alpha1 +kind: ResourceRecordSet +metadata: + annotations: + crossplane.io/paused: "true" + creationTimestamp: "2024-01-11T04:16:15Z" + generation: 1 + name: www-domain + resourceVersion: "187746011" + uid: 5517b419-5052-43d9-941e-c32f60d8c7e5 +spec: + providerConfigRef: + name: crossplane + forProvider: + resourceRecords: + - value: www.crossplane.io + setIdentifier: www + ttl: 60 + type: CNAME + weight: 0 + zoneId: ABCDEFGAB07CD +status: + conditions: + - lastTransitionTime: "2024-01-11T04:16:16Z" + reason: ReconcilePaused + status: "False" + type: Synced diff --git a/server/application/application.go b/server/application/application.go index 12484685e52b3..8ee16b93494c8 100644 --- a/server/application/application.go +++ b/server/application/application.go @@ -116,7 +116,10 @@ func NewServer( if appBroadcaster == nil { appBroadcaster = &broadcasterHandler{} } - appInformer.AddEventHandler(appBroadcaster) + _, err := appInformer.AddEventHandler(appBroadcaster) + if err != nil { + log.Error(err) + } s := &Server{ ns: namespace, appclientset: appclientset, @@ -149,7 +152,12 @@ func NewServer( // If the user does provide a "project," we can respond more specifically. If the user does not have access to the given // app name in the given project, we return "permission denied." If the app exists, but the project is different from func (s *Server) getAppEnforceRBAC(ctx context.Context, action, project, namespace, name string, getApp func() (*appv1.Application, error)) (*appv1.Application, error) { + user := session.Username(ctx) + if user == "" { + user = "Unknown user" + } logCtx := log.WithFields(map[string]interface{}{ + "user": user, "application": name, "namespace": namespace, }) @@ -1216,9 +1224,9 @@ func (s *Server) getCachedAppState(ctx context.Context, a *appv1.Application, ge return errors.New(argoutil.FormatAppConditions(conditions)) } _, err = s.Get(ctx, &application.ApplicationQuery{ - Name: pointer.StringPtr(a.GetName()), - AppNamespace: pointer.StringPtr(a.GetNamespace()), - Refresh: pointer.StringPtr(string(appv1.RefreshTypeNormal)), + Name: pointer.String(a.GetName()), + AppNamespace: pointer.String(a.GetNamespace()), + Refresh: pointer.String(string(appv1.RefreshTypeNormal)), }) if err != nil { return fmt.Errorf("error getting application by query: %w", err) @@ -1749,7 +1757,7 @@ func (s *Server) Sync(ctx context.Context, syncReq *application.ApplicationSyncR if a.DeletionTimestamp != nil { return nil, status.Errorf(codes.FailedPrecondition, "application is deleting") } - if a.Spec.SyncPolicy != nil && a.Spec.SyncPolicy.Automated != nil { + if a.Spec.SyncPolicy != nil && a.Spec.SyncPolicy.Automated != nil && !syncReq.GetDryRun() { if syncReq.GetRevision() != "" && syncReq.GetRevision() != text.FirstNonEmpty(source.TargetRevision, "HEAD") { return nil, status.Errorf(codes.FailedPrecondition, "Cannot sync to %s: auto-sync currently set to %s", syncReq.GetRevision(), source.TargetRevision) } diff --git a/server/application/application.proto b/server/application/application.proto index 53f161795902d..4736219cb4594 100644 --- a/server/application/application.proto +++ b/server/application/application.proto @@ -21,7 +21,7 @@ import "github.com/argoproj/argo-cd/v2/reposerver/repository/repository.proto"; message ApplicationQuery { // the application's name optional string name = 1; - // forces application reconciliation if set to true + // forces application reconciliation if set to 'hard' optional string refresh = 2; // the project names to restrict returned list applications repeated string projects = 3; diff --git a/server/application/application_test.go b/server/application/application_test.go index 56be539e48ac0..65600ad629d3f 100644 --- a/server/application/application_test.go +++ b/server/application/application_test.go @@ -76,7 +76,7 @@ func fakeRepo() *appsv1.Repository { func fakeCluster() *appsv1.Cluster { return &appsv1.Cluster{ - Server: "https://cluster-api.com", + Server: "https://cluster-api.example.com", Name: "fake-cluster", Config: appsv1.ClusterConfig{}, } @@ -209,7 +209,7 @@ func newTestAppServerWithEnforcerConfigure(f func(*rbac.Enforcer), t *testing.T, // populate the app informer with the fake objects appInformer := factory.Argoproj().V1alpha1().Applications().Informer() // TODO(jessesuen): probably should return cancel function so tests can stop background informer - //ctx, cancel := context.WithCancel(context.Background()) + // ctx, cancel := context.WithCancel(context.Background()) go appInformer.Run(ctx.Done()) if !k8scache.WaitForCacheSync(ctx.Done(), appInformer.HasSynced) { panic("Timed out waiting for caches to sync") @@ -503,7 +503,7 @@ spec: environment: default destination: namespace: ` + test.FakeDestNamespace + ` - server: https://cluster-api.com + server: https://cluster-api.example.com ` const fakeAppWithDestName = ` @@ -541,7 +541,7 @@ spec: environment: default destination: namespace: ` + test.FakeDestNamespace + ` - server: https://cluster-api.com + server: https://cluster-api.example.com ` func newTestAppWithDestName(opts ...func(app *appsv1.Application)) *appsv1.Application { @@ -797,22 +797,22 @@ func TestNoAppEnumeration(t *testing.T) { t.Run("UpdateSpec", func(t *testing.T) { _, err := appServer.UpdateSpec(adminCtx, &application.ApplicationUpdateSpecRequest{Name: pointer.String("test"), Spec: &appsv1.ApplicationSpec{ - Destination: appsv1.ApplicationDestination{Namespace: "default", Server: "https://cluster-api.com"}, + Destination: appsv1.ApplicationDestination{Namespace: "default", Server: "https://cluster-api.example.com"}, Source: &appsv1.ApplicationSource{RepoURL: "https://some-fake-source", Path: "."}, }}) assert.NoError(t, err) _, err = appServer.UpdateSpec(noRoleCtx, &application.ApplicationUpdateSpecRequest{Name: pointer.String("test"), Spec: &appsv1.ApplicationSpec{ - Destination: appsv1.ApplicationDestination{Namespace: "default", Server: "https://cluster-api.com"}, + Destination: appsv1.ApplicationDestination{Namespace: "default", Server: "https://cluster-api.example.com"}, Source: &appsv1.ApplicationSource{RepoURL: "https://some-fake-source", Path: "."}, }}) assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") _, err = appServer.UpdateSpec(adminCtx, &application.ApplicationUpdateSpecRequest{Name: pointer.String("doest-not-exist"), Spec: &appsv1.ApplicationSpec{ - Destination: appsv1.ApplicationDestination{Namespace: "default", Server: "https://cluster-api.com"}, + Destination: appsv1.ApplicationDestination{Namespace: "default", Server: "https://cluster-api.example.com"}, Source: &appsv1.ApplicationSource{RepoURL: "https://some-fake-source", Path: "."}, }}) assert.Equal(t, permissionDeniedErr.Error(), err.Error(), "error message must be _only_ the permission error, to avoid leaking information about app existence") _, err = appServer.UpdateSpec(adminCtx, &application.ApplicationUpdateSpecRequest{Name: pointer.String("doest-not-exist"), Project: pointer.String("test"), Spec: &appsv1.ApplicationSpec{ - Destination: appsv1.ApplicationDestination{Namespace: "default", Server: "https://cluster-api.com"}, + Destination: appsv1.ApplicationDestination{Namespace: "default", Server: "https://cluster-api.example.com"}, Source: &appsv1.ApplicationSource{RepoURL: "https://some-fake-source", Path: "."}, }}) assert.Equal(t, "rpc error: code = NotFound desc = applications.argoproj.io \"doest-not-exist\" not found", err.Error(), "when the request specifies a project, we can return the standard k8s error message") @@ -1136,7 +1136,7 @@ func testListAppsWithLabels(t *testing.T, appQuery application.ApplicationQuery, label: "!key2", expectedResult: []string{"App2", "App3"}}, } - //test valid scenarios + // test valid scenarios for _, validTest := range validTests { t.Run(validTest.testName, func(t *testing.T) { appQuery.Selector = &validTest.label @@ -1162,7 +1162,7 @@ func testListAppsWithLabels(t *testing.T, appQuery application.ApplicationQuery, label: "key1= minVersion { return diff --git a/server/applicationset/applicationset_test.go b/server/applicationset/applicationset_test.go index aef61f289d494..c49ddb35a7970 100644 --- a/server/applicationset/applicationset_test.go +++ b/server/applicationset/applicationset_test.go @@ -38,7 +38,7 @@ func fakeRepo() *appsv1.Repository { func fakeCluster() *appsv1.Cluster { return &appsv1.Cluster{ - Server: "https://cluster-api.com", + Server: "https://cluster-api.example.com", Name: "fake-cluster", Config: appsv1.ClusterConfig{}, } @@ -50,10 +50,21 @@ func newTestAppSetServer(objects ...runtime.Object) *Server { _ = enf.SetBuiltinPolicy(assets.BuiltinPolicyCSV) enf.SetDefaultRole("role:admin") } - return newTestAppSetServerWithEnforcerConfigure(f, objects...) + scopedNamespaces := "" + return newTestAppSetServerWithEnforcerConfigure(f, scopedNamespaces, objects...) } -func newTestAppSetServerWithEnforcerConfigure(f func(*rbac.Enforcer), objects ...runtime.Object) *Server { +// return an ApplicationServiceServer which returns fake data +func newTestNamespacedAppSetServer(objects ...runtime.Object) *Server { + f := func(enf *rbac.Enforcer) { + _ = enf.SetBuiltinPolicy(assets.BuiltinPolicyCSV) + enf.SetDefaultRole("role:admin") + } + scopedNamespaces := "argocd" + return newTestAppSetServerWithEnforcerConfigure(f, scopedNamespaces, objects...) +} + +func newTestAppSetServerWithEnforcerConfigure(f func(*rbac.Enforcer), namespace string, objects ...runtime.Object) *Server { kubeclientset := fake.NewSimpleClientset(&v1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Namespace: testNamespace, @@ -97,7 +108,7 @@ func newTestAppSetServerWithEnforcerConfigure(f func(*rbac.Enforcer), objects .. objects = append(objects, defaultProj, myProj) fakeAppsClientset := apps.NewSimpleClientset(objects...) - factory := appinformer.NewSharedInformerFactoryWithOptions(fakeAppsClientset, 0, appinformer.WithNamespace(""), appinformer.WithTweakListOptions(func(options *metav1.ListOptions) {})) + factory := appinformer.NewSharedInformerFactoryWithOptions(fakeAppsClientset, 0, appinformer.WithNamespace(namespace), appinformer.WithTweakListOptions(func(options *metav1.ListOptions) {})) fakeProjLister := factory.Argoproj().V1alpha1().AppProjects().Lister().AppProjects(testNamespace) enforcer := rbac.NewEnforcer(kubeclientset, testNamespace, common.ArgoCDRBACConfigMapName, nil) @@ -114,6 +125,12 @@ func newTestAppSetServerWithEnforcerConfigure(f func(*rbac.Enforcer), objects .. if !k8scache.WaitForCacheSync(ctx.Done(), appInformer.HasSynced) { panic("Timed out waiting for caches to sync") } + // populate the appset informer with the fake objects + appsetInformer := factory.Argoproj().V1alpha1().ApplicationSets().Informer() + go appsetInformer.Run(ctx.Done()) + if !k8scache.WaitForCacheSync(ctx.Done(), appsetInformer.HasSynced) { + panic("Timed out waiting for caches to sync") + } projInformer := factory.Argoproj().V1alpha1().AppProjects().Informer() go projInformer.Run(ctx.Done()) @@ -125,11 +142,9 @@ func newTestAppSetServerWithEnforcerConfigure(f func(*rbac.Enforcer), objects .. db, kubeclientset, enforcer, - nil, fakeAppsClientset, - factory.Argoproj().V1alpha1().Applications().Lister(), appInformer, - factory.Argoproj().V1alpha1().ApplicationSets().Lister().ApplicationSets(testNamespace), + factory.Argoproj().V1alpha1().ApplicationSets().Lister(), fakeProjLister, settingsMgr, testNamespace, @@ -223,21 +238,22 @@ func testListAppsetsWithLabels(t *testing.T, appsetQuery applicationset.Applicat } func TestListAppSetsInNamespaceWithLabels(t *testing.T) { + testNamespace := "test-namespace" appSetServer := newTestAppSetServer(newTestAppSet(func(appset *appsv1.ApplicationSet) { appset.Name = "AppSet1" - appset.ObjectMeta.Namespace = "test-namespace" + appset.ObjectMeta.Namespace = testNamespace appset.SetLabels(map[string]string{"key1": "value1", "key2": "value1"}) }), newTestAppSet(func(appset *appsv1.ApplicationSet) { appset.Name = "AppSet2" - appset.ObjectMeta.Namespace = "test-namespace" + appset.ObjectMeta.Namespace = testNamespace appset.SetLabels(map[string]string{"key1": "value2"}) }), newTestAppSet(func(appset *appsv1.ApplicationSet) { appset.Name = "AppSet3" - appset.ObjectMeta.Namespace = "test-namespace" + appset.ObjectMeta.Namespace = testNamespace appset.SetLabels(map[string]string{"key1": "value3"}) })) - appSetServer.ns = "test-namespace" - appsetQuery := applicationset.ApplicationSetListQuery{AppsetNamespace: "test-namespace"} + appSetServer.enabledNamespaces = []string{testNamespace} + appsetQuery := applicationset.ApplicationSetListQuery{AppsetNamespace: testNamespace} testListAppsetsWithLabels(t, appsetQuery, appSetServer) } @@ -258,6 +274,32 @@ func TestListAppSetsInDefaultNSWithLabels(t *testing.T) { testListAppsetsWithLabels(t, appsetQuery, appSetServer) } +// This test covers https://github.com/argoproj/argo-cd/issues/15429 +// If the namespace isn't provided during listing action, argocd's +// default namespace must be used and not all the namespaces +func TestListAppSetsWithoutNamespace(t *testing.T) { + testNamespace := "test-namespace" + appSetServer := newTestNamespacedAppSetServer(newTestAppSet(func(appset *appsv1.ApplicationSet) { + appset.Name = "AppSet1" + appset.ObjectMeta.Namespace = testNamespace + appset.SetLabels(map[string]string{"key1": "value1", "key2": "value1"}) + }), newTestAppSet(func(appset *appsv1.ApplicationSet) { + appset.Name = "AppSet2" + appset.ObjectMeta.Namespace = testNamespace + appset.SetLabels(map[string]string{"key1": "value2"}) + }), newTestAppSet(func(appset *appsv1.ApplicationSet) { + appset.Name = "AppSet3" + appset.ObjectMeta.Namespace = testNamespace + appset.SetLabels(map[string]string{"key1": "value3"}) + })) + appSetServer.enabledNamespaces = []string{testNamespace} + appsetQuery := applicationset.ApplicationSetListQuery{} + + res, err := appSetServer.List(context.Background(), &appsetQuery) + assert.NoError(t, err) + assert.Equal(t, 0, len(res.Items)) +} + func TestCreateAppSet(t *testing.T) { testAppSet := newTestAppSet() appServer := newTestAppSetServer() diff --git a/server/cache/cache.go b/server/cache/cache.go index ccbebd256be78..c2042c3f0e8d1 100644 --- a/server/cache/cache.go +++ b/server/cache/cache.go @@ -6,7 +6,6 @@ import ( "math" "time" - "github.com/redis/go-redis/v9" "github.com/spf13/cobra" appv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" @@ -33,7 +32,7 @@ func NewCache( return &Cache{cache, connectionStatusCacheExpiration, oidcCacheExpiration, loginAttemptsExpiration} } -func AddCacheFlagsToCmd(cmd *cobra.Command, opts ...func(client *redis.Client)) func() (*Cache, error) { +func AddCacheFlagsToCmd(cmd *cobra.Command, opts ...cacheutil.Options) func() (*Cache, error) { var connectionStatusCacheExpiration time.Duration var oidcCacheExpiration time.Duration var loginAttemptsExpiration time.Duration diff --git a/server/cluster/cluster_test.go b/server/cluster/cluster_test.go index c29a1b2d77c04..e7e206a57b129 100644 --- a/server/cluster/cluster_test.go +++ b/server/cluster/cluster_test.go @@ -278,7 +278,7 @@ func TestUpdateCluster_FieldsPathSet(t *testing.T) { _, err := server.Update(context.Background(), &clusterapi.ClusterUpdateRequest{ Cluster: &v1alpha1.Cluster{ Server: "https://127.0.0.1", - Shard: pointer.Int64Ptr(1), + Shard: pointer.Int64(1), }, UpdatedFields: []string{"shard"}, }) diff --git a/server/deeplinks/deeplinks_test.go b/server/deeplinks/deeplinks_test.go index abebe691c29c1..09ad64671af9b 100644 --- a/server/deeplinks/deeplinks_test.go +++ b/server/deeplinks/deeplinks_test.go @@ -35,7 +35,7 @@ func TestDeepLinks(t *testing.T) { }, Spec: v1alpha1.ApplicationSpec{ Destination: v1alpha1.ApplicationDestination{ - Server: "test.com", + Server: "test.example.com", Namespace: "testns", }, }, diff --git a/server/extension/extension.go b/server/extension/extension.go index aca924620756c..9f8edcd6184fc 100644 --- a/server/extension/extension.go +++ b/server/extension/extension.go @@ -12,6 +12,7 @@ import ( "strings" "time" + "github.com/felixge/httpsnoop" log "github.com/sirupsen/logrus" "gopkg.in/yaml.v3" @@ -300,6 +301,19 @@ type Manager struct { project ProjectGetter rbac RbacEnforcer registry ExtensionRegistry + metricsReg ExtensionMetricsRegistry +} + +// ExtensionMetricsRegistry exposes operations to update http metrics in the Argo CD +// API server. +type ExtensionMetricsRegistry interface { + // IncExtensionRequestCounter will increase the request counter for the given + // extension with the given status. + IncExtensionRequestCounter(extension string, status int) + // ObserveExtensionRequestDuration will register the request roundtrip duration + // between Argo CD API Server and the extension backend service for the given + // extension. + ObserveExtensionRequestDuration(extension string, duration time.Duration) } // NewManager will initialize a new manager. @@ -423,7 +437,8 @@ func validateConfigs(configs *ExtensionConfigs) error { } // NewProxy will instantiate a new reverse proxy based on the provided -// targetURL and config. +// targetURL and config. It will remove sensitive information from the +// incoming request such as the Authorization and Cookie headers. func NewProxy(targetURL string, headers []Header, config ProxyConfig) (*httputil.ReverseProxy, error) { url, err := url.Parse(targetURL) if err != nil { @@ -484,6 +499,10 @@ func (m *Manager) RegisterExtensions() error { if err != nil { return fmt.Errorf("error getting settings: %s", err) } + if settings.ExtensionConfig == "" { + m.log.Infof("No extensions configured.") + return nil + } err = m.UpdateExtensionRegistry(settings) if err != nil { return fmt.Errorf("error updating extension registry: %s", err) @@ -683,13 +702,26 @@ func (m *Manager) CallExtension() func(http.ResponseWriter, *http.Request) { prepareRequest(r, extName, app) m.log.Debugf("proxing request for extension %q", extName) - proxy.ServeHTTP(w, r) + // httpsnoop package is used to properly wrap the responseWriter + // and avoid optional intefaces issue: + // https://github.com/felixge/httpsnoop#why-this-package-exists + // CaptureMetrics will call the proxy and return the metrics from it. + metrics := httpsnoop.CaptureMetrics(proxy, w, r) + + go registerMetrics(extName, metrics, m.metricsReg) } } -// prepareRequest is reponsible for preparing and cleaning the given -// request, removing sensitive information before forwarding it to the -// proxy extension. +func registerMetrics(extName string, metrics httpsnoop.Metrics, extensionMetricsRegistry ExtensionMetricsRegistry) { + if extensionMetricsRegistry != nil { + extensionMetricsRegistry.IncExtensionRequestCounter(extName, metrics.Code) + extensionMetricsRegistry.ObserveExtensionRequestDuration(extName, metrics.Duration) + } +} + +// prepareRequest is reponsible for cleaning the incoming request URL removing +// the Argo CD extension API section from it. It will set the cluster destination name +// and cluster destination server in the headers as it is defined in the given app. func prepareRequest(r *http.Request, extName string, app *v1alpha1.Application) { r.URL.Path = strings.TrimPrefix(r.URL.Path, fmt.Sprintf("%s/%s", URLPrefix, extName)) if app.Spec.Destination.Name != "" { @@ -699,3 +731,8 @@ func prepareRequest(r *http.Request, extName string, app *v1alpha1.Application) r.Header.Set(HeaderArgoCDTargetClusterURL, app.Spec.Destination.Server) } } + +// AddMetricsRegistry will associate the given metricsReg in the Manager. +func (m *Manager) AddMetricsRegistry(metricsReg ExtensionMetricsRegistry) { + m.metricsReg = metricsReg +} diff --git a/server/extension/extension_test.go b/server/extension/extension_test.go index 273779d59ca29..ff287dde80424 100644 --- a/server/extension/extension_test.go +++ b/server/extension/extension_test.go @@ -8,6 +8,7 @@ import ( "net/http" "net/http/httptest" "strings" + "sync" "testing" "github.com/sirupsen/logrus/hooks/test" @@ -188,10 +189,6 @@ func TestRegisterExtensions(t *testing.T) { configYaml string } cases := []testCase{ - { - name: "no config", - configYaml: "", - }, { name: "no name", configYaml: getExtensionConfigNoName(), @@ -234,7 +231,7 @@ func TestRegisterExtensions(t *testing.T) { err := f.manager.RegisterExtensions() // then - assert.Error(t, err) + assert.Error(t, err, fmt.Sprintf("expected error in test %s but got nil", tc.name)) }) } }) @@ -247,6 +244,7 @@ func TestCallExtension(t *testing.T) { settingsGetterMock *mocks.SettingsGetter rbacMock *mocks.RbacEnforcer projMock *mocks.ProjectGetter + metricsMock *mocks.ExtensionMetricsRegistry manager *extension.Manager } defaultProjectName := "project-name" @@ -256,10 +254,12 @@ func TestCallExtension(t *testing.T) { settMock := &mocks.SettingsGetter{} rbacMock := &mocks.RbacEnforcer{} projMock := &mocks.ProjectGetter{} + metricsMock := &mocks.ExtensionMetricsRegistry{} logger, _ := test.NewNullLogger() logEntry := logger.WithContext(context.Background()) m := extension.NewManager(logEntry, settMock, appMock, projMock, rbacMock) + m.AddMetricsRegistry(metricsMock) mux := http.NewServeMux() extHandler := http.HandlerFunc(m.CallExtension()) @@ -271,6 +271,7 @@ func TestCallExtension(t *testing.T) { settingsGetterMock: settMock, rbacMock: rbacMock, projMock: projMock, + metricsMock: metricsMock, manager: m, } } @@ -328,6 +329,11 @@ func TestCallExtension(t *testing.T) { f.projMock.On("Get", prj.GetName()).Return(prj, nil) } + withMetrics := func(f *fixture) { + f.metricsMock.On("IncExtensionRequestCounter", mock.Anything, mock.Anything) + f.metricsMock.On("ObserveExtensionRequestDuration", mock.Anything, mock.Anything) + } + withRbac := func(f *fixture, allowApp, allowExt bool) { var appAccessError error var extAccessError error @@ -406,6 +412,18 @@ func TestCallExtension(t *testing.T) { proj := getProjectWithDestinations("project-name", nil, []string{clusterURL}) f.appGetterMock.On("Get", mock.Anything, mock.Anything).Return(app, nil) withProject(proj, f) + var wg sync.WaitGroup + wg.Add(2) + f.metricsMock. + On("IncExtensionRequestCounter", mock.Anything, mock.Anything). + Run(func(args mock.Arguments) { + wg.Done() + }) + f.metricsMock. + On("ObserveExtensionRequestDuration", mock.Anything, mock.Anything). + Run(func(args mock.Arguments) { + wg.Done() + }) // when resp, err := http.DefaultClient.Do(r) @@ -420,6 +438,13 @@ func TestCallExtension(t *testing.T) { assert.Equal(t, backendResponse, actual) assert.Equal(t, clusterURL, resp.Header.Get(extension.HeaderArgoCDTargetClusterURL)) assert.Equal(t, "Bearer some-bearer-token", resp.Header.Get("Authorization")) + + // waitgroup is necessary to make sure assertions aren't executed before + // the goroutine initiated by extension.CallExtension concludes which would + // lead to flaky test. + wg.Wait() + f.metricsMock.AssertCalled(t, "IncExtensionRequestCounter", backendEndpoint, http.StatusOK) + f.metricsMock.AssertCalled(t, "ObserveExtensionRequestDuration", backendEndpoint, mock.Anything) }) t.Run("proxy will return 404 if extension endpoint not registered", func(t *testing.T) { // given @@ -427,6 +452,7 @@ func TestCallExtension(t *testing.T) { f := setup() withExtensionConfig(getExtensionConfigString(), f) withRbac(f, true, true) + withMetrics(f) cluster1Name := "cluster1" f.appGetterMock.On("Get", "namespace", "app-name").Return(getApp(cluster1Name, "", defaultProjectName), nil) withProject(getProjectWithDestinations("project-name", []string{cluster1Name}, []string{"some-url"}), f) @@ -466,6 +492,7 @@ func TestCallExtension(t *testing.T) { withRbac(f, true, true) withExtensionConfig(getExtensionConfigWith2Backends(extName, beSrv1.URL, cluster1Name, beSrv2.URL, cluster2URL), f) withProject(getProjectWithDestinations("project-name", []string{cluster1Name}, []string{cluster2URL}), f) + withMetrics(f) ts := startTestServer(t, f) defer ts.Close() @@ -511,6 +538,7 @@ func TestCallExtension(t *testing.T) { extName := "some-extension" withRbac(f, allowApp, allowExtension) withExtensionConfig(getExtensionConfig(extName, "http://fake"), f) + withMetrics(f) ts := startTestServer(t, f) defer ts.Close() r := newExtensionRequest(t, "Get", fmt.Sprintf("%s/extensions/%s/", ts.URL, extName)) @@ -533,6 +561,7 @@ func TestCallExtension(t *testing.T) { extName := "some-extension" withRbac(f, allowApp, allowExtension) withExtensionConfig(getExtensionConfig(extName, "http://fake"), f) + withMetrics(f) ts := startTestServer(t, f) defer ts.Close() r := newExtensionRequest(t, "Get", fmt.Sprintf("%s/extensions/%s/", ts.URL, extName)) @@ -556,6 +585,7 @@ func TestCallExtension(t *testing.T) { noCluster := []string{} withRbac(f, allowApp, allowExtension) withExtensionConfig(getExtensionConfig(extName, "http://fake"), f) + withMetrics(f) ts := startTestServer(t, f) defer ts.Close() r := newExtensionRequest(t, "Get", fmt.Sprintf("%s/extensions/%s/", ts.URL, extName)) @@ -580,6 +610,7 @@ func TestCallExtension(t *testing.T) { extName := "some-extension" withRbac(f, allowApp, allowExtension) withExtensionConfig(getExtensionConfig(extName, "http://fake"), f) + withMetrics(f) ts := startTestServer(t, f) defer ts.Close() r := newExtensionRequest(t, "Get", fmt.Sprintf("%s/extensions/%s/", ts.URL, extName)) @@ -604,6 +635,7 @@ func TestCallExtension(t *testing.T) { differentProject := "differentProject" withRbac(f, allowApp, allowExtension) withExtensionConfig(getExtensionConfig(extName, "http://fake"), f) + withMetrics(f) ts := startTestServer(t, f) defer ts.Close() r := newExtensionRequest(t, "Get", fmt.Sprintf("%s/extensions/%s/", ts.URL, extName)) @@ -634,6 +666,7 @@ func TestCallExtension(t *testing.T) { withRbac(f, true, true) withExtensionConfig(getExtensionConfigWith2Backends(extName, "url1", "clusterName", "url2", "clusterURL"), f) withProject(getProjectWithDestinations("project-name", nil, []string{"srv1", destinationServer}), f) + withMetrics(f) ts := startTestServer(t, f) defer ts.Close() @@ -666,6 +699,7 @@ func TestCallExtension(t *testing.T) { differentProject := "differentProject" withRbac(f, allowApp, allowExtension) withExtensionConfig(getExtensionConfig(extName, "http://fake"), f) + withMetrics(f) ts := startTestServer(t, f) defer ts.Close() r := newExtensionRequest(t, "Get", fmt.Sprintf("%s/extensions/", ts.URL)) diff --git a/server/extension/mocks/ExtensionMetricsRegistry.go b/server/extension/mocks/ExtensionMetricsRegistry.go new file mode 100644 index 0000000000000..78e583929f74d --- /dev/null +++ b/server/extension/mocks/ExtensionMetricsRegistry.go @@ -0,0 +1,38 @@ +// Code generated by mockery v2.38.0. DO NOT EDIT. + +package mocks + +import ( + time "time" + + mock "github.com/stretchr/testify/mock" +) + +// ExtensionMetricsRegistry is an autogenerated mock type for the ExtensionMetricsRegistry type +type ExtensionMetricsRegistry struct { + mock.Mock +} + +// IncExtensionRequestCounter provides a mock function with given fields: _a0, status +func (_m *ExtensionMetricsRegistry) IncExtensionRequestCounter(_a0 string, status int) { + _m.Called(_a0, status) +} + +// ObserveExtensionRequestDuration provides a mock function with given fields: _a0, duration +func (_m *ExtensionMetricsRegistry) ObserveExtensionRequestDuration(_a0 string, duration time.Duration) { + _m.Called(_a0, duration) +} + +// NewExtensionMetricsRegistry creates a new instance of ExtensionMetricsRegistry. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewExtensionMetricsRegistry(t interface { + mock.TestingT + Cleanup(func()) +}) *ExtensionMetricsRegistry { + mock := &ExtensionMetricsRegistry{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/server/metrics/metrics.go b/server/metrics/metrics.go index 40698e742b093..4afac9da26c02 100644 --- a/server/metrics/metrics.go +++ b/server/metrics/metrics.go @@ -14,8 +14,10 @@ import ( type MetricsServer struct { *http.Server - redisRequestCounter *prometheus.CounterVec - redisRequestHistogram *prometheus.HistogramVec + redisRequestCounter *prometheus.CounterVec + redisRequestHistogram *prometheus.HistogramVec + extensionRequestCounter *prometheus.CounterVec + extensionRequestDuration *prometheus.HistogramVec } var ( @@ -34,6 +36,21 @@ var ( }, []string{"initiator"}, ) + extensionRequestCounter = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "argocd_proxy_extension_request_total", + Help: "Number of requests sent to configured proxy extensions.", + }, + []string{"extension", "status"}, + ) + extensionRequestDuration = prometheus.NewHistogramVec( + prometheus.HistogramOpts{ + Name: "argocd_proxy_extension_request_duration_seconds", + Help: "Request duration in seconds between the Argo CD API server and the extension backend.", + Buckets: []float64{0.1, 0.25, .5, 1, 2, 5, 10}, + }, + []string{"extension"}, + ) ) // NewMetricsServer returns a new prometheus server which collects api server metrics @@ -48,14 +65,18 @@ func NewMetricsServer(host string, port int) *MetricsServer { registry.MustRegister(redisRequestCounter) registry.MustRegister(redisRequestHistogram) + registry.MustRegister(extensionRequestCounter) + registry.MustRegister(extensionRequestDuration) return &MetricsServer{ Server: &http.Server{ Addr: fmt.Sprintf("%s:%d", host, port), Handler: mux, }, - redisRequestCounter: redisRequestCounter, - redisRequestHistogram: redisRequestHistogram, + redisRequestCounter: redisRequestCounter, + redisRequestHistogram: redisRequestHistogram, + extensionRequestCounter: extensionRequestCounter, + extensionRequestDuration: extensionRequestDuration, } } @@ -67,3 +88,11 @@ func (m *MetricsServer) IncRedisRequest(failed bool) { func (m *MetricsServer) ObserveRedisRequestDuration(duration time.Duration) { m.redisRequestHistogram.WithLabelValues("argocd-server").Observe(duration.Seconds()) } + +func (m *MetricsServer) IncExtensionRequestCounter(extension string, status int) { + m.extensionRequestCounter.WithLabelValues(extension, strconv.Itoa(status)).Inc() +} + +func (m *MetricsServer) ObserveExtensionRequestDuration(extension string, duration time.Duration) { + m.extensionRequestDuration.WithLabelValues(extension).Observe(duration.Seconds()) +} diff --git a/server/notification/notification_test.go b/server/notification/notification_test.go index 47606b24ea855..ee913926bc010 100644 --- a/server/notification/notification_test.go +++ b/server/notification/notification_test.go @@ -41,7 +41,7 @@ func TestNotificationServer(t *testing.T) { Name: "argocd-notifications-cm", }, Data: map[string]string{ - "service.webhook.test": "url: https://test.com", + "service.webhook.test": "url: https://test.example.com", "template.app-created": "email:\n subject: Application {{.app.metadata.name}} has been created.\nmessage: Application {{.app.metadata.name}} has been created.\nteams:\n title: Application {{.app.metadata.name}} has been created.\n", "trigger.on-created": "- description: Application is created.\n oncePer: app.metadata.name\n send:\n - app-created\n when: \"true\"\n", }, @@ -70,7 +70,7 @@ func TestNotificationServer(t *testing.T) { argocdService, err := service.NewArgoCDService(kubeclientset, testNamespace, mockRepoClient) require.NoError(t, err) defer argocdService.Close() - apiFactory := api.NewFactory(settings.GetFactorySettings(argocdService, "argocd-notifications-secret", "argocd-notifications-cm"), testNamespace, secretInformer, configMapInformer) + apiFactory := api.NewFactory(settings.GetFactorySettings(argocdService, "argocd-notifications-secret", "argocd-notifications-cm", false), testNamespace, secretInformer, configMapInformer) t.Run("TestListServices", func(t *testing.T) { server := NewServer(apiFactory) diff --git a/server/server.go b/server/server.go index a0fc5327e985c..e42e6f59a49a3 100644 --- a/server/server.go +++ b/server/server.go @@ -178,7 +178,7 @@ type ArgoCDServer struct { appInformer cache.SharedIndexInformer appLister applisters.ApplicationLister appsetInformer cache.SharedIndexInformer - appsetLister applisters.ApplicationSetNamespaceLister + appsetLister applisters.ApplicationSetLister db db.ArgoDB // stopCh is the channel which when closed, will shutdown the Argo CD server @@ -197,6 +197,7 @@ type ArgoCDServer struct { type ArgoCDServerOpts struct { DisableAuth bool + ContentTypes []string EnableGZip bool Insecure bool StaticAssetsDir string @@ -213,6 +214,7 @@ type ArgoCDServerOpts struct { AppClientset appclientset.Interface RepoClientset repoapiclient.Clientset Cache *servercache.Cache + RepoServerCache *repocache.Cache RedisClient *redis.Client TLSConfigCustomizer tlsutil.ConfigCustomizer XFrameOptions string @@ -221,6 +223,18 @@ type ArgoCDServerOpts struct { EnableProxyExtension bool } +// HTTPMetricsRegistry exposes operations to update http metrics in the Argo CD +// API server. +type HTTPMetricsRegistry interface { + // IncExtensionRequestCounter will increase the request counter for the given + // extension with the given status. + IncExtensionRequestCounter(extension string, status int) + // ObserveExtensionRequestDuration will register the request roundtrip duration + // between Argo CD API Server and the extension backend service for the given + // extension. + ObserveExtensionRequestDuration(extension string, duration time.Duration) +} + // initializeDefaultProject creates the default project if it does not already exist func initializeDefaultProject(opts ArgoCDServerOpts) error { defaultProj := &v1alpha1.AppProject{ @@ -264,7 +278,7 @@ func NewServer(ctx context.Context, opts ArgoCDServerOpts) *ArgoCDServer { appLister := appFactory.Argoproj().V1alpha1().Applications().Lister() appsetInformer := appFactory.Argoproj().V1alpha1().ApplicationSets().Informer() - appsetLister := appFactory.Argoproj().V1alpha1().ApplicationSets().Lister().ApplicationSets(opts.Namespace) + appsetLister := appFactory.Argoproj().V1alpha1().ApplicationSets().Lister() userStateStorage := util_session.NewUserStateStorage(opts.RedisClient) sessionMgr := util_session.NewSessionManager(settingsMgr, projLister, opts.DexServerAddr, opts.DexTLSConfig, userStateStorage) @@ -288,7 +302,7 @@ func NewServer(ctx context.Context, opts ArgoCDServerOpts) *ArgoCDServer { secretInformer := k8s.NewSecretInformer(opts.KubeClientset, opts.Namespace, "argocd-notifications-secret") configMapInformer := k8s.NewConfigMapInformer(opts.KubeClientset, opts.Namespace, "argocd-notifications-cm") - apiFactory := api.NewFactory(settings_notif.GetFactorySettings(argocdService, "argocd-notifications-secret", "argocd-notifications-cm"), opts.Namespace, secretInformer, configMapInformer) + apiFactory := api.NewFactory(settings_notif.GetFactorySettings(argocdService, "argocd-notifications-secret", "argocd-notifications-cm", false), opts.Namespace, secretInformer, configMapInformer) dbInstance := db.NewDB(opts.Namespace, settingsMgr, opts.KubeClientset) logger := log.NewEntry(log.StandardLogger()) @@ -471,6 +485,7 @@ func (a *ArgoCDServer) Listen() (*Listeners, error) { func (a *ArgoCDServer) Init(ctx context.Context) { go a.projInformer.Run(ctx.Done()) go a.appInformer.Run(ctx.Done()) + go a.appsetInformer.Run(ctx.Done()) go a.configMapInformer.Run(ctx.Done()) go a.secretInformer.Run(ctx.Done()) } @@ -481,6 +496,12 @@ func (a *ArgoCDServer) Init(ctx context.Context) { // golang/protobuf). func (a *ArgoCDServer) Run(ctx context.Context, listeners *Listeners) { a.userStateStorage.Init(ctx) + + metricsServ := metrics.NewMetricsServer(a.MetricsHost, a.MetricsPort) + if a.RedisClient != nil { + cacheutil.CollectMetrics(a.RedisClient, metricsServ) + } + svcSet := newArgoCDServiceSet(a) a.serviceSet = svcSet grpcS, appResourceTreeFn := a.newGRPCServer() @@ -489,9 +510,9 @@ func (a *ArgoCDServer) Run(ctx context.Context, listeners *Listeners) { var httpsS *http.Server if a.useTLS() { httpS = newRedirectServer(a.ListenPort, a.RootPath) - httpsS = a.newHTTPServer(ctx, a.ListenPort, grpcWebS, appResourceTreeFn, listeners.GatewayConn) + httpsS = a.newHTTPServer(ctx, a.ListenPort, grpcWebS, appResourceTreeFn, listeners.GatewayConn, metricsServ) } else { - httpS = a.newHTTPServer(ctx, a.ListenPort, grpcWebS, appResourceTreeFn, listeners.GatewayConn) + httpS = a.newHTTPServer(ctx, a.ListenPort, grpcWebS, appResourceTreeFn, listeners.GatewayConn, metricsServ) } if a.RootPath != "" { httpS.Handler = withRootPath(httpS.Handler, a) @@ -505,11 +526,6 @@ func (a *ArgoCDServer) Run(ctx context.Context, listeners *Listeners) { httpsS.Handler = &bug21955Workaround{handler: httpsS.Handler} } - metricsServ := metrics.NewMetricsServer(a.MetricsHost, a.MetricsPort) - if a.RedisClient != nil { - cacheutil.CollectMetrics(a.RedisClient, metricsServ) - } - // CMux is used to support servicing gRPC and HTTP1.1+JSON on the same port tcpm := cmux.New(listeners.Main) var tlsm cmux.CMux @@ -731,7 +747,7 @@ func (a *ArgoCDServer) newGRPCServer() (*grpc.Server, application.AppResourceTre grpc.ConnectionTimeout(300 * time.Second), grpc.KeepaliveEnforcementPolicy( keepalive.EnforcementPolicy{ - MinTime: common.GRPCKeepAliveEnforcementMinimum, + MinTime: common.GetGRPCKeepAliveEnforcementMinimum(), }, ), } @@ -852,9 +868,7 @@ func newArgoCDServiceSet(a *ArgoCDServer) *ArgoCDServiceSet { a.db, a.KubeClientset, a.enf, - a.Cache, a.AppClientset, - a.appLister, a.appsetInformer, a.appsetLister, a.projLister, @@ -959,7 +973,7 @@ func compressHandler(handler http.Handler) http.Handler { // newHTTPServer returns the HTTP server to serve HTTP/HTTPS requests. This is implemented // using grpc-gateway as a proxy to the gRPC server. -func (a *ArgoCDServer) newHTTPServer(ctx context.Context, port int, grpcWebHandler http.Handler, appResourceTreeFn application.AppResourceTreeFn, conn *grpc.ClientConn) *http.Server { +func (a *ArgoCDServer) newHTTPServer(ctx context.Context, port int, grpcWebHandler http.Handler, appResourceTreeFn application.AppResourceTreeFn, conn *grpc.ClientConn, metricsReg HTTPMetricsRegistry) *http.Server { endpoint := fmt.Sprintf("localhost:%d", port) mux := http.NewServeMux() httpS := http.Server{ @@ -990,6 +1004,11 @@ func (a *ArgoCDServer) newHTTPServer(ctx context.Context, port int, grpcWebHandl if a.EnableGZip { handler = compressHandler(handler) } + if len(a.ContentTypes) > 0 { + handler = enforceContentTypes(handler, a.ContentTypes) + } else { + log.WithField(common.SecurityField, common.SecurityHigh).Warnf("Content-Type enforcement is disabled, which may make your API vulnerable to CSRF attacks") + } mux.Handle("/api/", handler) terminal := application.NewHandler(a.appLister, a.Namespace, a.ApplicationNamespaces, a.db, a.enf, a.Cache, appResourceTreeFn, a.settings.ExecShells, *a.sessionMgr). @@ -1003,7 +1022,7 @@ func (a *ArgoCDServer) newHTTPServer(ctx context.Context, port int, grpcWebHandl // API server won't panic if extensions fail to register. In // this case an error log will be sent and no extension route // will be added in mux. - registerExtensions(mux, a) + registerExtensions(mux, a, metricsReg) } mustRegisterGWHandler(versionpkg.RegisterVersionServiceHandler, ctx, gwmux, conn) @@ -1029,7 +1048,7 @@ func (a *ArgoCDServer) newHTTPServer(ctx context.Context, port int, grpcWebHandl // Webhook handler for git events (Note: cache timeouts are hardcoded because API server does not write to cache and not really using them) argoDB := db.NewDB(a.Namespace, a.settingsMgr, a.KubeClientset) - acdWebhookHandler := webhook.NewHandler(a.Namespace, a.ArgoCDServerOpts.ApplicationNamespaces, a.AppClientset, a.settings, a.settingsMgr, repocache.NewCache(a.Cache.GetCache(), 24*time.Hour, 3*time.Minute), a.Cache, argoDB) + acdWebhookHandler := webhook.NewHandler(a.Namespace, a.ArgoCDServerOpts.ApplicationNamespaces, a.AppClientset, a.settings, a.settingsMgr, a.RepoServerCache, a.Cache, argoDB) mux.HandleFunc("/api/webhook", acdWebhookHandler.Handler) @@ -1056,16 +1075,32 @@ func (a *ArgoCDServer) newHTTPServer(ctx context.Context, port int, grpcWebHandl return &httpS } +func enforceContentTypes(handler http.Handler, types []string) http.Handler { + allowedTypes := map[string]bool{} + for _, t := range types { + allowedTypes[strings.ToLower(t)] = true + } + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Method == http.MethodGet || allowedTypes[strings.ToLower(r.Header.Get("Content-Type"))] { + handler.ServeHTTP(w, r) + } else { + http.Error(w, "Invalid content type", http.StatusUnsupportedMediaType) + } + }) +} + // registerExtensions will try to register all configured extensions // in the given mux. If any error is returned while registering // extensions handlers, no route will be added in the given mux. -func registerExtensions(mux *http.ServeMux, a *ArgoCDServer) { +func registerExtensions(mux *http.ServeMux, a *ArgoCDServer, metricsReg HTTPMetricsRegistry) { a.log.Info("Registering extensions...") extHandler := http.HandlerFunc(a.extensionManager.CallExtension()) authMiddleware := a.sessionMgr.AuthMiddlewareFunc(a.DisableAuth) // auth middleware ensures that requests to all extensions are authenticated first mux.Handle(fmt.Sprintf("%s/", extension.URLPrefix), authMiddleware(extHandler)) + a.extensionManager.AddMetricsRegistry(metricsReg) + err := a.extensionManager.RegisterExtensions() if err != nil { a.log.Errorf("Error registering extensions: %s", err) @@ -1122,7 +1157,7 @@ func (a *ArgoCDServer) registerDexHandlers(mux *http.ServeMux) { // Run dex OpenID Connect Identity Provider behind a reverse proxy (served at /api/dex) var err error mux.HandleFunc(common.DexAPIEndpoint+"/", dexutil.NewDexHTTPReverseProxy(a.DexServerAddr, a.BaseHRef, a.DexTLSConfig)) - a.ssoClientApp, err = oidc.NewClientApp(a.settings, a.DexServerAddr, a.DexTLSConfig, a.BaseHRef) + a.ssoClientApp, err = oidc.NewClientApp(a.settings, a.DexServerAddr, a.DexTLSConfig, a.BaseHRef, cacheutil.NewRedisCache(a.RedisClient, a.settings.UserInfoCacheExpiration(), cacheutil.RedisCompressionNone)) errorsutil.CheckError(err) mux.HandleFunc(common.LoginEndpoint, a.ssoClientApp.HandleLogin) mux.HandleFunc(common.CallbackEndpoint, a.ssoClientApp.HandleCallback) @@ -1316,7 +1351,35 @@ func (a *ArgoCDServer) getClaims(ctx context.Context) (jwt.Claims, string, error if err != nil { return claims, "", status.Errorf(codes.Unauthenticated, "invalid session: %v", err) } - return claims, newToken, nil + + // Some SSO implementations (Okta) require a call to + // the OIDC user info path to get attributes like groups + // we assume that everywhere in argocd jwt.MapClaims is used as type for interface jwt.Claims + // otherwise this would cause a panic + var groupClaims jwt.MapClaims + if groupClaims, ok = claims.(jwt.MapClaims); !ok { + if tmpClaims, ok := claims.(*jwt.MapClaims); ok { + groupClaims = *tmpClaims + } + } + iss := jwtutil.StringField(groupClaims, "iss") + if iss != util_session.SessionManagerClaimsIssuer && a.settings.UserInfoGroupsEnabled() && a.settings.UserInfoPath() != "" { + userInfo, unauthorized, err := a.ssoClientApp.GetUserInfo(groupClaims, a.settings.IssuerURL(), a.settings.UserInfoPath()) + if unauthorized { + log.Errorf("error while quering userinfo endpoint: %v", err) + return claims, "", status.Errorf(codes.Unauthenticated, "invalid session") + } + if err != nil { + log.Errorf("error fetching user info endpoint: %v", err) + return claims, "", status.Errorf(codes.Internal, "invalid userinfo response") + } + if groupClaims["sub"] != userInfo["sub"] { + return claims, "", status.Error(codes.Unknown, "subject of claims from user info endpoint didn't match subject of idToken, see https://openid.net/specs/openid-connect-core-1_0.html#UserInfo") + } + groupClaims["groups"] = userInfo["groups"] + } + + return groupClaims, newToken, nil } // getToken extracts the token from gRPC metadata or cookie headers diff --git a/server/server_test.go b/server/server_test.go index 303f938871f38..c4f4153f24d89 100644 --- a/server/server_test.go +++ b/server/server_test.go @@ -32,8 +32,10 @@ import ( "github.com/argoproj/argo-cd/v2/server/rbacpolicy" "github.com/argoproj/argo-cd/v2/test" "github.com/argoproj/argo-cd/v2/util/assets" + "github.com/argoproj/argo-cd/v2/util/cache" cacheutil "github.com/argoproj/argo-cd/v2/util/cache" appstatecache "github.com/argoproj/argo-cd/v2/util/cache/appstate" + "github.com/argoproj/argo-cd/v2/util/oidc" "github.com/argoproj/argo-cd/v2/util/rbac" settings_util "github.com/argoproj/argo-cd/v2/util/settings" testutil "github.com/argoproj/argo-cd/v2/util/test" @@ -533,7 +535,7 @@ func dexMockHandler(t *testing.T, url string) func(http.ResponseWriter, *http.Re } } -func getTestServer(t *testing.T, anonymousEnabled bool, withFakeSSO bool, useDexForSSO bool) (argocd *ArgoCDServer, oidcURL string) { +func getTestServer(t *testing.T, anonymousEnabled bool, withFakeSSO bool, useDexForSSO bool, additionalOIDCConfig settings_util.OIDCConfig) (argocd *ArgoCDServer, oidcURL string) { cm := test.NewFakeConfigMap() if anonymousEnabled { cm.Data["users.anonymous.enabled"] = "true" @@ -562,13 +564,12 @@ connectors: clientID: test-client clientSecret: $dex.oidc.clientSecret` } else { - oidcConfig := settings_util.OIDCConfig{ - Name: "Okta", - Issuer: oidcServer.URL, - ClientID: "argo-cd", - ClientSecret: "$oidc.okta.clientSecret", - } - oidcConfigString, err := yaml.Marshal(oidcConfig) + // override required oidc config fields but keep other configs as passed in + additionalOIDCConfig.Name = "Okta" + additionalOIDCConfig.Issuer = oidcServer.URL + additionalOIDCConfig.ClientID = "argo-cd" + additionalOIDCConfig.ClientSecret = "$oidc.okta.clientSecret" + oidcConfigString, err := yaml.Marshal(additionalOIDCConfig) require.NoError(t, err) cm.Data["oidc.config"] = string(oidcConfigString) // Avoid bothering with certs for local tests. @@ -589,9 +590,109 @@ connectors: argoCDOpts.DexServerAddr = ts.URL } argocd = NewServer(context.Background(), argoCDOpts) + var err error + argocd.ssoClientApp, err = oidc.NewClientApp(argocd.settings, argocd.DexServerAddr, argocd.DexTLSConfig, argocd.BaseHRef, cache.NewInMemoryCache(24*time.Hour)) + require.NoError(t, err) return argocd, oidcServer.URL } +func TestGetClaims(t *testing.T) { + + defaultExpiry := jwt.NewNumericDate(time.Now().Add(time.Hour * 24)) + defaultExpiryUnix := float64(defaultExpiry.Unix()) + + type testData struct { + test string + claims jwt.MapClaims + expectedErrorContains string + expectedClaims jwt.MapClaims + expectNewToken bool + additionalOIDCConfig settings_util.OIDCConfig + } + var tests = []testData{ + { + test: "GetClaims", + claims: jwt.MapClaims{ + "aud": "argo-cd", + "exp": defaultExpiry, + "sub": "randomUser", + }, + expectedErrorContains: "", + expectedClaims: jwt.MapClaims{ + "aud": "argo-cd", + "exp": defaultExpiryUnix, + "sub": "randomUser", + }, + expectNewToken: false, + additionalOIDCConfig: settings_util.OIDCConfig{}, + }, + { + // note: a passing test with user info groups can never be achieved since the user never logged in properly + // therefore the oidcClient's cache contains no accessToken for the user info endpoint + // and since the oidcClient cache is unexported (for good reasons) we can't mock this behaviour + test: "GetClaimsWithUserInfoGroupsEnabled", + claims: jwt.MapClaims{ + "aud": common.ArgoCDClientAppID, + "exp": defaultExpiry, + "sub": "randomUser", + }, + expectedErrorContains: "invalid session", + expectedClaims: jwt.MapClaims{ + "aud": common.ArgoCDClientAppID, + "exp": defaultExpiryUnix, + "sub": "randomUser", + }, + expectNewToken: false, + additionalOIDCConfig: settings_util.OIDCConfig{ + EnableUserInfoGroups: true, + UserInfoPath: "/userinfo", + UserInfoCacheExpiration: "5m", + }, + }, + } + + for _, testData := range tests { + testDataCopy := testData + + t.Run(testDataCopy.test, func(t *testing.T) { + t.Parallel() + + // Must be declared here to avoid race. + ctx := context.Background() //nolint:ineffassign,staticcheck + + argocd, oidcURL := getTestServer(t, false, true, false, testDataCopy.additionalOIDCConfig) + + // create new JWT and store it on the context to simulate an incoming request + testDataCopy.claims["iss"] = oidcURL + testDataCopy.expectedClaims["iss"] = oidcURL + token := jwt.NewWithClaims(jwt.SigningMethodRS512, testDataCopy.claims) + key, err := jwt.ParseRSAPrivateKeyFromPEM(testutil.PrivateKey) + require.NoError(t, err) + tokenString, err := token.SignedString(key) + require.NoError(t, err) + ctx = metadata.NewIncomingContext(context.Background(), metadata.Pairs(apiclient.MetaDataTokenKey, tokenString)) + + gotClaims, newToken, err := argocd.getClaims(ctx) + + // Note: testutil.oidcMockHandler currently doesn't implement reissuing expired tokens + // so newToken will always be empty + if testDataCopy.expectNewToken { + assert.NotEmpty(t, newToken) + } + if testDataCopy.expectedClaims == nil { + assert.Nil(t, gotClaims) + } else { + assert.Equal(t, testDataCopy.expectedClaims, gotClaims) + } + if testDataCopy.expectedErrorContains != "" { + assert.ErrorContains(t, err, testDataCopy.expectedErrorContains, "getClaims should have thrown an error and return an error") + } else { + assert.NoError(t, err) + } + }) + } +} + func TestAuthenticate_3rd_party_JWTs(t *testing.T) { // Marshaling single strings to strings is typical, so we test for this relatively common behavior. jwt.MarshalSingleStringAsArray = false @@ -723,7 +824,7 @@ func TestAuthenticate_3rd_party_JWTs(t *testing.T) { // Must be declared here to avoid race. ctx := context.Background() //nolint:ineffassign,staticcheck - argocd, oidcURL := getTestServer(t, testDataCopy.anonymousEnabled, true, testDataCopy.useDex) + argocd, oidcURL := getTestServer(t, testDataCopy.anonymousEnabled, true, testDataCopy.useDex, settings_util.OIDCConfig{}) if testDataCopy.useDex { testDataCopy.claims.Issuer = fmt.Sprintf("%s/api/dex", oidcURL) @@ -779,7 +880,7 @@ func TestAuthenticate_no_request_metadata(t *testing.T) { t.Run(testDataCopy.test, func(t *testing.T) { t.Parallel() - argocd, _ := getTestServer(t, testDataCopy.anonymousEnabled, true, true) + argocd, _ := getTestServer(t, testDataCopy.anonymousEnabled, true, true, settings_util.OIDCConfig{}) ctx := context.Background() ctx, err := argocd.Authenticate(ctx) @@ -825,7 +926,7 @@ func TestAuthenticate_no_SSO(t *testing.T) { // Must be declared here to avoid race. ctx := context.Background() //nolint:ineffassign,staticcheck - argocd, dexURL := getTestServer(t, testDataCopy.anonymousEnabled, false, true) + argocd, dexURL := getTestServer(t, testDataCopy.anonymousEnabled, false, true, settings_util.OIDCConfig{}) token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.RegisteredClaims{Issuer: fmt.Sprintf("%s/api/dex", dexURL)}) tokenString, err := token.SignedString([]byte("key")) require.NoError(t, err) @@ -933,7 +1034,7 @@ func TestAuthenticate_bad_request_metadata(t *testing.T) { // Must be declared here to avoid race. ctx := context.Background() //nolint:ineffassign,staticcheck - argocd, _ := getTestServer(t, testDataCopy.anonymousEnabled, true, true) + argocd, _ := getTestServer(t, testDataCopy.anonymousEnabled, true, true, settings_util.OIDCConfig{}) ctx = metadata.NewIncomingContext(context.Background(), testDataCopy.metadata) ctx, err := argocd.Authenticate(ctx) @@ -1425,3 +1526,46 @@ func TestReplaceBaseHRef(t *testing.T) { }) } } + +func Test_enforceContentTypes(t *testing.T) { + getBaseHandler := func(t *testing.T, allow bool) http.Handler { + return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { + assert.True(t, allow, "http handler was hit when it should have been blocked by content type enforcement") + writer.WriteHeader(200) + }) + } + + t.Parallel() + + t.Run("GET - not providing a content type, should still succeed", func(t *testing.T) { + handler := enforceContentTypes(getBaseHandler(t, true), []string{"application/json"}).(http.HandlerFunc) + req := httptest.NewRequest("GET", "/", nil) + w := httptest.NewRecorder() + handler(w, req) + resp := w.Result() + assert.Equal(t, 200, resp.StatusCode) + }) + + t.Run("POST", func(t *testing.T) { + handler := enforceContentTypes(getBaseHandler(t, true), []string{"application/json"}).(http.HandlerFunc) + req := httptest.NewRequest("POST", "/", nil) + w := httptest.NewRecorder() + handler(w, req) + resp := w.Result() + assert.Equal(t, 415, resp.StatusCode, "didn't provide a content type, should have gotten an error") + + req = httptest.NewRequest("POST", "/", nil) + req.Header = map[string][]string{"Content-Type": {"application/json"}} + w = httptest.NewRecorder() + handler(w, req) + resp = w.Result() + assert.Equal(t, 200, resp.StatusCode, "should have passed, since an allowed content type was provided") + + req = httptest.NewRequest("POST", "/", nil) + req.Header = map[string][]string{"Content-Type": {"not-allowed"}} + w = httptest.NewRecorder() + handler(w, req) + resp = w.Result() + assert.Equal(t, 415, resp.StatusCode, "should not have passed, since a disallowed content type was provided") + }) +} diff --git a/server/settings/settings.go b/server/settings/settings.go index 2f797d552f4ce..32f5016419b4b 100644 --- a/server/settings/settings.go +++ b/server/settings/settings.go @@ -131,11 +131,12 @@ func (s *Server) Get(ctx context.Context, q *settingspkg.SettingsQuery) (*settin } if oidcConfig := argoCDSettings.OIDCConfig(); oidcConfig != nil { set.OIDCConfig = &settingspkg.OIDCConfig{ - Name: oidcConfig.Name, - Issuer: oidcConfig.Issuer, - ClientID: oidcConfig.ClientID, - CLIClientID: oidcConfig.CLIClientID, - Scopes: oidcConfig.RequestedScopes, + Name: oidcConfig.Name, + Issuer: oidcConfig.Issuer, + ClientID: oidcConfig.ClientID, + CLIClientID: oidcConfig.CLIClientID, + Scopes: oidcConfig.RequestedScopes, + EnablePKCEAuthentication: oidcConfig.EnablePKCEAuthentication, } if len(argoCDSettings.OIDCConfig().RequestedIDTokenClaims) > 0 { set.OIDCConfig.IDTokenClaims = argoCDSettings.OIDCConfig().RequestedIDTokenClaims diff --git a/server/settings/settings.proto b/server/settings/settings.proto index 9f95c9433b545..a6aa97120c8de 100644 --- a/server/settings/settings.proto +++ b/server/settings/settings.proto @@ -85,6 +85,7 @@ message OIDCConfig { string cliClientID = 4 [(gogoproto.customname) = "CLIClientID"]; repeated string scopes = 5; map idTokenClaims = 6 [(gogoproto.customname) = "IDTokenClaims"]; + bool enablePKCEAuthentication = 7; } // SettingsService diff --git a/test/container/Dockerfile b/test/container/Dockerfile index c86fbb1f387b1..9db9a2b07c33f 100644 --- a/test/container/Dockerfile +++ b/test/container/Dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/library/redis:7.0.11@sha256:f50031a49f41e493087fb95f96fdb3523bb25dcf6a3f0b07c588ad3cdbe1d0aa as redis +FROM docker.io/library/redis:7.2.4@sha256:cc8b0b85fe6917a401334fd285f9a8d66fae231abcf13aadfd02975bf3924a47 as redis # There are libraries we will want to copy from here in the final stage of the # build, but the COPY directive does not have a way to determine system @@ -6,7 +6,7 @@ FROM docker.io/library/redis:7.0.11@sha256:f50031a49f41e493087fb95f96fdb3523bb25 RUN ln -s /usr/lib/$(uname -m)-linux-gnu /usr/lib/linux-gnu # Please make sure to also check the contained yarn version and update the references below when upgrading this image's version -FROM docker.io/library/node:20.7.0@sha256:f08c20b9f9c55dd47b1841793f0ee480c5395aa165cd02edfd68b068ed64bfb5 as node +FROM docker.io/library/node:21.6.1@sha256:abc4a25c8b5a2b460f3144aabfc8941ecd7e4fb721e0b14b635e70394c1899fb as node FROM docker.io/library/golang:1.21.3@sha256:02d7116222536a5cf0fcf631f90b507758b669648e0f20186d2dc94a9b419a9b as golang diff --git a/test/container/Procfile b/test/container/Procfile index ef5100e71bab3..3ec9add44d5a7 100644 --- a/test/container/Procfile +++ b/test/container/Procfile @@ -1,6 +1,6 @@ controller: [ "$BIN_MODE" = 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} ARGOCD_BINARY_NAME=argocd-application-controller $COMMAND --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081} --application-namespaces=${ARGOCD_APPLICATION_NAMESPACES:-''}" api-server: [ "$BIN_MODE" = 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_BINARY_NAME=argocd-server $COMMAND --loglevel debug --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379} --disable-auth=${ARGOCD_E2E_DISABLE_AUTH:-'true'} --insecure --dex-server http://localhost:${ARGOCD_E2E_DEX_PORT:-5556} --repo-server localhost:${ARGOCD_E2E_REPOSERVER_PORT:-8081} --port ${ARGOCD_E2E_APISERVER_PORT:-8080} --application-namespaces=${ARGOCD_APPLICATION_NAMESPACES:-''} " -dex: sh -c "test $ARGOCD_IN_CI = true && exit 0; ARGOCD_BINARY_NAME=argocd-dex go run github.com/argoproj/argo-cd/cmd gendexcfg -o `pwd`/dist/dex.yaml && docker run --rm -p ${ARGOCD_E2E_DEX_PORT:-5556}:${ARGOCD_E2E_DEX_PORT:-5556} -v `pwd`/dist/dex.yaml:/dex.yaml ghcr.io/dexidp/dex:v2.37.0 serve /dex.yaml" +dex: sh -c "test $ARGOCD_IN_CI = true && exit 0; ARGOCD_BINARY_NAME=argocd-dex go run github.com/argoproj/argo-cd/cmd gendexcfg -o `pwd`/dist/dex.yaml && docker run --rm -p ${ARGOCD_E2E_DEX_PORT:-5556}:${ARGOCD_E2E_DEX_PORT:-5556} -v `pwd`/dist/dex.yaml:/dex.yaml ghcr.io/dexidp/dex:v2.38.0 serve /dex.yaml" redis: sh -c "/usr/local/bin/redis-server --save "" --appendonly no --port ${ARGOCD_E2E_REDIS_PORT:-6379}" repo-server: [ "$BIN_MODE" = 'true' ] && COMMAND=./dist/argocd || COMMAND='go run ./cmd/main.go' && sh -c "FORCE_LOG_COLORS=1 ARGOCD_FAKE_IN_CLUSTER=true ARGOCD_GNUPGHOME=${ARGOCD_GNUPGHOME:-/tmp/argocd-local/gpg/keys} ARGOCD_PLUGINSOCKFILEPATH=${ARGOCD_PLUGINSOCKFILEPATH:-./test/cmp} ARGOCD_GPG_DATA_PATH=${ARGOCD_GPG_DATA_PATH:-/tmp/argocd-local/gpg/source} ARGOCD_BINARY_NAME=argocd-repo-server $COMMAND --loglevel debug --port ${ARGOCD_E2E_REPOSERVER_PORT:-8081} --redis localhost:${ARGOCD_E2E_REDIS_PORT:-6379}" ui: sh -c "test $ARGOCD_IN_CI = true && exit 0; cd ui && ARGOCD_E2E_YARN_HOST=0.0.0.0 ${ARGOCD_E2E_YARN_CMD:-yarn} start" diff --git a/test/e2e/app_management_ns_test.go b/test/e2e/app_management_ns_test.go index 15cbd43534025..32636e2b52c49 100644 --- a/test/e2e/app_management_ns_test.go +++ b/test/e2e/app_management_ns_test.go @@ -748,7 +748,7 @@ func TestNamespacedResourceDiffing(t *testing.T) { Then(). Expect(SyncStatusIs(SyncStatusCodeOutOfSync)). And(func(app *Application) { - diffOutput, err := RunCli("app", "diff", ctx.AppQualifiedName(), "--local", "testdata/guestbook") + diffOutput, err := RunCli("app", "diff", ctx.AppQualifiedName(), "--local-repo-root", ".", "--local", "testdata/guestbook") assert.Error(t, err) assert.Contains(t, diffOutput, fmt.Sprintf("===== apps/Deployment %s/guestbook-ui ======", DeploymentNamespace())) }). @@ -761,7 +761,7 @@ func TestNamespacedResourceDiffing(t *testing.T) { Then(). Expect(SyncStatusIs(SyncStatusCodeSynced)). And(func(app *Application) { - diffOutput, err := RunCli("app", "diff", ctx.AppQualifiedName(), "--local", "testdata/guestbook") + diffOutput, err := RunCli("app", "diff", ctx.AppQualifiedName(), "--local-repo-root", ".", "--local", "testdata/guestbook") assert.NoError(t, err) assert.Empty(t, diffOutput) }). @@ -897,7 +897,7 @@ func testNSEdgeCasesApplicationResources(t *testing.T, appPath string, statusCod expect. Expect(HealthIs(statusCode)). And(func(app *Application) { - diffOutput, err := RunCli("app", "diff", ctx.AppQualifiedName(), "--local", path.Join("testdata", appPath)) + diffOutput, err := RunCli("app", "diff", ctx.AppQualifiedName(), "--local-repo-root", ".", "--local", path.Join("testdata", appPath)) assert.Empty(t, diffOutput) assert.NoError(t, err) }) @@ -998,7 +998,7 @@ func TestNamespacedLocalManifestSync(t *testing.T) { Given(). LocalPath(guestbookPathLocal). When(). - Sync(). + Sync("--local-repo-root", "."). Then(). Expect(SyncStatusIs(SyncStatusCodeSynced)). And(func(app *Application) { @@ -1066,7 +1066,7 @@ func TestNamespacedLocalSyncDryRunWithASEnabled(t *testing.T) { assert.NoError(t, err) appBefore := app.DeepCopy() - _, err = RunCli("app", "sync", app.QualifiedName(), "--dry-run", "--local", guestbookPathLocal) + _, err = RunCli("app", "sync", app.QualifiedName(), "--dry-run", "--local-repo-root", ".", "--local", guestbookPathLocal) assert.NoError(t, err) appAfter := app.DeepCopy() @@ -1483,7 +1483,7 @@ func TestNamespacedOrphanedResource(t *testing.T) { ProjectSpec(AppProjectSpec{ SourceRepos: []string{"*"}, Destinations: []ApplicationDestination{{Namespace: "*", Server: "*"}}, - OrphanedResources: &OrphanedResourcesMonitorSettings{Warn: pointer.BoolPtr(true)}, + OrphanedResources: &OrphanedResourcesMonitorSettings{Warn: pointer.Bool(true)}, SourceNamespaces: []string{AppNamespace()}, }). SetTrackingMethod("annotation"). @@ -1515,7 +1515,7 @@ func TestNamespacedOrphanedResource(t *testing.T) { ProjectSpec(AppProjectSpec{ SourceRepos: []string{"*"}, Destinations: []ApplicationDestination{{Namespace: "*", Server: "*"}}, - OrphanedResources: &OrphanedResourcesMonitorSettings{Warn: pointer.BoolPtr(true), Ignore: []OrphanedResourceKey{{Group: "Test", Kind: "ConfigMap"}}}, + OrphanedResources: &OrphanedResourcesMonitorSettings{Warn: pointer.Bool(true), Ignore: []OrphanedResourceKey{{Group: "Test", Kind: "ConfigMap"}}}, SourceNamespaces: []string{AppNamespace()}, }). When(). @@ -1531,7 +1531,7 @@ func TestNamespacedOrphanedResource(t *testing.T) { ProjectSpec(AppProjectSpec{ SourceRepos: []string{"*"}, Destinations: []ApplicationDestination{{Namespace: "*", Server: "*"}}, - OrphanedResources: &OrphanedResourcesMonitorSettings{Warn: pointer.BoolPtr(true), Ignore: []OrphanedResourceKey{{Kind: "ConfigMap"}}}, + OrphanedResources: &OrphanedResourcesMonitorSettings{Warn: pointer.Bool(true), Ignore: []OrphanedResourceKey{{Kind: "ConfigMap"}}}, SourceNamespaces: []string{AppNamespace()}, }). When(). @@ -1548,7 +1548,7 @@ func TestNamespacedOrphanedResource(t *testing.T) { ProjectSpec(AppProjectSpec{ SourceRepos: []string{"*"}, Destinations: []ApplicationDestination{{Namespace: "*", Server: "*"}}, - OrphanedResources: &OrphanedResourcesMonitorSettings{Warn: pointer.BoolPtr(true), Ignore: []OrphanedResourceKey{{Kind: "ConfigMap", Name: "orphaned-configmap"}}}, + OrphanedResources: &OrphanedResourcesMonitorSettings{Warn: pointer.Bool(true), Ignore: []OrphanedResourceKey{{Kind: "ConfigMap", Name: "orphaned-configmap"}}}, SourceNamespaces: []string{AppNamespace()}, }). When(). @@ -1770,7 +1770,7 @@ func TestNamespacedListResource(t *testing.T) { ProjectSpec(AppProjectSpec{ SourceRepos: []string{"*"}, Destinations: []ApplicationDestination{{Namespace: "*", Server: "*"}}, - OrphanedResources: &OrphanedResourcesMonitorSettings{Warn: pointer.BoolPtr(true)}, + OrphanedResources: &OrphanedResourcesMonitorSettings{Warn: pointer.Bool(true)}, SourceNamespaces: []string{AppNamespace()}, }). Path(guestbookPath). @@ -1863,7 +1863,7 @@ func TestNamespacedNamespaceAutoCreation(t *testing.T) { Then(). Expect(Success("")). And(func(app *Application) { - //Verify delete app does not delete the namespace auto created + // Verify delete app does not delete the namespace auto created output, err := Run("", "kubectl", "get", "namespace", updatedNamespace) assert.NoError(t, err) assert.Contains(t, output, updatedNamespace) @@ -2089,8 +2089,8 @@ metadata: delete(ns.Annotations, "argocd.argoproj.io/tracking-id") delete(ns.Annotations, "kubectl.kubernetes.io/last-applied-configuration") - assert.Equal(t, map[string]string{"test": "true", "foo": "bar"}, ns.Labels) - assert.Equal(t, map[string]string{"argocd.argoproj.io/sync-options": "ServerSideApply=true", "something": "whatevs", "bar": "bat"}, ns.Annotations) + assert.Equal(t, map[string]string{"foo": "bar"}, ns.Labels) + assert.Equal(t, map[string]string{"argocd.argoproj.io/sync-options": "ServerSideApply=true", "bar": "bat"}, ns.Annotations) })). When(). And(func() { @@ -2109,7 +2109,7 @@ metadata: delete(ns.Annotations, "kubectl.kubernetes.io/last-applied-configuration") delete(ns.Annotations, "argocd.argoproj.io/tracking-id") - assert.Equal(t, map[string]string{"test": "true", "foo": "bar"}, ns.Labels) + assert.Equal(t, map[string]string{"foo": "bar"}, ns.Labels) assert.Equal(t, map[string]string{"argocd.argoproj.io/sync-options": "ServerSideApply=true", "something": "hmm", "bar": "bat"}, ns.Annotations) assert.Equal(t, map[string]string{"something": "hmm", "bar": "bat"}, app.Spec.SyncPolicy.ManagedNamespaceMetadata.Annotations) })). @@ -2130,7 +2130,7 @@ metadata: delete(ns.Annotations, "kubectl.kubernetes.io/last-applied-configuration") delete(ns.Annotations, "argocd.argoproj.io/tracking-id") - assert.Equal(t, map[string]string{"test": "true", "foo": "bar"}, ns.Labels) + assert.Equal(t, map[string]string{"foo": "bar"}, ns.Labels) assert.Equal(t, map[string]string{"argocd.argoproj.io/sync-options": "ServerSideApply=true", "bar": "bat"}, ns.Annotations) assert.Equal(t, map[string]string{"bar": "bat"}, app.Spec.SyncPolicy.ManagedNamespaceMetadata.Annotations) })). @@ -2448,6 +2448,7 @@ func TestNamespacedDisableManifestGeneration(t *testing.T) { }). When(). And(func() { + time.Sleep(3 * time.Second) SetEnableManifestGeneration(map[ApplicationSourceType]bool{ ApplicationSourceTypeKustomize: false, }) diff --git a/test/e2e/app_management_test.go b/test/e2e/app_management_test.go index 2a4c7d1461ef5..10b2cf926723c 100644 --- a/test/e2e/app_management_test.go +++ b/test/e2e/app_management_test.go @@ -1324,7 +1324,7 @@ func TestLocalManifestSync(t *testing.T) { Given(). LocalPath(guestbookPathLocal). When(). - Sync(). + Sync("--local-repo-root", "."). Then(). Expect(SyncStatusIs(SyncStatusCodeSynced)). And(func(app *Application) { @@ -1385,7 +1385,7 @@ func TestLocalSyncDryRunWithAutosyncEnabled(t *testing.T) { assert.NoError(t, err) appBefore := app.DeepCopy() - _, err = RunCli("app", "sync", app.Name, "--dry-run", "--local", guestbookPathLocal) + _, err = RunCli("app", "sync", app.Name, "--dry-run", "--local-repo-root", ".", "--local", guestbookPathLocal) assert.NoError(t, err) appAfter := app.DeepCopy() @@ -1864,7 +1864,7 @@ func TestOrphanedResource(t *testing.T) { ProjectSpec(AppProjectSpec{ SourceRepos: []string{"*"}, Destinations: []ApplicationDestination{{Namespace: "*", Server: "*"}}, - OrphanedResources: &OrphanedResourcesMonitorSettings{Warn: pointer.BoolPtr(true)}, + OrphanedResources: &OrphanedResourcesMonitorSettings{Warn: pointer.Bool(true)}, }). Path(guestbookPath). When(). @@ -1893,7 +1893,7 @@ func TestOrphanedResource(t *testing.T) { ProjectSpec(AppProjectSpec{ SourceRepos: []string{"*"}, Destinations: []ApplicationDestination{{Namespace: "*", Server: "*"}}, - OrphanedResources: &OrphanedResourcesMonitorSettings{Warn: pointer.BoolPtr(true), Ignore: []OrphanedResourceKey{{Group: "Test", Kind: "ConfigMap"}}}, + OrphanedResources: &OrphanedResourcesMonitorSettings{Warn: pointer.Bool(true), Ignore: []OrphanedResourceKey{{Group: "Test", Kind: "ConfigMap"}}}, }). When(). Refresh(RefreshTypeNormal). @@ -1908,7 +1908,7 @@ func TestOrphanedResource(t *testing.T) { ProjectSpec(AppProjectSpec{ SourceRepos: []string{"*"}, Destinations: []ApplicationDestination{{Namespace: "*", Server: "*"}}, - OrphanedResources: &OrphanedResourcesMonitorSettings{Warn: pointer.BoolPtr(true), Ignore: []OrphanedResourceKey{{Kind: "ConfigMap"}}}, + OrphanedResources: &OrphanedResourcesMonitorSettings{Warn: pointer.Bool(true), Ignore: []OrphanedResourceKey{{Kind: "ConfigMap"}}}, }). When(). Refresh(RefreshTypeNormal). @@ -1924,7 +1924,7 @@ func TestOrphanedResource(t *testing.T) { ProjectSpec(AppProjectSpec{ SourceRepos: []string{"*"}, Destinations: []ApplicationDestination{{Namespace: "*", Server: "*"}}, - OrphanedResources: &OrphanedResourcesMonitorSettings{Warn: pointer.BoolPtr(true), Ignore: []OrphanedResourceKey{{Kind: "ConfigMap", Name: "orphaned-configmap"}}}, + OrphanedResources: &OrphanedResourcesMonitorSettings{Warn: pointer.Bool(true), Ignore: []OrphanedResourceKey{{Kind: "ConfigMap", Name: "orphaned-configmap"}}}, }). When(). Refresh(RefreshTypeNormal). @@ -2133,7 +2133,7 @@ func TestListResource(t *testing.T) { ProjectSpec(AppProjectSpec{ SourceRepos: []string{"*"}, Destinations: []ApplicationDestination{{Namespace: "*", Server: "*"}}, - OrphanedResources: &OrphanedResourcesMonitorSettings{Warn: pointer.BoolPtr(true)}, + OrphanedResources: &OrphanedResourcesMonitorSettings{Warn: pointer.Bool(true)}, }). Path(guestbookPath). When(). @@ -2208,7 +2208,7 @@ func TestNamespaceAutoCreation(t *testing.T) { CreateApp("--sync-option", "CreateNamespace=true"). Then(). And(func(app *Application) { - //Make sure the namespace we are about to update to does not exist + // Make sure the namespace we are about to update to does not exist _, err := Run("", "kubectl", "get", "namespace", updatedNamespace) assert.Error(t, err) assert.Contains(t, err.Error(), "not found") @@ -2227,7 +2227,7 @@ func TestNamespaceAutoCreation(t *testing.T) { Then(). Expect(Success("")). And(func(app *Application) { - //Verify delete app does not delete the namespace auto created + // Verify delete app does not delete the namespace auto created output, err := Run("", "kubectl", "get", "namespace", updatedNamespace) assert.NoError(t, err) assert.Contains(t, output, updatedNamespace) diff --git a/test/e2e/app_sync_options_test.go b/test/e2e/app_sync_options_test.go new file mode 100644 index 0000000000000..7d0a0ffeabb99 --- /dev/null +++ b/test/e2e/app_sync_options_test.go @@ -0,0 +1,61 @@ +package e2e + +import ( + "testing" + + "github.com/argoproj/gitops-engine/pkg/health" + . "github.com/argoproj/gitops-engine/pkg/sync/common" + "github.com/stretchr/testify/assert" + v1 "k8s.io/api/core/v1" + + . "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + . "github.com/argoproj/argo-cd/v2/test/e2e/fixture" + . "github.com/argoproj/argo-cd/v2/test/e2e/fixture/app" +) + +// Given application is set with --sync-option CreateNamespace=true and --sync-option ServerSideApply=true +// +// application --dest-namespace exists +// +// Then, --dest-namespace is created with server side apply +// application is synced and healthy with resource +// application resources created with server side apply in the newly created namespace. +func TestNamespaceCreationWithSSA(t *testing.T) { + SkipOnEnv(t, "OPENSHIFT") + namespace := "guestbook-ui-with-ssa" + defer func() { + if !t.Skipped() { + _, err := Run("", "kubectl", "delete", "namespace", namespace) + assert.NoError(t, err) + } + }() + + ctx := Given(t) + ctx. + SetAppNamespace(AppNamespace()). + Timeout(30). + Path("guestbook"). + When(). + CreateFromFile(func(app *Application) { + app.Spec.SyncPolicy = &SyncPolicy{ + SyncOptions: SyncOptions{"CreateNamespace=true", "ServerSideApply=true"}, + } + }). + Then(). + Expect(NoNamespace(namespace)). + When(). + AppSet("--dest-namespace", namespace). + Sync(). + Then(). + Expect(Success("")). + Expect(Namespace(namespace, func(app *Application, ns *v1.Namespace) { + assert.NotContains(t, ns.Annotations, "kubectl.kubernetes.io/last-applied-configuration") + })). + Expect(SyncStatusIs(SyncStatusCodeSynced)). + Expect(HealthIs(health.HealthStatusHealthy)). + Expect(OperationPhaseIs(OperationSucceeded)). + Expect(ResourceHealthWithNamespaceIs("Deployment", "guestbook-ui", namespace, health.HealthStatusHealthy)). + Expect(ResourceSyncStatusWithNamespaceIs("Deployment", "guestbook-ui", namespace, SyncStatusCodeSynced)). + Expect(ResourceHealthWithNamespaceIs("Service", "guestbook-ui", namespace, health.HealthStatusHealthy)). + Expect(ResourceSyncStatusWithNamespaceIs("Service", "guestbook-ui", namespace, SyncStatusCodeSynced)) +} diff --git a/test/e2e/applicationset_test.go b/test/e2e/applicationset_test.go index f56f9f552e9f6..5b9b8190c5437 100644 --- a/test/e2e/applicationset_test.go +++ b/test/e2e/applicationset_test.go @@ -53,6 +53,8 @@ var ( func TestSimpleListGeneratorExternalNamespace(t *testing.T) { + var externalNamespace = string(utils.ArgoCDExternalNamespace) + expectedApp := argov1alpha1.Application{ TypeMeta: metav1.TypeMeta{ Kind: "Application", @@ -60,7 +62,7 @@ func TestSimpleListGeneratorExternalNamespace(t *testing.T) { }, ObjectMeta: metav1.ObjectMeta{ Name: "my-cluster-guestbook", - Namespace: utils.ArgoCDExternalNamespace, + Namespace: externalNamespace, Finalizers: []string{"resources-finalizer.argocd.argoproj.io"}, }, Spec: argov1alpha1.ApplicationSpec{ @@ -82,10 +84,10 @@ func TestSimpleListGeneratorExternalNamespace(t *testing.T) { Given(t). // Create a ListGenerator-based ApplicationSet When(). - SwitchToExternalNamespace(). - CreateNamespace(utils.ArgoCDExternalNamespace).Create(v1alpha1.ApplicationSet{ObjectMeta: metav1.ObjectMeta{ + SwitchToExternalNamespace(utils.ArgoCDExternalNamespace). + CreateNamespace(externalNamespace).Create(v1alpha1.ApplicationSet{ObjectMeta: metav1.ObjectMeta{ Name: "simple-list-generator-external", - Namespace: utils.ArgoCDExternalNamespace, + Namespace: externalNamespace, }, Spec: v1alpha1.ApplicationSetSpec{ GoTemplate: true, @@ -151,6 +153,191 @@ func TestSimpleListGeneratorExternalNamespace(t *testing.T) { } +func TestSimpleListGeneratorExternalNamespaceNoConflict(t *testing.T) { + + var externalNamespace = string(utils.ArgoCDExternalNamespace) + var externalNamespace2 = string(utils.ArgoCDExternalNamespace2) + + expectedApp := argov1alpha1.Application{ + TypeMeta: metav1.TypeMeta{ + Kind: "Application", + APIVersion: "argoproj.io/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "my-cluster-guestbook", + Namespace: externalNamespace, + Finalizers: []string{"resources-finalizer.argocd.argoproj.io"}, + }, + Spec: argov1alpha1.ApplicationSpec{ + Project: "default", + Source: &argov1alpha1.ApplicationSource{ + RepoURL: "https://github.com/argoproj/argocd-example-apps.git", + TargetRevision: "HEAD", + Path: "guestbook", + }, + Destination: argov1alpha1.ApplicationDestination{ + Server: "https://kubernetes.default.svc", + Namespace: "guestbook", + }, + }, + } + + expectedAppExternalNamespace2 := argov1alpha1.Application{ + TypeMeta: metav1.TypeMeta{ + Kind: "Application", + APIVersion: "argoproj.io/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "my-cluster-guestbook", + Namespace: externalNamespace2, + Finalizers: []string{"resources-finalizer.argocd.argoproj.io"}, + }, + Spec: argov1alpha1.ApplicationSpec{ + Project: "default", + Source: &argov1alpha1.ApplicationSource{ + RepoURL: "https://github.com/argoproj/argocd-example-apps.git", + TargetRevision: "HEAD", + Path: "guestbook", + }, + Destination: argov1alpha1.ApplicationDestination{ + Server: "https://kubernetes.default.svc", + Namespace: "guestbook", + }, + }, + } + + var expectedAppNewNamespace *argov1alpha1.Application + var expectedAppNewMetadata *argov1alpha1.Application + + Given(t). + // Create a ListGenerator-based ApplicationSet + When(). + SwitchToExternalNamespace(utils.ArgoCDExternalNamespace2). + CreateNamespace(externalNamespace2).Create(v1alpha1.ApplicationSet{ObjectMeta: metav1.ObjectMeta{ + Name: "simple-list-generator-external", + Namespace: externalNamespace2, + }, + Spec: v1alpha1.ApplicationSetSpec{ + GoTemplate: true, + Template: v1alpha1.ApplicationSetTemplate{ + ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{Name: "{{.cluster}}-guestbook"}, + Spec: argov1alpha1.ApplicationSpec{ + Project: "default", + Source: &argov1alpha1.ApplicationSource{ + RepoURL: "https://github.com/argoproj/argocd-example-apps.git", + TargetRevision: "HEAD", + Path: "guestbook", + }, + Destination: argov1alpha1.ApplicationDestination{ + Server: "{{.url}}", + Namespace: "guestbook", + }, + }, + }, + Generators: []v1alpha1.ApplicationSetGenerator{ + { + List: &v1alpha1.ListGenerator{ + Elements: []apiextensionsv1.JSON{{ + Raw: []byte(`{"cluster": "my-cluster","url": "https://kubernetes.default.svc"}`), + }}, + }, + }, + }, + }, + }).Then().Expect(ApplicationsExist([]argov1alpha1.Application{expectedAppExternalNamespace2})). + When(). + SwitchToExternalNamespace(utils.ArgoCDExternalNamespace). + CreateNamespace(externalNamespace).Create(v1alpha1.ApplicationSet{ObjectMeta: metav1.ObjectMeta{ + Name: "simple-list-generator-external", + Namespace: externalNamespace, + }, + Spec: v1alpha1.ApplicationSetSpec{ + GoTemplate: true, + Template: v1alpha1.ApplicationSetTemplate{ + ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{Name: "{{.cluster}}-guestbook"}, + Spec: argov1alpha1.ApplicationSpec{ + Project: "default", + Source: &argov1alpha1.ApplicationSource{ + RepoURL: "https://github.com/argoproj/argocd-example-apps.git", + TargetRevision: "HEAD", + Path: "guestbook", + }, + Destination: argov1alpha1.ApplicationDestination{ + Server: "{{.url}}", + Namespace: "guestbook", + }, + }, + }, + Generators: []v1alpha1.ApplicationSetGenerator{ + { + List: &v1alpha1.ListGenerator{ + Elements: []apiextensionsv1.JSON{{ + Raw: []byte(`{"cluster": "my-cluster","url": "https://kubernetes.default.svc"}`), + }}, + }, + }, + }, + }, + }).Then().Expect(ApplicationsExist([]argov1alpha1.Application{expectedApp})). + When(). + SwitchToExternalNamespace(utils.ArgoCDExternalNamespace2). + Then(). + Expect(ApplicationsExist([]argov1alpha1.Application{expectedAppExternalNamespace2})). + When(). + SwitchToExternalNamespace(utils.ArgoCDExternalNamespace). + Then(). + // Update the ApplicationSet template namespace, and verify it updates the Applications + When(). + And(func() { + expectedAppNewNamespace = expectedApp.DeepCopy() + expectedAppNewNamespace.Spec.Destination.Namespace = "guestbook2" + }). + Update(func(appset *v1alpha1.ApplicationSet) { + appset.Spec.Template.Spec.Destination.Namespace = "guestbook2" + }).Then().Expect(ApplicationsExist([]argov1alpha1.Application{*expectedAppNewNamespace})). + When(). + SwitchToExternalNamespace(utils.ArgoCDExternalNamespace2). + Then(). + Expect(ApplicationsExist([]argov1alpha1.Application{expectedAppExternalNamespace2})). + When(). + SwitchToExternalNamespace(utils.ArgoCDExternalNamespace). + Then(). + // Update the metadata fields in the appset template, and make sure it propagates to the apps + When(). + And(func() { + expectedAppNewMetadata = expectedAppNewNamespace.DeepCopy() + expectedAppNewMetadata.ObjectMeta.Annotations = map[string]string{"annotation-key": "annotation-value"} + expectedAppNewMetadata.ObjectMeta.Labels = map[string]string{ + "label-key": "label-value", + } + }). + Update(func(appset *v1alpha1.ApplicationSet) { + appset.Spec.Template.Annotations = map[string]string{"annotation-key": "annotation-value"} + appset.Spec.Template.Labels = map[string]string{ + "label-key": "label-value", + } + }).Then().Expect(ApplicationsExist([]argov1alpha1.Application{*expectedAppNewMetadata})). + + // verify the ApplicationSet status conditions were set correctly + Expect(ApplicationSetHasConditions("simple-list-generator-external", ExpectedConditions)). + When(). + SwitchToExternalNamespace(utils.ArgoCDExternalNamespace2). + Then(). + Expect(ApplicationsExist([]argov1alpha1.Application{expectedAppExternalNamespace2})). + When(). + SwitchToExternalNamespace(utils.ArgoCDExternalNamespace). + Then(). + // Delete the ApplicationSet, and verify it deletes the Applications + When(). + Delete().Then().Expect(ApplicationsDoNotExist([]argov1alpha1.Application{*expectedAppNewMetadata})). + When(). + SwitchToExternalNamespace(utils.ArgoCDExternalNamespace2). + Then(). + Expect(ApplicationsExist([]argov1alpha1.Application{expectedAppExternalNamespace2})). + When(). + Delete().Then().Expect(ApplicationsDoNotExist([]argov1alpha1.Application{expectedAppExternalNamespace2})) +} + func TestSimpleListGenerator(t *testing.T) { expectedApp := argov1alpha1.Application{ @@ -412,6 +599,134 @@ func TestRenderHelmValuesObject(t *testing.T) { } +func TestTemplatePatch(t *testing.T) { + + expectedApp := argov1alpha1.Application{ + TypeMeta: metav1.TypeMeta{ + Kind: application.ApplicationKind, + APIVersion: "argoproj.io/v1alpha1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "my-cluster-guestbook", + Namespace: fixture.TestNamespace(), + Finalizers: []string{"resources-finalizer.argocd.argoproj.io"}, + Annotations: map[string]string{ + "annotation-some-key": "annotation-some-value", + }, + }, + Spec: argov1alpha1.ApplicationSpec{ + Project: "default", + Source: &argov1alpha1.ApplicationSource{ + RepoURL: "https://github.com/argoproj/argocd-example-apps.git", + TargetRevision: "HEAD", + Path: "guestbook", + }, + Destination: argov1alpha1.ApplicationDestination{ + Server: "https://kubernetes.default.svc", + Namespace: "guestbook", + }, + SyncPolicy: &argov1alpha1.SyncPolicy{ + SyncOptions: argov1alpha1.SyncOptions{"CreateNamespace=true"}, + }, + }, + } + + templatePatch := `{ + "metadata": { + "annotations": { + {{- range $k, $v := .annotations }} + "{{ $k }}": "{{ $v }}" + {{- end }} + } + }, + {{- if .createNamespace }} + "spec": { + "syncPolicy": { + "syncOptions": [ + "CreateNamespace=true" + ] + } + } + {{- end }} + } + ` + + var expectedAppNewNamespace *argov1alpha1.Application + var expectedAppNewMetadata *argov1alpha1.Application + + Given(t). + // Create a ListGenerator-based ApplicationSet + When().Create(v1alpha1.ApplicationSet{ObjectMeta: metav1.ObjectMeta{ + Name: "patch-template", + }, + Spec: v1alpha1.ApplicationSetSpec{ + GoTemplate: true, + Template: v1alpha1.ApplicationSetTemplate{ + ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{Name: "{{.cluster}}-guestbook"}, + Spec: argov1alpha1.ApplicationSpec{ + Project: "default", + Source: &argov1alpha1.ApplicationSource{ + RepoURL: "https://github.com/argoproj/argocd-example-apps.git", + TargetRevision: "HEAD", + Path: "guestbook", + }, + Destination: argov1alpha1.ApplicationDestination{ + Server: "{{.url}}", + Namespace: "guestbook", + }, + }, + }, + TemplatePatch: &templatePatch, + Generators: []v1alpha1.ApplicationSetGenerator{ + { + List: &v1alpha1.ListGenerator{ + Elements: []apiextensionsv1.JSON{{ + Raw: []byte(`{ + "cluster": "my-cluster", + "url": "https://kubernetes.default.svc", + "createNamespace": true, + "annotations": { + "annotation-some-key": "annotation-some-value" + } + }`), + }}, + }, + }, + }, + }, + }).Then().Expect(ApplicationsExist([]argov1alpha1.Application{expectedApp})). + + // Update the ApplicationSet template namespace, and verify it updates the Applications + When(). + And(func() { + expectedAppNewNamespace = expectedApp.DeepCopy() + expectedAppNewNamespace.Spec.Destination.Namespace = "guestbook2" + }). + Update(func(appset *v1alpha1.ApplicationSet) { + appset.Spec.Template.Spec.Destination.Namespace = "guestbook2" + }).Then().Expect(ApplicationsExist([]argov1alpha1.Application{*expectedAppNewNamespace})). + + // Update the metadata fields in the appset template, and make sure it propagates to the apps + When(). + And(func() { + expectedAppNewMetadata = expectedAppNewNamespace.DeepCopy() + expectedAppNewMetadata.ObjectMeta.Labels = map[string]string{ + "label-key": "label-value", + } + }). + Update(func(appset *v1alpha1.ApplicationSet) { + appset.Spec.Template.Labels = map[string]string{"label-key": "label-value"} + }).Then().Expect(ApplicationsExist([]argov1alpha1.Application{*expectedAppNewMetadata})). + + // verify the ApplicationSet status conditions were set correctly + Expect(ApplicationSetHasConditions("patch-template", ExpectedConditions)). + + // Delete the ApplicationSet, and verify it deletes the Applications + When(). + Delete().Then().Expect(ApplicationsDoNotExist([]argov1alpha1.Application{*expectedAppNewMetadata})) + +} + func TestSyncPolicyCreateUpdate(t *testing.T) { expectedApp := argov1alpha1.Application{ diff --git a/test/e2e/cluster_generator_test.go b/test/e2e/cluster_generator_test.go index 7cac40aa569fb..1d5699e23503d 100644 --- a/test/e2e/cluster_generator_test.go +++ b/test/e2e/cluster_generator_test.go @@ -18,6 +18,8 @@ import ( func TestSimpleClusterGeneratorExternalNamespace(t *testing.T) { + var externalNamespace = string(utils.ArgoCDExternalNamespace) + expectedApp := argov1alpha1.Application{ TypeMeta: metav1.TypeMeta{ Kind: "Application", @@ -25,7 +27,7 @@ func TestSimpleClusterGeneratorExternalNamespace(t *testing.T) { }, ObjectMeta: metav1.ObjectMeta{ Name: "cluster1-guestbook", - Namespace: utils.ArgoCDExternalNamespace, + Namespace: externalNamespace, Finalizers: []string{"resources-finalizer.argocd.argoproj.io"}, }, Spec: argov1alpha1.ApplicationSpec{ @@ -49,8 +51,8 @@ func TestSimpleClusterGeneratorExternalNamespace(t *testing.T) { // Create a ClusterGenerator-based ApplicationSet When(). CreateClusterSecret("my-secret", "cluster1", "https://kubernetes.default.svc"). - SwitchToExternalNamespace(). - CreateNamespace(utils.ArgoCDExternalNamespace). + SwitchToExternalNamespace(utils.ArgoCDExternalNamespace). + CreateNamespace(externalNamespace). Create(v1alpha1.ApplicationSet{ObjectMeta: metav1.ObjectMeta{ Name: "simple-cluster-generator", }, diff --git a/test/e2e/cluster_test.go b/test/e2e/cluster_test.go index e57b2132b7472..2074a6aa1b7b1 100644 --- a/test/e2e/cluster_test.go +++ b/test/e2e/cluster_test.go @@ -38,7 +38,7 @@ https://kubernetes.default.svc in-cluster %v Successful `, GetVe When(). CreateApp() - tries := 2 + tries := 5 for i := 0; i <= tries; i += 1 { clusterFixture.GivenWithSameState(t). When(). diff --git a/test/e2e/clusterdecisiongenerator_e2e_test.go b/test/e2e/clusterdecisiongenerator_e2e_test.go index 97d1327fe0331..5f0d6ff6ae3c7 100644 --- a/test/e2e/clusterdecisiongenerator_e2e_test.go +++ b/test/e2e/clusterdecisiongenerator_e2e_test.go @@ -19,6 +19,8 @@ var tenSec = int64(10) func TestSimpleClusterDecisionResourceGeneratorExternalNamespace(t *testing.T) { + var externalNamespace = string(utils.ArgoCDExternalNamespace) + expectedApp := argov1alpha1.Application{ TypeMeta: metav1.TypeMeta{ Kind: "Application", @@ -26,7 +28,7 @@ func TestSimpleClusterDecisionResourceGeneratorExternalNamespace(t *testing.T) { }, ObjectMeta: metav1.ObjectMeta{ Name: "cluster1-guestbook", - Namespace: utils.ArgoCDExternalNamespace, + Namespace: externalNamespace, Finalizers: []string{"resources-finalizer.argocd.argoproj.io"}, }, Spec: argov1alpha1.ApplicationSpec{ @@ -61,8 +63,8 @@ func TestSimpleClusterDecisionResourceGeneratorExternalNamespace(t *testing.T) { CreatePlacementDecisionConfigMap("my-configmap"). CreatePlacementDecision("my-placementdecision"). StatusUpdatePlacementDecision("my-placementdecision", clusterList). - CreateNamespace(utils.ArgoCDExternalNamespace). - SwitchToExternalNamespace(). + CreateNamespace(externalNamespace). + SwitchToExternalNamespace(utils.ArgoCDExternalNamespace). Create(v1alpha1.ApplicationSet{ObjectMeta: metav1.ObjectMeta{ Name: "simple-cluster-generator", }, diff --git a/test/e2e/delarative_test.go b/test/e2e/declarative_test.go similarity index 100% rename from test/e2e/delarative_test.go rename to test/e2e/declarative_test.go diff --git a/test/e2e/fixture/applicationsets/actions.go b/test/e2e/fixture/applicationsets/actions.go index 78878bcc24cbc..0b167c2b1a734 100644 --- a/test/e2e/fixture/applicationsets/actions.go +++ b/test/e2e/fixture/applicationsets/actions.go @@ -64,14 +64,14 @@ func (a *Actions) Then() *Consequences { return &Consequences{a.context, a} } -func (a *Actions) SwitchToExternalNamespace() *Actions { - a.context.useExternalNamespace = true - log.Infof("switched to external namespace: %s", utils.ArgoCDExternalNamespace) +func (a *Actions) SwitchToExternalNamespace(namespace utils.ExternalNamespace) *Actions { + a.context.switchToNamespace = namespace + log.Infof("switched to external namespace: %s", namespace) return a } func (a *Actions) SwitchToArgoCDNamespace() *Actions { - a.context.useExternalNamespace = false + a.context.switchToNamespace = "" log.Infof("switched to argocd namespace: %s", utils.ArgoCDNamespace) return a } @@ -216,8 +216,13 @@ func (a *Actions) Create(appSet v1alpha1.ApplicationSet) *Actions { var appSetClientSet dynamic.ResourceInterface - if a.context.useExternalNamespace { - appSetClientSet = fixtureClient.ExternalAppSetClientset + if a.context.switchToNamespace != "" { + externalAppSetClientset, found := fixtureClient.ExternalAppSetClientsets[utils.ExternalNamespace(a.context.switchToNamespace)] + if !found { + a.lastOutput, a.lastError = "", fmt.Errorf("No external clientset found for %s", a.context.switchToNamespace) + return a + } + appSetClientSet = externalAppSetClientset } else { appSetClientSet = fixtureClient.AppSetClientset } @@ -390,8 +395,13 @@ func (a *Actions) Delete() *Actions { var appSetClientSet dynamic.ResourceInterface - if a.context.useExternalNamespace { - appSetClientSet = fixtureClient.ExternalAppSetClientset + if a.context.switchToNamespace != "" { + externalAppSetClientset, found := fixtureClient.ExternalAppSetClientsets[utils.ExternalNamespace(a.context.switchToNamespace)] + if !found { + a.lastOutput, a.lastError = "", fmt.Errorf("No external clientset found for %s", a.context.switchToNamespace) + return a + } + appSetClientSet = externalAppSetClientset } else { appSetClientSet = fixtureClient.AppSetClientset } @@ -413,8 +423,12 @@ func (a *Actions) get() (*v1alpha1.ApplicationSet, error) { var appSetClientSet dynamic.ResourceInterface - if a.context.useExternalNamespace { - appSetClientSet = fixtureClient.ExternalAppSetClientset + if a.context.switchToNamespace != "" { + externalAppSetClientset, found := fixtureClient.ExternalAppSetClientsets[utils.ExternalNamespace(a.context.switchToNamespace)] + if !found { + return nil, fmt.Errorf("No external clientset found for %s", a.context.switchToNamespace) + } + appSetClientSet = externalAppSetClientset } else { appSetClientSet = fixtureClient.AppSetClientset } @@ -460,8 +474,13 @@ func (a *Actions) Update(toUpdate func(*v1alpha1.ApplicationSet)) *Actions { var appSetClientSet dynamic.ResourceInterface - if a.context.useExternalNamespace { - appSetClientSet = fixtureClient.ExternalAppSetClientset + if a.context.switchToNamespace != "" { + externalAppSetClientset, found := fixtureClient.ExternalAppSetClientsets[utils.ExternalNamespace(a.context.switchToNamespace)] + if !found { + a.lastOutput, a.lastError = "", fmt.Errorf("No external clientset found for %s", a.context.switchToNamespace) + return a + } + appSetClientSet = externalAppSetClientset } else { appSetClientSet = fixtureClient.AppSetClientset } diff --git a/test/e2e/fixture/applicationsets/consequences.go b/test/e2e/fixture/applicationsets/consequences.go index 2672b58fe9317..db614f3cf3075 100644 --- a/test/e2e/fixture/applicationsets/consequences.go +++ b/test/e2e/fixture/applicationsets/consequences.go @@ -77,8 +77,8 @@ func (c *Consequences) app(name string) *v1alpha1.Application { func (c *Consequences) apps() []v1alpha1.Application { var namespace string - if c.context.useExternalNamespace { - namespace = utils.ArgoCDExternalNamespace + if c.context.switchToNamespace != "" { + namespace = string(c.context.switchToNamespace) } else { namespace = fixture.TestNamespace() } @@ -100,8 +100,8 @@ func (c *Consequences) applicationSet(applicationSetName string) *v1alpha1.Appli var appSetClientSet dynamic.ResourceInterface - if c.context.useExternalNamespace { - appSetClientSet = fixtureClient.ExternalAppSetClientset + if c.context.switchToNamespace != "" { + appSetClientSet = fixtureClient.ExternalAppSetClientsets[c.context.switchToNamespace] } else { appSetClientSet = fixtureClient.AppSetClientset } diff --git a/test/e2e/fixture/applicationsets/context.go b/test/e2e/fixture/applicationsets/context.go index d2a0479a62aee..a7e91f4d0c8ff 100644 --- a/test/e2e/fixture/applicationsets/context.go +++ b/test/e2e/fixture/applicationsets/context.go @@ -4,7 +4,7 @@ import ( "testing" "time" - . "github.com/argoproj/argo-cd/v2/test/e2e/fixture/applicationsets/utils" + "github.com/argoproj/argo-cd/v2/test/e2e/fixture/applicationsets/utils" ) // Context implements the "given" part of given/when/then @@ -12,13 +12,13 @@ type Context struct { t *testing.T // name is the ApplicationSet's name, created by a Create action - name string - namespace string - useExternalNamespace bool + name string + namespace string + switchToNamespace utils.ExternalNamespace } func Given(t *testing.T) *Context { - EnsureCleanState(t) + utils.EnsureCleanState(t) return &Context{t: t} } diff --git a/test/e2e/fixture/applicationsets/utils/fixture.go b/test/e2e/fixture/applicationsets/utils/fixture.go index b81a8875498a0..0074fe76bf5c8 100644 --- a/test/e2e/fixture/applicationsets/utils/fixture.go +++ b/test/e2e/fixture/applicationsets/utils/fixture.go @@ -25,15 +25,21 @@ import ( "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" appclientset "github.com/argoproj/argo-cd/v2/pkg/client/clientset/versioned" "github.com/argoproj/argo-cd/v2/test/e2e/fixture" + "github.com/argoproj/argo-cd/v2/util/errors" ) +type ExternalNamespace string + const ( // ArgoCDNamespace is the namespace into which Argo CD and ApplicationSet controller are deployed, // and in which Application resources should be created. ArgoCDNamespace = "argocd-e2e" // ArgoCDExternalNamespace is an external namespace to test additional namespaces - ArgoCDExternalNamespace = "argocd-e2e-external" + ArgoCDExternalNamespace ExternalNamespace = "argocd-e2e-external" + + // ArgoCDExternalNamespace2 is an external namespace to test additional namespaces + ArgoCDExternalNamespace2 ExternalNamespace = "argocd-e2e-external-2" // ApplicationsResourcesNamespace is the namespace into which temporary resources (such as Deployments/Pods/etc) // can be deployed, such as using it as the target namespace in an Application resource. @@ -54,11 +60,11 @@ var ( // E2EFixtureK8sClient contains Kubernetes clients initialized from local k8s configuration type E2EFixtureK8sClient struct { - KubeClientset kubernetes.Interface - DynamicClientset dynamic.Interface - AppClientset appclientset.Interface - AppSetClientset dynamic.ResourceInterface - ExternalAppSetClientset dynamic.ResourceInterface + KubeClientset kubernetes.Interface + DynamicClientset dynamic.Interface + AppClientset appclientset.Interface + AppSetClientset dynamic.ResourceInterface + ExternalAppSetClientsets map[ExternalNamespace]dynamic.ResourceInterface } func GetEnvWithDefault(envName, defaultValue string) string { @@ -91,7 +97,11 @@ func GetE2EFixtureK8sClient() *E2EFixtureK8sClient { } internalClientVars.AppSetClientset = internalClientVars.DynamicClientset.Resource(v1alpha1.SchemeGroupVersion.WithResource("applicationsets")).Namespace(TestNamespace()) - internalClientVars.ExternalAppSetClientset = internalClientVars.DynamicClientset.Resource(v1alpha1.SchemeGroupVersion.WithResource("applicationsets")).Namespace(ArgoCDExternalNamespace) + internalClientVars.ExternalAppSetClientsets = map[ExternalNamespace]dynamic.ResourceInterface{ + ArgoCDExternalNamespace: internalClientVars.DynamicClientset.Resource(v1alpha1.SchemeGroupVersion.WithResource("applicationsets")).Namespace(string(ArgoCDExternalNamespace)), + ArgoCDExternalNamespace2: internalClientVars.DynamicClientset.Resource(v1alpha1.SchemeGroupVersion.WithResource("applicationsets")).Namespace(string(ArgoCDExternalNamespace2)), + } + }) return internalClientVars } @@ -112,9 +122,15 @@ func EnsureCleanState(t *testing.T) { } // Delete the argocd-e2e-external namespace, if it exists - err2 := fixtureClient.KubeClientset.CoreV1().Namespaces().Delete(context.Background(), ArgoCDExternalNamespace, v1.DeleteOptions{PropagationPolicy: &policy}) + err2 := fixtureClient.KubeClientset.CoreV1().Namespaces().Delete(context.Background(), string(ArgoCDExternalNamespace), v1.DeleteOptions{PropagationPolicy: &policy}) if err2 != nil && !strings.Contains(err2.Error(), "not found") { // 'not found' error is expected - CheckError(err) + CheckError(err2) + } + + // Delete the argocd-e2e-external namespace, if it exists + err3 := fixtureClient.KubeClientset.CoreV1().Namespaces().Delete(context.Background(), string(ArgoCDExternalNamespace2), v1.DeleteOptions{PropagationPolicy: &policy}) + if err3 != nil && !strings.Contains(err3.Error(), "not found") { // 'not found' error is expected + CheckError(err3) } // delete resources @@ -177,6 +193,15 @@ func EnsureCleanState(t *testing.T) { func waitForExpectedClusterState() error { fixtureClient := GetE2EFixtureK8sClient() + + SetProjectSpec(fixtureClient, "default", v1alpha1.AppProjectSpec{ + OrphanedResources: nil, + SourceRepos: []string{"*"}, + Destinations: []v1alpha1.ApplicationDestination{{Namespace: "*", Server: "*"}}, + ClusterResourceWhitelist: []v1.GroupKind{{Group: "*", Kind: "*"}}, + SourceNamespaces: []string{string(ArgoCDExternalNamespace), string(ArgoCDExternalNamespace2)}, + }) + // Wait up to 60 seconds for all the ApplicationSets to delete if err := waitForSuccess(func() error { list, err := fixtureClient.AppSetClientset.List(context.Background(), v1.ListOptions{}) @@ -210,56 +235,45 @@ func waitForExpectedClusterState() error { } // Wait up to 120 seconds for namespace to not exist - if err := waitForSuccess(func() error { - _, err := fixtureClient.KubeClientset.CoreV1().Namespaces().Get(context.Background(), ApplicationsResourcesNamespace, v1.GetOptions{}) - - msg := "" - - if err == nil { - msg = fmt.Sprintf("namespace '%s' still exists, after delete", ApplicationsResourcesNamespace) - } - - if msg == "" && err != nil && strings.Contains(err.Error(), "not found") { - // Success is an error containing 'applicationset-e2e' not found. - return nil - } - - if msg == "" { - msg = err.Error() + for _, namespace := range []string{string(ApplicationsResourcesNamespace), string(ArgoCDExternalNamespace), string(ArgoCDExternalNamespace2)} { + // Wait up to 120 seconds for namespace to not exist + if err := waitForSuccess(func() error { + return cleanUpNamespace(fixtureClient, namespace) + }, time.Now().Add(120*time.Second)); err != nil { + return err } - - return fmt.Errorf(msg) - - }, time.Now().Add(120*time.Second)); err != nil { - return err } - // Wait up to 120 seconds for namespace to not exist - if err := waitForSuccess(func() error { - _, err := fixtureClient.KubeClientset.CoreV1().Namespaces().Get(context.Background(), ArgoCDExternalNamespace, v1.GetOptions{}) + return nil +} - msg := "" +func SetProjectSpec(fixtureClient *E2EFixtureK8sClient, project string, spec v1alpha1.AppProjectSpec) { + proj, err := fixtureClient.AppClientset.ArgoprojV1alpha1().AppProjects(TestNamespace()).Get(context.Background(), project, v1.GetOptions{}) + errors.CheckError(err) + proj.Spec = spec + _, err = fixtureClient.AppClientset.ArgoprojV1alpha1().AppProjects(TestNamespace()).Update(context.Background(), proj, v1.UpdateOptions{}) + errors.CheckError(err) +} - if err == nil { - msg = fmt.Sprintf("namespace '%s' still exists, after delete", ArgoCDExternalNamespace) - } +func cleanUpNamespace(fixtureClient *E2EFixtureK8sClient, namespace string) error { + _, err := fixtureClient.KubeClientset.CoreV1().Namespaces().Get(context.Background(), namespace, v1.GetOptions{}) - if msg == "" && err != nil && strings.Contains(err.Error(), "not found") { - // Success is an error containing 'applicationset-e2e' not found. - return nil - } + msg := "" - if msg == "" { - msg = err.Error() - } + if err == nil { + msg = fmt.Sprintf("namespace '%s' still exists, after delete", namespace) + } - return fmt.Errorf(msg) + if msg == "" && err != nil && strings.Contains(err.Error(), "not found") { + // Success is an error containing 'applicationset-e2e' not found. + return nil + } - }, time.Now().Add(120*time.Second)); err != nil { - return err + if msg == "" { + msg = err.Error() } - return nil + return fmt.Errorf(msg) } // waitForSuccess waits for the condition to return a non-error value. diff --git a/test/e2e/fixture/fixture.go b/test/e2e/fixture/fixture.go index 0d8affabf5fca..f8dd60cb74974 100644 --- a/test/e2e/fixture/fixture.go +++ b/test/e2e/fixture/fixture.go @@ -938,8 +938,8 @@ func RestartRepoServer() { if prefix != "" { workload = prefix + "-repo-server" } - FailOnErr(Run("", "kubectl", "rollout", "restart", "deployment", workload)) - FailOnErr(Run("", "kubectl", "rollout", "status", "deployment", workload)) + FailOnErr(Run("", "kubectl", "rollout", "-n", TestNamespace(), "restart", "deployment", workload)) + FailOnErr(Run("", "kubectl", "rollout", "-n", TestNamespace(), "status", "deployment", workload)) // wait longer to avoid error on s390x time.Sleep(10 * time.Second) } @@ -955,8 +955,8 @@ func RestartAPIServer() { if prefix != "" { workload = prefix + "-server" } - FailOnErr(Run("", "kubectl", "rollout", "restart", "deployment", workload)) - FailOnErr(Run("", "kubectl", "rollout", "status", "deployment", workload)) + FailOnErr(Run("", "kubectl", "rollout", "-n", TestNamespace(), "restart", "deployment", workload)) + FailOnErr(Run("", "kubectl", "rollout", "-n", TestNamespace(), "status", "deployment", workload)) } } diff --git a/test/e2e/fixture/http.go b/test/e2e/fixture/http.go index 1e818f5262024..00c123ab5d893 100644 --- a/test/e2e/fixture/http.go +++ b/test/e2e/fixture/http.go @@ -28,6 +28,7 @@ func DoHttpRequest(method string, path string, data ...byte) (*http.Response, er return nil, err } req.AddCookie(&http.Cookie{Name: common.AuthCookieName, Value: token}) + req.Header.Set("Content-Type", "application/json") httpClient := &http.Client{ Transport: &http.Transport{ diff --git a/test/e2e/hook_test.go b/test/e2e/hook_test.go index f6bb1be872ac6..2db8ff87795ad 100644 --- a/test/e2e/hook_test.go +++ b/test/e2e/hook_test.go @@ -1,12 +1,14 @@ package e2e import ( + "context" "fmt" "testing" "time" "github.com/stretchr/testify/assert" v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/argoproj/gitops-engine/pkg/health" . "github.com/argoproj/gitops-engine/pkg/sync/common" @@ -48,6 +50,24 @@ func testHookSuccessful(t *testing.T, hookType HookType) { Expect(ResourceResultIs(ResourceResult{Version: "v1", Kind: "Pod", Namespace: DeploymentNamespace(), Name: "hook", Message: "pod/hook created", HookType: hookType, HookPhase: OperationSucceeded, SyncPhase: SyncPhase(hookType)})) } +func TestPostDeleteHook(t *testing.T) { + Given(t). + Path("post-delete-hook"). + When(). + CreateApp(). + Refresh(RefreshTypeNormal). + Delete(true). + Then(). + Expect(DoesNotExist()). + AndAction(func() { + hooks, err := KubeClientset.CoreV1().Pods(DeploymentNamespace()).List(context.Background(), metav1.ListOptions{}) + CheckError(err) + assert.Len(t, hooks.Items, 1) + assert.Equal(t, "hook", hooks.Items[0].Name) + }) + +} + // make sure that that hooks do not appear in "argocd app diff" func TestHookDiff(t *testing.T) { Given(t). diff --git a/test/e2e/notification_test.go b/test/e2e/notification_test.go index 363cb87454a0f..eebe4d8991ae5 100644 --- a/test/e2e/notification_test.go +++ b/test/e2e/notification_test.go @@ -12,7 +12,7 @@ import ( func TestNotificationsListServices(t *testing.T) { ctx := notifFixture.Given(t) ctx.When(). - SetParamInNotificationConfigMap("service.webhook.test", "url: https://test.com"). + SetParamInNotificationConfigMap("service.webhook.test", "url: https://test.example.com"). Then().Services(func(services *notification.ServiceList, err error) { assert.Nil(t, err) assert.Equal(t, []*notification.Service{{Name: pointer.String("test")}}, services.Items) diff --git a/test/e2e/project_management_test.go b/test/e2e/project_management_test.go index 24aa4e6d473c0..fb8886a21dbd4 100644 --- a/test/e2e/project_management_test.go +++ b/test/e2e/project_management_test.go @@ -437,7 +437,7 @@ func TestRemoveOrphanedIgnore(t *testing.T) { ObjectMeta: metav1.ObjectMeta{Name: projectName}, Spec: v1alpha1.AppProjectSpec{ OrphanedResources: &v1alpha1.OrphanedResourcesMonitorSettings{ - Warn: pointer.BoolPtr(true), + Warn: pointer.Bool(true), Ignore: []v1alpha1.OrphanedResourceKey{{Group: "group", Kind: "kind", Name: "name"}}, }, }, @@ -477,7 +477,7 @@ func TestRemoveOrphanedIgnore(t *testing.T) { } func createAndConfigGlobalProject() error { - //Create global project + // Create global project projectGlobalName := "proj-g-" + fixture.Name() _, err := fixture.RunCli("proj", "create", projectGlobalName, "--description", "Test description", @@ -519,7 +519,7 @@ func createAndConfigGlobalProject() error { return err } - //Configure global project settings + // Configure global project settings globalProjectsSettings := `data: accounts.config-service: apiKey globalProjects: | @@ -547,7 +547,7 @@ func TestGetVirtualProjectNoMatch(t *testing.T) { err := createAndConfigGlobalProject() assert.NoError(t, err) - //Create project which does not match global project settings + // Create project which does not match global project settings projectName := "proj-" + fixture.Name() _, err = fixture.RunCli("proj", "create", projectName, "--description", "Test description", @@ -559,7 +559,7 @@ func TestGetVirtualProjectNoMatch(t *testing.T) { proj, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Get(context.Background(), projectName, metav1.GetOptions{}) assert.NoError(t, err) - //Create an app belongs to proj project + // Create an app belongs to proj project _, err = fixture.RunCli("app", "create", fixture.Name(), "--repo", fixture.RepoURL(fixture.RepoURLTypeFile), "--path", guestbookPath, "--project", proj.Name, "--dest-server", v1alpha1.KubernetesInternalAPIServerAddr, "--dest-namespace", fixture.DeploymentNamespace()) assert.NoError(t, err) @@ -568,11 +568,11 @@ func TestGetVirtualProjectNoMatch(t *testing.T) { // Else the sync would fail to retrieve the app resources. time.Sleep(time.Second * 2) - //App trying to sync a resource which is not blacked listed anywhere + // App trying to sync a resource which is not blacked listed anywhere _, err = fixture.RunCli("app", "sync", fixture.Name(), "--resource", "apps:Deployment:guestbook-ui", "--timeout", fmt.Sprintf("%v", 10)) assert.NoError(t, err) - //app trying to sync a resource which is black listed by global project + // app trying to sync a resource which is black listed by global project _, err = fixture.RunCli("app", "sync", fixture.Name(), "--resource", ":Service:guestbook-ui", "--timeout", fmt.Sprintf("%v", 10)) assert.NoError(t, err) @@ -583,7 +583,7 @@ func TestGetVirtualProjectMatch(t *testing.T) { err := createAndConfigGlobalProject() assert.NoError(t, err) - //Create project which matches global project settings + // Create project which matches global project settings projectName := "proj-" + fixture.Name() _, err = fixture.RunCli("proj", "create", projectName, "--description", "Test description", @@ -595,12 +595,12 @@ func TestGetVirtualProjectMatch(t *testing.T) { proj, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Get(context.Background(), projectName, metav1.GetOptions{}) assert.NoError(t, err) - //Add a label to this project so that this project match global project selector + // Add a label to this project so that this project match global project selector proj.Labels = map[string]string{"opt": "me"} _, err = fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Update(context.Background(), proj, metav1.UpdateOptions{}) assert.NoError(t, err) - //Create an app belongs to proj project + // Create an app belongs to proj project _, err = fixture.RunCli("app", "create", fixture.Name(), "--repo", fixture.RepoURL(fixture.RepoURLTypeFile), "--path", guestbookPath, "--project", proj.Name, "--dest-server", v1alpha1.KubernetesInternalAPIServerAddr, "--dest-namespace", fixture.DeploymentNamespace()) assert.NoError(t, err) @@ -609,12 +609,12 @@ func TestGetVirtualProjectMatch(t *testing.T) { // Else the sync would fail to retrieve the app resources. time.Sleep(time.Second * 2) - //App trying to sync a resource which is not blacked listed anywhere + // App trying to sync a resource which is not blacked listed anywhere _, err = fixture.RunCli("app", "sync", fixture.Name(), "--resource", "apps:Deployment:guestbook-ui", "--timeout", fmt.Sprintf("%v", 10)) assert.Error(t, err) assert.Contains(t, err.Error(), "blocked by sync window") - //app trying to sync a resource which is black listed by global project + // app trying to sync a resource which is black listed by global project _, err = fixture.RunCli("app", "sync", fixture.Name(), "--resource", ":Service:guestbook-ui", "--timeout", fmt.Sprintf("%v", 10)) assert.Contains(t, err.Error(), "blocked by sync window") diff --git a/test/e2e/sync_waves_test.go b/test/e2e/sync_waves_test.go index ac5db15eee57d..8d0ee14e487d1 100644 --- a/test/e2e/sync_waves_test.go +++ b/test/e2e/sync_waves_test.go @@ -9,6 +9,8 @@ import ( "github.com/argoproj/gitops-engine/pkg/health" . "github.com/argoproj/gitops-engine/pkg/sync/common" + + v1 "k8s.io/api/core/v1" ) func TestFixingDegradedApp(t *testing.T) { @@ -100,3 +102,46 @@ func TestDegradedDeploymentIsSucceededAndSynced(t *testing.T) { Expect(SyncStatusIs(SyncStatusCodeSynced)). Expect(ResourceResultNumbering(1)) } + +// resources should be pruned in reverse of creation order(syncwaves order) +func TestSyncPruneOrderWithSyncWaves(t *testing.T) { + ctx := Given(t).Timeout(60) + + // remove finalizer to ensure proper cleanup if test fails at early stage + defer func() { + _, _ = RunCli("app", "patch-resource", ctx.AppQualifiedName(), + "--kind", "Pod", + "--resource-name", "pod-with-finalizers", + "--patch", `[{"op": "remove", "path": "/metadata/finalizers"}]`, + "--patch-type", "application/json-patch+json", "--all", + ) + }() + + ctx.Path("syncwaves-prune-order"). + When(). + CreateApp(). + // creation order: sa & role -> rolebinding -> pod + Sync(). + Wait(). + Then(). + Expect(SyncStatusIs(SyncStatusCodeSynced)). + Expect(HealthIs(health.HealthStatusHealthy)). + When(). + // delete files to remove resources + DeleteFile("pod.yaml"). + DeleteFile("rbac.yaml"). + Refresh(RefreshTypeHard). + IgnoreErrors(). + Then(). + Expect(SyncStatusIs(SyncStatusCodeOutOfSync)). + When(). + // prune order: pod -> rolebinding -> sa & role + Sync("--prune"). + Wait(). + Then(). + Expect(OperationPhaseIs(OperationSucceeded)). + Expect(SyncStatusIs(SyncStatusCodeSynced)). + Expect(HealthIs(health.HealthStatusHealthy)). + Expect(NotPod(func(p v1.Pod) bool { return p.Name == "pod-with-finalizers" })). + Expect(ResourceResultNumbering(4)) +} diff --git a/test/e2e/testdata/networking/guestbook-ui-svc-ingress.yaml b/test/e2e/testdata/networking/guestbook-ui-svc-ingress.yaml index d499de1e9c308..a4427135b193d 100644 --- a/test/e2e/testdata/networking/guestbook-ui-svc-ingress.yaml +++ b/test/e2e/testdata/networking/guestbook-ui-svc-ingress.yaml @@ -9,7 +9,7 @@ metadata: ingress.kubernetes.io/app-root: "/" spec: rules: - - host: myhost.com + - host: example.com http: paths: - path: / @@ -27,7 +27,7 @@ metadata: ingress.kubernetes.io/app-root: "/" spec: rules: - - host: myhost.com + - host: example.com http: paths: - path: / diff --git a/test/e2e/testdata/post-delete-hook/hook.yaml b/test/e2e/testdata/post-delete-hook/hook.yaml new file mode 100644 index 0000000000000..5631db681f1d0 --- /dev/null +++ b/test/e2e/testdata/post-delete-hook/hook.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: Pod +metadata: + annotations: + argocd.argoproj.io/hook: PostDelete + name: hook +spec: + containers: + - command: + - "true" + image: quay.io/argoprojlabs/argocd-e2e-container:0.1 + imagePullPolicy: IfNotPresent + name: main + restartPolicy: Never \ No newline at end of file diff --git a/test/e2e/testdata/syncwaves-prune-order/README.md b/test/e2e/testdata/syncwaves-prune-order/README.md new file mode 100644 index 0000000000000..92a62fdfe109d --- /dev/null +++ b/test/e2e/testdata/syncwaves-prune-order/README.md @@ -0,0 +1,15 @@ +## Test Scenario + +This test example is for testing the reverse pruning of resources with syncwaves during sync operation. + +Resource creation happens in below order +- wave 0: sa & role +- wave 1: rolebinding +- wave 2: pod + +They are setup in such a way that the resources will be cleaned up properly only if they are deleted in the reverse order of creation i.e +- wave 0: pod +- wave 1: rolebinding +- wave 2: sa & role + +If above delete order is not followed the pod gets stuck in terminating state due to a finalizer which is supposed to be removed by k8s container lifecycle hook on delete if delete order is correct. \ No newline at end of file diff --git a/test/e2e/testdata/syncwaves-prune-order/pod.yaml b/test/e2e/testdata/syncwaves-prune-order/pod.yaml new file mode 100644 index 0000000000000..f801a3992aa37 --- /dev/null +++ b/test/e2e/testdata/syncwaves-prune-order/pod.yaml @@ -0,0 +1,41 @@ +apiVersion: v1 +kind: Pod +metadata: + name: pod-with-finalizers + annotations: + argocd.argoproj.io/sync-wave: "2" + # remove this finalizers using container preStop lifecycle hook on delete + finalizers: + - example.com/block-delete +spec: + serviceAccountName: modify-pods-sa # sa with permissions to modify pods + terminationGracePeriodSeconds: 15 + containers: + - name: container + image: nginx:alpine + command: ["/bin/sh", "-c"] + args: ["sleep 10h"] + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + lifecycle: + # remove finalizers for successful delete of pod + preStop: + exec: + command: + - /bin/sh + - -c + - | + set -e + + SERVICE_ACCOUNT_TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token) + POD_URL="https://kubernetes.default.svc/api/v1/namespaces/$NAMESPACE/pods/$POD_NAME" + PATCH_PAYLOAD='[{"op": "remove", "path": "/metadata/finalizers"}]' + + curl -k -v -H "Authorization: Bearer $SERVICE_ACCOUNT_TOKEN" -H "Content-Type: application/json-patch+json" -X PATCH --data "$PATCH_PAYLOAD" $POD_URL diff --git a/test/e2e/testdata/syncwaves-prune-order/rbac.yaml b/test/e2e/testdata/syncwaves-prune-order/rbac.yaml new file mode 100644 index 0000000000000..9512644b731db --- /dev/null +++ b/test/e2e/testdata/syncwaves-prune-order/rbac.yaml @@ -0,0 +1,37 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: modify-pods-sa + annotations: + argocd.argoproj.io/sync-wave: "0" +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: modify-pods-role + annotations: + argocd.argoproj.io/sync-wave: "0" +rules: + - apiGroups: [""] + resources: + - pods + verbs: + - get + - list + - delete + - update + - patch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: modify-pods-rolebinding + annotations: + argocd.argoproj.io/sync-wave: "1" +subjects: + - kind: ServiceAccount + name: modify-pods-sa +roleRef: + kind: Role + name: modify-pods-role + apiGroup: rbac.authorization.k8s.io \ No newline at end of file diff --git a/test/remote/Dockerfile b/test/remote/Dockerfile index 8d03d1321d25b..886a855f92597 100644 --- a/test/remote/Dockerfile +++ b/test/remote/Dockerfile @@ -1,6 +1,6 @@ ARG BASE_IMAGE=docker.io/library/ubuntu:22.04 -FROM docker.io/library/golang:1.21.3@sha256:02d7116222536a5cf0fcf631f90b507758b669648e0f20186d2dc94a9b419a9b AS go +FROM docker.io/library/golang:1.22.0@sha256:094e47ef90125eb49dfbc67d3480b56ee82ea9b05f50b750b5e85fab9606c2de AS go RUN go install github.com/mattn/goreman@latest && \ go install github.com/kisielk/godepgraph@latest diff --git a/ui-test/Dockerfile b/ui-test/Dockerfile index a5a77710eca52..7327aa1b6dcd7 100644 --- a/ui-test/Dockerfile +++ b/ui-test/Dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/library/node:20.7.0@sha256:f08c20b9f9c55dd47b1841793f0ee480c5395aa165cd02edfd68b068ed64bfb5 as node +FROM docker.io/library/node:21.6.1@sha256:abc4a25c8b5a2b460f3144aabfc8941ecd7e4fb721e0b14b635e70394c1899fb as node RUN apt-get update && apt-get install --no-install-recommends -y \ software-properties-common diff --git a/ui-test/package.json b/ui-test/package.json index 1875e31b6fd62..fd34ca2edab4a 100644 --- a/ui-test/package.json +++ b/ui-test/package.json @@ -27,6 +27,6 @@ "tslint-config-prettier": "^1.18.0", "tslint-plugin-prettier": "^2.0.1", "typescript": "^4.0.3", - "yarn": "^1.22.10" + "yarn": "^1.22.13" } } diff --git a/ui-test/yarn.lock b/ui-test/yarn.lock index b80910028fb7f..6765cbf79d61b 100644 --- a/ui-test/yarn.lock +++ b/ui-test/yarn.lock @@ -540,9 +540,9 @@ flat@^5.0.2: integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== follow-redirects@^1.14.0: - version "1.14.9" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.9.tgz#dd4ea157de7bfaf9ea9b3fbd85aa16951f78d8d7" - integrity sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w== + version "1.15.5" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.5.tgz#54d4d6d062c0fa7d9d17feb008461550e3ba8020" + integrity sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw== foreach@^2.0.5: version "2.0.5" @@ -1510,10 +1510,10 @@ yargs@13.3.2: y18n "^4.0.0" yargs-parser "^13.1.2" -yarn@^1.22.10: - version "1.22.10" - resolved "https://registry.npmjs.org/yarn/-/yarn-1.22.10.tgz" - integrity sha512-IanQGI9RRPAN87VGTF7zs2uxkSyQSrSPsju0COgbsKQOOXr5LtcVPeyXWgwVa0ywG3d8dg6kSYKGBuYK021qeA== +yarn@^1.22.13: + version "1.22.13" + resolved "https://registry.yarnpkg.com/yarn/-/yarn-1.22.13.tgz#8789ef23b630fe99b819b044f4b7b93ab1bc1b8f" + integrity sha512-G8qG4t7Ef5cLVpzbM3HWWsow4hpfeSCfKtMnjfERmp9V5qSCOKz0uGAIQCM/x3gWfCzH8Bvb4hl3ZfhG/XD1Jg== yauzl@^2.10.0: version "2.10.0" diff --git a/ui/.nvmrc b/ui/.nvmrc index 376d26203e61e..a8d3ff91fa10d 100644 --- a/ui/.nvmrc +++ b/ui/.nvmrc @@ -1 +1 @@ -v20.7.0 +v21.6.1 diff --git a/ui/jest.config.js b/ui/jest.config.js index abd8a45bcecd6..524b493f546fc 100644 --- a/ui/jest.config.js +++ b/ui/jest.config.js @@ -1,12 +1,11 @@ module.exports = { preset: 'ts-jest', - testEnvironment: 'node', + testEnvironment: 'jsdom', reporters: ['default', 'jest-junit'], collectCoverage: true, transformIgnorePatterns: ['node_modules/(?!(argo-ui)/)'], globals: { 'self': {}, - 'window': {localStorage: { getItem: () => '{}', setItem: () => null }}, 'ts-jest': { isolatedModules: true, }, @@ -17,20 +16,3 @@ module.exports = { '.+\\.(css|styl|less|sass|scss)$': 'jest-transform-css', }, }; - -const localStorageMock = (() => { - let store = {}; - return { - getItem: (key) => store[key], - setItem: (key, value) => { - store[key] = value.toString(); - }, - clear: () => { - store = {}; - }, - removeItem: (key) => { - delete store[key]; - } - }; -})(); -global.localStorage = localStorageMock; \ No newline at end of file diff --git a/ui/package.json b/ui/package.json index d5a4896ec78be..e5979d7ec5bc7 100644 --- a/ui/package.json +++ b/ui/package.json @@ -13,7 +13,7 @@ "dependencies": { "@fortawesome/fontawesome-free": "^6.4.0", "@types/react-virtualized": "^9.21.21", - "@types/superagent": "^4.1.15", + "@types/superagent": "^4.1.21", "ansi-to-react": "^6.1.6", "argo-ui": "git+https://github.com/argoproj/argo-ui.git", "buffer": "^6.0.3", @@ -31,6 +31,7 @@ "minimatch": "^3.1.2", "moment": "^2.29.4", "monaco-editor": "^0.33.0", + "oauth4webapi": "^2.3.0", "path": "^0.12.7", "prop-types": "^15.8.1", "react": "^16.9.3", @@ -49,7 +50,7 @@ "react-virtualized": "^9.22.3", "redoc": "^2.0.0-rc.64", "rxjs": "^6.6.6", - "superagent": "^8.0.9", + "superagent": "^8.1.2", "timezones-list": "3.0.1", "tsx": "^3.4.0", "unidiff": "^1.0.2", @@ -119,6 +120,6 @@ "webpack": "^5.84.1", "webpack-cli": "^4.9.2", "webpack-dev-server": "^4.7.4", - "yarn": "^1.22.10" + "yarn": "^1.22.21" } } diff --git a/ui/src/app/app.tsx b/ui/src/app/app.tsx index e38e28d91a9db..d0a58d3fbdc7f 100644 --- a/ui/src/app/app.tsx +++ b/ui/src/app/app.tsx @@ -18,6 +18,7 @@ import {hashCode} from './shared/utils'; import {Banner} from './ui-banner/ui-banner'; import userInfo from './user-info'; import {AuthSettings} from './shared/models'; +import {PKCEVerification} from './login/components/pkce-verify'; services.viewPreferences.init(); const bases = document.getElementsByTagName('base'); @@ -32,7 +33,8 @@ const routes: Routes = { '/applications': {component: applications.component}, '/settings': {component: settings.component}, '/user-info': {component: userInfo.component}, - '/help': {component: help.component} + '/help': {component: help.component}, + '/pkce/verify': {component: PKCEVerification, noLayout: true} }; interface NavItem { @@ -217,7 +219,9 @@ export class App extends React.Component< - {this.state.popupProps && } + services.viewPreferences.getPreferences()}> + {pref =>
    {this.state.popupProps && }
    } +
    diff --git a/ui/src/app/applications/components/application-deployment-history/application-deployment-history.tsx b/ui/src/app/applications/components/application-deployment-history/application-deployment-history.tsx index 55734b69ea0c4..37908fb1a35b8 100644 --- a/ui/src/app/applications/components/application-deployment-history/application-deployment-history.tsx +++ b/ui/src/app/applications/components/application-deployment-history/application-deployment-history.tsx @@ -1,4 +1,5 @@ import {DataLoader, DropDownMenu, Duration} from 'argo-ui'; +import {InitiatedBy} from './initiated-by'; import * as moment from 'moment'; import * as React from 'react'; import {Revision, Timestamp} from '../../../shared/components'; @@ -42,6 +43,12 @@ export const ApplicationDeploymentHistory = ({
    {(info.deployStartedAt && ) || 'Unknown'} +
    +
    + Initiated by: +
    + +

    Active for: diff --git a/ui/src/app/applications/components/application-deployment-history/initiated-by.tsx b/ui/src/app/applications/components/application-deployment-history/initiated-by.tsx new file mode 100644 index 0000000000000..f691389b5daca --- /dev/null +++ b/ui/src/app/applications/components/application-deployment-history/initiated-by.tsx @@ -0,0 +1,6 @@ +import * as React from 'react'; + +export const InitiatedBy = (props: {username: string; automated: boolean}) => { + const initiator = props.automated ? 'automated sync policy' : props.username || 'Unknown'; + return {initiator}; +}; diff --git a/ui/src/app/applications/components/application-details/application-details.scss b/ui/src/app/applications/components/application-details/application-details.scss index a653063fdc102..82402ffd0d8b4 100644 --- a/ui/src/app/applications/components/application-details/application-details.scss +++ b/ui/src/app/applications/components/application-details/application-details.scss @@ -1,5 +1,6 @@ @import 'node_modules/argo-ui/src/styles/config'; @import 'node_modules/foundation-sites/scss/util/util'; +@import 'node_modules/argo-ui/src/styles/theme'; @import '../../../shared/config.scss'; $header: 120px; @@ -7,16 +8,16 @@ $header: 120px; .application-details { height: 100vh; width: 100%; - &__status-panel { - position: fixed; - left: $sidebar-width; - right: 0; - z-index: 3; - @media screen and (max-width: map-get($breakpoints, xlarge)) { - top: 150px; - } - @media screen and (max-width: map-get($breakpoints, large)) { - top: 146px; + + &__wrapper { + display: flex; + flex-direction: column; + height: calc(100vh - 2 * $top-bar-height); + overflow: hidden; + + @media screen and (max-width: map-get($breakpoints, xxlarge)) { + height: calc(100vh - 3 * $top-bar-height); + margin-top: $top-bar-height; } } @@ -26,13 +27,11 @@ $header: 120px; &__tree { padding: 1em; + + flex: 1; overflow-x: auto; overflow-y: auto; - margin-top: 150px; - height: calc(100vh - 2 * 70px - 115px); - @media screen and (max-width: map-get($breakpoints, xlarge)) { - margin-top: 165px; - } + overscroll-behavior-x: none; } &__sliding-panel-pagination-wrap { @@ -211,9 +210,14 @@ $header: 120px; z-index: 1; padding: 5px; display: inline-block; - background-color: $argo-color-gray-1; box-shadow: 1px 1px 3px $argo-color-gray-5; position: absolute; + + @include themify($themes) { + background: themed('background-2'); + } + + a { padding: 5px; margin: 2px; @@ -255,7 +259,9 @@ $header: 120px; } .separator { - border-right: 1px solid $argo-color-gray-4; + @include themify($themes) { + border-right: 1px solid themed('border'); + } padding-top: 6px; padding-bottom: 6px; } diff --git a/ui/src/app/applications/components/application-details/application-details.tsx b/ui/src/app/applications/components/application-details/application-details.tsx index 3a556dd0b2524..a3e8175591dde 100644 --- a/ui/src/app/applications/components/application-details/application-details.tsx +++ b/ui/src/app/applications/components/application-details/application-details.tsx @@ -30,7 +30,7 @@ import {ApplicationsDetailsAppDropdown} from './application-details-app-dropdown import {useSidebarTarget} from '../../../sidebar/sidebar'; import './application-details.scss'; -import {AppViewExtension} from '../../../shared/services/extensions-service'; +import {AppViewExtension, StatusPanelExtension} from '../../../shared/services/extensions-service'; interface ApplicationDetailsState { page: number; @@ -42,6 +42,8 @@ interface ApplicationDetailsState { collapsedNodes?: string[]; extensions?: AppViewExtension[]; extensionsMap?: {[key: string]: AppViewExtension}; + statusExtensions?: StatusPanelExtension[]; + statusExtensionsMap?: {[key: string]: StatusPanelExtension}; } interface FilterInput { @@ -87,6 +89,11 @@ export class ApplicationDetails extends React.Component { extensionsMap[ext.title] = ext; }); + const statusExtensions = services.extensions.getStatusPanelExtensions(); + const statusExtensionsMap: {[key: string]: StatusPanelExtension} = {}; + statusExtensions.forEach(ext => { + statusExtensionsMap[ext.id] = ext; + }); this.state = { page: 0, groupedResources: [], @@ -95,7 +102,9 @@ export class ApplicationDetails extends React.Component ) }}> -
    - this.selectNode(appFullName, 0, 'diff')} - showOperation={() => this.setOperationStatusVisible(true)} - showConditions={() => this.setConditionsStatusVisible(true)} - showMetadataInfo={revision => this.setState({...this.state, revision})} - /> -
    -
    - {refreshing &&

    Refreshing

    } - {((pref.view === 'tree' || pref.view === 'network') && ( - <> - services.viewPreferences.getPreferences()}> - {viewPref => ( - - )} - - - this.filterTreeNode(node, treeFilter)} - selectedNodeFullName={this.selectedNodeKey} - onNodeClick={fullName => this.selectNode(fullName)} - nodeMenu={node => - AppUtils.renderResourceMenu(node, application, tree, this.appContext.apis, this.appChanged, () => - this.getApplicationActionMenu(application, false) - ) - } - showCompactNodes={pref.groupNodes} - userMsgs={pref.userHelpTipMsgs} - tree={tree} - app={application} - showOrphanedResources={pref.orphanedResources} - useNetworkingHierarchy={pref.view === 'network'} - onClearFilter={clearFilter} - onGroupdNodeClick={groupdedNodeIds => openGroupNodeDetails(groupdedNodeIds)} - zoom={pref.zoom} - podGroupCount={pref.podGroupCount} - appContext={this.appContext} - nameDirection={this.state.truncateNameOnRight} - filters={pref.resourceFilter} - setTreeFilterGraph={setFilterGraph} - updateUsrHelpTipMsgs={updateHelpTipState} - setShowCompactNodes={setShowCompactNodes} - setNodeExpansion={(node, isExpanded) => this.setNodeExpansion(node, isExpanded)} - getNodeExpansion={node => this.getNodeExpansion(node)} - /> - - )) || - (pref.view === 'pods' && ( - this.selectNode(fullName)} - nodeMenu={node => - AppUtils.renderResourceMenu(node, application, tree, this.appContext.apis, this.appChanged, () => - this.getApplicationActionMenu(application, false) - ) - } - quickStarts={node => AppUtils.renderResourceButtons(node, application, tree, this.appContext.apis, this.appChanged)} - /> - )) || - (this.state.extensionsMap[pref.view] != null && ( - - )) || ( -
    +
    +
    + this.selectNode(appFullName, 0, 'diff')} + showOperation={() => this.setOperationStatusVisible(true)} + showConditions={() => this.setConditionsStatusVisible(true)} + showExtension={id => this.setExtensionPanelVisible(id)} + showMetadataInfo={revision => this.setState({...this.state, revision})} + /> +
    +
    + {refreshing &&

    Refreshing

    } + {((pref.view === 'tree' || pref.view === 'network') && ( + <> services.viewPreferences.getPreferences()}> {viewPref => ( )} - {(filteredRes.length > 0 && ( - this.setState({page})} - preferencesKey='application-details'> - {data => ( - this.selectNode(fullName)} - resources={data} - nodeMenu={node => - AppUtils.renderResourceMenu( - {...node, root: node}, - application, - tree, - this.appContext.apis, - this.appChanged, - () => this.getApplicationActionMenu(application, false) - ) - } + + this.filterTreeNode(node, treeFilter)} + selectedNodeFullName={this.selectedNodeKey} + onNodeClick={fullName => this.selectNode(fullName)} + nodeMenu={node => + AppUtils.renderResourceMenu(node, application, tree, this.appContext.apis, this.appChanged, () => + this.getApplicationActionMenu(application, false) + ) + } + showCompactNodes={pref.groupNodes} + userMsgs={pref.userHelpTipMsgs} + tree={tree} + app={application} + showOrphanedResources={pref.orphanedResources} + useNetworkingHierarchy={pref.view === 'network'} + onClearFilter={clearFilter} + onGroupdNodeClick={groupdedNodeIds => openGroupNodeDetails(groupdedNodeIds)} + zoom={pref.zoom} + podGroupCount={pref.podGroupCount} + appContext={this.appContext} + nameDirection={this.state.truncateNameOnRight} + filters={pref.resourceFilter} + setTreeFilterGraph={setFilterGraph} + updateUsrHelpTipMsgs={updateHelpTipState} + setShowCompactNodes={setShowCompactNodes} + setNodeExpansion={(node, isExpanded) => this.setNodeExpansion(node, isExpanded)} + getNodeExpansion={node => this.getNodeExpansion(node)} + /> + + )) || + (pref.view === 'pods' && ( + this.selectNode(fullName)} + nodeMenu={node => + AppUtils.renderResourceMenu(node, application, tree, this.appContext.apis, this.appChanged, () => + this.getApplicationActionMenu(application, false) + ) + } + quickStarts={node => AppUtils.renderResourceButtons(node, application, tree, this.appContext.apis, this.appChanged)} + /> + )) || + (this.state.extensionsMap[pref.view] != null && ( + + )) || ( +
    + services.viewPreferences.getPreferences()}> + {viewPref => ( + )} - - )) || ( - -

    No resources found

    -
    Try to change filter criteria
    -
    - )} -
    - )} + + {(filteredRes.length > 0 && ( + this.setState({page})} + preferencesKey='application-details'> + {data => ( + this.selectNode(fullName)} + resources={data} + nodeMenu={node => + AppUtils.renderResourceMenu( + {...node, root: node}, + application, + tree, + this.appContext.apis, + this.appChanged, + () => this.getApplicationActionMenu(application, false) + ) + } + tree={tree} + /> + )} + + )) || ( + +

    No resources found

    +
    Try to change filter criteria
    +
    + )} +
    + )} +
    0} onClose={() => this.closeGroupedNodesPanel()}>
    @@ -729,6 +749,13 @@ export class ApplicationDetails extends React.Component ))} + this.setExtensionPanelVisible('')}> + {this.selectedExtension !== '' && activeExtension && activeExtension.flyout && ( + + )} +
    ); @@ -747,12 +774,12 @@ export class ApplicationDetails extends React.Component, + title: , action: () => this.selectNode(fullName) }, { iconClassName: 'fa fa-file-medical', - title: , + title: , action: () => this.selectNode(fullName, 0, 'diff'), disabled: app.status.sync.status === appModels.SyncStatuses.Synced }, @@ -963,6 +990,10 @@ export class ApplicationDetails extends React.Component 0 && (getResNode(tree.nodes, nodeKey(resources[0])) as ResourceNode)?.parentRefs?.[0]) || ({} as ResourceRef); + const searchParams = new URLSearchParams(window.location.search); + const view = searchParams.get('view'); + const ParentRefDetails = () => { + return Object.keys(parentNode).length > 0 ? ( +
    +
    Parent Node Info
    +
    +
    Name:
    +
    {parentNode?.name}
    +
    +
    +
    Kind:
    +
    {parentNode?.kind}
    +
    +
    + ) : ( +
    + ); + }; return (
    -
    - {Object.keys(parentNode).length > 0 && ( -
    -
    Parent Node Info
    -
    -
    Name:
    -
    {parentNode?.name}
    -
    -
    -
    Kind:
    -
    {parentNode?.kind}
    -
    -
    - )} -
    + {/* Display only when the view is set to or network */} + {(view === 'tree' || view === 'network') && ( +
    + +
    + )}
    -
    NAME
    +
    NAME
    GROUP/KIND
    SYNC ORDER
    -
    NAMESPACE
    +
    NAMESPACE
    {(parentNode.kind === 'Rollout' || parentNode.kind === 'Deployment') &&
    REVISION
    } -
    CREATED AT
    -
    STATUS
    +
    CREATED AT
    +
    STATUS
    {resources @@ -79,13 +90,16 @@ export const ApplicationResourceList = ({
    {ResourceLabel({kind: res.kind})}
    -
    - {res.name} +
    + {res.name} {res.kind === 'Application' && ( {ctx => ( - + e.stopPropagation()} + title='Open application'> @@ -95,7 +109,7 @@ export const ApplicationResourceList = ({
    {[res.group, res.kind].filter(item => !!item).join('/')}
    {res.syncWave || '-'}
    -
    {res.namespace}
    +
    {res.namespace}
    {res.kind === 'ReplicaSet' && ((getResNode(tree.nodes, nodeKey(res)) as ResourceNode).info || []) .filter(tag => !tag.name.includes('Node')) @@ -108,7 +122,7 @@ export const ApplicationResourceList = ({ ); })} -
    +
    {res.createdAt && ( @@ -118,7 +132,7 @@ export const ApplicationResourceList = ({ )}
    -
    +
    {res.health && ( {res.health.status}   diff --git a/ui/src/app/applications/components/application-resource-tree/application-resource-tree.scss b/ui/src/app/applications/components/application-resource-tree/application-resource-tree.scss index f4c6ba0d0df9f..0cc459b0dc52b 100644 --- a/ui/src/app/applications/components/application-resource-tree/application-resource-tree.scss +++ b/ui/src/app/applications/components/application-resource-tree/application-resource-tree.scss @@ -79,6 +79,10 @@ border: 1px solid transparent; cursor: pointer; + .theme-dark & { + box-shadow: 1px 1px 1px $argo-color-gray-7; + } + .icon { font-size: 2em; } @@ -120,6 +124,10 @@ } margin-top: 9px; margin-left: 215px; + + .theme-dark & { + box-shadow: 1px 1px 1px $argo-color-gray-7; + } } &--podgroup--expansion { @@ -131,6 +139,10 @@ box-shadow: 1px 1px 1px $argo-color-gray-4; background-color: white; margin-left: 215px; + + .theme-dark & { + box-shadow: 1px 1px 1px $argo-color-gray-7; + } } &--pod { @@ -348,8 +360,12 @@ border-radius: 33px; left: -20px; top: -8px; - border: 4px solid white; text-align: center; + + @include themify($themes) { + border: 4px solid themed('background-2'); + } + i { color: $white-color; line-height: 56px; diff --git a/ui/src/app/applications/components/application-resource-tree/application-resource-tree.tsx b/ui/src/app/applications/components/application-resource-tree/application-resource-tree.tsx index 6f28a40ea5046..3d5b1782a0e0c 100644 --- a/ui/src/app/applications/components/application-resource-tree/application-resource-tree.tsx +++ b/ui/src/app/applications/components/application-resource-tree/application-resource-tree.tsx @@ -564,11 +564,13 @@ function renderPodGroup(props: ApplicationResourceTreeProps, id: string, node: R
    {[podGroupHealthy, podGroupDegraded, podGroupInProgress].map((pods, index) => { - return ( -
    - {renderPodGroupByStatus(props, node, pods, showPodGroupByStatus)} -
    - ); + if (pods.length > 0) { + return ( +
    + {renderPodGroupByStatus(props, node, pods, showPodGroupByStatus)} +
    + ); + } })}
    diff --git a/ui/src/app/applications/components/application-status-panel/application-status-panel.scss b/ui/src/app/applications/components/application-status-panel/application-status-panel.scss index 9898db27d2ba6..e96c29624d5d1 100644 --- a/ui/src/app/applications/components/application-status-panel/application-status-panel.scss +++ b/ui/src/app/applications/components/application-status-panel/application-status-panel.scss @@ -101,7 +101,9 @@ } &:not(:first-child) { - border-left: 1px solid $argo-color-gray-3; + @include themify($themes) { + border-left: 1px solid themed('border'); + } } & { diff --git a/ui/src/app/applications/components/application-status-panel/application-status-panel.tsx b/ui/src/app/applications/components/application-status-panel/application-status-panel.tsx index c82252144849c..7c2b65cd3ce27 100644 --- a/ui/src/app/applications/components/application-status-panel/application-status-panel.tsx +++ b/ui/src/app/applications/components/application-status-panel/application-status-panel.tsx @@ -16,6 +16,7 @@ interface Props { showDiff?: () => any; showOperation?: () => any; showConditions?: () => any; + showExtension?: (id: string) => any; showMetadataInfo?: (revision: string) => any; } @@ -45,7 +46,7 @@ const sectionHeader = (info: SectionInfo, hasMultipleSources: boolean, onClick?: ); }; -export const ApplicationStatusPanel = ({application, showDiff, showOperation, showConditions, showMetadataInfo}: Props) => { +export const ApplicationStatusPanel = ({application, showDiff, showOperation, showConditions, showExtension, showMetadataInfo}: Props) => { const today = new Date(); let daysSinceLastSynchronized = 0; @@ -63,6 +64,8 @@ export const ApplicationStatusPanel = ({application, showDiff, showOperation, sh showOperation = null; } + const statusExtensions = services.extensions.getStatusPanelExtensions(); + const infos = cntByCategory.get('info'); const warnings = cntByCategory.get('warning'); const errors = cntByCategory.get('error'); @@ -89,20 +92,18 @@ export const ApplicationStatusPanel = ({application, showDiff, showOperation, sh hasMultipleSources, () => showMetadataInfo(application.status.sync ? application.status.sync.revision : '') )} - {appOperationState && ( -
    -
    - {application.status.sync.status === models.SyncStatuses.OutOfSync ? ( - showDiff && showDiff()}> - - - ) : ( +
    +
    + {application.status.sync.status === models.SyncStatuses.OutOfSync ? ( + showDiff && showDiff()}> - )} -
    -
    {syncStatusMessage(application)}
    +
    + ) : ( + + )}
    - )} +
    {syncStatusMessage(application)}
    +
    {application.spec.syncPolicy?.automated ? 'Auto sync is enabled.' : 'Auto sync is not enabled.'}
    @@ -205,6 +206,7 @@ export const ApplicationStatusPanel = ({application, showDiff, showOperation, sh )} + {statusExtensions && statusExtensions.map(ext => showExtension && showExtension(ext.id)} />)}
    ); }; diff --git a/ui/src/app/applications/components/application-summary/application-summary.tsx b/ui/src/app/applications/components/application-summary/application-summary.tsx index 9072f650f5026..4f372ef8f55c0 100644 --- a/ui/src/app/applications/components/application-summary/application-summary.tsx +++ b/ui/src/app/applications/components/application-summary/application-summary.tsx @@ -15,7 +15,7 @@ import { RevisionHelpIcon } from '../../../shared/components'; import {BadgePanel, Spinner} from '../../../shared/components'; -import {Consumer, ContextApis} from '../../../shared/context'; +import {AuthSettingsCtx, Consumer, ContextApis} from '../../../shared/context'; import * as models from '../../../shared/models'; import {services} from '../../../shared/services'; @@ -37,6 +37,16 @@ function swap(array: any[], a: number, b: number) { return array; } +function processPath(path: string) { + if (path !== null && path !== undefined) { + if (path === '.') { + return '(root)'; + } + return path; + } + return ''; +} + export interface ApplicationSummaryProps { app: models.Application; updateApp: (app: models.Application, query: {validate?: boolean}) => Promise; @@ -47,6 +57,7 @@ export const ApplicationSummary = (props: ApplicationSummaryProps) => { const source = getAppDefaultSource(app); const isHelm = source.hasOwnProperty('chart'); const initialState = app.spec.destination.server === undefined ? 'NAME' : 'URL'; + const useAuthSettingsCtx = React.useContext(AuthSettingsCtx); const [destFormat, setDestFormat] = React.useState(initialState); const [changeSync, setChangeSync] = React.useState(false); @@ -238,7 +249,7 @@ export const ApplicationSummary = (props: ApplicationSummaryProps) => { title: 'PATH', view: ( - {source.path ?? ''} + {processPath(source.path)} ), edit: (formApi: FormApi) => @@ -271,7 +282,7 @@ export const ApplicationSummary = (props: ApplicationSummaryProps) => { { title: 'SYNC OPTIONS', view: ( -
    +
    {((app.spec.syncPolicy || {}).syncOptions || []).map(opt => opt.endsWith('=true') || opt.endsWith('=false') ? (
    @@ -589,7 +600,7 @@ export const ApplicationSummary = (props: ApplicationSummaryProps) => {
    )} - + { setPending(true); - let resources = appResources.filter((_, i) => params.resources[i]); - if (resources.length === appResources.length) { - resources = null; + let selectedResources = appResources.filter((_, i) => params.resources[i]); + const allResourcesAreSelected = selectedResources.length === appResources.length; + const syncFlags = {...params.syncFlags} as SyncFlags; + + const allRequirePruning = !selectedResources.some(resource => !resource?.requiresPruning); + if (syncFlags.Prune && allRequirePruning && allResourcesAreSelected) { + const confirmed = await ctx.popup.confirm('Prune all resources?', () => ( +
    + + {PRUNE_ALL_WARNING} Are you sure you want to continue? +
    + )); + if (!confirmed) { + setPending(false); + return; + } + } + if (allResourcesAreSelected) { + selectedResources = null; } const replace = params.syncOptions?.findIndex((opt: string) => opt === 'Replace=true') > -1; if (replace) { @@ -74,7 +97,6 @@ export const ApplicationSyncPanel = ({application, selectedResource, hide}: {app } } - const syncFlags = {...params.syncFlags} as SyncFlags; const force = syncFlags.Force || false; if (syncFlags.ApplyOnly) { @@ -102,7 +124,7 @@ export const ApplicationSyncPanel = ({application, selectedResource, hide}: {app syncFlags.Prune || false, syncFlags.DryRun || false, syncStrategy, - resources, + selectedResources, params.syncOptions, params.retryStrategy ); diff --git a/ui/src/app/applications/components/applications-list/applications-list.scss b/ui/src/app/applications/components/applications-list/applications-list.scss index fbe03245e94e6..6d359e59723e3 100644 --- a/ui/src/app/applications/components/applications-list/applications-list.scss +++ b/ui/src/app/applications/components/applications-list/applications-list.scss @@ -118,9 +118,9 @@ } &__search { - border: 1px solid $argo-color-gray-4; @include themify($themes) { background-color: themed('light-argo-gray-2'); + border: 1px solid themed('border'); } border-radius: 7px; position: relative; diff --git a/ui/src/app/applications/components/applications-list/applications-tiles.scss b/ui/src/app/applications/components/applications-list/applications-tiles.scss index 65514f82d0f93..2e63152d53201 100644 --- a/ui/src/app/applications/components/applications-list/applications-tiles.scss +++ b/ui/src/app/applications/components/applications-list/applications-tiles.scss @@ -1,6 +1,24 @@ @import 'node_modules/argo-ui/src/styles/config'; .applications-tiles { + display: grid; + gap: 24px; + grid-template-columns: repeat(auto-fill,minmax(380px,1fr)); + padding: 0 12px; + + &__wrapper { + height: 100%; + } + + &__item { + display: flex; + flex-direction: column; + } + + &__actions { + margin-top: auto; + } + .argo-table-list__row { padding-top: 0; padding-bottom: 0; diff --git a/ui/src/app/applications/components/applications-list/applications-tiles.tsx b/ui/src/app/applications/components/applications-list/applications-tiles.tsx index 7665c472e80b1..b69d4e4540348 100644 --- a/ui/src/app/applications/components/applications-list/applications-tiles.tsx +++ b/ui/src/app/applications/components/applications-list/applications-tiles.tsx @@ -111,197 +111,195 @@ export const ApplicationTiles = ({applications, syncApplication, refreshApplicat {applications.map((app, i) => { const source = getAppDefaultSource(app); return ( -
    +
    + className='row applications-tiles__wrapper' + onClick={e => + ctx.navigation.goto(`/applications/${app.metadata.namespace}/${app.metadata.name}`, {view: pref.appDetails.view}, {event: e}) + }>
    - ctx.navigation.goto( - `/applications/${app.metadata.namespace}/${app.metadata.name}`, - {view: pref.appDetails.view}, - {event: e} - ) - }> -
    -
    -
    0 ? 'columns small-10' : 'columns small-11'}> - - - - {AppUtils.appQualifiedName(app, useAuthSettingsCtx?.appsInAnyNamespaceEnabled)} - + className={`columns small-12 applications-list__info qe-applications-list-${AppUtils.appInstanceName( + app + )} applications-tiles__item`}> +
    +
    0 ? 'columns small-10' : 'columns small-11'}> + + + + {AppUtils.appQualifiedName(app, useAuthSettingsCtx?.appsInAnyNamespaceEnabled)} + + +
    +
    0 ? 'columns small-2' : 'columns small-1'}> +
    + + +
    -
    0 ? 'columns small-2' : 'columns small-1'}> -
    - - - - -
    -
    -
    -
    - Project: -
    -
    {app.spec.project}
    +
    +
    +
    + Project:
    -
    -
    - Labels: -
    -
    - - {Object.keys(app.metadata.labels || {}) - .map(label => ({label, value: app.metadata.labels[label]})) - .map(item => ( -
    - {item.label}={item.value} -
    - ))} -
    - }> - +
    {app.spec.project}
    +
    +
    +
    + Labels: +
    +
    + {Object.keys(app.metadata.labels || {}) - .map(label => `${label}=${app.metadata.labels[label]}`) - .join(', ')} - - -
    + .map(label => ({label, value: app.metadata.labels[label]})) + .map(item => ( +
    + {item.label}={item.value} +
    + ))} +
    + }> + + {Object.keys(app.metadata.labels || {}) + .map(label => `${label}=${app.metadata.labels[label]}`) + .join(', ')} + +
    -
    -
    - Status: -
    -
    - {app.status.health.status} -   - {app.status.sync.status} -   - -
    +
    +
    +
    + Status:
    -
    -
    - Repository: -
    -
    - - {source.repoURL} - -
    +
    + {app.status.health.status} +   + {app.status.sync.status} +   +
    -
    -
    - Target Revision: -
    -
    {source.targetRevision || 'HEAD'}
    +
    +
    +
    + Repository:
    - {source.path && ( -
    -
    - Path: -
    -
    {source.path}
    -
    - )} - {source.chart && ( -
    -
    - Chart: -
    -
    {source.chart}
    -
    - )} -
    -
    - Destination: -
    -
    - -
    +
    + + {source.repoURL} +
    +
    +
    +
    + Target Revision: +
    +
    {source.targetRevision || 'HEAD'}
    +
    + {source.path && (
    -
    - Namespace: +
    + Path:
    -
    {app.spec.destination.namespace}
    +
    {source.path}
    + )} + {source.chart && (
    -
    - Created At: +
    + Chart:
    -
    {AppUtils.formatCreationTimestamp(app.metadata.creationTimestamp)}
    +
    {source.chart}
    - {app.status.operationState && ( -
    -
    - Last Sync: -
    -
    - {AppUtils.formatCreationTimestamp(app.status.operationState.finishedAt || app.status.operationState.startedAt)} -
    -
    - )} + )} +
    +
    + Destination: +
    +
    + +
    +
    +
    +
    + Namespace: +
    +
    {app.spec.destination.namespace}
    +
    +
    +
    + Created At: +
    +
    {AppUtils.formatCreationTimestamp(app.metadata.creationTimestamp)}
    +
    + {app.status.operationState && (
    - + )} +
    diff --git a/ui/src/app/applications/components/pod-logs-viewer/pod-logs-viewer.tsx b/ui/src/app/applications/components/pod-logs-viewer/pod-logs-viewer.tsx index 30b101eecc4f8..309287fab2f37 100644 --- a/ui/src/app/applications/components/pod-logs-viewer/pod-logs-viewer.tsx +++ b/ui/src/app/applications/components/pod-logs-viewer/pod-logs-viewer.tsx @@ -1,7 +1,7 @@ import {DataLoader} from 'argo-ui'; import * as classNames from 'classnames'; import * as React from 'react'; -import {useEffect, useState} from 'react'; +import {useEffect, useState, useRef} from 'react'; import {bufferTime, delay, retryWhen} from 'rxjs/operators'; import {LogEntry} from '../../../shared/models'; @@ -83,6 +83,7 @@ export const PodsLogsViewer = (props: PodLogsProps) => { const [highlight, setHighlight] = useState(matchNothing); const [scrollToBottom, setScrollToBottom] = useState(true); const [logs, setLogs] = useState([]); + const logsContainerRef = useRef(null); useEffect(() => { if (viewPodNames) { @@ -102,6 +103,15 @@ export const PodsLogsViewer = (props: PodLogsProps) => { useEffect(() => setScrollToBottom(true), [follow]); + useEffect(() => { + if (scrollToBottom) { + const element = logsContainerRef.current; + if (element) { + element.scrollTop = element.scrollHeight; + } + } + }, [logs, scrollToBottom]); + useEffect(() => { setLogs([]); const logsSource = services.applications @@ -125,6 +135,10 @@ export const PodsLogsViewer = (props: PodLogsProps) => { return () => logsSource.unsubscribe(); }, [applicationName, applicationNamespace, namespace, podName, group, kind, name, containerName, tail, follow, sinceSeconds, filter, previous]); + const handleScroll = (event: React.WheelEvent) => { + if (event.deltaY < 0) setScrollToBottom(false); + }; + const renderLog = (log: LogEntry, lineNum: number) => // show the pod name if there are multiple pods, pad with spaces to align (viewPodNames ? (lineNum === 0 || logs[lineNum - 1].podName !== log.podName ? podColor(podName) + log.podName + reset : ' '.repeat(log.podName.length)) + ' ' : '') + @@ -133,11 +147,11 @@ export const PodsLogsViewer = (props: PodLogsProps) => { // show the log content, highlight the filter text log.content?.replace(highlight, (substring: string) => whiteOnYellow + substring + reset); const logsContent = (width: number, height: number, isWrapped: boolean) => ( -
    +
    {logs.map((log, lineNum) => ( -
    +                
    {renderLog(log, lineNum)} -
    +
    ))}
    ); @@ -177,11 +191,7 @@ export const PodsLogsViewer = (props: PodLogsProps) => {
    -
    { - if (e.deltaY < 0) setScrollToBottom(false); - }}> +
    {({width, height}: {width: number; height: number}) => logsContent(width, height, prefs.appDetails.wrapLines)}
    diff --git a/ui/src/app/applications/components/resource-details/resource-details.tsx b/ui/src/app/applications/components/resource-details/resource-details.tsx index 6477509370905..52d2fef184703 100644 --- a/ui/src/app/applications/components/resource-details/resource-details.tsx +++ b/ui/src/app/applications/components/resource-details/resource-details.tsx @@ -280,7 +280,7 @@ export const ResourceDetails = (props: ResourceDetailsProps) => { const settings = await services.authService.settings(); const execEnabled = settings.execEnabled; const logsAllowed = await services.accounts.canI('logs', 'get', application.spec.project + '/' + application.metadata.name); - const execAllowed = await services.accounts.canI('exec', 'create', application.spec.project + '/' + application.metadata.name); + const execAllowed = execEnabled && (await services.accounts.canI('exec', 'create', application.spec.project + '/' + application.metadata.name)); const links = await services.applications.getResourceLinks(application.metadata.name, application.metadata.namespace, selectedNode).catch(() => null); return {controlledState, liveState, events, podState, execEnabled, execAllowed, logsAllowed, links}; }}> diff --git a/ui/src/app/applications/components/utils.scss b/ui/src/app/applications/components/utils.scss index 24d9c275bff62..245573df95d92 100644 --- a/ui/src/app/applications/components/utils.scss +++ b/ui/src/app/applications/components/utils.scss @@ -1,3 +1,5 @@ +@import 'node_modules/argo-ui/src/styles/theme'; + .propagation-policy-list { display: flex; justify-content: left; @@ -9,9 +11,12 @@ padding-right: 2em; label { - color: #6D7F8B; font-size: 15px; cursor: pointer; + + @include themify($themes) { + color: themed('light-argo-gray-6'); + } } input { diff --git a/ui/src/app/applications/components/utils.tsx b/ui/src/app/applications/components/utils.tsx index 674ffc6728db4..cd39470bfb25b 100644 --- a/ui/src/app/applications/components/utils.tsx +++ b/ui/src/app/applications/components/utils.tsx @@ -361,7 +361,7 @@ export const deletePopup = async (ctx: ContextApis, resource: ResourceTreeNode, handleStateChange('force')} style={{marginRight: '5px'}} id='force-delete-radio' /> handleStateChange('orphan')} style={{marginRight: '5px'}} id='cascade-delete-radio' /> @@ -473,8 +473,8 @@ function getActionItems( const execAction = services.authService .settings() .then(async settings => { - const execAllowed = await services.accounts.canI('exec', 'create', application.spec.project + '/' + application.metadata.name); - if (resource.kind === 'Pod' && settings.execEnabled && execAllowed) { + const execAllowed = settings.execEnabled && (await services.accounts.canI('exec', 'create', application.spec.project + '/' + application.metadata.name)); + if (resource.kind === 'Pod' && execAllowed) { return [ { title: 'Exec', diff --git a/ui/src/app/login/components/login.tsx b/ui/src/app/login/components/login.tsx index db67ff185cf78..b00ef04bcacc4 100644 --- a/ui/src/app/login/components/login.tsx +++ b/ui/src/app/login/components/login.tsx @@ -1,4 +1,4 @@ -import {FormField} from 'argo-ui'; +import {FormField, NotificationType} from 'argo-ui'; import * as PropTypes from 'prop-types'; import * as React from 'react'; import {Form, Text} from 'react-form'; @@ -7,6 +7,7 @@ import {RouteComponentProps} from 'react-router'; import {AppContext} from '../../shared/context'; import {AuthSettings} from '../../shared/models'; import {services} from '../../shared/services'; +import {getPKCERedirectURI, pkceLogin} from './utils'; require('./login.scss'); @@ -61,7 +62,19 @@ export class Login extends React.Component, State> {
    {ssoConfigured && (
    - + { + pkceLogin(authSettings.oidcConfig, getPKCERedirectURI().toString()).catch(err => { + this.appContext.apis.notifications.show({ + type: NotificationType.Error, + content: err?.message || JSON.stringify(err) + }); + }); + } + } + : {href: `auth/login?return_url=${encodeURIComponent(this.state.returnUrl)}`})}> + + )} + items={[]} + /> + ) + } + this.saveProject(item)} values={proj} diff --git a/ui/src/app/settings/components/project-details/resource-lists-panel.tsx b/ui/src/app/settings/components/project-details/resource-lists-panel.tsx index 2e5c1d1fedd72..ec9e617ac9122 100644 --- a/ui/src/app/settings/components/project-details/resource-lists-panel.tsx +++ b/ui/src/app/settings/components/project-details/resource-lists-panel.tsx @@ -99,6 +99,36 @@ function viewSourceReposInfoList(type: field, proj: Project) { ); } +const sourceNamespacesInfoByField: {[type: string]: {title: string; helpText: string}} = { + sourceNamespaces: { + title: 'source namespaces', + helpText: 'Kubernetes namespaces where application resources are allowed to be created in' + } +}; + +function viewSourceNamespacesInfoList(type: field, proj: Project) { + const info = sourceNamespacesInfoByField[type]; + const list = proj.spec[type] as Array; + return ( + +

    + {info.title} {helpTip(info.helpText)} +

    + {(list || []).length > 0 ? ( + + {list.map((namespace, i) => ( +
    +
    {namespace}
    +
    + ))} +
    + ) : ( +

    The {info.title} is empty

    + )} +
    + ); +} + const destinationsInfoByField: {[type: string]: {title: string; helpText: string}} = { destinations: { title: 'destinations', @@ -180,6 +210,8 @@ export const ResourceListsPanel = ({proj, saveProject, title}: {proj: Project; t {viewList(key as field, proj)} ))} {!proj.metadata && Object.keys(sourceReposInfoByField).map(key => {viewSourceReposInfoList(key as field, proj)})} + {!proj.metadata && + Object.keys(sourceNamespacesInfoByField).map(key => {viewSourceNamespacesInfoList(key as field, proj)})} {!proj.metadata && Object.keys(destinationsInfoByField).map(key => {viewDestinationsInfoList(key as field, proj)})} } diff --git a/ui/src/app/settings/components/repo-details/repo-details.tsx b/ui/src/app/settings/components/repo-details/repo-details.tsx index 6075dfbde3b22..25fa983172700 100644 --- a/ui/src/app/settings/components/repo-details/repo-details.tsx +++ b/ui/src/app/settings/components/repo-details/repo-details.tsx @@ -65,7 +65,8 @@ export const RepoDetails = (props: {repo: models.Repository; save?: (params: New enableLfs: repo.enableLfs || false, proxy: repo.proxy || '', project: repo.project || '', - enableOCI: repo.enableOCI || false + enableOCI: repo.enableOCI || false, + forceHttpBasicAuth: repo.forceHttpBasicAuth || false }; return ( diff --git a/ui/src/app/shared/components/badge-panel/badge-panel.tsx b/ui/src/app/shared/components/badge-panel/badge-panel.tsx index ad6a4f6c187e2..999e7bfd49d6b 100644 --- a/ui/src/app/shared/components/badge-panel/badge-panel.tsx +++ b/ui/src/app/shared/components/badge-panel/badge-panel.tsx @@ -6,7 +6,7 @@ import {Context} from '../../context'; require('./badge-panel.scss'); -export const BadgePanel = ({app, project}: {app?: string; project?: string}) => { +export const BadgePanel = ({app, project, appNamespace, nsEnabled}: {app?: string; project?: string; appNamespace?: string; nsEnabled?: boolean}) => { const [badgeType, setBadgeType] = React.useState('URL'); const context = React.useContext(Context); if (!app && !project) { @@ -20,6 +20,9 @@ export const BadgePanel = ({app, project}: {app?: string; project?: string}) => let alt = ''; if (app) { badgeURL = `${root}api/badge?name=${app}&revision=true`; + if (nsEnabled) { + badgeURL += `&namespace=${appNamespace}`; + } entityURL = `${root}applications/${app}`; alt = 'App Status'; } else if (project) { diff --git a/ui/src/app/shared/components/layout/layout.tsx b/ui/src/app/shared/components/layout/layout.tsx index dcf98dde565eb..096fdde68e99b 100644 --- a/ui/src/app/shared/components/layout/layout.tsx +++ b/ui/src/app/shared/components/layout/layout.tsx @@ -14,14 +14,21 @@ export interface LayoutProps { const getBGColor = (theme: string): string => (theme === 'light' ? '#dee6eb' : '#100f0f'); -export const Layout = (props: LayoutProps) => ( -
    -
    - - {props.pref.theme ? (document.body.style.background = getBGColor(props.pref.theme)) : null} -
    - {props.children} +export const Layout = (props: LayoutProps) => { + React.useEffect(() => { + if (props.pref.theme) { + document.body.style.background = getBGColor(props.pref.theme); + } + }, [props.pref.theme]); + + return ( +
    +
    + +
    + {props.children} +
    -
    -); + ); +}; diff --git a/ui/src/app/shared/components/page/page.scss b/ui/src/app/shared/components/page/page.scss index 4194f2b00693f..1031a121bedb4 100644 --- a/ui/src/app/shared/components/page/page.scss +++ b/ui/src/app/shared/components/page/page.scss @@ -75,10 +75,10 @@ } .sb-page-wrapper { - padding-left: $sidebar-width - 60px; + padding-left: $sidebar-width; &__sidebar-collapsed { - padding-left: $collapsed-sidebar-width - 60px; + padding-left: $collapsed-sidebar-width; .flex-top-bar { left: $collapsed-sidebar-width; } diff --git a/ui/src/app/shared/models.ts b/ui/src/app/shared/models.ts index 23643f7bbbb53..823c61c34dc9a 100644 --- a/ui/src/app/shared/models.ts +++ b/ui/src/app/shared/models.ts @@ -297,6 +297,7 @@ export interface RevisionHistory { sources: ApplicationSource[]; deployStartedAt: models.Time; deployedAt: models.Time; + initiatedBy: OperationInitiator; } export type SyncStatusCode = 'Unknown' | 'Synced' | 'OutOfSync'; @@ -468,6 +469,10 @@ export interface AuthSettings { }; oidcConfig: { name: string; + issuer: string; + clientID: string; + scopes: string[]; + enablePKCEAuthentication: boolean; }; help: { chatUrl: string; @@ -710,6 +715,7 @@ export interface ProjectSignatureKey { export interface ProjectSpec { sourceRepos: string[]; + sourceNamespaces: string[]; destinations: ApplicationDestination[]; description: string; roles: ProjectRole[]; diff --git a/ui/src/app/shared/services/extensions-service.ts b/ui/src/app/shared/services/extensions-service.ts index 3975fb1aec018..e26f3577b3487 100644 --- a/ui/src/app/shared/services/extensions-service.ts +++ b/ui/src/app/shared/services/extensions-service.ts @@ -6,7 +6,8 @@ import {Application, ApplicationTree, State} from '../models'; const extensions = { resourceExtentions: new Array(), systemLevelExtensions: new Array(), - appViewExtensions: new Array() + appViewExtensions: new Array(), + statusPanelExtensions: new Array() }; function registerResourceExtension(component: ExtensionComponent, group: string, kind: string, tabTitle: string, opts?: {icon: string}) { @@ -21,6 +22,10 @@ function registerAppViewExtension(component: ExtensionComponent, title: string, extensions.appViewExtensions.push({component, title, icon}); } +function registerStatusPanelExtension(component: StatusPanelExtensionComponent, title: string, id: string, flyout?: ExtensionComponent) { + extensions.statusPanelExtensions.push({component, flyout, title, id}); +} + let legacyInitialized = false; function initLegacyExtensions() { @@ -56,9 +61,18 @@ export interface AppViewExtension { icon?: string; } +export interface StatusPanelExtension { + component: StatusPanelExtensionComponent; + flyout?: StatusPanelExtensionFlyoutComponent; + title: string; + id: string; +} + export type ExtensionComponent = React.ComponentType; export type SystemExtensionComponent = React.ComponentType; export type AppViewExtensionComponent = React.ComponentType; +export type StatusPanelExtensionComponent = React.ComponentType; +export type StatusPanelExtensionFlyoutComponent = React.ComponentType; export interface Extension { component: ExtensionComponent; @@ -75,6 +89,16 @@ export interface AppViewComponentProps { tree: ApplicationTree; } +export interface StatusPanelComponentProps { + application: Application; + openFlyout: () => any; +} + +export interface StatusPanelFlyoutProps { + application: Application; + tree: ApplicationTree; +} + export class ExtensionsService { public getResourceTabs(group: string, kind: string): ResourceTabExtension[] { initLegacyExtensions(); @@ -89,6 +113,10 @@ export class ExtensionsService { public getAppViewExtensions(): AppViewExtension[] { return extensions.appViewExtensions.slice(); } + + public getStatusPanelExtensions(): StatusPanelExtension[] { + return extensions.statusPanelExtensions.slice(); + } } ((window: any) => { @@ -97,6 +125,7 @@ export class ExtensionsService { window.extensionsAPI = { registerResourceExtension, registerSystemLevelExtension, - registerAppViewExtension + registerAppViewExtension, + registerStatusPanelExtension }; })(window); diff --git a/ui/src/app/shared/services/repo-service.ts b/ui/src/app/shared/services/repo-service.ts index 09f8c169ac9ae..94378bee8352b 100644 --- a/ui/src/app/shared/services/repo-service.ts +++ b/ui/src/app/shared/services/repo-service.ts @@ -62,7 +62,9 @@ export class RepositoriesService { insecure, enableLfs, proxy, - project + project, + forceHttpBasicAuth, + enableOCI }: { type: string; name: string; @@ -75,10 +77,12 @@ export class RepositoriesService { enableLfs: boolean; proxy: string; project?: string; + forceHttpBasicAuth?: boolean; + enableOCI: boolean; }): Promise { return requests .put(`/repositories/${encodeURIComponent(url)}`) - .send({type, name, repo: url, username, password, tlsClientCertData, tlsClientCertKey, insecure, enableLfs, proxy, project}) + .send({type, name, repo: url, username, password, tlsClientCertData, tlsClientCertKey, insecure, enableLfs, proxy, project, forceHttpBasicAuth, enableOCI}) .then(res => res.body as models.Repository); } diff --git a/ui/src/app/shared/services/requests.ts b/ui/src/app/shared/services/requests.ts index 207917a318529..4df6d1e4ddf19 100644 --- a/ui/src/app/shared/services/requests.ts +++ b/ui/src/app/shared/services/requests.ts @@ -51,19 +51,19 @@ export default { }, post(url: string) { - return initHandlers(agent.post(`${apiRoot()}${url}`)); + return initHandlers(agent.post(`${apiRoot()}${url}`)).set('Content-Type', 'application/json'); }, put(url: string) { - return initHandlers(agent.put(`${apiRoot()}${url}`)); + return initHandlers(agent.put(`${apiRoot()}${url}`)).set('Content-Type', 'application/json'); }, patch(url: string) { - return initHandlers(agent.patch(`${apiRoot()}${url}`)); + return initHandlers(agent.patch(`${apiRoot()}${url}`)).set('Content-Type', 'application/json'); }, delete(url: string) { - return initHandlers(agent.del(`${apiRoot()}${url}`)); + return initHandlers(agent.del(`${apiRoot()}${url}`)).set('Content-Type', 'application/json'); }, loadEventSource(url: string): Observable { diff --git a/ui/src/app/sidebar/sidebar.scss b/ui/src/app/sidebar/sidebar.scss index a3ff7a0355c28..d41cbeed3f7cf 100644 --- a/ui/src/app/sidebar/sidebar.scss +++ b/ui/src/app/sidebar/sidebar.scss @@ -58,6 +58,13 @@ $deselected-text: #818d94; text-overflow: ellipsis; } + &__tooltip { + max-width: 300px; + @media screen and (max-width: 590px) { + max-width: 250px; + } + } + &__nav-item { cursor: pointer; display: flex; @@ -81,6 +88,7 @@ $deselected-text: #818d94; margin-left: 2px; margin-right: -2px; margin-top: 12px; + width: 32px; } &--active { diff --git a/ui/src/app/sidebar/sidebar.tsx b/ui/src/app/sidebar/sidebar.tsx index c690565d01cb5..1aeb77c9112ee 100644 --- a/ui/src/app/sidebar/sidebar.tsx +++ b/ui/src/app/sidebar/sidebar.tsx @@ -64,7 +64,7 @@ export const Sidebar = (props: SidebarProps) => {
    {(props.navItems || []).map(item => ( - + {item?.tooltip || item.title}
    } {...tooltipProps}>
    void; + prefs: object; +}) => { + return ( +
    +
    + {props.url !== undefined ? ( + + {props.content} + + ) : ( + {props.content} + )} +
    + {!props.permanent ? ( + <> + + + + ) : ( + <> + )} +
    + ); +}; + export const Banner = (props: React.Props) => { const [visible, setVisible] = React.useState(true); return ( @@ -60,9 +100,8 @@ export const Banner = (props: React.Props) => { const isTop = position !== 'bottom'; const bannerClassName = isTop ? 'ui-banner-top' : 'ui-banner-bottom'; const wrapperClassname = bannerClassName + '--wrapper ' + (!permanent ? bannerClassName + '--wrapper-multiline' : bannerClassName + '--wrapper-singleline'); - const combinedBannerClassName = isTop ? 'ui-banner ui-banner-top' : 'ui-banner ui-banner-bottom'; let chatBottomPosition = 10; - if (show && !isTop) { + if (show && (!isTop || position === 'both')) { if (permanent) { chatBottomPosition = 40; } else { @@ -77,33 +116,36 @@ export const Banner = (props: React.Props) => { chatUrl = 'invalid-url'; } } + const shouldRenderTop = position === 'top' || position === 'both' || (!position && content); + const shouldRenderBottom = position === 'bottom' || position === 'both'; return ( -
    -
    - {url !== undefined ? ( - - {content} - - ) : ( - {content} - )} -
    - {!permanent ? ( - <> - - - - ) : ( - <> - )} -
    + {shouldRenderTop && ( + + )} + {shouldRenderBottom && ( + + )} {show ?
    {props.children}
    : props.children} {chatUrl && (
    diff --git a/ui/yarn.lock b/ui/yarn.lock index 5d1c7a8bad561..a3a25d70166a8 100644 --- a/ui/yarn.lock +++ b/ui/yarn.lock @@ -1903,12 +1903,7 @@ resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== -"@types/node@*": - version "16.3.1" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.3.1.tgz#24691fa2b0c3ec8c0d34bfcfd495edac5593ebb4" - integrity sha512-N87VuQi7HEeRJkhzovao/JviiqKjDKMVKxKMfUvSKw+MbkbW8R0nA3fi/MQhhlxV2fQ+2ReM+/Nt4efdrJx3zA== - -"@types/node@20.6.3": +"@types/node@*", "@types/node@20.6.3": version "20.6.3" resolved "https://registry.yarnpkg.com/@types/node/-/node-20.6.3.tgz#5b763b321cd3b80f6b8dde7a37e1a77ff9358dd9" integrity sha512-HksnYH4Ljr4VQgEy2lTStbCKv/P590tmPe5HqOnv9Gprffgv5WXAY+Y5Gqniu0GGqeTCUdBnzC3QSrzPkBkAMA== @@ -2058,10 +2053,10 @@ resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== -"@types/superagent@^4.1.15": - version "4.1.15" - resolved "https://registry.yarnpkg.com/@types/superagent/-/superagent-4.1.15.tgz#63297de457eba5e2bc502a7609426c4cceab434a" - integrity sha512-mu/N4uvfDN2zVQQ5AYJI/g4qxn2bHB6521t1UuH09ShNWjebTqN0ZFuYK9uYjcgmI0dTQEs+Owi1EO6U0OkOZQ== +"@types/superagent@^4.1.21": + version "4.1.21" + resolved "https://registry.yarnpkg.com/@types/superagent/-/superagent-4.1.21.tgz#78e2c2d6894c5f8ece228f0df4912906133d97c3" + integrity sha512-yrbAccEEY9+BSa1wji3ry8R3/BdW9kyWnjkRKctrtw5ebn/k2a2CsMeaQ7dD4iLfomgHkomBVIVgOFRMV4XYHA== dependencies: "@types/cookiejar" "*" "@types/node" "*" @@ -2513,7 +2508,7 @@ arg@^4.1.0: "argo-ui@git+https://github.com/argoproj/argo-ui.git": version "1.0.0" - resolved "git+https://github.com/argoproj/argo-ui.git#002d01b18e8aaf4b21307a3b87341ab05230483f" + resolved "git+https://github.com/argoproj/argo-ui.git#5ff344ac9692c14dd108468bd3c020c3c75181cb" dependencies: "@fortawesome/fontawesome-free" "^6.2.1" "@tippy.js/react" "^3.1.1" @@ -4525,9 +4520,9 @@ find-up@^4.0.0, find-up@^4.1.0: path-exists "^4.0.0" follow-redirects@^1.0.0: - version "1.14.9" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.9.tgz#dd4ea157de7bfaf9ea9b3fbd85aa16951f78d8d7" - integrity sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w== + version "1.15.5" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.5.tgz#54d4d6d062c0fa7d9d17feb008461550e3ba8020" + integrity sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw== for-in@^1.0.2: version "1.0.2" @@ -6682,6 +6677,11 @@ oas-validator@^5.0.8: should "^13.2.1" yaml "^1.10.0" +oauth4webapi@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/oauth4webapi/-/oauth4webapi-2.3.0.tgz#d01aeb83b60dbe3ff9ef1c6ec4a39e29c7be7ff6" + integrity sha512-JGkb5doGrwzVDuHwgrR4nHJayzN4h59VCed6EW8Tql6iHDfZIabCJvg6wtbn5q6pyB2hZruI3b77Nudvq7NmvA== + object-assign@^4.0.1, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" @@ -8447,20 +8447,20 @@ semver@7.0.0: integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== semver@7.x, semver@^7.3.2, semver@^7.3.8: - version "7.5.2" - resolved "https://registry.npmjs.org/semver/-/semver-7.5.2.tgz#5b851e66d1be07c1cdaf37dfc856f543325a2beb" - integrity sha512-SoftuTROv/cRjCze/scjGyiDtcUyxw1rgYQSZY7XTmtR5hX+dm76iDbTH8TkLPHCQmlbQVSSbNZCPM2hb0knnQ== + version "7.5.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" + integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== dependencies: lru-cache "^6.0.0" semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0: version "5.7.2" - resolved "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== semver@^6.0.0, semver@^6.3.0: version "6.3.1" - resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== send@0.17.2: @@ -8969,10 +8969,10 @@ stylis@^4.0.13: resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.2.0.tgz#79daee0208964c8fe695a42fcffcac633a211a51" integrity sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw== -superagent@^8.0.9: - version "8.0.9" - resolved "https://registry.npmjs.org/superagent/-/superagent-8.0.9.tgz#2c6fda6fadb40516515f93e9098c0eb1602e0535" - integrity sha512-4C7Bh5pyHTvU33KpZgwrNKh/VQnvgtCSqPRfJAUdmrtSYePVzVg4E4OzsrbkhJj9O7SO6Bnv75K/F8XVZT8YHA== +superagent@^8.1.2: + version "8.1.2" + resolved "https://registry.yarnpkg.com/superagent/-/superagent-8.1.2.tgz#03cb7da3ec8b32472c9d20f6c2a57c7f3765f30b" + integrity sha512-6WTxW1EB6yCxV5VFOIPQruWGHqc3yI7hEmZK6h+pyk69Lk/Ut7rLUY6W/ONF2MjBuGjvmMiIpsrVJ2vjrHlslA== dependencies: component-emitter "^1.3.0" cookiejar "^2.1.4" @@ -9941,10 +9941,10 @@ yargs@^17.0.1: y18n "^5.0.5" yargs-parser "^20.2.2" -yarn@^1.22.10: - version "1.22.10" - resolved "https://registry.yarnpkg.com/yarn/-/yarn-1.22.10.tgz#c99daa06257c80f8fa2c3f1490724e394c26b18c" - integrity sha512-IanQGI9RRPAN87VGTF7zs2uxkSyQSrSPsju0COgbsKQOOXr5LtcVPeyXWgwVa0ywG3d8dg6kSYKGBuYK021qeA== +yarn@^1.22.21: + version "1.22.21" + resolved "https://registry.yarnpkg.com/yarn/-/yarn-1.22.21.tgz#1959a18351b811cdeedbd484a8f86c3cc3bbaf72" + integrity sha512-ynXaJsADJ9JiZ84zU25XkPGOvVMmZ5b7tmTSpKURYwgELdjucAOydqIOrOfTxVYcNXe91xvLZwcRh68SR3liCg== yn@3.1.1: version "3.1.1" diff --git a/util/argo/argo.go b/util/argo/argo.go index 9b08d3aeeb847..36e513cf0f534 100644 --- a/util/argo/argo.go +++ b/util/argo/argo.go @@ -35,6 +35,10 @@ const ( errDestinationMissing = "Destination server missing from app spec" ) +var ( + ErrAnotherOperationInProgress = status.Errorf(codes.FailedPrecondition, "another operation is already in progress") +) + // AugmentSyncMsg enrich the K8s message with user-relevant information func AugmentSyncMsg(res common.ResourceSyncResult, apiResourceInfoGetter func() ([]kube.APIResourceInfo, error)) (string, error) { switch res.Message { @@ -800,7 +804,7 @@ func SetAppOperation(appIf v1alpha1.ApplicationInterface, appName string, op *ar return nil, fmt.Errorf("error getting application %q: %w", appName, err) } if a.Operation != nil { - return nil, status.Errorf(codes.FailedPrecondition, "another operation is already in progress") + return nil, ErrAnotherOperationInProgress } a.Operation = op a.Status.OperationState = nil @@ -851,7 +855,9 @@ func NormalizeApplicationSpec(spec *argoappv1.ApplicationSpec) *argoappv1.Applic if spec.Project == "" { spec.Project = argoappv1.DefaultAppProjectName } - + if spec.SyncPolicy.IsZero() { + spec.SyncPolicy = nil + } if spec.Sources != nil && len(spec.Sources) > 0 { for _, source := range spec.Sources { NormalizeSource(&source) diff --git a/util/argo/audit_logger.go b/util/argo/audit_logger.go index 1645e8d7d65d8..104b0dcd6143e 100644 --- a/util/argo/audit_logger.go +++ b/util/argo/audit_logger.go @@ -2,6 +2,7 @@ package argo import ( "context" + "encoding/json" "fmt" "time" @@ -45,7 +46,7 @@ const ( EventReasonOperationCompleted = "OperationCompleted" ) -func (l *AuditLogger) logEvent(objMeta ObjectRef, gvk schema.GroupVersionKind, info EventInfo, message string, logFields map[string]string) { +func (l *AuditLogger) logEvent(objMeta ObjectRef, gvk schema.GroupVersionKind, info EventInfo, message string, logFields map[string]interface{}) { logCtx := log.WithFields(log.Fields{ "type": info.Type, "reason": info.Reason, @@ -53,6 +54,19 @@ func (l *AuditLogger) logEvent(objMeta ObjectRef, gvk schema.GroupVersionKind, i for field, val := range logFields { logCtx = logCtx.WithField(field, val) } + logFieldStrings := make(map[string]string) + for field, val := range logFields { + if valStr, ok := val.(string); ok { + logFieldStrings[field] = valStr + continue + } + vJsonStr, err := json.Marshal(val) + if err != nil { + logCtx.Errorf("Unable to marshal audit event field %v: %v", field, err) + continue + } + logFieldStrings[field] = string(vJsonStr) + } switch gvk.Kind { case application.ApplicationKind: @@ -66,7 +80,7 @@ func (l *AuditLogger) logEvent(objMeta ObjectRef, gvk schema.GroupVersionKind, i event := v1.Event{ ObjectMeta: metav1.ObjectMeta{ Name: fmt.Sprintf("%v.%x", objMeta.Name, t.UnixNano()), - Annotations: logFields, + Annotations: logFieldStrings, }, Source: v1.EventSource{ Component: l.component, @@ -101,13 +115,14 @@ func (l *AuditLogger) LogAppEvent(app *v1alpha1.Application, info EventInfo, mes ResourceVersion: app.ObjectMeta.ResourceVersion, UID: app.ObjectMeta.UID, } - fields := map[string]string{ + fields := map[string]interface{}{ "dest-server": app.Spec.Destination.Server, "dest-namespace": app.Spec.Destination.Namespace, } if user != "" { fields["user"] = user } + fields["spec"] = app.Spec l.logEvent(objectMeta, v1alpha1.ApplicationSchemaGroupVersionKind, info, message, fields) } @@ -118,7 +133,7 @@ func (l *AuditLogger) LogAppSetEvent(app *v1alpha1.ApplicationSet, info EventInf ResourceVersion: app.ObjectMeta.ResourceVersion, UID: app.ObjectMeta.UID, } - fields := map[string]string{} + fields := make(map[string]interface{}) if user != "" { fields["user"] = user } @@ -132,7 +147,7 @@ func (l *AuditLogger) LogResourceEvent(res *v1alpha1.ResourceNode, info EventInf ResourceVersion: res.ResourceRef.Version, UID: types.UID(res.ResourceRef.UID), } - fields := map[string]string{} + fields := make(map[string]interface{}) if user != "" { fields["user"] = user } diff --git a/util/argo/diff/diff.go b/util/argo/diff/diff.go index 9b104719c5616..c99a04354c751 100644 --- a/util/argo/diff/diff.go +++ b/util/argo/diff/diff.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/go-logr/logr" + log "github.com/sirupsen/logrus" k8smanagedfields "k8s.io/apimachinery/pkg/util/managedfields" @@ -26,7 +27,9 @@ type DiffConfigBuilder struct { // NewDiffConfigBuilder create a new DiffConfigBuilder instance. func NewDiffConfigBuilder() *DiffConfigBuilder { return &DiffConfigBuilder{ - diffConfig: &diffConfig{}, + diffConfig: &diffConfig{ + ignoreMutationWebhook: true, + }, } } @@ -63,7 +66,6 @@ func (b *DiffConfigBuilder) WithNoCache() *DiffConfigBuilder { // WithCache sets the appstatecache.Cache and the appName in the diff config. Those the // are two objects necessary to retrieve a cached diff. func (b *DiffConfigBuilder) WithCache(s *appstatecache.Cache, appName string) *DiffConfigBuilder { - b.diffConfig.noCache = false b.diffConfig.stateCache = s b.diffConfig.appName = appName return b @@ -95,6 +97,21 @@ func (b *DiffConfigBuilder) WithManager(manager string) *DiffConfigBuilder { return b } +func (b *DiffConfigBuilder) WithServerSideDryRunner(ssdr diff.ServerSideDryRunner) *DiffConfigBuilder { + b.diffConfig.serverSideDryRunner = ssdr + return b +} + +func (b *DiffConfigBuilder) WithServerSideDiff(ssd bool) *DiffConfigBuilder { + b.diffConfig.serverSideDiff = ssd + return b +} + +func (b *DiffConfigBuilder) WithIgnoreMutationWebhook(m bool) *DiffConfigBuilder { + b.diffConfig.ignoreMutationWebhook = m + return b +} + // Build will first validate the current state of the diff config and return the // DiffConfig implementation if no errors are found. Will return nil and the error // details otherwise. @@ -140,6 +157,10 @@ type DiffConfig interface { // Manager returns the manager that should be used by the diff while // calculating the structured merge diff. Manager() string + + ServerSideDiff() bool + ServerSideDryRunner() diff.ServerSideDryRunner + IgnoreMutationWebhook() bool } // diffConfig defines the configurations used while applying diffs. @@ -156,6 +177,9 @@ type diffConfig struct { gvkParser *k8smanagedfields.GvkParser structuredMergeDiff bool manager string + serverSideDiff bool + serverSideDryRunner diff.ServerSideDryRunner + ignoreMutationWebhook bool } func (c *diffConfig) Ignores() []v1alpha1.ResourceIgnoreDifferences { @@ -194,6 +218,15 @@ func (c *diffConfig) StructuredMergeDiff() bool { func (c *diffConfig) Manager() string { return c.manager } +func (c *diffConfig) ServerSideDryRunner() diff.ServerSideDryRunner { + return c.serverSideDryRunner +} +func (c *diffConfig) ServerSideDiff() bool { + return c.serverSideDiff +} +func (c *diffConfig) IgnoreMutationWebhook() bool { + return c.ignoreMutationWebhook +} // Validate will check the current state of this diffConfig and return // error if it finds any required configuration missing. @@ -213,6 +246,9 @@ func (c *diffConfig) Validate() error { return fmt.Errorf("%s: StateCache must be set when retrieving from cache", msg) } } + if c.serverSideDiff && c.serverSideDryRunner == nil { + return fmt.Errorf("%s: serverSideDryRunner must be set when using server side diff", msg) + } return nil } @@ -254,6 +290,9 @@ func StateDiffs(lives, configs []*unstructured.Unstructured, diffConfig DiffConf diff.WithStructuredMergeDiff(diffConfig.StructuredMergeDiff()), diff.WithGVKParser(diffConfig.GVKParser()), diff.WithManager(diffConfig.Manager()), + diff.WithServerSideDiff(diffConfig.ServerSideDiff()), + diff.WithServerSideDryRunner(diffConfig.ServerSideDryRunner()), + diff.WithIgnoreMutationWebhook(diffConfig.IgnoreMutationWebhook()), } if diffConfig.Logger() != nil { @@ -282,9 +321,8 @@ func diffArrayCached(configArray []*unstructured.Unstructured, liveArray []*unst } diffByKey := map[kube.ResourceKey]*v1alpha1.ResourceDiff{} - for i := range cachedDiff { - res := cachedDiff[i] - diffByKey[kube.NewResourceKey(res.Group, res.Kind, res.Namespace, res.Name)] = cachedDiff[i] + for _, res := range cachedDiff { + diffByKey[kube.NewResourceKey(res.Group, res.Kind, res.Namespace, res.Name)] = res } diffResultList := diff.DiffResultList{ @@ -335,7 +373,12 @@ func (c *diffConfig) DiffFromCache(appName string) (bool, []*v1alpha1.ResourceDi return false, nil } cachedDiff := make([]*v1alpha1.ResourceDiff, 0) - if c.stateCache != nil && c.stateCache.GetAppManagedResources(appName, &cachedDiff) == nil { + if c.stateCache != nil { + err := c.stateCache.GetAppManagedResources(appName, &cachedDiff) + if err != nil { + log.Errorf("DiffFromCache error: error getting managed resources for app %s: %s", appName, err) + return false, nil + } return true, cachedDiff } return false, nil diff --git a/util/argo/normalizers/corev1_known_types.go b/util/argo/normalizers/corev1_known_types.go index 84c20ec03d08c..8309d85be8890 100644 --- a/util/argo/normalizers/corev1_known_types.go +++ b/util/argo/normalizers/corev1_known_types.go @@ -49,6 +49,9 @@ func init() { knownTypes["core/v1/CinderVolumeSource"] = func() interface{} { return &corev1.CinderVolumeSource{} } + knownTypes["core/v1/ClaimSource"] = func() interface{} { + return &corev1.ClaimSource{} + } knownTypes["core/v1/ClientIPConfig"] = func() interface{} { return &corev1.ClientIPConfig{} } @@ -409,6 +412,12 @@ func init() { knownTypes["core/v1/PodReadinessGate"] = func() interface{} { return &corev1.PodReadinessGate{} } + knownTypes["core/v1/PodResourceClaim"] = func() interface{} { + return &corev1.PodResourceClaim{} + } + knownTypes["core/v1/PodSchedulingGate"] = func() interface{} { + return &corev1.PodSchedulingGate{} + } knownTypes["core/v1/PodSecurityContext"] = func() interface{} { return &corev1.PodSecurityContext{} } @@ -484,6 +493,9 @@ func init() { knownTypes["core/v1/ReplicationControllerStatus"] = func() interface{} { return &corev1.ReplicationControllerStatus{} } + knownTypes["core/v1/ResourceClaim"] = func() interface{} { + return &corev1.ResourceClaim{} + } knownTypes["core/v1/ResourceFieldSelector"] = func() interface{} { return &corev1.ResourceFieldSelector{} } @@ -610,6 +622,9 @@ func init() { knownTypes["core/v1/TypedLocalObjectReference"] = func() interface{} { return &corev1.TypedLocalObjectReference{} } + knownTypes["core/v1/TypedObjectReference"] = func() interface{} { + return &corev1.TypedObjectReference{} + } knownTypes["core/v1/Volume"] = func() interface{} { return &corev1.Volume{} } diff --git a/util/argo/normalizers/diffing_known_types.txt b/util/argo/normalizers/diffing_known_types.txt index fb7e50a4e9038..e83d14a28f201 100644 --- a/util/argo/normalizers/diffing_known_types.txt +++ b/util/argo/normalizers/diffing_known_types.txt @@ -13,6 +13,7 @@ core/v1/CephFSPersistentVolumeSource core/v1/CephFSVolumeSource core/v1/CinderPersistentVolumeSource core/v1/CinderVolumeSource +core/v1/ClaimSource core/v1/ClientIPConfig core/v1/ComponentCondition core/v1/ComponentStatus @@ -133,6 +134,8 @@ core/v1/PodOS core/v1/PodPortForwardOptions core/v1/PodProxyOptions core/v1/PodReadinessGate +core/v1/PodResourceClaim +core/v1/PodSchedulingGate core/v1/PodSecurityContext core/v1/PodSignature core/v1/PodSpec @@ -158,6 +161,7 @@ core/v1/ReplicationControllerCondition core/v1/ReplicationControllerList core/v1/ReplicationControllerSpec core/v1/ReplicationControllerStatus +core/v1/ResourceClaim core/v1/ResourceFieldSelector core/v1/ResourceList core/v1/ResourceQuota @@ -200,6 +204,7 @@ core/v1/TopologySelectorLabelRequirement core/v1/TopologySelectorTerm core/v1/TopologySpreadConstraint core/v1/TypedLocalObjectReference +core/v1/TypedObjectReference core/v1/Volume core/v1/VolumeDevice core/v1/VolumeMount diff --git a/util/argo/normalizers/knowntypes_normalizer.go b/util/argo/normalizers/knowntypes_normalizer.go index 403065c58a6df..f96a366a75d6a 100644 --- a/util/argo/normalizers/knowntypes_normalizer.go +++ b/util/argo/normalizers/knowntypes_normalizer.go @@ -8,6 +8,7 @@ import ( log "github.com/sirupsen/logrus" v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime/schema" @@ -32,6 +33,9 @@ func init() { knownTypes["core/Quantity"] = func() interface{} { return &resource.Quantity{} } + knownTypes["meta/v1/Duration"] = func() interface{} { + return &metav1.Duration{} + } } // NewKnownTypesNormalizer create a normalizer that re-format custom resource fields using built-in Kubernetes types. diff --git a/util/argo/normalizers/knowntypes_normalizer_test.go b/util/argo/normalizers/knowntypes_normalizer_test.go index 57e436195f890..37c34d37509b3 100644 --- a/util/argo/normalizers/knowntypes_normalizer_test.go +++ b/util/argo/normalizers/knowntypes_normalizer_test.go @@ -11,6 +11,7 @@ import ( "github.com/argoproj/pkg/errors" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime/schema" "sigs.k8s.io/yaml" @@ -228,6 +229,33 @@ spec: assert.Equal(t, "1250M", ram) } +func TestNormalize_Duration(t *testing.T) { + cert := mustUnmarshalYAML(` +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: my-cert +spec: + duration: 8760h +`) + normalizer, err := NewKnownTypesNormalizer(map[string]v1alpha1.ResourceOverride{ + "cert-manager.io/Certificate": { + KnownTypeFields: []v1alpha1.KnownTypeField{{ + Type: "meta/v1/Duration", + Field: "spec.duration", + }}, + }, + }) + require.NoError(t, err) + + require.NoError(t, normalizer.Normalize(cert)) + + duration, ok, err := unstructured.NestedFieldNoCopy(cert.Object, "spec", "duration") + require.NoError(t, err) + require.True(t, ok) + require.Equal(t, "8760h0m0s", duration) +} + func TestFieldDoesNotExist(t *testing.T) { rollout := mustUnmarshalYAML(someCRDYaml) normalizer, err := NewKnownTypesNormalizer(map[string]v1alpha1.ResourceOverride{ diff --git a/util/cache/appstate/cache.go b/util/cache/appstate/cache.go index d59d31befb12e..bb161a429eff9 100644 --- a/util/cache/appstate/cache.go +++ b/util/cache/appstate/cache.go @@ -6,7 +6,6 @@ import ( "sort" "time" - "github.com/redis/go-redis/v9" "github.com/spf13/cobra" appv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" @@ -29,7 +28,7 @@ func NewCache(cache *cacheutil.Cache, appStateCacheExpiration time.Duration) *Ca return &Cache{cache, appStateCacheExpiration} } -func AddCacheFlagsToCmd(cmd *cobra.Command, opts ...func(client *redis.Client)) func() (*Cache, error) { +func AddCacheFlagsToCmd(cmd *cobra.Command, opts ...cacheutil.Options) func() (*Cache, error) { var appStateCacheExpiration time.Duration cmd.Flags().DurationVar(&appStateCacheExpiration, "app-state-cache-expiration", env.ParseDurationFromEnv("ARGOCD_APP_STATE_CACHE_EXPIRATION", 1*time.Hour, 0, 10*time.Hour), "Cache expiration for app state") diff --git a/util/cache/cache.go b/util/cache/cache.go index fdea46cdea0d2..b632824e9c96b 100644 --- a/util/cache/cache.go +++ b/util/cache/cache.go @@ -5,17 +5,17 @@ import ( "fmt" "math" "os" + "strings" "time" "crypto/tls" "crypto/x509" - "github.com/redis/go-redis/v9" - "github.com/spf13/cobra" - "github.com/argoproj/argo-cd/v2/common" certutil "github.com/argoproj/argo-cd/v2/util/cert" "github.com/argoproj/argo-cd/v2/util/env" + "github.com/redis/go-redis/v9" + "github.com/spf13/cobra" ) const ( @@ -27,6 +27,15 @@ const ( envRedisRetryCount = "REDIS_RETRY_COUNT" // defaultRedisRetryCount holds default number of retries defaultRedisRetryCount = 3 + // envRedisSentinelPassword is an env variable name which stores redis sentinel password + envRedisSentinelPassword = "REDIS_SENTINEL_PASSWORD" + // envRedisSentinelUsername is an env variable name which stores redis sentinel username + envRedisSentinelUsername = "REDIS_SENTINEL_USERNAME" +) + +const ( + // CLIFlagRedisCompress is a cli flag name to define the redis compression setting for data sent to redis + CLIFlagRedisCompress = "redis-compress" ) func NewCache(client CacheClient) *Cache { @@ -52,28 +61,74 @@ func buildRedisClient(redisAddress, password, username string, redisDB, maxRetri return client } -func buildFailoverRedisClient(sentinelMaster, password, username string, redisDB, maxRetries int, tlsConfig *tls.Config, sentinelAddresses []string) *redis.Client { +func buildFailoverRedisClient(sentinelMaster, sentinelUsername, sentinelPassword, password, username string, redisDB, maxRetries int, tlsConfig *tls.Config, sentinelAddresses []string) *redis.Client { opts := &redis.FailoverOptions{ - MasterName: sentinelMaster, - SentinelAddrs: sentinelAddresses, - DB: redisDB, - Password: password, - MaxRetries: maxRetries, - TLSConfig: tlsConfig, - Username: username, + MasterName: sentinelMaster, + SentinelAddrs: sentinelAddresses, + DB: redisDB, + Password: password, + MaxRetries: maxRetries, + TLSConfig: tlsConfig, + Username: username, + SentinelUsername: sentinelUsername, + SentinelPassword: sentinelPassword, } client := redis.NewFailoverClient(opts) client.AddHook(redis.Hook(NewArgoRedisHook(func() { - *client = *buildFailoverRedisClient(sentinelMaster, password, username, redisDB, maxRetries, tlsConfig, sentinelAddresses) + *client = *buildFailoverRedisClient(sentinelMaster, sentinelUsername, sentinelPassword, password, username, redisDB, maxRetries, tlsConfig, sentinelAddresses) }))) return client } +type Options struct { + FlagPrefix string + OnClientCreated func(client *redis.Client) +} + +func (o *Options) callOnClientCreated(client *redis.Client) { + if o.OnClientCreated != nil { + o.OnClientCreated(client) + } +} + +func (o *Options) getEnvPrefix() string { + return strings.Replace(strings.ToUpper(o.FlagPrefix), "-", "_", -1) +} + +func mergeOptions(opts ...Options) Options { + var result Options + for _, o := range opts { + if o.FlagPrefix != "" { + result.FlagPrefix = o.FlagPrefix + } + if o.OnClientCreated != nil { + result.OnClientCreated = o.OnClientCreated + } + } + return result +} + +func getFlagVal[T any](cmd *cobra.Command, o Options, name string, getVal func(name string) (T, error)) func() T { + return func() T { + var res T + var err error + if o.FlagPrefix != "" && cmd.Flags().Changed(o.FlagPrefix+name) { + res, err = getVal(o.FlagPrefix + name) + } else { + res, err = getVal(name) + } + if err != nil { + panic(err) + } + return res + } +} + // AddCacheFlagsToCmd adds flags which control caching to the specified command -func AddCacheFlagsToCmd(cmd *cobra.Command, opts ...func(client *redis.Client)) func() (*Cache, error) { +func AddCacheFlagsToCmd(cmd *cobra.Command, opts ...Options) func() (*Cache, error) { redisAddress := "" sentinelAddresses := make([]string, 0) sentinelMaster := "" @@ -84,20 +139,44 @@ func AddCacheFlagsToCmd(cmd *cobra.Command, opts ...func(client *redis.Client)) redisUseTLS := false insecureRedis := false compressionStr := "" + opt := mergeOptions(opts...) var defaultCacheExpiration time.Duration - cmd.Flags().StringVar(&redisAddress, "redis", env.StringFromEnv("REDIS_SERVER", ""), "Redis server hostname and port (e.g. argocd-redis:6379). ") - cmd.Flags().IntVar(&redisDB, "redisdb", env.ParseNumFromEnv("REDISDB", 0, 0, math.MaxInt32), "Redis database.") - cmd.Flags().StringArrayVar(&sentinelAddresses, "sentinel", []string{}, "Redis sentinel hostname and port (e.g. argocd-redis-ha-announce-0:6379). ") - cmd.Flags().StringVar(&sentinelMaster, "sentinelmaster", "master", "Redis sentinel master group name.") - cmd.Flags().DurationVar(&defaultCacheExpiration, "default-cache-expiration", env.ParseDurationFromEnv("ARGOCD_DEFAULT_CACHE_EXPIRATION", 24*time.Hour, 0, math.MaxInt64), "Cache expiration default") - cmd.Flags().BoolVar(&redisUseTLS, "redis-use-tls", false, "Use TLS when connecting to Redis. ") - cmd.Flags().StringVar(&redisClientCertificate, "redis-client-certificate", "", "Path to Redis client certificate (e.g. /etc/certs/redis/client.crt).") - cmd.Flags().StringVar(&redisClientKey, "redis-client-key", "", "Path to Redis client key (e.g. /etc/certs/redis/client.crt).") - cmd.Flags().BoolVar(&insecureRedis, "redis-insecure-skip-tls-verify", false, "Skip Redis server certificate validation.") - cmd.Flags().StringVar(&redisCACertificate, "redis-ca-certificate", "", "Path to Redis server CA certificate (e.g. /etc/certs/redis/ca.crt). If not specified, system trusted CAs will be used for server certificate validation.") - cmd.Flags().StringVar(&compressionStr, "redis-compress", env.StringFromEnv("REDIS_COMPRESSION", string(RedisCompressionGZip)), "Enable compression for data sent to Redis with the required compression algorithm. (possible values: gzip, none)") + cmd.Flags().StringVar(&redisAddress, opt.FlagPrefix+"redis", env.StringFromEnv(opt.getEnvPrefix()+"REDIS_SERVER", ""), "Redis server hostname and port (e.g. argocd-redis:6379). ") + redisAddressSrc := getFlagVal(cmd, opt, "redis", cmd.Flags().GetString) + cmd.Flags().IntVar(&redisDB, opt.FlagPrefix+"redisdb", env.ParseNumFromEnv(opt.getEnvPrefix()+"REDISDB", 0, 0, math.MaxInt32), "Redis database.") + redisDBSrc := getFlagVal(cmd, opt, "redisdb", cmd.Flags().GetInt) + cmd.Flags().StringArrayVar(&sentinelAddresses, opt.FlagPrefix+"sentinel", []string{}, "Redis sentinel hostname and port (e.g. argocd-redis-ha-announce-0:6379). ") + sentinelAddressesSrc := getFlagVal(cmd, opt, "sentinel", cmd.Flags().GetStringArray) + cmd.Flags().StringVar(&sentinelMaster, opt.FlagPrefix+"sentinelmaster", "master", "Redis sentinel master group name.") + sentinelMasterSrc := getFlagVal(cmd, opt, "sentinelmaster", cmd.Flags().GetString) + cmd.Flags().DurationVar(&defaultCacheExpiration, opt.FlagPrefix+"default-cache-expiration", env.ParseDurationFromEnv("ARGOCD_DEFAULT_CACHE_EXPIRATION", 24*time.Hour, 0, math.MaxInt64), "Cache expiration default") + defaultCacheExpirationSrc := getFlagVal(cmd, opt, "default-cache-expiration", cmd.Flags().GetDuration) + cmd.Flags().BoolVar(&redisUseTLS, opt.FlagPrefix+"redis-use-tls", false, "Use TLS when connecting to Redis. ") + redisUseTLSSrc := getFlagVal(cmd, opt, "redis-use-tls", cmd.Flags().GetBool) + cmd.Flags().StringVar(&redisClientCertificate, opt.FlagPrefix+"redis-client-certificate", "", "Path to Redis client certificate (e.g. /etc/certs/redis/client.crt).") + redisClientCertificateSrc := getFlagVal(cmd, opt, "redis-client-certificate", cmd.Flags().GetString) + cmd.Flags().StringVar(&redisClientKey, opt.FlagPrefix+"redis-client-key", "", "Path to Redis client key (e.g. /etc/certs/redis/client.crt).") + redisClientKeySrc := getFlagVal(cmd, opt, "redis-client-key", cmd.Flags().GetString) + cmd.Flags().BoolVar(&insecureRedis, opt.FlagPrefix+"redis-insecure-skip-tls-verify", false, "Skip Redis server certificate validation.") + insecureRedisSrc := getFlagVal(cmd, opt, "redis-insecure-skip-tls-verify", cmd.Flags().GetBool) + cmd.Flags().StringVar(&redisCACertificate, opt.FlagPrefix+"redis-ca-certificate", "", "Path to Redis server CA certificate (e.g. /etc/certs/redis/ca.crt). If not specified, system trusted CAs will be used for server certificate validation.") + redisCACertificateSrc := getFlagVal(cmd, opt, "redis-ca-certificate", cmd.Flags().GetString) + cmd.Flags().StringVar(&compressionStr, opt.FlagPrefix+CLIFlagRedisCompress, env.StringFromEnv(opt.getEnvPrefix()+"REDIS_COMPRESSION", string(RedisCompressionGZip)), "Enable compression for data sent to Redis with the required compression algorithm. (possible values: gzip, none)") + compressionStrSrc := getFlagVal(cmd, opt, CLIFlagRedisCompress, cmd.Flags().GetString) return func() (*Cache, error) { + redisAddress := redisAddressSrc() + redisDB := redisDBSrc() + sentinelAddresses := sentinelAddressesSrc() + sentinelMaster := sentinelMasterSrc() + defaultCacheExpiration := defaultCacheExpirationSrc() + redisUseTLS := redisUseTLSSrc() + redisClientCertificate := redisClientCertificateSrc() + redisClientKey := redisClientKeySrc() + insecureRedis := insecureRedisSrc() + redisCACertificate := redisCACertificateSrc() + compressionStr := compressionStrSrc() + var tlsConfig *tls.Config = nil if redisUseTLS { tlsConfig = &tls.Config{} @@ -126,16 +205,31 @@ func AddCacheFlagsToCmd(cmd *cobra.Command, opts ...func(client *redis.Client)) } password := os.Getenv(envRedisPassword) username := os.Getenv(envRedisUsername) + sentinelUsername := os.Getenv(envRedisSentinelUsername) + sentinelPassword := os.Getenv(envRedisSentinelPassword) + if opt.FlagPrefix != "" { + if val := os.Getenv(opt.getEnvPrefix() + envRedisUsername); val != "" { + username = val + } + if val := os.Getenv(opt.getEnvPrefix() + envRedisPassword); val != "" { + password = val + } + if val := os.Getenv(opt.getEnvPrefix() + envRedisSentinelUsername); val != "" { + sentinelUsername = val + } + if val := os.Getenv(opt.getEnvPrefix() + envRedisSentinelPassword); val != "" { + sentinelPassword = val + } + } + maxRetries := env.ParseNumFromEnv(envRedisRetryCount, defaultRedisRetryCount, 0, math.MaxInt32) compression, err := CompressionTypeFromString(compressionStr) if err != nil { return nil, err } if len(sentinelAddresses) > 0 { - client := buildFailoverRedisClient(sentinelMaster, password, username, redisDB, maxRetries, tlsConfig, sentinelAddresses) - for i := range opts { - opts[i](client) - } + client := buildFailoverRedisClient(sentinelMaster, sentinelUsername, sentinelPassword, password, username, redisDB, maxRetries, tlsConfig, sentinelAddresses) + opt.callOnClientCreated(client) return NewCache(NewRedisCache(client, defaultCacheExpiration, compression)), nil } if redisAddress == "" { @@ -143,9 +237,7 @@ func AddCacheFlagsToCmd(cmd *cobra.Command, opts ...func(client *redis.Client)) } client := buildRedisClient(redisAddress, password, username, redisDB, maxRetries, tlsConfig) - for i := range opts { - opts[i](client) - } + opt.callOnClientCreated(client) return NewCache(NewRedisCache(client, defaultCacheExpiration, compression)), nil } } @@ -163,6 +255,10 @@ func (c *Cache) SetClient(client CacheClient) { c.client = client } +func (c *Cache) RenameItem(oldKey string, newKey string, expiration time.Duration) error { + return c.client.Rename(fmt.Sprintf("%s|%s", oldKey, common.CacheVersion), fmt.Sprintf("%s|%s", newKey, common.CacheVersion), expiration) +} + func (c *Cache) SetItem(key string, item interface{}, expiration time.Duration, delete bool) error { key = fmt.Sprintf("%s|%s", key, common.CacheVersion) if delete { diff --git a/util/cache/client.go b/util/cache/client.go index 434c2a8da187a..c8c7b4a6baa80 100644 --- a/util/cache/client.go +++ b/util/cache/client.go @@ -17,6 +17,7 @@ type Item struct { type CacheClient interface { Set(item *Item) error + Rename(oldKey string, newKey string, expiration time.Duration) error Get(key string, obj interface{}) error Delete(key string) error OnUpdated(ctx context.Context, key string, callback func() error) error diff --git a/util/cache/inmemory.go b/util/cache/inmemory.go index 53e690925d940..6d970c1d4f567 100644 --- a/util/cache/inmemory.go +++ b/util/cache/inmemory.go @@ -16,6 +16,10 @@ func NewInMemoryCache(expiration time.Duration) *InMemoryCache { } } +func init() { + gob.Register([]interface{}{}) +} + // compile-time validation of adherance of the CacheClient contract var _ CacheClient = &InMemoryCache{} @@ -33,6 +37,16 @@ func (i *InMemoryCache) Set(item *Item) error { return nil } +func (i *InMemoryCache) Rename(oldKey string, newKey string, expiration time.Duration) error { + bufIf, found := i.memCache.Get(oldKey) + if !found { + return ErrCacheMiss + } + i.memCache.Set(newKey, bufIf, expiration) + i.memCache.Delete(oldKey) + return nil +} + // HasSame returns true if key with the same value already present in cache func (i *InMemoryCache) HasSame(key string, obj interface{}) (bool, error) { var buf bytes.Buffer diff --git a/util/cache/mocks/cacheclient.go b/util/cache/mocks/cacheclient.go new file mode 100644 index 0000000000000..2fdd9fc37f8be --- /dev/null +++ b/util/cache/mocks/cacheclient.go @@ -0,0 +1,74 @@ +package mocks + +import ( + "context" + "time" + + "github.com/stretchr/testify/mock" + + "github.com/argoproj/argo-cd/v2/util/cache" +) + +type MockCacheClient struct { + mock.Mock + BaseCache cache.CacheClient + ReadDelay time.Duration + WriteDelay time.Duration +} + +func (c *MockCacheClient) Rename(oldKey string, newKey string, expiration time.Duration) error { + args := c.Called(oldKey, newKey, expiration) + if len(args) > 0 && args.Get(0) != nil { + return args.Get(0).(error) + } + return c.BaseCache.Rename(oldKey, newKey, expiration) +} + +func (c *MockCacheClient) Set(item *cache.Item) error { + args := c.Called(item) + if len(args) > 0 && args.Get(0) != nil { + return args.Get(0).(error) + } + if c.WriteDelay > 0 { + time.Sleep(c.WriteDelay) + } + return c.BaseCache.Set(item) +} + +func (c *MockCacheClient) Get(key string, obj interface{}) error { + args := c.Called(key, obj) + if len(args) > 0 && args.Get(0) != nil { + return args.Get(0).(error) + } + if c.ReadDelay > 0 { + time.Sleep(c.ReadDelay) + } + return c.BaseCache.Get(key, obj) +} + +func (c *MockCacheClient) Delete(key string) error { + args := c.Called(key) + if len(args) > 0 && args.Get(0) != nil { + return args.Get(0).(error) + } + if c.WriteDelay > 0 { + time.Sleep(c.WriteDelay) + } + return c.BaseCache.Delete(key) +} + +func (c *MockCacheClient) OnUpdated(ctx context.Context, key string, callback func() error) error { + args := c.Called(ctx, key, callback) + if len(args) > 0 && args.Get(0) != nil { + return args.Get(0).(error) + } + return c.BaseCache.OnUpdated(ctx, key, callback) +} + +func (c *MockCacheClient) NotifyUpdated(key string) error { + args := c.Called(key) + if len(args) > 0 && args.Get(0) != nil { + return args.Get(0).(error) + } + return c.BaseCache.NotifyUpdated(key) +} diff --git a/util/cache/redis.go b/util/cache/redis.go index c5365c4984e21..4648a553f08cc 100644 --- a/util/cache/redis.go +++ b/util/cache/redis.go @@ -7,6 +7,7 @@ import ( "encoding/json" "fmt" "io" + "net" "time" ioutil "github.com/argoproj/argo-cd/v2/util/io" @@ -95,6 +96,10 @@ func (r *redisCache) unmarshal(data []byte, obj interface{}) error { return nil } +func (r *redisCache) Rename(oldKey string, newKey string, _ time.Duration) error { + return r.client.Rename(context.TODO(), r.getKey(oldKey), r.getKey(newKey)).Err() +} + func (r *redisCache) Set(item *Item) error { expiration := item.Expiration if expiration == 0 { @@ -155,41 +160,27 @@ type MetricsRegistry interface { ObserveRedisRequestDuration(duration time.Duration) } -var metricStartTimeKey = struct{}{} - type redisHook struct { registry MetricsRegistry } -func (rh *redisHook) BeforeProcess(ctx context.Context, cmd redis.Cmder) (context.Context, error) { - return context.WithValue(ctx, metricStartTimeKey, time.Now()), nil -} - -func (rh *redisHook) AfterProcess(ctx context.Context, cmd redis.Cmder) error { - cmdErr := cmd.Err() - rh.registry.IncRedisRequest(cmdErr != nil && cmdErr != redis.Nil) - - startTime := ctx.Value(metricStartTimeKey).(time.Time) - duration := time.Since(startTime) - rh.registry.ObserveRedisRequestDuration(duration) - - return nil -} - -func (redisHook) BeforeProcessPipeline(ctx context.Context, _ []redis.Cmder) (context.Context, error) { - return ctx, nil +func (rh *redisHook) DialHook(next redis.DialHook) redis.DialHook { + return func(ctx context.Context, network, addr string) (net.Conn, error) { + conn, err := next(ctx, network, addr) + return conn, err + } } -func (redisHook) AfterProcessPipeline(_ context.Context, _ []redis.Cmder) error { - return nil -} +func (rh *redisHook) ProcessHook(next redis.ProcessHook) redis.ProcessHook { + return func(ctx context.Context, cmd redis.Cmder) error { + startTime := time.Now() -func (redisHook) DialHook(next redis.DialHook) redis.DialHook { - return nil -} + err := next(ctx, cmd) + rh.registry.IncRedisRequest(err != nil && err != redis.Nil) + rh.registry.ObserveRedisRequestDuration(time.Since(startTime)) -func (redisHook) ProcessHook(next redis.ProcessHook) redis.ProcessHook { - return nil + return err + } } func (redisHook) ProcessPipelineHook(next redis.ProcessPipelineHook) redis.ProcessPipelineHook { diff --git a/util/cache/redis_hook.go b/util/cache/redis_hook.go index 455ad03eb5bbf..e7cc3f4bcc68e 100644 --- a/util/cache/redis_hook.go +++ b/util/cache/redis_hook.go @@ -2,14 +2,13 @@ package cache import ( "context" - "strings" + "errors" + "net" "github.com/redis/go-redis/v9" log "github.com/sirupsen/logrus" ) -const NoSuchHostErr = "no such host" - type argoRedisHooks struct { reconnectCallback func() } @@ -18,32 +17,23 @@ func NewArgoRedisHook(reconnectCallback func()) *argoRedisHooks { return &argoRedisHooks{reconnectCallback: reconnectCallback} } -func (hook *argoRedisHooks) BeforeProcess(ctx context.Context, cmd redis.Cmder) (context.Context, error) { - return ctx, nil -} - -func (hook *argoRedisHooks) AfterProcess(ctx context.Context, cmd redis.Cmder) error { - if cmd.Err() != nil && strings.Contains(cmd.Err().Error(), NoSuchHostErr) { - log.Warnf("Reconnect to redis because error: \"%v\"", cmd.Err()) - hook.reconnectCallback() - } - return nil -} - -func (hook *argoRedisHooks) BeforeProcessPipeline(ctx context.Context, cmds []redis.Cmder) (context.Context, error) { - return ctx, nil -} - -func (hook *argoRedisHooks) AfterProcessPipeline(ctx context.Context, cmds []redis.Cmder) error { - return nil -} - func (hook *argoRedisHooks) DialHook(next redis.DialHook) redis.DialHook { - return nil + return func(ctx context.Context, network, addr string) (net.Conn, error) { + conn, err := next(ctx, network, addr) + return conn, err + } } func (hook *argoRedisHooks) ProcessHook(next redis.ProcessHook) redis.ProcessHook { - return nil + return func(ctx context.Context, cmd redis.Cmder) error { + var dnsError *net.DNSError + err := next(ctx, cmd) + if err != nil && errors.As(err, &dnsError) { + log.Warnf("Reconnect to redis because error: \"%v\"", err) + hook.reconnectCallback() + } + return err + } } func (hook *argoRedisHooks) ProcessPipelineHook(next redis.ProcessPipelineHook) redis.ProcessPipelineHook { diff --git a/util/cache/redis_hook_test.go b/util/cache/redis_hook_test.go index ef9e6a1c85537..4d7d9b7aaf41d 100644 --- a/util/cache/redis_hook_test.go +++ b/util/cache/redis_hook_test.go @@ -1,38 +1,53 @@ package cache import ( - "context" - "errors" "testing" + "time" + "github.com/alicebob/miniredis/v2" "github.com/stretchr/testify/assert" "github.com/redis/go-redis/v9" ) func Test_ReconnectCallbackHookCalled(t *testing.T) { + mr, err := miniredis.Run() + if err != nil { + panic(err) + } + defer mr.Close() + called := false hook := NewArgoRedisHook(func() { called = true }) - cmd := &redis.StringCmd{} - cmd.SetErr(errors.New("Failed to resync revoked tokens. retrying again in 1 minute: dial tcp: lookup argocd-redis on 10.179.0.10:53: no such host")) - - _ = hook.AfterProcess(context.Background(), cmd) + faultyDNSRedisClient := redis.NewClient(&redis.Options{Addr: "invalidredishost.invalid:12345"}) + faultyDNSRedisClient.AddHook(hook) + faultyDNSClient := NewRedisCache(faultyDNSRedisClient, 60*time.Second, RedisCompressionNone) + err = faultyDNSClient.Set(&Item{Key: "baz", Object: "foo"}) assert.Equal(t, called, true) + assert.Error(t, err) } func Test_ReconnectCallbackHookNotCalled(t *testing.T) { + mr, err := miniredis.Run() + if err != nil { + panic(err) + } + defer mr.Close() + called := false hook := NewArgoRedisHook(func() { called = true }) - cmd := &redis.StringCmd{} - cmd.SetErr(errors.New("Something wrong")) - _ = hook.AfterProcess(context.Background(), cmd) + redisClient := redis.NewClient(&redis.Options{Addr: mr.Addr()}) + redisClient.AddHook(hook) + client := NewRedisCache(redisClient, 60*time.Second, RedisCompressionNone) + err = client.Set(&Item{Key: "foo", Object: "bar"}) assert.Equal(t, called, false) + assert.NoError(t, err) } diff --git a/util/cache/redis_test.go b/util/cache/redis_test.go index 3800753cee3ec..e05c7541f5ff1 100644 --- a/util/cache/redis_test.go +++ b/util/cache/redis_test.go @@ -2,14 +2,59 @@ package cache import ( "context" + "strconv" "testing" "time" + promcm "github.com/prometheus/client_model/go" + "github.com/alicebob/miniredis/v2" + "github.com/prometheus/client_golang/prometheus" "github.com/redis/go-redis/v9" "github.com/stretchr/testify/assert" ) +var ( + redisRequestCounter = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "argocd_redis_request_total", + }, + []string{"initiator", "failed"}, + ) + redisRequestHistogram = prometheus.NewHistogramVec( + prometheus.HistogramOpts{ + Name: "argocd_redis_request_duration", + Buckets: []float64{0.1, 0.25, .5, 1, 2}, + }, + []string{"initiator"}, + ) +) + +type MockMetricsServer struct { + registry *prometheus.Registry + redisRequestCounter *prometheus.CounterVec + redisRequestHistogram *prometheus.HistogramVec +} + +func NewMockMetricsServer() *MockMetricsServer { + registry := prometheus.NewRegistry() + registry.MustRegister(redisRequestCounter) + registry.MustRegister(redisRequestHistogram) + return &MockMetricsServer{ + registry: registry, + redisRequestCounter: redisRequestCounter, + redisRequestHistogram: redisRequestHistogram, + } +} + +func (m *MockMetricsServer) IncRedisRequest(failed bool) { + m.redisRequestCounter.WithLabelValues("mock", strconv.FormatBool(failed)).Inc() +} + +func (m *MockMetricsServer) ObserveRedisRequestDuration(duration time.Duration) { + m.redisRequestHistogram.WithLabelValues("mock").Observe(duration.Seconds()) +} + func TestRedisSetCache(t *testing.T) { mr, err := miniredis.Run() if err != nil { @@ -70,3 +115,50 @@ func TestRedisSetCacheCompressed(t *testing.T) { assert.Equal(t, testValue, result) } + +func TestRedisMetrics(t *testing.T) { + mr, err := miniredis.Run() + if err != nil { + panic(err) + } + defer mr.Close() + + metric := &promcm.Metric{} + ms := NewMockMetricsServer() + redisClient := redis.NewClient(&redis.Options{Addr: mr.Addr()}) + faultyRedisClient := redis.NewClient(&redis.Options{Addr: "invalidredishost.invalid:12345"}) + CollectMetrics(redisClient, ms) + CollectMetrics(faultyRedisClient, ms) + + client := NewRedisCache(redisClient, 60*time.Second, RedisCompressionNone) + faultyClient := NewRedisCache(faultyRedisClient, 60*time.Second, RedisCompressionNone) + var res string + + //client successful request + err = client.Set(&Item{Key: "foo", Object: "bar"}) + assert.NoError(t, err) + err = client.Get("foo", &res) + assert.NoError(t, err) + + c, err := ms.redisRequestCounter.GetMetricWithLabelValues("mock", "false") + assert.NoError(t, err) + err = c.Write(metric) + assert.NoError(t, err) + assert.Equal(t, metric.Counter.GetValue(), float64(2)) + + //faulty client failed request + err = faultyClient.Get("foo", &res) + assert.Error(t, err) + c, err = ms.redisRequestCounter.GetMetricWithLabelValues("mock", "true") + assert.NoError(t, err) + err = c.Write(metric) + assert.NoError(t, err) + assert.Equal(t, metric.Counter.GetValue(), float64(1)) + + //both clients histogram count + o, err := ms.redisRequestHistogram.GetMetricWithLabelValues("mock") + assert.NoError(t, err) + err = o.(prometheus.Metric).Write(metric) + assert.NoError(t, err) + assert.Equal(t, int(metric.Histogram.GetSampleCount()), 3) +} diff --git a/util/cache/twolevelclient.go b/util/cache/twolevelclient.go index 14a4279e87c89..f221099844876 100644 --- a/util/cache/twolevelclient.go +++ b/util/cache/twolevelclient.go @@ -18,6 +18,14 @@ type twoLevelClient struct { externalCache CacheClient } +func (c *twoLevelClient) Rename(oldKey string, newKey string, expiration time.Duration) error { + err := c.inMemoryCache.Rename(oldKey, newKey, expiration) + if err != nil { + log.Warnf("Failed to move key '%s' in in-memory cache: %v", oldKey, err) + } + return c.externalCache.Rename(oldKey, newKey, expiration) +} + // Set stores the given value in both in-memory and external cache. // Skip storing the value in external cache if the same value already exists in memory to avoid requesting external cache. func (c *twoLevelClient) Set(item *Item) error { diff --git a/util/db/cluster.go b/util/db/cluster.go index 69da0a3bd8fd2..dad8a62010adc 100644 --- a/util/db/cluster.go +++ b/util/db/cluster.go @@ -393,7 +393,7 @@ func SecretToCluster(s *apiv1.Secret) (*appv1.Cluster, error) { if val, err := strconv.Atoi(string(shardStr)); err != nil { log.Warnf("Error while parsing shard in cluster secret '%s': %v", s.Name, err) } else { - shard = pointer.Int64Ptr(int64(val)) + shard = pointer.Int64(int64(val)) } } diff --git a/util/db/helmrepository.go b/util/db/helmrepository.go index 8659e170d48ef..6fb66a962cc70 100644 --- a/util/db/helmrepository.go +++ b/util/db/helmrepository.go @@ -59,7 +59,7 @@ func (db *db) ListHelmRepositories(ctx context.Context) ([]*v1alpha1.Repository, } result[i] = repo } - repos, err := db.listRepositories(ctx, pointer.StringPtr("helm")) + repos, err := db.listRepositories(ctx, pointer.String("helm")) if err != nil { return nil, fmt.Errorf("failed to list Helm repositories: %w", err) } diff --git a/util/db/repository_secrets.go b/util/db/repository_secrets.go index 31152300b0b8b..2d96c1c3a99eb 100644 --- a/util/db/repository_secrets.go +++ b/util/db/repository_secrets.go @@ -489,6 +489,9 @@ func (s *secretsRepositoryBackend) getRepositoryCredentialIndex(repoCredentials for i, cred := range repoCredentials { credUrl := git.NormalizeGitURL(string(cred.Data["url"])) if strings.HasPrefix(repoURL, credUrl) { + if len(credUrl) == max { + log.Warnf("Found multiple credentials for repoURL: %s", repoURL) + } if len(credUrl) > max { max = len(credUrl) idx = i diff --git a/util/db/secrets.go b/util/db/secrets.go index 7021226c4bf4c..3c3ad10fc6954 100644 --- a/util/db/secrets.go +++ b/util/db/secrets.go @@ -140,7 +140,10 @@ func (db *db) watchSecrets(ctx context.Context, indexers := cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc} clusterSecretInformer := informerv1.NewFilteredSecretInformer(db.kubeclientset, db.ns, 3*time.Minute, indexers, secretListOptions) - clusterSecretInformer.AddEventHandler(secretEventHandler) + _, err := clusterSecretInformer.AddEventHandler(secretEventHandler) + if err != nil { + log.Error(err) + } log.Info("Starting secretInformer for", secretType) go func() { diff --git a/util/dex/config.go b/util/dex/config.go index 44d853674b19b..b8e412c189fca 100644 --- a/util/dex/config.go +++ b/util/dex/config.go @@ -63,6 +63,14 @@ func GenerateDexConfigYAML(argocdSettings *settings.ArgoCDSettings, disableTls b redirectURL, }, } + argoCDPKCEStaticClient := map[string]interface{}{ + "id": "argo-cd-pkce", + "name": "Argo CD PKCE", + "redirectURIs": []string{ + "http://localhost:4000/pkce/verify", + }, + "public": true, + } argoCDCLIStaticClient := map[string]interface{}{ "id": common.ArgoCDCLIClientAppID, "name": common.ArgoCDCLIClientAppName, @@ -75,9 +83,9 @@ func GenerateDexConfigYAML(argocdSettings *settings.ArgoCDSettings, disableTls b staticClients, ok := dexCfg["staticClients"].([]interface{}) if ok { - dexCfg["staticClients"] = append([]interface{}{argoCDStaticClient, argoCDCLIStaticClient}, staticClients...) + dexCfg["staticClients"] = append([]interface{}{argoCDStaticClient, argoCDCLIStaticClient, argoCDPKCEStaticClient}, staticClients...) } else { - dexCfg["staticClients"] = []interface{}{argoCDStaticClient, argoCDCLIStaticClient} + dexCfg["staticClients"] = []interface{}{argoCDStaticClient, argoCDCLIStaticClient, argoCDPKCEStaticClient} } dexRedirectURL, err := argocdSettings.DexRedirectURL() diff --git a/util/dex/dex_test.go b/util/dex/dex_test.go index a993db3375cb7..e15726d44f501 100644 --- a/util/dex/dex_test.go +++ b/util/dex/dex_test.go @@ -42,7 +42,7 @@ connectors: id: acme-github name: Acme GitHub config: - hostName: github.acme.com + hostName: github.acme.example.com clientID: abcdefghijklmnopqrst clientSecret: $dex.acme.clientSecret orgs: @@ -79,7 +79,7 @@ connectors: id: acme-github name: Acme GitHub config: - hostName: github.acme.com + hostName: github.acme.example.com clientID: abcdefghijklmnopqrst clientSecret: $dex.acme.clientSecret orgs: @@ -293,9 +293,9 @@ func Test_GenerateDexConfig(t *testing.T) { } clients, ok := dexCfg["staticClients"].([]interface{}) assert.True(t, ok) - assert.Equal(t, 3, len(clients)) + assert.Equal(t, 4, len(clients)) - customClient := clients[2].(map[string]interface{}) + customClient := clients[3].(map[string]interface{}) assert.Equal(t, "argo-workflow", customClient["id"].(string)) assert.Equal(t, 1, len(customClient["redirectURIs"].([]interface{}))) }) @@ -315,9 +315,9 @@ func Test_GenerateDexConfig(t *testing.T) { } clients, ok := dexCfg["staticClients"].([]interface{}) assert.True(t, ok) - assert.Equal(t, 3, len(clients)) + assert.Equal(t, 4, len(clients)) - customClient := clients[2].(map[string]interface{}) + customClient := clients[3].(map[string]interface{}) assert.Equal(t, "barfoo", customClient["secret"]) }) t.Run("Override dex oauth2 configuration", func(t *testing.T) { diff --git a/util/env/env.go b/util/env/env.go index 1b49a0c322065..985484c1ae80b 100644 --- a/util/env/env.go +++ b/util/env/env.go @@ -96,6 +96,33 @@ func ParseFloatFromEnv(env string, defaultValue, min, max float32) float32 { return float32(num) } +// Helper function to parse a float64 from an environment variable. Returns a +// default if env is not set, is not parseable to a number, exceeds max (if +// max is greater than 0) or is less than min (and min is greater than 0). +// +// nolint:unparam +func ParseFloat64FromEnv(env string, defaultValue, min, max float64) float64 { + str := os.Getenv(env) + if str == "" { + return defaultValue + } + + num, err := strconv.ParseFloat(str, 64) + if err != nil { + log.Warnf("Could not parse '%s' as a float32 from environment %s", str, env) + return defaultValue + } + if num < min { + log.Warnf("Value in %s is %f, which is less than minimum %f allowed", env, num, min) + return defaultValue + } + if num > max { + log.Warnf("Value in %s is %f, which is greater than maximum %f allowed", env, num, max) + return defaultValue + } + return num +} + // Helper function to parse a time duration from an environment variable. Returns a // default if env is not set, is not parseable to a duration, exceeds max (if // max is greater than 0) or is less than min. @@ -159,3 +186,30 @@ func ParseBoolFromEnv(envVar string, defaultValue bool) bool { } return defaultValue } + +// ParseStringToStringVar parses given value from the environment as a map of string. +// Returns default value if envVar is not set. +func ParseStringToStringFromEnv(envVar string, defaultValue map[string]string, seperator string) map[string]string { + str := os.Getenv(envVar) + str = strings.TrimSpace(str) + if str == "" { + return defaultValue + } + + parsed := make(map[string]string) + for _, pair := range strings.Split(str, seperator) { + keyvalue := strings.Split(pair, "=") + if len(keyvalue) != 2 { + log.Warnf("Invalid key-value pair when parsing environment '%s' as a string map", str) + return defaultValue + } + key := strings.TrimSpace(keyvalue[0]) + value := strings.TrimSpace(keyvalue[1]) + if _, ok := parsed[key]; ok { + log.Warnf("Duplicate key '%s' when parsing environment '%s' as a string map", key, str) + return defaultValue + } + parsed[key] = value + } + return parsed +} diff --git a/util/env/env_test.go b/util/env/env_test.go index 691d235805b23..9178592ed3552 100644 --- a/util/env/env_test.go +++ b/util/env/env_test.go @@ -210,3 +210,41 @@ func TestStringsFromEnv(t *testing.T) { }) } } + +func TestParseStringToStringFromEnv(t *testing.T) { + envKey := "SOMEKEY" + def := map[string]string{} + + testCases := []struct { + name string + env string + expected map[string]string + def map[string]string + sep string + }{ + {"success, no key-value", "", map[string]string{}, def, ","}, + {"success, one key, no value", "key1=", map[string]string{"key1": ""}, def, ","}, + {"success, one key, no value, with spaces", "key1 = ", map[string]string{"key1": ""}, def, ","}, + {"success, one pair", "key1=value1", map[string]string{"key1": "value1"}, def, ","}, + {"success, one pair with spaces", "key1 = value1", map[string]string{"key1": "value1"}, def, ","}, + {"success, one pair with spaces and no value", "key1 = ", map[string]string{"key1": ""}, def, ","}, + {"success, two keys, no value", "key1=,key2=", map[string]string{"key1": "", "key2": ""}, def, ","}, + {"success, two keys, no value, with spaces", "key1 = , key2 = ", map[string]string{"key1": "", "key2": ""}, def, ","}, + {"success, two pairs", "key1=value1,key2=value2", map[string]string{"key1": "value1", "key2": "value2"}, def, ","}, + {"success, two pairs with semicolon as seperator", "key1=value1;key2=value2", map[string]string{"key1": "value1", "key2": "value2"}, def, ";"}, + {"success, two pairs with spaces", "key1 = value1, key2 = value2", map[string]string{"key1": "value1", "key2": "value2"}, def, ","}, + {"failure, one key", "key1", map[string]string{}, def, ","}, + {"failure, duplicate keys", "key1=value1,key1=value2", map[string]string{}, def, ","}, + {"failure, one key ending with two successive equals to", "key1==", map[string]string{}, def, ","}, + {"failure, one valid pair and invalid one key", "key1=value1,key2", map[string]string{}, def, ","}, + {"failure, two valid pairs and invalid two keys", "key1=value1,key2=value2,key3,key4", map[string]string{}, def, ","}, + } + + for _, tt := range testCases { + t.Run(tt.name, func(t *testing.T) { + t.Setenv(envKey, tt.env) + got := ParseStringToStringFromEnv(envKey, tt.def, tt.sep) + assert.Equal(t, tt.expected, got) + }) + } +} diff --git a/util/git/client.go b/util/git/client.go index 6b8587c0b3660..73c85b54f3c1f 100644 --- a/util/git/client.go +++ b/util/git/client.go @@ -174,6 +174,10 @@ func NewClientExt(rawRepoURL string, root string, creds Creds, insecure bool, en return client, nil } +var ( + gitClientTimeout = env.ParseDurationFromEnv("ARGOCD_GIT_REQUEST_TIMEOUT", 15*time.Second, 0, math.MaxInt64) +) + // Returns a HTTP client object suitable for go-git to use using the following // pattern: // - If insecure is true, always returns a client with certificate verification @@ -185,8 +189,8 @@ func NewClientExt(rawRepoURL string, root string, creds Creds, insecure bool, en func GetRepoHTTPClient(repoURL string, insecure bool, creds Creds, proxyURL string) *http.Client { // Default HTTP client var customHTTPClient = &http.Client{ - // 15 second timeout - Timeout: 15 * time.Second, + // 15 second timeout by default + Timeout: gitClientTimeout, // don't follow redirect CheckRedirect: func(req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse @@ -737,7 +741,6 @@ func (m *nativeGitClient) runCmdOutput(cmd *exec.Cmd, ropts runOpts) (string, er } } } - cmd.Env = proxy.UpsertEnv(cmd, m.proxy) opts := executil.ExecRunOpts{ TimeoutBehavior: argoexec.TimeoutBehavior{ diff --git a/util/git/creds.go b/util/git/creds.go index c3d09574eeb84..18698449082bf 100644 --- a/util/git/creds.go +++ b/util/git/creds.go @@ -8,6 +8,7 @@ import ( "errors" "fmt" "io" + "net/url" "os" "strconv" "strings" @@ -241,10 +242,11 @@ type SSHCreds struct { caPath string insecure bool store CredsStore + proxy string } -func NewSSHCreds(sshPrivateKey string, caPath string, insecureIgnoreHostKey bool, store CredsStore) SSHCreds { - return SSHCreds{sshPrivateKey, caPath, insecureIgnoreHostKey, store} +func NewSSHCreds(sshPrivateKey string, caPath string, insecureIgnoreHostKey bool, store CredsStore, proxy string) SSHCreds { + return SSHCreds{sshPrivateKey, caPath, insecureIgnoreHostKey, store, proxy} } type sshPrivateKeyFile string @@ -303,7 +305,25 @@ func (c SSHCreds) Environ() (io.Closer, []string, error) { knownHostsFile := certutil.GetSSHKnownHostsDataPath() args = append(args, "-o", "StrictHostKeyChecking=yes", "-o", fmt.Sprintf("UserKnownHostsFile=%s", knownHostsFile)) } + // Handle SSH socks5 proxy settings + proxyEnv := []string{} + if c.proxy != "" { + parsedProxyURL, err := url.Parse(c.proxy) + if err != nil { + return nil, nil, fmt.Errorf("failed to set environment variables related to socks5 proxy, could not parse proxy URL '%s': %w", c.proxy, err) + } + args = append(args, "-o", fmt.Sprintf("ProxyCommand='connect-proxy -S %s:%s -5 %%h %%p'", + parsedProxyURL.Hostname(), + parsedProxyURL.Port())) + if parsedProxyURL.User != nil { + proxyEnv = append(proxyEnv, fmt.Sprintf("SOCKS5_USER=%s", parsedProxyURL.User.Username())) + if socks5_passwd, isPasswdSet := parsedProxyURL.User.Password(); isPasswdSet { + proxyEnv = append(proxyEnv, fmt.Sprintf("SOCKS5_PASSWD=%s", socks5_passwd)) + } + } + } env = append(env, []string{fmt.Sprintf("GIT_SSH_COMMAND=%s", strings.Join(args, " "))}...) + env = append(env, proxyEnv...) return sshPrivateKeyFile(file.Name()), env, nil } diff --git a/util/git/creds_test.go b/util/git/creds_test.go index 40cc39c10f1bc..23a705ed33574 100644 --- a/util/git/creds_test.go +++ b/util/git/creds_test.go @@ -205,7 +205,7 @@ func Test_SSHCreds_Environ(t *testing.T) { caFile := path.Join(tempDir, "caFile") err := os.WriteFile(caFile, []byte(""), os.FileMode(0600)) require.NoError(t, err) - creds := NewSSHCreds("sshPrivateKey", caFile, insecureIgnoreHostKey, &NoopCredsStore{}) + creds := NewSSHCreds("sshPrivateKey", caFile, insecureIgnoreHostKey, &NoopCredsStore{}, "") closer, env, err := creds.Environ() require.NoError(t, err) require.Len(t, env, 2) @@ -232,6 +232,76 @@ func Test_SSHCreds_Environ(t *testing.T) { } } +func Test_SSHCreds_Environ_WithProxy(t *testing.T) { + for _, insecureIgnoreHostKey := range []bool{false, true} { + tempDir := t.TempDir() + caFile := path.Join(tempDir, "caFile") + err := os.WriteFile(caFile, []byte(""), os.FileMode(0600)) + require.NoError(t, err) + creds := NewSSHCreds("sshPrivateKey", caFile, insecureIgnoreHostKey, &NoopCredsStore{}, "socks5://127.0.0.1:1080") + closer, env, err := creds.Environ() + require.NoError(t, err) + require.Len(t, env, 2) + + assert.Equal(t, fmt.Sprintf("GIT_SSL_CAINFO=%s/caFile", tempDir), env[0], "CAINFO env var must be set") + + assert.True(t, strings.HasPrefix(env[1], "GIT_SSH_COMMAND=")) + + if insecureIgnoreHostKey { + assert.Contains(t, env[1], "-o StrictHostKeyChecking=no") + assert.Contains(t, env[1], "-o UserKnownHostsFile=/dev/null") + } else { + assert.Contains(t, env[1], "-o StrictHostKeyChecking=yes") + hostsPath := cert.GetSSHKnownHostsDataPath() + assert.Contains(t, env[1], fmt.Sprintf("-o UserKnownHostsFile=%s", hostsPath)) + } + assert.Contains(t, env[1], "-o ProxyCommand='connect-proxy -S 127.0.0.1:1080 -5 %h %p'") + + envRegex := regexp.MustCompile("-i ([^ ]+)") + assert.Regexp(t, envRegex, env[1]) + privateKeyFile := envRegex.FindStringSubmatch(env[1])[1] + assert.FileExists(t, privateKeyFile) + io.Close(closer) + assert.NoFileExists(t, privateKeyFile) + } +} + +func Test_SSHCreds_Environ_WithProxyUserNamePassword(t *testing.T) { + for _, insecureIgnoreHostKey := range []bool{false, true} { + tempDir := t.TempDir() + caFile := path.Join(tempDir, "caFile") + err := os.WriteFile(caFile, []byte(""), os.FileMode(0600)) + require.NoError(t, err) + creds := NewSSHCreds("sshPrivateKey", caFile, insecureIgnoreHostKey, &NoopCredsStore{}, "socks5://user:password@127.0.0.1:1080") + closer, env, err := creds.Environ() + require.NoError(t, err) + require.Len(t, env, 4) + + assert.Equal(t, fmt.Sprintf("GIT_SSL_CAINFO=%s/caFile", tempDir), env[0], "CAINFO env var must be set") + + assert.True(t, strings.HasPrefix(env[1], "GIT_SSH_COMMAND=")) + assert.Equal(t, "SOCKS5_USER=user", env[2], "SOCKS5 user env var must be set") + assert.Equal(t, "SOCKS5_PASSWD=password", env[3], "SOCKS5 password env var must be set") + + if insecureIgnoreHostKey { + assert.Contains(t, env[1], "-o StrictHostKeyChecking=no") + assert.Contains(t, env[1], "-o UserKnownHostsFile=/dev/null") + } else { + assert.Contains(t, env[1], "-o StrictHostKeyChecking=yes") + hostsPath := cert.GetSSHKnownHostsDataPath() + assert.Contains(t, env[1], fmt.Sprintf("-o UserKnownHostsFile=%s", hostsPath)) + } + assert.Contains(t, env[1], "-o ProxyCommand='connect-proxy -S 127.0.0.1:1080 -5 %h %p'") + + envRegex := regexp.MustCompile("-i ([^ ]+)") + assert.Regexp(t, envRegex, env[1]) + privateKeyFile := envRegex.FindStringSubmatch(env[1])[1] + assert.FileExists(t, privateKeyFile) + io.Close(closer) + assert.NoFileExists(t, privateKeyFile) + } +} + const gcpServiceAccountKeyJSON = `{ "type": "service_account", "project_id": "my-google-project", diff --git a/util/git/workaround.go b/util/git/workaround.go index c364c093c853e..47636125cf349 100644 --- a/util/git/workaround.go +++ b/util/git/workaround.go @@ -1,6 +1,9 @@ package git import ( + "fmt" + neturl "net/url" + "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing" "github.com/go-git/go-git/v5/plumbing/transport" @@ -30,6 +33,23 @@ func newClient(url string, insecure bool, creds Creds, proxy string) (transport. if !IsHTTPSURL(url) && !IsHTTPURL(url) { // use the default client for protocols other than HTTP/HTTPS + ep.InsecureSkipTLS = insecure + if proxy != "" { + parsedProxyURL, err := neturl.Parse(proxy) + if err != nil { + return nil, nil, fmt.Errorf("failed to create client for url '%s', error parsing proxy url '%s': %w", url, proxy, err) + } + var proxyUsername, proxyPasswd string + if parsedProxyURL.User != nil { + proxyUsername = parsedProxyURL.User.Username() + proxyPasswd, _ = parsedProxyURL.User.Password() + } + ep.Proxy = transport.ProxyOptions{ + URL: fmt.Sprintf("%s://%s:%s", parsedProxyURL.Scheme, parsedProxyURL.Hostname(), parsedProxyURL.Port()), + Username: proxyUsername, + Password: proxyPasswd, + } + } c, err := client.NewClient(ep) if err != nil { return nil, nil, err diff --git a/util/grpc/grpc.go b/util/grpc/grpc.go index 323d78398a8ce..536da792e3048 100644 --- a/util/grpc/grpc.go +++ b/util/grpc/grpc.go @@ -10,6 +10,7 @@ import ( "github.com/argoproj/argo-cd/v2/common" "github.com/sirupsen/logrus" + "golang.org/x/net/proxy" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials" @@ -63,7 +64,7 @@ func BlockingDial(ctx context.Context, network, address string, creds credential dialer := func(ctx context.Context, address string) (net.Conn, error) { - conn, err := (&net.Dialer{Cancel: ctx.Done()}).Dial(network, address) + conn, err := proxy.Dial(ctx, network, address) if err != nil { writeResult(err) return nil, err @@ -88,7 +89,7 @@ func BlockingDial(ctx context.Context, network, address string, creds credential grpc.FailOnNonTempDialError(true), grpc.WithContextDialer(dialer), grpc.WithTransportCredentials(insecure.NewCredentials()), // we are handling TLS, so tell grpc not to - grpc.WithKeepaliveParams(keepalive.ClientParameters{Time: common.GRPCKeepAliveTime}), + grpc.WithKeepaliveParams(keepalive.ClientParameters{Time: common.GetGRPCKeepAliveTime()}), ) conn, err := grpc.DialContext(ctx, address, opts...) var res interface{} diff --git a/util/helm/cmd.go b/util/helm/cmd.go index f8240d555217e..cc2a1388d65a2 100644 --- a/util/helm/cmd.go +++ b/util/helm/cmd.go @@ -91,6 +91,28 @@ func (c *Cmd) RegistryLogin(repo string, creds Creds) (string, error) { args = append(args, "--password", creds.Password) } + if creds.CAPath != "" { + args = append(args, "--ca-file", creds.CAPath) + } + + if len(creds.CertData) > 0 { + filePath, closer, err := writeToTmp(creds.CertData) + if err != nil { + return "", err + } + defer argoio.Close(closer) + args = append(args, "--cert-file", filePath) + } + + if len(creds.KeyData) > 0 { + filePath, closer, err := writeToTmp(creds.KeyData) + if err != nil { + return "", err + } + defer argoio.Close(closer) + args = append(args, "--key-file", filePath) + } + if creds.InsecureSkipVerify { args = append(args, "--insecure") } @@ -238,6 +260,25 @@ func (c *Cmd) PullOCI(repo string, chart string, version string, destination str if creds.CAPath != "" { args = append(args, "--ca-file", creds.CAPath) } + + if len(creds.CertData) > 0 { + filePath, closer, err := writeToTmp(creds.CertData) + if err != nil { + return "", err + } + defer argoio.Close(closer) + args = append(args, "--cert-file", filePath) + } + + if len(creds.KeyData) > 0 { + filePath, closer, err := writeToTmp(creds.KeyData) + if err != nil { + return "", err + } + defer argoio.Close(closer) + args = append(args, "--key-file", filePath) + } + if creds.InsecureSkipVerify && c.insecureSkipVerifySupported { args = append(args, "--insecure-skip-tls-verify") } @@ -274,6 +315,10 @@ var ( ) func cleanSetParameters(val string) string { + // `{}` equal helm list parameters format, so don't escape `,`. + if strings.HasPrefix(val, `{`) && strings.HasSuffix(val, `}`) { + return val + } return re.ReplaceAllString(val, `$1\,`) } diff --git a/util/helm/helm_test.go b/util/helm/helm_test.go index ab8e3bc58008c..a91968e45b5b4 100644 --- a/util/helm/helm_test.go +++ b/util/helm/helm_test.go @@ -165,6 +165,7 @@ func TestHelmArgCleaner(t *testing.T) { `bar`: `bar`, `not, clean`: `not\, clean`, `a\,b,c`: `a\,b\,c`, + `{a,b,c}`: `{a,b,c}`, } { cleaned := cleanSetParameters(input) assert.Equal(t, expected, cleaned) diff --git a/util/http/http.go b/util/http/http.go index 2572e739f009d..7c13c71fde223 100644 --- a/util/http/http.go +++ b/util/http/http.go @@ -1,25 +1,36 @@ package http import ( + "bytes" "fmt" + "io" "math" "net/http" "net/http/httputil" "strconv" "strings" + "time" - "github.com/argoproj/argo-cd/v2/util/env" + log "github.com/sirupsen/logrus" + "k8s.io/client-go/transport" "github.com/argoproj/argo-cd/v2/common" - - log "github.com/sirupsen/logrus" + "github.com/argoproj/argo-cd/v2/util/env" ) -const maxCookieLength = 4093 +const ( + maxCookieLength = 4093 + + // limit size of the resp to 512KB + respReadLimit = int64(524288) + retryWaitMax = time.Duration(10) * time.Second + EnvRetryMax = "ARGOCD_K8SCLIENT_RETRY_MAX" + EnvRetryBaseBackoff = "ARGOCD_K8SCLIENT_RETRY_BASE_BACKOFF" +) // max number of chunks a cookie can be broken into. To be compatible with // widest range of browsers, you shouldn't create more than 30 cookies per domain -var maxCookieNumber = env.ParseNumFromEnv(common.EnvMaxCookieNumber, 20, 0, math.MaxInt64) +var maxCookieNumber = env.ParseNumFromEnv(common.EnvMaxCookieNumber, 20, 0, math.MaxInt) // MakeCookieMetadata generates a string representing a Web cookie. Yum! func MakeCookieMetadata(key, value string, flags ...string) ([]string, error) { @@ -160,3 +171,71 @@ func (rt *TransportWithHeader) RoundTrip(r *http.Request) (*http.Response, error } return rt.RoundTripper.RoundTrip(r) } + +func WithRetry(maxRetries int64, baseRetryBackoff time.Duration) transport.WrapperFunc { + return func(rt http.RoundTripper) http.RoundTripper { + return &retryTransport{ + inner: rt, + maxRetries: maxRetries, + backoff: baseRetryBackoff, + } + } +} + +type retryTransport struct { + inner http.RoundTripper + maxRetries int64 + backoff time.Duration +} + +func isRetriable(resp *http.Response) bool { + if resp == nil { + return false + } + if resp.StatusCode == http.StatusTooManyRequests { + return true + } + if resp.StatusCode == 0 || (resp.StatusCode >= 500 && resp.StatusCode != http.StatusNotImplemented) { + return true + } + return false +} + +func (t *retryTransport) RoundTrip(req *http.Request) (*http.Response, error) { + var resp *http.Response + var err error + backoff := t.backoff + var bodyBytes []byte + if req.Body != nil { + bodyBytes, _ = io.ReadAll(req.Body) + } + for i := 0; i <= int(t.maxRetries); i++ { + req.Body = io.NopCloser(bytes.NewBuffer(bodyBytes)) + resp, err = t.inner.RoundTrip(req) + if i < int(t.maxRetries) && (err != nil || isRetriable(resp)) { + if resp != nil && resp.Body != nil { + drainBody(resp.Body) + } + if backoff > retryWaitMax { + backoff = retryWaitMax + } + select { + case <-time.After(backoff): + case <-req.Context().Done(): + return nil, req.Context().Err() + } + backoff *= 2 + continue + } + break + } + return resp, err +} + +func drainBody(body io.ReadCloser) { + defer body.Close() + _, err := io.Copy(io.Discard, io.LimitReader(body, respReadLimit)) + if err != nil { + log.Warnf("error reading response body: %s", err.Error()) + } +} diff --git a/util/kustomize/kustomize.go b/util/kustomize/kustomize.go index b18fcf6c43e93..d938beeceb578 100644 --- a/util/kustomize/kustomize.go +++ b/util/kustomize/kustomize.go @@ -35,8 +35,9 @@ type Kustomize interface { } // NewKustomizeApp create a new wrapper to run commands on the `kustomize` command-line tool. -func NewKustomizeApp(path string, creds git.Creds, fromRepo string, binaryPath string) Kustomize { +func NewKustomizeApp(repoRoot string, path string, creds git.Creds, fromRepo string, binaryPath string) Kustomize { return &kustomize{ + repoRoot: repoRoot, path: path, creds: creds, repo: fromRepo, @@ -45,6 +46,8 @@ func NewKustomizeApp(path string, creds git.Creds, fromRepo string, binaryPath s } type kustomize struct { + // path to the Git repository root + repoRoot string // path inside the checked out tree path string // creds structure @@ -87,6 +90,40 @@ func mapToEditAddArgs(val map[string]string) []string { func (k *kustomize) Build(opts *v1alpha1.ApplicationSourceKustomize, kustomizeOptions *v1alpha1.KustomizeOptions, envVars *v1alpha1.Env) ([]*unstructured.Unstructured, []Image, error) { + env := os.Environ() + if envVars != nil { + env = append(env, envVars.Environ()...) + } + + closer, environ, err := k.creds.Environ() + if err != nil { + return nil, nil, err + } + defer func() { _ = closer.Close() }() + + // If we were passed a HTTPS URL, make sure that we also check whether there + // is a custom CA bundle configured for connecting to the server. + if k.repo != "" && git.IsHTTPSURL(k.repo) { + parsedURL, err := url.Parse(k.repo) + if err != nil { + log.Warnf("Could not parse URL %s: %v", k.repo, err) + } else { + caPath, err := certutil.GetCertBundlePathForRepository(parsedURL.Host) + if err != nil { + // Some error while getting CA bundle + log.Warnf("Could not get CA bundle path for %s: %v", parsedURL.Host, err) + } else if caPath == "" { + // No cert configured + log.Debugf("No caCert found for repo %s", parsedURL.Host) + } else { + // Make Git use CA bundle + environ = append(environ, fmt.Sprintf("GIT_SSL_CAINFO=%s", caPath)) + } + } + } + + env = append(env, environ...) + if opts != nil { if opts.NamePrefix != "" { cmd := exec.Command(k.getBinaryPath(), "edit", "set", "nameprefix", "--", opts.NamePrefix) @@ -238,6 +275,25 @@ func (k *kustomize) Build(opts *v1alpha1.ApplicationSourceKustomize, kustomizeOp return nil, nil, fmt.Errorf("failed to write kustomization.yaml with updated 'patches' field: %w", err) } } + + if len(opts.Components) > 0 { + // components only supported in kustomize >= v3.7.0 + // https://github.com/kubernetes-sigs/kustomize/blob/master/examples/components.md + if getSemverSafe().LessThan(semver.MustParse("v3.7.0")) { + return nil, nil, fmt.Errorf("kustomize components require kustomize v3.7.0 and above") + } + + // add components + args := []string{"edit", "add", "component"} + args = append(args, opts.Components...) + cmd := exec.Command(k.getBinaryPath(), args...) + cmd.Dir = k.path + cmd.Env = env + _, err := executil.Run(cmd) + if err != nil { + return nil, nil, err + } + } } var cmd *exec.Cmd @@ -247,40 +303,8 @@ func (k *kustomize) Build(opts *v1alpha1.ApplicationSourceKustomize, kustomizeOp } else { cmd = exec.Command(k.getBinaryPath(), "build", k.path) } - - env := os.Environ() - if envVars != nil { - env = append(env, envVars.Environ()...) - } cmd.Env = env - closer, environ, err := k.creds.Environ() - if err != nil { - return nil, nil, err - } - defer func() { _ = closer.Close() }() - - // If we were passed a HTTPS URL, make sure that we also check whether there - // is a custom CA bundle configured for connecting to the server. - if k.repo != "" && git.IsHTTPSURL(k.repo) { - parsedURL, err := url.Parse(k.repo) - if err != nil { - log.Warnf("Could not parse URL %s: %v", k.repo, err) - } else { - caPath, err := certutil.GetCertBundlePathForRepository(parsedURL.Host) - if err != nil { - // Some error while getting CA bundle - log.Warnf("Could not get CA bundle path for %s: %v", parsedURL.Host, err) - } else if caPath == "" { - // No cert configured - log.Debugf("No caCert found for repo %s", parsedURL.Host) - } else { - // Make Git use CA bundle - environ = append(environ, fmt.Sprintf("GIT_SSL_CAINFO=%s", caPath)) - } - } - } - - cmd.Env = append(cmd.Env, environ...) + cmd.Dir = k.repoRoot out, err := executil.Run(cmd) if err != nil { return nil, nil, err @@ -295,7 +319,7 @@ func (k *kustomize) Build(opts *v1alpha1.ApplicationSourceKustomize, kustomizeOp } func parseKustomizeBuildOptions(path, buildOptions string) []string { - return append([]string{"build", path}, strings.Split(buildOptions, " ")...) + return append([]string{"build", path}, strings.Fields(buildOptions)...) } var KustomizationNames = []string{"kustomization.yaml", "kustomization.yml", "Kustomization"} diff --git a/util/kustomize/kustomize_test.go b/util/kustomize/kustomize_test.go index 573cb87fb602c..b7a8e319c3295 100644 --- a/util/kustomize/kustomize_test.go +++ b/util/kustomize/kustomize_test.go @@ -23,6 +23,7 @@ const kustomization2b = "Kustomization" const kustomization3 = "force_common" const kustomization4 = "custom_version" const kustomization5 = "kustomization_yaml_patches" +const kustomization6 = "kustomization_yaml_components" func testDataDir(tb testing.TB, testData string) (string, error) { res := tb.TempDir() @@ -39,7 +40,7 @@ func TestKustomizeBuild(t *testing.T) { namePrefix := "namePrefix-" nameSuffix := "-nameSuffix" namespace := "custom-namespace" - kustomize := NewKustomizeApp(appPath, git.NopCreds{}, "", "") + kustomize := NewKustomizeApp(appPath, appPath, git.NopCreds{}, "", "") env := &v1alpha1.Env{ &v1alpha1.EnvEntry{Name: "ARGOCD_APP_NAME", Value: "argo-cd-tests"}, } @@ -122,7 +123,7 @@ func TestKustomizeBuild(t *testing.T) { func TestFailKustomizeBuild(t *testing.T) { appPath, err := testDataDir(t, kustomization1) assert.Nil(t, err) - kustomize := NewKustomizeApp(appPath, git.NopCreds{}, "", "") + kustomize := NewKustomizeApp(appPath, appPath, git.NopCreds{}, "", "") kustomizeSource := v1alpha1.ApplicationSourceKustomize{ Replicas: []v1alpha1.KustomizeReplica{ { @@ -221,7 +222,7 @@ func TestKustomizeBuildForceCommonLabels(t *testing.T) { for _, tc := range testCases { appPath, err := testDataDir(t, tc.TestData) assert.Nil(t, err) - kustomize := NewKustomizeApp(appPath, git.NopCreds{}, "", "") + kustomize := NewKustomizeApp(appPath, appPath, git.NopCreds{}, "", "") objs, _, err := kustomize.Build(&tc.KustomizeSource, nil, tc.Env) switch tc.ExpectErr { case true: @@ -313,7 +314,7 @@ func TestKustomizeBuildForceCommonAnnotations(t *testing.T) { for _, tc := range testCases { appPath, err := testDataDir(t, tc.TestData) assert.Nil(t, err) - kustomize := NewKustomizeApp(appPath, git.NopCreds{}, "", "") + kustomize := NewKustomizeApp(appPath, appPath, git.NopCreds{}, "", "") objs, _, err := kustomize.Build(&tc.KustomizeSource, nil, tc.Env) switch tc.ExpectErr { case true: @@ -333,7 +334,7 @@ func TestKustomizeCustomVersion(t *testing.T) { kustomizePath, err := testDataDir(t, kustomization4) assert.Nil(t, err) envOutputFile := kustomizePath + "/env_output" - kustomize := NewKustomizeApp(appPath, git.NopCreds{}, "", kustomizePath+"/kustomize.special") + kustomize := NewKustomizeApp(appPath, appPath, git.NopCreds{}, "", kustomizePath+"/kustomize.special") kustomizeSource := v1alpha1.ApplicationSourceKustomize{ Version: "special", } @@ -352,10 +353,31 @@ func TestKustomizeCustomVersion(t *testing.T) { assert.Equal(t, "ARGOCD_APP_NAME=argo-cd-tests\n", string(content)) } +func TestKustomizeBuildComponents(t *testing.T) { + appPath, err := testDataDir(t, kustomization6) + assert.Nil(t, err) + kustomize := NewKustomizeApp(appPath, appPath, git.NopCreds{}, "", "") + + kustomizeSource := v1alpha1.ApplicationSourceKustomize{ + Components: []string{"./components"}, + } + objs, _, err := kustomize.Build(&kustomizeSource, nil, nil) + assert.Nil(t, err) + obj := objs[0] + assert.Equal(t, "nginx-deployment", obj.GetName()) + assert.Equal(t, map[string]string{ + "app": "nginx", + }, obj.GetLabels()) + replicas, ok, err := unstructured.NestedInt64(obj.Object, "spec", "replicas") + require.NoError(t, err) + require.True(t, ok) + assert.Equal(t, int64(3), replicas) +} + func TestKustomizeBuildPatches(t *testing.T) { appPath, err := testDataDir(t, kustomization5) assert.Nil(t, err) - kustomize := NewKustomizeApp(appPath, git.NopCreds{}, "", "") + kustomize := NewKustomizeApp(appPath, appPath, git.NopCreds{}, "", "") kustomizeSource := v1alpha1.ApplicationSourceKustomize{ Patches: []v1alpha1.KustomizePatch{ diff --git a/util/kustomize/testdata/kustomization_yaml_components/components/deployment.yaml b/util/kustomize/testdata/kustomization_yaml_components/components/deployment.yaml new file mode 100644 index 0000000000000..545961bb6094d --- /dev/null +++ b/util/kustomize/testdata/kustomization_yaml_components/components/deployment.yaml @@ -0,0 +1,21 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment + labels: + app: nginx +spec: + replicas: 3 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:1.15.4 + ports: + - containerPort: 80 \ No newline at end of file diff --git a/util/kustomize/testdata/kustomization_yaml_components/components/kustomization.yaml b/util/kustomize/testdata/kustomization_yaml_components/components/kustomization.yaml new file mode 100644 index 0000000000000..4fe48f72bced8 --- /dev/null +++ b/util/kustomize/testdata/kustomization_yaml_components/components/kustomization.yaml @@ -0,0 +1,4 @@ +apiVersion: kustomize.config.k8s.io/v1alpha1 +kind: Component +resources: + - ./deployment.yaml \ No newline at end of file diff --git a/util/kustomize/testdata/kustomization_yaml_components/kustomization.yaml b/util/kustomize/testdata/kustomization_yaml_components/kustomization.yaml new file mode 100644 index 0000000000000..c3dec961314f3 --- /dev/null +++ b/util/kustomize/testdata/kustomization_yaml_components/kustomization.yaml @@ -0,0 +1,5 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +components: + - ./components \ No newline at end of file diff --git a/util/notification/expression/repo/repo.go b/util/notification/expression/repo/repo.go index 060060cbccd68..110c278cb486b 100644 --- a/util/notification/expression/repo/repo.go +++ b/util/notification/expression/repo/repo.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "errors" + "net/url" "regexp" "strings" @@ -90,6 +91,7 @@ func NewExprs(argocdService service.Service, app *unstructured.Unstructured) map return map[string]interface{}{ "RepoURLToHTTPS": repoURLToHTTPS, "FullNameByRepoURL": FullNameByRepoURL, + "QueryEscape": url.QueryEscape, "GetCommitMetadata": func(commitSHA string) interface{} { meta, err := getCommitMetadata(commitSHA, app, argocdService) if err != nil { diff --git a/util/notification/settings/settings.go b/util/notification/settings/settings.go index 865a627747d31..79d70499aaea6 100644 --- a/util/notification/settings/settings.go +++ b/util/notification/settings/settings.go @@ -12,17 +12,20 @@ import ( service "github.com/argoproj/argo-cd/v2/util/notification/argocd" ) -func GetFactorySettings(argocdService service.Service, secretName, configMapName string) api.Settings { +func GetFactorySettings(argocdService service.Service, secretName, configMapName string, selfServiceNotificationEnabled bool) api.Settings { return api.Settings{ SecretName: secretName, ConfigMapName: configMapName, InitGetVars: func(cfg *api.Config, configMap *v1.ConfigMap, secret *v1.Secret) (api.GetVars, error) { + if selfServiceNotificationEnabled { + return initGetVarsWithoutSecret(argocdService, cfg, configMap, secret) + } return initGetVars(argocdService, cfg, configMap, secret) }, } } -func initGetVars(argocdService service.Service, cfg *api.Config, configMap *v1.ConfigMap, secret *v1.Secret) (api.GetVars, error) { +func getContext(cfg *api.Config, configMap *v1.ConfigMap, secret *v1.Secret) (map[string]string, error) { context := map[string]string{} if contextYaml, ok := configMap.Data["context"]; ok { if err := yaml.Unmarshal([]byte(contextYaml), &context); err != nil { @@ -32,11 +35,34 @@ func initGetVars(argocdService service.Service, cfg *api.Config, configMap *v1.C if err := ApplyLegacyConfig(cfg, context, configMap, secret); err != nil { return nil, err } + return context, nil +} + +func initGetVarsWithoutSecret(argocdService service.Service, cfg *api.Config, configMap *v1.ConfigMap, secret *v1.Secret) (api.GetVars, error) { + context, err := getContext(cfg, configMap, secret) + if err != nil { + return nil, err + } + + return func(obj map[string]interface{}, dest services.Destination) map[string]interface{} { + return expression.Spawn(&unstructured.Unstructured{Object: obj}, argocdService, map[string]interface{}{ + "app": obj, + "context": injectLegacyVar(context, dest.Service), + }) + }, nil +} + +func initGetVars(argocdService service.Service, cfg *api.Config, configMap *v1.ConfigMap, secret *v1.Secret) (api.GetVars, error) { + context, err := getContext(cfg, configMap, secret) + if err != nil { + return nil, err + } return func(obj map[string]interface{}, dest services.Destination) map[string]interface{} { return expression.Spawn(&unstructured.Unstructured{Object: obj}, argocdService, map[string]interface{}{ "app": obj, "context": injectLegacyVar(context, dest.Service), + "secrets": secret.Data, }) }, nil } diff --git a/util/notification/settings/settings_test.go b/util/notification/settings/settings_test.go new file mode 100644 index 0000000000000..176839b51740e --- /dev/null +++ b/util/notification/settings/settings_test.go @@ -0,0 +1,92 @@ +package settings + +import ( + "fmt" + "testing" + + "github.com/argoproj/argo-cd/v2/reposerver/apiclient/mocks" + service "github.com/argoproj/argo-cd/v2/util/notification/argocd" + "github.com/argoproj/notifications-engine/pkg/api" + "github.com/argoproj/notifications-engine/pkg/services" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + corev1 "k8s.io/api/core/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes/fake" +) + +const testNamespace = "default" +const testContextKey = "test-context-key" +const testContextKeyValue = "test-context-key-value" + +func TestInitGetVars(t *testing.T) { + notificationsCm := corev1.ConfigMap{ + ObjectMeta: v1.ObjectMeta{ + Namespace: testNamespace, + Name: "argocd-notifications-cm", + }, + Data: map[string]string{ + "context": fmt.Sprintf("%s: %s", testContextKey, testContextKeyValue), + "service.webhook.test": "url: https://test.example.com", + "template.app-created": "email:\n subject: Application {{.app.metadata.name}} has been created.\nmessage: Application {{.app.metadata.name}} has been created.\nteams:\n title: Application {{.app.metadata.name}} has been created.\n", + "trigger.on-created": "- description: Application is created.\n oncePer: app.metadata.name\n send:\n - app-created\n when: \"true\"\n", + }, + } + notificationsSecret := corev1.Secret{ + ObjectMeta: v1.ObjectMeta{ + Name: "argocd-notifications-secret", + Namespace: testNamespace, + }, + Data: map[string][]byte{ + "notification-secret": []byte("secret-value"), + }, + } + kubeclientset := fake.NewSimpleClientset(&corev1.ConfigMap{ + ObjectMeta: v1.ObjectMeta{ + Namespace: testNamespace, + Name: "argocd-notifications-cm", + }, + Data: notificationsCm.Data, + }, + &corev1.Secret{ + ObjectMeta: v1.ObjectMeta{ + Name: "argocd-notifications-secret", + Namespace: testNamespace, + }, + Data: notificationsSecret.Data, + }) + mockRepoClient := &mocks.Clientset{RepoServerServiceClient: &mocks.RepoServerServiceClient{}} + argocdService, err := service.NewArgoCDService(kubeclientset, testNamespace, mockRepoClient) + require.NoError(t, err) + defer argocdService.Close() + config := api.Config{} + testDestination := services.Destination{ + Service: "webhook", + } + emptyAppData := map[string]interface{}{} + + varsProvider, _ := initGetVars(argocdService, &config, ¬ificationsCm, ¬ificationsSecret) + + t.Run("Vars provider serves Application data on app key", func(t *testing.T) { + appData := map[string]interface{}{ + "name": "app-name", + } + result := varsProvider(appData, testDestination) + assert.NotNil(t, t, result["app"]) + assert.Equal(t, result["app"], appData) + }) + t.Run("Vars provider serves notification context data on context key", func(t *testing.T) { + expectedContext := map[string]string{ + testContextKey: testContextKeyValue, + "notificationType": testDestination.Service, + } + result := varsProvider(emptyAppData, testDestination) + assert.NotNil(t, result["context"]) + assert.Equal(t, result["context"], expectedContext) + }) + t.Run("Vars provider serves notification secrets on secrets key", func(t *testing.T) { + result := varsProvider(emptyAppData, testDestination) + assert.NotNil(t, result["secrets"]) + assert.Equal(t, result["secrets"], notificationsSecret.Data) + }) +} diff --git a/util/oidc/oidc.go b/util/oidc/oidc.go index 3df3166490172..2c376cc7e5b5b 100644 --- a/util/oidc/oidc.go +++ b/util/oidc/oidc.go @@ -6,6 +6,7 @@ import ( "fmt" "html" "html/template" + "io" "net" "net/http" "net/url" @@ -21,9 +22,12 @@ import ( "github.com/argoproj/argo-cd/v2/common" "github.com/argoproj/argo-cd/v2/server/settings/oidc" + "github.com/argoproj/argo-cd/v2/util/cache" "github.com/argoproj/argo-cd/v2/util/crypto" "github.com/argoproj/argo-cd/v2/util/dex" + httputil "github.com/argoproj/argo-cd/v2/util/http" + jwtutil "github.com/argoproj/argo-cd/v2/util/jwt" "github.com/argoproj/argo-cd/v2/util/rand" "github.com/argoproj/argo-cd/v2/util/settings" ) @@ -31,9 +35,11 @@ import ( var InvalidRedirectURLError = fmt.Errorf("invalid return URL") const ( - GrantTypeAuthorizationCode = "authorization_code" - GrantTypeImplicit = "implicit" - ResponseTypeCode = "code" + GrantTypeAuthorizationCode = "authorization_code" + GrantTypeImplicit = "implicit" + ResponseTypeCode = "code" + UserInfoResponseCachePrefix = "userinfo_response" + AccessTokenCachePrefix = "access_token" ) // OIDCConfiguration holds a subset of interested fields from the OIDC configuration spec @@ -57,6 +63,8 @@ type ClientApp struct { redirectURI string // URL of the issuer (e.g. https://argocd.example.com/api/dex) issuerURL string + // the path where the issuer providers user information (e.g /user-info for okta) + userInfoPath string // The URL endpoint at which the ArgoCD server is accessed. baseHRef string // client is the HTTP client which is used to query the IDp @@ -70,6 +78,8 @@ type ClientApp struct { encryptionKey []byte // provider is the OIDC provider provider Provider + // clientCache represent a cache of sso artifact + clientCache cache.CacheClient } func GetScopesOrDefault(scopes []string) []string { @@ -81,7 +91,7 @@ func GetScopesOrDefault(scopes []string) []string { // NewClientApp will register the Argo CD client app (either via Dex or external OIDC) and return an // object which has HTTP handlers for handling the HTTP responses for login and callback -func NewClientApp(settings *settings.ArgoCDSettings, dexServerAddr string, dexTlsConfig *dex.DexTLSConfig, baseHRef string) (*ClientApp, error) { +func NewClientApp(settings *settings.ArgoCDSettings, dexServerAddr string, dexTlsConfig *dex.DexTLSConfig, baseHRef string, cacheClient cache.CacheClient) (*ClientApp, error) { redirectURL, err := settings.RedirectURL() if err != nil { return nil, err @@ -95,8 +105,10 @@ func NewClientApp(settings *settings.ArgoCDSettings, dexServerAddr string, dexTl clientSecret: settings.OAuth2ClientSecret(), redirectURI: redirectURL, issuerURL: settings.IssuerURL(), + userInfoPath: settings.UserInfoPath(), baseHRef: baseHRef, encryptionKey: encryptionKey, + clientCache: cacheClient, } log.Infof("Creating client app (%s)", a.clientID) u, err := url.Parse(settings.URL) @@ -376,6 +388,26 @@ func (a *ClientApp) HandleCallback(w http.ResponseWriter, r *http.Request) { http.Error(w, err.Error(), http.StatusInternalServerError) return } + // save the accessToken in memory for later use + encToken, err := crypto.Encrypt([]byte(token.AccessToken), a.encryptionKey) + if err != nil { + claimsJSON, _ := json.Marshal(claims) + http.Error(w, "failed encrypting token", http.StatusInternalServerError) + log.Errorf("cannot encrypt accessToken: %v (claims=%s)", err, claimsJSON) + return + } + sub := jwtutil.StringField(claims, "sub") + err = a.clientCache.Set(&cache.Item{ + Key: formatAccessTokenCacheKey(AccessTokenCachePrefix, sub), + Object: encToken, + Expiration: getTokenExpiration(claims), + }) + if err != nil { + claimsJSON, _ := json.Marshal(claims) + http.Error(w, fmt.Sprintf("claims=%s, err=%v", claimsJSON, err), http.StatusInternalServerError) + return + } + if idTokenRAW != "" { cookies, err := httputil.MakeCookieMetadata(common.AuthCookieName, idTokenRAW, flags...) if err != nil { @@ -509,3 +541,145 @@ func createClaimsAuthenticationRequestParameter(requestedClaims map[string]*oidc } return oauth2.SetAuthURLParam("claims", string(claimsRequestRAW)), nil } + +// GetUserInfo queries the IDP userinfo endpoint for claims +func (a *ClientApp) GetUserInfo(actualClaims jwt.MapClaims, issuerURL, userInfoPath string) (jwt.MapClaims, bool, error) { + sub := jwtutil.StringField(actualClaims, "sub") + var claims jwt.MapClaims + var encClaims []byte + + // in case we got it in the cache, we just return the item + clientCacheKey := formatUserInfoResponseCacheKey(UserInfoResponseCachePrefix, sub) + if err := a.clientCache.Get(clientCacheKey, &encClaims); err == nil { + claimsRaw, err := crypto.Decrypt(encClaims, a.encryptionKey) + if err != nil { + log.Errorf("decrypting the cached claims failed (sub=%s): %s", sub, err) + } else { + err = json.Unmarshal(claimsRaw, &claims) + if err != nil { + log.Errorf("cannot unmarshal cached claims structure: %s", err) + } else { + // return the cached claims since they are not yet expired, were successfully decrypted and unmarshaled + return claims, false, err + } + } + } + + // check if the accessToken for the user is still present + var encAccessToken []byte + err := a.clientCache.Get(formatAccessTokenCacheKey(AccessTokenCachePrefix, sub), &encAccessToken) + // without an accessToken we can't query the user info endpoint + // thus the user needs to reauthenticate for argocd to get a new accessToken + if err == cache.ErrCacheMiss { + return claims, true, fmt.Errorf("no accessToken for %s: %w", sub, err) + } else if err != nil { + return claims, true, fmt.Errorf("couldn't read accessToken from cache for %s: %w", sub, err) + } + + accessToken, err := crypto.Decrypt(encAccessToken, a.encryptionKey) + if err != nil { + return claims, true, fmt.Errorf("couldn't decrypt accessToken for %s: %w", sub, err) + } + + url := issuerURL + userInfoPath + request, err := http.NewRequest("GET", url, nil) + + if err != nil { + err = fmt.Errorf("failed creating new http request: %w", err) + return claims, false, err + } + + bearer := fmt.Sprintf("Bearer %s", accessToken) + request.Header.Set("Authorization", bearer) + + response, err := a.client.Do(request) + if err != nil { + return claims, false, fmt.Errorf("failed to query userinfo endpoint of IDP: %w", err) + } + defer response.Body.Close() + if response.StatusCode == http.StatusUnauthorized { + return claims, true, err + } + + // according to https://openid.net/specs/openid-connect-core-1_0.html#UserInfoResponseValidation + // the response should be validated + header := response.Header.Get("content-type") + rawBody, err := io.ReadAll(response.Body) + if err != nil { + return claims, false, fmt.Errorf("got error reading response body: %w", err) + } + switch header { + case "application/jwt": + // if body is JWT, first validate it before extracting claims + idToken, err := a.provider.Verify(string(rawBody), a.settings) + if err != nil { + return claims, false, fmt.Errorf("user info response in jwt format not valid: %w", err) + } + err = idToken.Claims(claims) + if err != nil { + return claims, false, fmt.Errorf("cannot get claims from userinfo jwt: %w", err) + } + default: + // if body is json, unsigned and unencrypted claims can be deserialized + err = json.Unmarshal(rawBody, &claims) + if err != nil { + return claims, false, fmt.Errorf("failed to decode response body to struct: %w", err) + } + } + + // in case response was successfully validated and there was no error, put item in cache + // but first let's determine the expiry of the cache + var cacheExpiry time.Duration + settingExpiry := a.settings.UserInfoCacheExpiration() + tokenExpiry := getTokenExpiration(claims) + + // only use configured expiry if the token lives longer and the expiry is configured + // if the token has no expiry, use the expiry of the actual token + // otherwise use the expiry of the token + if settingExpiry < tokenExpiry && settingExpiry != 0 { + cacheExpiry = settingExpiry + } else if tokenExpiry < 0 { + cacheExpiry = getTokenExpiration(actualClaims) + } else { + cacheExpiry = tokenExpiry + } + + rawClaims, err := json.Marshal(claims) + if err != nil { + return claims, false, fmt.Errorf("couldn't marshal claim to json: %w", err) + } + encClaims, err = crypto.Encrypt(rawClaims, a.encryptionKey) + if err != nil { + return claims, false, fmt.Errorf("couldn't encrypt user info response: %w", err) + } + + err = a.clientCache.Set(&cache.Item{ + Key: clientCacheKey, + Object: encClaims, + Expiration: cacheExpiry, + }) + if err != nil { + return claims, false, fmt.Errorf("couldn't put item to cache: %w", err) + } + + return claims, false, nil +} + +// getTokenExpiration returns a time.Duration until the token expires +func getTokenExpiration(claims jwt.MapClaims) time.Duration { + // get duration until token expires + exp := jwtutil.Float64Field(claims, "exp") + tm := time.Unix(int64(exp), 0) + tokenExpiry := time.Until(tm) + return tokenExpiry +} + +// formatUserInfoResponseCacheKey returns the key which is used to store userinfo of user in cache +func formatUserInfoResponseCacheKey(prefix, sub string) string { + return fmt.Sprintf("%s_%s", UserInfoResponseCachePrefix, sub) +} + +// formatAccessTokenCacheKey returns the key which is used to store the accessToken of a user in cache +func formatAccessTokenCacheKey(prefix, sub string) string { + return fmt.Sprintf("%s_%s", prefix, sub) +} diff --git a/util/oidc/oidc_test.go b/util/oidc/oidc_test.go index fe5fa77eed3b5..cd1d3fa1bf789 100644 --- a/util/oidc/oidc_test.go +++ b/util/oidc/oidc_test.go @@ -11,8 +11,10 @@ import ( "os" "strings" "testing" + "time" gooidc "github.com/coreos/go-oidc/v3/oidc" + "github.com/golang-jwt/jwt/v4" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "golang.org/x/oauth2" @@ -20,6 +22,7 @@ import ( "github.com/argoproj/argo-cd/v2/common" "github.com/argoproj/argo-cd/v2/server/settings/oidc" "github.com/argoproj/argo-cd/v2/util" + "github.com/argoproj/argo-cd/v2/util/cache" "github.com/argoproj/argo-cd/v2/util/crypto" "github.com/argoproj/argo-cd/v2/util/dex" "github.com/argoproj/argo-cd/v2/util/settings" @@ -126,7 +129,7 @@ clientID: xxx clientSecret: yyy requestedScopes: ["oidc"]`, oidcTestServer.URL), } - app, err := NewClientApp(cdSettings, dexTestServer.URL, nil, "https://argocd.example.com") + app, err := NewClientApp(cdSettings, dexTestServer.URL, nil, "https://argocd.example.com", cache.NewInMemoryCache(24*time.Hour)) require.NoError(t, err) req := httptest.NewRequest(http.MethodGet, "https://argocd.example.com/auth/login", nil) @@ -141,7 +144,7 @@ requestedScopes: ["oidc"]`, oidcTestServer.URL), cdSettings.OIDCTLSInsecureSkipVerify = true - app, err = NewClientApp(cdSettings, dexTestServer.URL, nil, "https://argocd.example.com") + app, err = NewClientApp(cdSettings, dexTestServer.URL, nil, "https://argocd.example.com", cache.NewInMemoryCache(24*time.Hour)) require.NoError(t, err) w = httptest.NewRecorder() @@ -166,7 +169,7 @@ requestedScopes: ["oidc"]`, oidcTestServer.URL), require.NoError(t, err) cdSettings.Certificate = &cert - app, err := NewClientApp(cdSettings, dexTestServer.URL, nil, "https://argocd.example.com") + app, err := NewClientApp(cdSettings, dexTestServer.URL, nil, "https://argocd.example.com", cache.NewInMemoryCache(24*time.Hour)) require.NoError(t, err) req := httptest.NewRequest(http.MethodGet, "https://argocd.example.com/auth/login", nil) @@ -179,7 +182,7 @@ requestedScopes: ["oidc"]`, oidcTestServer.URL), t.Fatal("did not receive expected certificate verification failure error") } - app, err = NewClientApp(cdSettings, dexTestServer.URL, &dex.DexTLSConfig{StrictValidation: false}, "https://argocd.example.com") + app, err = NewClientApp(cdSettings, dexTestServer.URL, &dex.DexTLSConfig{StrictValidation: false}, "https://argocd.example.com", cache.NewInMemoryCache(24*time.Hour)) require.NoError(t, err) w = httptest.NewRecorder() @@ -211,7 +214,7 @@ requestedScopes: ["oidc"]`, oidcTestServer.URL), // The base href (the last argument for NewClientApp) is what HandleLogin will fall back to when no explicit // redirect URL is given. - app, err := NewClientApp(cdSettings, "", nil, "/") + app, err := NewClientApp(cdSettings, "", nil, "/", cache.NewInMemoryCache(24*time.Hour)) require.NoError(t, err) w := httptest.NewRecorder() @@ -254,7 +257,7 @@ clientID: xxx clientSecret: yyy requestedScopes: ["oidc"]`, oidcTestServer.URL), } - app, err := NewClientApp(cdSettings, dexTestServer.URL, nil, "https://argocd.example.com") + app, err := NewClientApp(cdSettings, dexTestServer.URL, nil, "https://argocd.example.com", cache.NewInMemoryCache(24*time.Hour)) require.NoError(t, err) req := httptest.NewRequest(http.MethodGet, "https://argocd.example.com/auth/callback", nil) @@ -269,7 +272,7 @@ requestedScopes: ["oidc"]`, oidcTestServer.URL), cdSettings.OIDCTLSInsecureSkipVerify = true - app, err = NewClientApp(cdSettings, dexTestServer.URL, nil, "https://argocd.example.com") + app, err = NewClientApp(cdSettings, dexTestServer.URL, nil, "https://argocd.example.com", cache.NewInMemoryCache(24*time.Hour)) require.NoError(t, err) w = httptest.NewRecorder() @@ -294,7 +297,7 @@ requestedScopes: ["oidc"]`, oidcTestServer.URL), require.NoError(t, err) cdSettings.Certificate = &cert - app, err := NewClientApp(cdSettings, dexTestServer.URL, nil, "https://argocd.example.com") + app, err := NewClientApp(cdSettings, dexTestServer.URL, nil, "https://argocd.example.com", cache.NewInMemoryCache(24*time.Hour)) require.NoError(t, err) req := httptest.NewRequest(http.MethodGet, "https://argocd.example.com/auth/callback", nil) @@ -307,7 +310,7 @@ requestedScopes: ["oidc"]`, oidcTestServer.URL), t.Fatal("did not receive expected certificate verification failure error") } - app, err = NewClientApp(cdSettings, dexTestServer.URL, &dex.DexTLSConfig{StrictValidation: false}, "https://argocd.example.com") + app, err = NewClientApp(cdSettings, dexTestServer.URL, &dex.DexTLSConfig{StrictValidation: false}, "https://argocd.example.com", cache.NewInMemoryCache(24*time.Hour)) require.NoError(t, err) w = httptest.NewRecorder() @@ -406,7 +409,7 @@ func TestGenerateAppState(t *testing.T) { signature, err := util.MakeSignature(32) require.NoError(t, err) expectedReturnURL := "http://argocd.example.com/" - app, err := NewClientApp(&settings.ArgoCDSettings{ServerSignature: signature, URL: expectedReturnURL}, "", nil, "") + app, err := NewClientApp(&settings.ArgoCDSettings{ServerSignature: signature, URL: expectedReturnURL}, "", nil, "", cache.NewInMemoryCache(24*time.Hour)) require.NoError(t, err) generateResponse := httptest.NewRecorder() state, err := app.generateAppState(expectedReturnURL, generateResponse) @@ -443,7 +446,7 @@ func TestGenerateAppState_XSS(t *testing.T) { URL: "https://argocd.example.com", ServerSignature: signature, }, - "", nil, "", + "", nil, "", cache.NewInMemoryCache(24*time.Hour), ) require.NoError(t, err) @@ -495,7 +498,7 @@ func TestGenerateAppState_NoReturnURL(t *testing.T) { encrypted, err := crypto.Encrypt([]byte("123"), key) require.NoError(t, err) - app, err := NewClientApp(cdSettings, "", nil, "/argo-cd") + app, err := NewClientApp(cdSettings, "", nil, "/argo-cd", cache.NewInMemoryCache(24*time.Hour)) require.NoError(t, err) req.AddCookie(&http.Cookie{Name: common.StateCookieName, Value: hex.EncodeToString(encrypted)}) @@ -503,3 +506,270 @@ func TestGenerateAppState_NoReturnURL(t *testing.T) { assert.NoError(t, err) assert.Equal(t, "/argo-cd", returnURL) } + +func TestGetUserInfo(t *testing.T) { + + var tests = []struct { + name string + userInfoPath string + expectedOutput interface{} + expectError bool + expectUnauthenticated bool + expectedCacheItems []struct { // items to check in cache after function call + key string + value string + expectEncrypted bool + expectError bool + } + idpHandler func(w http.ResponseWriter, r *http.Request) + idpClaims jwt.MapClaims // as per specification sub and exp are REQUIRED fields + cache cache.CacheClient + cacheItems []struct { // items to put in cache before execution + key string + value string + encrypt bool + } + }{ + { + name: "call UserInfo with wrong userInfoPath", + userInfoPath: "/user", + expectedOutput: jwt.MapClaims(nil), + expectError: true, + expectUnauthenticated: false, + expectedCacheItems: []struct { + key string + value string + expectEncrypted bool + expectError bool + }{ + { + key: formatUserInfoResponseCacheKey(UserInfoResponseCachePrefix, "randomUser"), + expectError: true, + }, + }, + idpClaims: jwt.MapClaims{"sub": "randomUser", "exp": float64(time.Now().Add(5 * time.Minute).Unix())}, + idpHandler: func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusNotFound) + }, + cache: cache.NewInMemoryCache(24 * time.Hour), + cacheItems: []struct { + key string + value string + encrypt bool + }{ + { + key: formatAccessTokenCacheKey(AccessTokenCachePrefix, "randomUser"), + value: "FakeAccessToken", + encrypt: true, + }, + }, + }, + { + name: "call UserInfo with bad accessToken", + userInfoPath: "/user-info", + expectedOutput: jwt.MapClaims(nil), + expectError: false, + expectUnauthenticated: true, + expectedCacheItems: []struct { + key string + value string + expectEncrypted bool + expectError bool + }{ + { + key: formatUserInfoResponseCacheKey(UserInfoResponseCachePrefix, "randomUser"), + expectError: true, + }, + }, + idpClaims: jwt.MapClaims{"sub": "randomUser", "exp": float64(time.Now().Add(5 * time.Minute).Unix())}, + idpHandler: func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusUnauthorized) + }, + cache: cache.NewInMemoryCache(24 * time.Hour), + cacheItems: []struct { + key string + value string + encrypt bool + }{ + { + key: formatAccessTokenCacheKey(AccessTokenCachePrefix, "randomUser"), + value: "FakeAccessToken", + encrypt: true, + }, + }, + }, + { + name: "call UserInfo with garbage returned", + userInfoPath: "/user-info", + expectedOutput: jwt.MapClaims(nil), + expectError: true, + expectUnauthenticated: false, + expectedCacheItems: []struct { + key string + value string + expectEncrypted bool + expectError bool + }{ + { + key: formatUserInfoResponseCacheKey(UserInfoResponseCachePrefix, "randomUser"), + expectError: true, + }, + }, + idpClaims: jwt.MapClaims{"sub": "randomUser", "exp": float64(time.Now().Add(5 * time.Minute).Unix())}, + idpHandler: func(w http.ResponseWriter, r *http.Request) { + userInfoBytes := ` + notevenJsongarbage + ` + _, err := w.Write([]byte(userInfoBytes)) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + return + } + w.WriteHeader(http.StatusTeapot) + }, + cache: cache.NewInMemoryCache(24 * time.Hour), + cacheItems: []struct { + key string + value string + encrypt bool + }{ + { + key: formatAccessTokenCacheKey(AccessTokenCachePrefix, "randomUser"), + value: "FakeAccessToken", + encrypt: true, + }, + }, + }, + { + name: "call UserInfo without accessToken in cache", + userInfoPath: "/user-info", + expectedOutput: jwt.MapClaims(nil), + expectError: true, + expectUnauthenticated: true, + expectedCacheItems: []struct { + key string + value string + expectEncrypted bool + expectError bool + }{ + { + key: formatUserInfoResponseCacheKey(UserInfoResponseCachePrefix, "randomUser"), + expectError: true, + }, + }, + idpClaims: jwt.MapClaims{"sub": "randomUser", "exp": float64(time.Now().Add(5 * time.Minute).Unix())}, + idpHandler: func(w http.ResponseWriter, r *http.Request) { + userInfoBytes := ` + { + "groups":["githubOrg:engineers"] + }` + w.Header().Set("content-type", "application/json") + _, err := w.Write([]byte(userInfoBytes)) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + return + } + w.WriteHeader(http.StatusOK) + }, + cache: cache.NewInMemoryCache(24 * time.Hour), + }, + { + name: "call UserInfo with valid accessToken in cache", + userInfoPath: "/user-info", + expectedOutput: jwt.MapClaims{"groups": []interface{}{"githubOrg:engineers"}}, + expectError: false, + expectUnauthenticated: false, + expectedCacheItems: []struct { + key string + value string + expectEncrypted bool + expectError bool + }{ + { + key: formatUserInfoResponseCacheKey(UserInfoResponseCachePrefix, "randomUser"), + value: "{\"groups\":[\"githubOrg:engineers\"]}", + expectEncrypted: true, + expectError: false, + }, + }, + idpClaims: jwt.MapClaims{"sub": "randomUser", "exp": float64(time.Now().Add(5 * time.Minute).Unix())}, + idpHandler: func(w http.ResponseWriter, r *http.Request) { + userInfoBytes := ` + { + "groups":["githubOrg:engineers"] + }` + w.Header().Set("content-type", "application/json") + _, err := w.Write([]byte(userInfoBytes)) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + return + } + w.WriteHeader(http.StatusOK) + }, + cache: cache.NewInMemoryCache(24 * time.Hour), + cacheItems: []struct { + key string + value string + encrypt bool + }{ + { + key: formatAccessTokenCacheKey(AccessTokenCachePrefix, "randomUser"), + value: "FakeAccessToken", + encrypt: true, + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(tt.idpHandler)) + defer ts.Close() + + signature, err := util.MakeSignature(32) + require.NoError(t, err) + cdSettings := &settings.ArgoCDSettings{ServerSignature: signature} + encryptionKey, err := cdSettings.GetServerEncryptionKey() + assert.NoError(t, err) + a, _ := NewClientApp(cdSettings, "", nil, "/argo-cd", tt.cache) + + for _, item := range tt.cacheItems { + var newValue []byte + newValue = []byte(item.value) + if item.encrypt { + newValue, err = crypto.Encrypt([]byte(item.value), encryptionKey) + assert.NoError(t, err) + } + err := a.clientCache.Set(&cache.Item{ + Key: item.key, + Object: newValue, + }) + require.NoError(t, err) + } + + got, unauthenticated, err := a.GetUserInfo(tt.idpClaims, ts.URL, tt.userInfoPath) + assert.Equal(t, tt.expectedOutput, got) + assert.Equal(t, tt.expectUnauthenticated, unauthenticated) + if tt.expectError { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + for _, item := range tt.expectedCacheItems { + var tmpValue []byte + err := a.clientCache.Get(item.key, &tmpValue) + if item.expectError { + require.Error(t, err) + } else { + require.NoError(t, err) + if item.expectEncrypted { + tmpValue, err = crypto.Decrypt(tmpValue, encryptionKey) + require.NoError(t, err) + } + assert.Equal(t, item.value, string(tmpValue)) + } + } + }) + } + +} diff --git a/util/oidc/provider.go b/util/oidc/provider.go index fcb1a95b60f4f..d75bcf97efecd 100644 --- a/util/oidc/provider.go +++ b/util/oidc/provider.go @@ -73,6 +73,18 @@ func (p *providerImpl) newGoOIDCProvider() (*gooidc.Provider, error) { return prov, nil } +type tokenVerificationError struct { + errorsByAudience map[string]error +} + +func (t tokenVerificationError) Error() string { + var errorStrings []string + for aud, err := range t.errorsByAudience { + errorStrings = append(errorStrings, fmt.Sprintf("error for aud %q: %v", aud, err)) + } + return fmt.Sprintf("token verification failed for all audiences: %s", strings.Join(errorStrings, ", ")) +} + func (p *providerImpl) Verify(tokenString string, argoSettings *settings.ArgoCDSettings) (*gooidc.IDToken, error) { // According to the JWT spec, the aud claim is optional. The spec also says (emphasis mine): // @@ -104,6 +116,7 @@ func (p *providerImpl) Verify(tokenString string, argoSettings *settings.ArgoCDS if len(allowedAudiences) == 0 { return nil, errors.New("token has an audience claim, but no allowed audiences are configured") } + tokenVerificationErrors := make(map[string]error) // Token must be verified for at least one allowed audience for _, aud := range allowedAudiences { idToken, err = p.verify(aud, tokenString, false) @@ -117,6 +130,13 @@ func (p *providerImpl) Verify(tokenString string, argoSettings *settings.ArgoCDS if err == nil { break } + // We store the error for each audience so that we can return a more detailed error message to the user. + // If this gets merged, we'll be able to detect failures unrelated to audiences and short-circuit this loop + // to avoid logging irrelevant warnings: https://github.com/coreos/go-oidc/pull/406 + tokenVerificationErrors[aud] = err + } + if len(tokenVerificationErrors) > 0 { + err = tokenVerificationError{errorsByAudience: tokenVerificationErrors} } } diff --git a/util/rbac/rbac.go b/util/rbac/rbac.go index d0c4ca65630cf..aa487436378e1 100644 --- a/util/rbac/rbac.go +++ b/util/rbac/rbac.go @@ -363,7 +363,7 @@ func (e *Enforcer) RunPolicyLoader(ctx context.Context, onUpdated func(cm *apiv1 func (e *Enforcer) runInformer(ctx context.Context, onUpdated func(cm *apiv1.ConfigMap) error) { cmInformer := e.newInformer() - cmInformer.AddEventHandler( + _, err := cmInformer.AddEventHandler( cache.ResourceEventHandlerFuncs{ AddFunc: func(obj interface{}) { if cm, ok := obj.(*apiv1.ConfigMap); ok { @@ -390,6 +390,9 @@ func (e *Enforcer) runInformer(ctx context.Context, onUpdated func(cm *apiv1.Con }, }, ) + if err != nil { + log.Error(err) + } log.Info("Starting rbac config informer") cmInformer.Run(ctx.Done()) log.Info("rbac configmap informer cancelled") diff --git a/util/settings/settings.go b/util/settings/settings.go index b992a32ed164d..baff450aa817e 100644 --- a/util/settings/settings.go +++ b/util/settings/settings.go @@ -30,6 +30,9 @@ import ( "k8s.io/client-go/tools/cache" "sigs.k8s.io/yaml" + enginecache "github.com/argoproj/gitops-engine/pkg/cache" + timeutil "github.com/argoproj/pkg/time" + "github.com/argoproj/argo-cd/v2/common" "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" "github.com/argoproj/argo-cd/v2/server/settings/oidc" @@ -38,8 +41,6 @@ import ( "github.com/argoproj/argo-cd/v2/util/kube" "github.com/argoproj/argo-cd/v2/util/password" tlsutil "github.com/argoproj/argo-cd/v2/util/tls" - enginecache "github.com/argoproj/gitops-engine/pkg/cache" - timeutil "github.com/argoproj/pkg/time" ) // ArgoCDSettings holds in-memory runtime configuration options. @@ -155,28 +156,36 @@ func (o *oidcConfig) toExported() *OIDCConfig { return nil } return &OIDCConfig{ - Name: o.Name, - Issuer: o.Issuer, - ClientID: o.ClientID, - ClientSecret: o.ClientSecret, - CLIClientID: o.CLIClientID, - RequestedScopes: o.RequestedScopes, - RequestedIDTokenClaims: o.RequestedIDTokenClaims, - LogoutURL: o.LogoutURL, - RootCA: o.RootCA, + Name: o.Name, + Issuer: o.Issuer, + ClientID: o.ClientID, + ClientSecret: o.ClientSecret, + CLIClientID: o.CLIClientID, + UserInfoPath: o.UserInfoPath, + EnableUserInfoGroups: o.EnableUserInfoGroups, + UserInfoCacheExpiration: o.UserInfoCacheExpiration, + RequestedScopes: o.RequestedScopes, + RequestedIDTokenClaims: o.RequestedIDTokenClaims, + LogoutURL: o.LogoutURL, + RootCA: o.RootCA, + EnablePKCEAuthentication: o.EnablePKCEAuthentication, } } type OIDCConfig struct { - Name string `json:"name,omitempty"` - Issuer string `json:"issuer,omitempty"` - ClientID string `json:"clientID,omitempty"` - ClientSecret string `json:"clientSecret,omitempty"` - CLIClientID string `json:"cliClientID,omitempty"` - RequestedScopes []string `json:"requestedScopes,omitempty"` - RequestedIDTokenClaims map[string]*oidc.Claim `json:"requestedIDTokenClaims,omitempty"` - LogoutURL string `json:"logoutURL,omitempty"` - RootCA string `json:"rootCA,omitempty"` + Name string `json:"name,omitempty"` + Issuer string `json:"issuer,omitempty"` + ClientID string `json:"clientID,omitempty"` + ClientSecret string `json:"clientSecret,omitempty"` + CLIClientID string `json:"cliClientID,omitempty"` + EnableUserInfoGroups bool `json:"enableUserInfoGroups,omitempty"` + UserInfoPath string `json:"userInfoPath,omitempty"` + UserInfoCacheExpiration string `json:"userInfoCacheExpiration,omitempty"` + RequestedScopes []string `json:"requestedScopes,omitempty"` + RequestedIDTokenClaims map[string]*oidc.Claim `json:"requestedIDTokenClaims,omitempty"` + LogoutURL string `json:"logoutURL,omitempty"` + RootCA string `json:"rootCA,omitempty"` + EnablePKCEAuthentication bool `json:"enablePKCEAuthentication,omitempty"` } // DEPRECATED. Helm repository credentials are now managed using RepoCredentials @@ -1324,8 +1333,15 @@ func (mgr *SettingsManager) initialize(ctx context.Context) error { } cmInformer := v1.NewFilteredConfigMapInformer(mgr.clientset, mgr.namespace, 3*time.Minute, indexers, tweakConfigMap) secretsInformer := v1.NewSecretInformer(mgr.clientset, mgr.namespace, 3*time.Minute, indexers) - cmInformer.AddEventHandler(eventHandler) - secretsInformer.AddEventHandler(eventHandler) + _, err := cmInformer.AddEventHandler(eventHandler) + if err != nil { + log.Error(err) + } + + _, err = secretsInformer.AddEventHandler(eventHandler) + if err != nil { + log.Error(err) + } log.Info("Starting configmap/secret informers") go func() { @@ -1368,8 +1384,14 @@ func (mgr *SettingsManager) initialize(ctx context.Context) error { } }, } - secretsInformer.AddEventHandler(handler) - cmInformer.AddEventHandler(handler) + _, err = secretsInformer.AddEventHandler(handler) + if err != nil { + log.Error(err) + } + _, err = cmInformer.AddEventHandler(handler) + if err != nil { + log.Error(err) + } mgr.secrets = v1listers.NewSecretLister(secretsInformer.GetIndexer()) mgr.secretsInformer = secretsInformer mgr.configmaps = v1listers.NewConfigMapLister(cmInformer.GetIndexer()) @@ -1834,6 +1856,34 @@ func (a *ArgoCDSettings) IssuerURL() string { return "" } +// UserInfoGroupsEnabled returns whether group claims should be fetch from UserInfo endpoint +func (a *ArgoCDSettings) UserInfoGroupsEnabled() bool { + if oidcConfig := a.OIDCConfig(); oidcConfig != nil { + return oidcConfig.EnableUserInfoGroups + } + return false +} + +// UserInfoPath returns the sub-path on which the IDP exposes the UserInfo endpoint +func (a *ArgoCDSettings) UserInfoPath() string { + if oidcConfig := a.OIDCConfig(); oidcConfig != nil { + return oidcConfig.UserInfoPath + } + return "" +} + +// UserInfoCacheExpiration returns the expiry time of the UserInfo cache +func (a *ArgoCDSettings) UserInfoCacheExpiration() time.Duration { + if oidcConfig := a.OIDCConfig(); oidcConfig != nil && oidcConfig.UserInfoCacheExpiration != "" { + userInfoCacheExpiration, err := time.ParseDuration(oidcConfig.UserInfoCacheExpiration) + if err != nil { + log.Warnf("Failed to parse 'oidc.config.userInfoCacheExpiration' key: %v", err) + } + return userInfoCacheExpiration + } + return 0 +} + func (a *ArgoCDSettings) OAuth2ClientID() string { if oidcConfig := a.OIDCConfig(); oidcConfig != nil { return oidcConfig.ClientID diff --git a/util/test/testutil.go b/util/test/testutil.go index 6fdbd4151d82c..bb6c43313358c 100644 --- a/util/test/testutil.go +++ b/util/test/testutil.go @@ -8,9 +8,9 @@ import ( "net/http/httptest" "testing" + "github.com/go-jose/go-jose/v3" "github.com/golang-jwt/jwt/v4" "github.com/stretchr/testify/require" - "gopkg.in/square/go-jose.v2" ) // Cert is a certificate for tests. It was generated like this: @@ -168,6 +168,16 @@ func oidcMockHandler(t *testing.T, url string) func(http.ResponseWriter, *http.R "token_endpoint_auth_methods_supported": ["client_secret_basic", "client_secret_post"], "claims_supported": ["sub", "aud", "exp"] }`, url)) + require.NoError(t, err) + case "/userinfo": + w.Header().Set("content-type", "application/json") + _, err := io.WriteString(w, fmt.Sprintf(` +{ + "groups":["githubOrg:engineers"], + "iss": "%[1]s", + "sub": "randomUser" +}`, url)) + require.NoError(t, err) case "/keys": pubKey, err := jwt.ParseRSAPublicKeyFromPEM(Cert) diff --git a/util/trace/trace.go b/util/trace/trace.go index 64a0361dfa3d5..9d281bf0d4c76 100644 --- a/util/trace/trace.go +++ b/util/trace/trace.go @@ -13,10 +13,11 @@ import ( "go.opentelemetry.io/otel/sdk/resource" sdktrace "go.opentelemetry.io/otel/sdk/trace" semconv "go.opentelemetry.io/otel/semconv/v1.6.1" + "google.golang.org/grpc/credentials" ) // InitTracer initializes the trace provider and the otel grpc exporter. -func InitTracer(ctx context.Context, serviceName, otlpAddress string, otlpAttrs []string) (func(), error) { +func InitTracer(ctx context.Context, serviceName, otlpAddress string, otlpInsecure bool, otlpHeaders map[string]string, otlpAttrs []string) (func(), error) { attrs := make([]attribute.KeyValue, 0, len(otlpAttrs)) for i := range otlpAttrs { attr := otlpAttrs[i] @@ -38,10 +39,19 @@ func InitTracer(ctx context.Context, serviceName, otlpAddress string, otlpAttrs return nil, fmt.Errorf("failed to create resource: %w", err) } - // Set up a trace exporter + // set up grpc options based on secure/insecure connection + var secureOption otlptracegrpc.Option + if otlpInsecure { + secureOption = otlptracegrpc.WithInsecure() + } else { + secureOption = otlptracegrpc.WithTLSCredentials(credentials.NewClientTLSFromCert(nil, "")) + } + + // set up a trace exporter exporter, err := otlptracegrpc.New(ctx, - otlptracegrpc.WithInsecure(), + secureOption, otlptracegrpc.WithEndpoint(otlpAddress), + otlptracegrpc.WithHeaders(otlpHeaders), ) if err != nil { return nil, fmt.Errorf("failed to create trace exporter: %w", err) diff --git a/util/webhook/webhook.go b/util/webhook/webhook.go index 9955540ea04a9..25bd92e11802c 100644 --- a/util/webhook/webhook.go +++ b/util/webhook/webhook.go @@ -349,18 +349,12 @@ func (a *ArgoCDWebhookHandler) storePreviouslyCachedManifests(app *v1alpha1.Appl return fmt.Errorf("error getting ref sources: %w", err) } source := app.Spec.GetSource() - cache.LogDebugManifestCacheKeyFields("getting manifests cache", "webhook app revision changed", change.shaBefore, &source, refSources, &clusterInfo, app.Spec.Destination.Namespace, trackingMethod, appInstanceLabelKey, app.Name, nil) + cache.LogDebugManifestCacheKeyFields("moving manifests cache", "webhook app revision changed", change.shaBefore, &source, refSources, &clusterInfo, app.Spec.Destination.Namespace, trackingMethod, appInstanceLabelKey, app.Name, nil) - var cachedManifests cache.CachedManifestResponse - if err := a.repoCache.GetManifests(change.shaBefore, &source, refSources, &clusterInfo, app.Spec.Destination.Namespace, trackingMethod, appInstanceLabelKey, app.Name, &cachedManifests, nil); err != nil { + if err := a.repoCache.SetNewRevisionManifests(change.shaAfter, change.shaBefore, &source, refSources, &clusterInfo, app.Spec.Destination.Namespace, trackingMethod, appInstanceLabelKey, app.Name, nil); err != nil { return err } - cache.LogDebugManifestCacheKeyFields("setting manifests cache", "webhook app revision changed", change.shaAfter, &source, refSources, &clusterInfo, app.Spec.Destination.Namespace, trackingMethod, appInstanceLabelKey, app.Name, nil) - - if err = a.repoCache.SetManifests(change.shaAfter, &source, refSources, &clusterInfo, app.Spec.Destination.Namespace, trackingMethod, appInstanceLabelKey, app.Name, &cachedManifests, nil); err != nil { - return err - } return nil }